以太坊小知识(三)——区块奖励机制浅析

以太坊的区块奖励机制

以太坊中,区块奖励包含三部分,它们是区块奖励(类似比特币中的50BTC),交易费(这一部分比特币中也有)和打包叔伯块的奖励(这一部分比特币中没有)。

以太坊的区块奖励

以太坊中,每个区块奖励是5ether。

blockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block   5ether

但是拜占庭硬分叉以后,每个区块奖励是3ether。

ByzantiumBlockReward   *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium

叔伯块(uncle)及叔伯块奖励分发机制

每一个区块纳入的叔伯块个数最多为2个。

maxUncles            = 2                 // Maximum number of uncles allowed in a single block

根据以太坊设计指南中的叔伯块激励章节所述,叔伯块至多只能被其兄弟区块的第七代子孙引用。至于为什么选择7,设计指南里也给出了3个理由。因此在区块入链(/core/blockchain.go#(bc *BlockChain) InsertChain(…))验证区块头中的叔伯块时,也仅仅回溯了7层。下面是验证叔伯块的关键代码:

/consensus/ethash/consensus.go
func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
    //...
    // Gather the set of past uncles and ancestors
    uncles, ancestors := set.New(), make(map[common.Hash]*types.Header)
    number, parent := block.NumberU64()-1, block.ParentHash()
    //从当前区块回溯7层(或7代),搜集祖先(主链上的块)和叔伯块
    for i := 0; i < 7; i++ { 
        ancestor := chain.GetBlock(parent, number)  
        if ancestor == nil {
            break
        }
        ancestors[ancestor.Hash()] = ancestor.Header()
        for _, uncle := range ancestor.Uncles() {
            uncles.Add(uncle.Hash())
        }
        parent, number = ancestor.ParentHash(), number-1
    }
    // Verify each of the uncles that it's recent, but not an ancestor  验证叔伯块不是祖先(即不能是主链的块)
    for _, uncle := range block.Uncles() {
    // Make sure every uncle is rewarded only once  每一个叔伯块只能被奖励一次,否则就“多重奖励”了
    hash := uncle.Hash()
    if uncles.Has(hash) {
        return errDuplicateUncle
    }
    uncles.Add(hash)

    // Make sure the uncle has a valid ancestry 该叔伯块为祖先区块,即为主链上的块
    if ancestors[hash] != nil {
        return errUncleIsAncestor
    }
    //叔伯块的祖先不在7层祖先之中 或者 叔伯块和当前区块在同一区块高度
    if ancestors[uncle.ParentHash] == nil || uncle.ParentHash == block.ParentHash() {
        return errDanglingUncle
    }
    //验证叔伯块头部的有效性
    if err := ethash.verifyHeader(chain, uncle, ancestors[uncle.ParentHash], true, true); err != nil {
        return err
    }
    //...
}

叔伯块激励也是以太坊设计上的一大特色。因为在比特币中,产生孤儿块(即以太坊中的叔伯块)的矿工一般是无收益的。

计算累计收益的函数

func AccumulateRewards(state *state.StateDB, header *types.Header, uncles []*types.Header) {
    reward := new(big.Int).Set(blockReward)     //侄子区块拿到的恒定区块奖励
    r := new(big.Int)
    for _, uncle := range uncles {
        r.Add(uncle.Number, big8)
        r.Sub(r, header.Number)
        r.Mul(r, blockReward)
        r.Div(r, big8)
        state.AddBalance(uncle.Coinbase, r)     //叔伯块拿到的奖励

        r.Div(blockReward, big32)
        reward.Add(reward, r)                   //侄子区块确认叔伯块拿到的奖励r
    }
    state.AddBalance(header.Coinbase, reward)   //侄子区块获得的总的奖励
}

根据该函数,我们知道,后续区块对每一个叔伯块的引用(将叔伯块的区块摘要值纳入自己区块头部的相应字段中)会给自己带来1/32*5【其中5位系统发放给叔伯块的区块奖励】的区块奖励。这就是后续区块中叔伯块奖励的计算方式。

ps:拜占庭硬分叉后一个叔伯块奖励为1/32*3。Block #5931460中Block Reward中的0.09375便是1/32*3的结果。

你可能感兴趣的:(Ethereum)