美文网首页bitcoin
比特币钱包-btcwallet(五)接收区块,同步本地交易与UT

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

作者: 链人成长chainerup | 来源:发表于2019-10-17 16:55 被阅读0次

    本文讲解钱包收到区块链发来的交易通知,同步交易的操作:
    打开钱包,或者创建钱包之后,如果连接的区块链客户端不为空,则会调用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” 提问留言,或者加入知识星球“链人成长”~

    相关文章

      网友评论

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

        本文链接:https://www.haomeiwen.com/subject/nitvpctx.html