vneus daemon代码解析

venus启动venusdeamon启动时主要调用两个app/node.go的两个方法。其中一个是用(bBuilder)build()生成node对象,这个生成方法会调用(builderRPCBuilder)AddServices(services...RPCService)方法

venus启动

venus deamon启动时主要调用两个app/node.go的两个方法。其中一个是用(b *Builder) build()生成node对象,这个生成方法会调用(builder *RPCBuilder) AddServices(services ...RPCService)方法把各种api服务添加到node对象,后面调用(node *Node) RunRPCAndWait()方法启动对外服务。服务接口有rest api和rpc两种形式。每个服务都是一个submodule,定义在app/submodule目录下,***_submodule.go定义类,***_api.go类实现接口逻辑。

另一个是Start()方法来启动syncer,mpool,paychan,network, eth五个模块。

/ Start boots up the node.
func (node *Node) Start(ctx context.Context) error {
    .......

    // start syncer module to receive new blocks and start sync to latest height
    err = node.syncer.Start(syncCtx)
    if err != nil {
        return err
    }

    // Start mpool module to receive new message
    err = node.mpool.Start(syncCtx)
    if err != nil {
        return err
    }

    err = node.paychan.Start(ctx)
    if err != nil {
        return err
    }

    // network should start late,
    err = node.network.Start(syncCtx)
    if err != nil {
        return err
    }

    if err := node.eth.Start(ctx); err != nil {
        return fmt.Errorf("failed to start eth module %v", err)
    }
}

其中syncer的启动会产生一个goroutine,for循环不停的接受订阅的信息,仅仅是block信息,为什么这样设计呐?tipset的同步逻辑放在了别的包来实现。

// Start starts the syncer submodule for a node.
func (syncer *SyncerSubmodule) Start(ctx context.Context) error {
    .......
    // process incoming blocks
    go func() {
        for {
            received, err := syncer.BlockSub.Next(ctx)
            if err != nil {
                if ctx.Err() != context.Canceled {
                    log.Errorf("error reading message from topic %s: %s", syncer.BlockSub.Topic(), err)
                }
                return
            }

            if err := syncer.handleIncomingBlocks(ctx, received); err != nil {
                handlerName := runtime.FuncForPC(reflect.ValueOf(syncer.handleIncomingBlocks).Pointer()).Name()
                if err != context.Canceled {
                    log.Debugf("error in handler %s for topic %s: %s", handlerName, syncer.BlockSub.Topic(), err)
                }
            }
        }
    }()

    err = syncer.ChainModule.Start(ctx)
    if err != nil {
        return err
    }

    return syncer.ChainSyncManager.Start(ctx)
}

而其中的ChainModule.Start()方法最主要调用一个(c *ChainFork) preMigrationWorker()来提前进行状态数据的迁移。作为一个刚刚从以太坊系转过来的人,感觉好惊讶,每次启动都先检查一次状态迁移(状态数据修改)。 syncer.ChainSyncManager.Start(ctx)而这个方法会启动两个gorotine来处理信息的同步。

// Start launches the business logic for the syncing subsystem.
func (d *Dispatcher) Start(syncingCtx context.Context) {
    go d.processIncoming(syncingCtx)

    go d.syncWorker(syncingCtx)
}

具体的sync协议我们另外一篇来讲解。

mpool.Start()方法会订阅msg,验证msg合法后放进mpool。

node.paychan.Start(ctx)这个方法好像不是开启一个goroutine不停的处理事情,也许和chan不能一直存在的原因。

node.network.Start(syncCtx)方法主要作用是连接peer,是通过(pmgr *PeerMgr) doExpand(ctx context.Context)方法来实现的。

node.eth.Start(ctx)启动两个goroutine。

func (em *EthSubModule) Start(_ context.Context) error {
    if err := em.ethEventAPI.Start(em.ctx); err != nil {
        return err
    }

    return em.ethAPIAdapter.start(em.ctx)
}

一个用于事件订阅的goroutine,一个是开启msg接受的goroutine,接收到消息后放入mpool也许?需要更多确认。

执行区块,进行状态迁移

venus-miner服务获得出块权后会通过http请求来调用app/submodule/app/submodule/ming/ming_api.go: (miningAPI *MiningAPI) minerCreateBlock()接口。这个接口主要是调用pkg/statemanager/state_manager.go:(s *Stmgr) RunStateTransition()来执行父区块,得到父区块的receipt root和state root。最主要进行状态迁移的函数是:pkg/consensus/expected.go:(c *Expected) RunStateTransition()方法,这个方法会调用pkg/consensus/processor.go:(p *DefaultProcessor) ApplyBlocks()来执行区块,方法的内部再调用pkg/fvm/fvm.go:(fvm *FVM) ApplyMessage()来执行区块内的交易,真正执行交易的是extern/filecoin-ffi/fvm.go:(f *FVM) ApplyMessage()方法,这个方法会通过cgo调用rust的执行方法。但是这里要小心,cgo调用还是不是ref-fvm库的方法,还是filecoin-ffi库中的rust方法。 以上也只是把父区块执行一下而已,后面还需进行gas费用计算,reward奖励,签名的事情,才能完整的产生一个block。主要这里是不需要从mpool里面选择交易进行区块填充的,在venus-miner调用minerCreateBlock接口前,已经通过调用app/submodule/mpool/mpool_api.go:(a *MessagePoolAPI) MpoolSelects()接口从venus node选择了要打包的msg。为什么要这样设计啊?直接创建区块时,一起选择交易不是更有效率吗?就不需要来回传输了?

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
杜满想Elvin
杜满想Elvin
老程序员,区块链架构师