bitcoin

比特币钱包-btcwallet(五)接收区块,同步本地交易与UT

2019-10-17  本文已影响0人  链人成长chainerup

本文讲解钱包收到区块链发来的交易通知,同步交易的操作:
打开钱包,或者创建钱包之后,如果连接的区块链客户端不为空,则会调用SynchronizeRPC接口,准备接受请求。
比如OpenWallet的源码

func (s *loaderServer) OpenWallet(ctx context.Context, req *pb.OpenWalletRequest) (
    *pb.OpenWalletResponse, error) {

    // Use an insecure public passphrase when the request's is empty.
    pubPassphrase := req.PublicPassphrase
    if len(pubPassphrase) == 0 {
        pubPassphrase = []byte(wallet.InsecurePubPassphrase)
    }

    wallet, err := s.loader.OpenExistingWallet(pubPassphrase, false)
    if err != nil {
        return nil, translateError(err)
    }

    s.mu.Lock()
    if s.rpcClient != nil {
        // 打开同步RPC的接口。
        wallet.SynchronizeRPC(s.rpcClient)
    }
    s.mu.Unlock()

    return &pb.OpenWalletResponse{}, nil
}

在SynchronizeRPC 中启动了多个gorotine。

    go w.handleChainNotifications() // 处理来自区块链的消息,包括区块、交易的变换。
    go w.rescanBatchHandler() //
    go w.rescanProgressHandler()
    go w.rescanRPCHandler() // 

handleChainNotifications 中通知消息分了如下几种:(跟本文无关的代码省略了,只保留其对应的分支)

func (w *Wallet) handleChainNotifications() {
    defer w.wg.Done()
    log.Info("Welcome to zhangpeng's btcwallet , rpcClientConnectLoop in SynchronizeRPC, handleChainNotifications")

    chainClient, err := w.requireChainClient()
    if err != nil {
        log.Errorf("handleChainNotifications called without RPC client")
        return
    }

    for {
        select {
        case n, ok := <-chainClient.Notifications():
            if !ok {
                return
            }

            var notificationName string
            var err error
            switch n := n.(type) {
            case chain.ClientConnected:
                // 来自chain的连接请求。
                ...
            case chain.BlockConnected:
                // 区块已经连接的通知。
                ...
                notificationName = "block connected"
            case chain.BlockDisconnected:
                // 区块断开连接的通知
                ...
            case chain.RelevantTx:
                // 区块相关交易的通知。
                err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
                    return w.addRelevantTx(tx, n.TxRecord, n.Block)
                })
                notificationName = "relevant transaction"
            case chain.FilteredBlockConnected:
                                // 区块新产生,多个交易
                // Atomically update for the whole block.
                if len(n.RelevantTxs) > 0 {
                    err = walletdb.Update(w.db, func(
                        tx walletdb.ReadWriteTx) error {
                        var err error
                        for _, rec := range n.RelevantTxs {
                            err = w.addRelevantTx(tx, rec,
                                n.Block)
                            if err != nil {
                                return err
                            }
                        }
                        return nil
                    })
                }
                notificationName = "filtered block connected"

            // The following require some database maintenance, but also
            // need to be reported to the wallet's rescan goroutine.
            case *chain.RescanProgress:
                // rescan正在执行中的通知。一般发生在钱包刚刚连接区块链节点的时候
                ... 
            case *chain.RescanFinished:
                // rescan执行完成的通知。
                ...
            }
                ...
        case <-w.quit:
            return
        }
    }
}

当区块产生的时候,会发送 FilteredBlockConnected 消息。下面看一下FilteredBlockConnected 的流程。

case chain.FilteredBlockConnected:
                fmt.Println("zp wallet, 消息通知。。。。整个区块")
                // Atomically update for the whole block.
                if len(n.RelevantTxs) > 0 {
                    err = walletdb.Update(w.db, func(
                        tx walletdb.ReadWriteTx) error {
                        var err error
                        for _, rec := range n.RelevantTxs {
                            err = w.addRelevantTx(tx, rec,
                                n.Block)
                            if err != nil {
                                return err
                            }
                        }
                        return nil
                    })
                }
                notificationName = "filtered block connected"

里面最核心的方法是 addRelevantTx。 下面我们看一下其流程: https://github.com/btcsuite/btcwallet/blob/7abdd4f8ad7dcf22c5dd90d123b0c137f93d3879/wallet/chainntfns.go#L275

addRelevantTx.png

本文是《循序渐进比特币》的第十一篇-《btcwallet(五)接收区块,同步本地交易与UTXO》。
如果有疑问,可以直接留言,也可以关注公众号 “链人成长chainerup” 提问留言,或者加入知识星球“链人成长”~

上一篇 下一篇

猜你喜欢

热点阅读