以太坊中,区块奖励包含三部分,它们是区块奖励(类似比特币中的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
每一个区块纳入的叔伯块个数最多为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的结果。