ethereum挖矿流程

作者: 吾王呆毛 | 来源:发表于2018-11-15 17:48 被阅读6次
    miners

    本文主要梳理eth挖矿的代码流程结构。

    global.png

    geth的挖矿逻辑都由miner.Miner结构管理,在程序启动时,miner主要启动了5个核心协程并行处理挖矿逻辑,其中挖矿worker负责维护4个最关键协程。

    协程1. newWorkLoop

    work ch.png

    该协程负责周期性地提交新的挖矿任务。当程序启动或者区块同步完成,或者新区块挖掘完毕,miner.start()方法会被调用,则startCh通道激活,此时协程清理过期的挖矿任务,构建新的挖矿任务并投递到新任务通道newWorkCh,等待挖矿执行。

    协程2. mainLoop

    挖矿的主要逻辑都位于该协程。

    该协程监听newWorkCh通道,接收到新挖矿请求后,开始挖矿。挖矿的逻辑位于commitNewWork函数内,如下图所示,首先准备区块头,调用共识引擎engine.Prepare准备共识信息,目前的共识使用了PoW共识算法,主要是为区块头计算出本次需要满足的区块PoW难度并写入到区块头;然后再讲收集到达叔区块引入,注意,以太坊最多只能引用2个叔区块,此外,优先引用本地叔区块再引入远端叔区块;然后开始执行收集到pending队列里的交易,也是本地优先远端执行;最后,进行交易后处理,这里也是调用共识引擎engine.Finalize实现,主要功能是计算矿工奖励;最后把封装好的区块投递到taskCh通道等待挖矿计算验证。

    commitNewWork.png

    同时还监听chainSideCh通道,再检测到叔区块后,如果当前正在挖矿就提交新的叔区块并重新挖矿。

    在监听txsCh通道时,收到新交易后,如果当前正在挖矿,则执行新交易并重新挖矿,否则直接触发一次新挖矿。

    该协程主要都是收集不同信息(交易,叔区块)并封装区块,投递到任务通道准备共识计算。

    task ch.png

    另外,这里有个问题,如果前面一个共识计算正在进行中,此时收到新交易或新uncle则立刻进行新的区块,而这两次计算都是针对同一区块(高度),这样岂不是必然有一次计算浪费?

    协程3. taskLoop

    这一步是挖矿的核心,然而从流程上却是最简单的,就是从taskCh获取封装好的区块,进行共识计算,并将成功的结果投递到resultCh

    result ch.png

    协程4. resultLoop

    区块挖出来之后.png

    该协程将达成共识的区块(即成功挖出的区块)写入DB,并且向周边p2p节点广播NewMinedBlockEvent,然后触发链变更事件(ChainEvent+ChainHeadEventChainSideEvent),最后将区块插入待确认区块集合。

    1. 为什么resultLoop变更链事件触发有两种情况(ChainEvent+ChainHeadEvent)或(ChainSideEvent) ?

    这是因为写入DB时,会进行链分叉判断,如果当前写入的链难度低,说明需要进行链重组,则次数会导致触发ChainSideEvent事件。

    另外,注意如果发生链重组,则会从删除旧链的交易:

    // reorgs takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them
    // to be part of the new canonical chain and accumulates potential missing transactions and post an
    // event about them
    func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
        // .......
        for _, tx := range diff {
            rawdb.DeleteTxLookupEntry(batch, tx.Hash())
        }
        // ......
    }
    

    那么删除的交易再什么时候被重新打包的呢?答案是,txpool监听了ChainHeadEvent事件,当接收到新区块时,会进行分叉判断,再此时会将之前删除的交易重新放入交易池等待打包

    
    // reset retrieves the current state of the blockchain and ensures the content
    // of the transaction pool is valid with regard to the chain state.
    func (pool *TxPool) reset(oldHead, newHead *types.Header) {
        // If we're reorging an old state, reinject all dropped transactions
        var reinject types.Transactions
        // ....
        // Inject any transactions discarded due to reorgs
        log.Debug("Reinjecting stale transactions", "count", len(reinject))
        senderCacher.recover(pool.signer, reinject)
        pool.addTxsLocked(reinject, false)
        // ...
    }
    
    1. 区块什么时候从unconfirmed集合移除?

    答案是插入即确认,这个队列时环形的,并且矿工在创建unconfirmed队列会指定长度,这个长度即确认高度,当超过这个高度的区块被插入,自然就有最早的区块被移除,达到天然确认的目的。

    协程5. update

    该协程主要保证区块同步和挖矿互斥进行,即同步区块时暂停挖矿,同步完毕启动挖矿。

    相关文章

      网友评论

        本文标题:ethereum挖矿流程

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