以太坊叔块相关

转载于:https://blog.csdn.net/csds319/article/details/80619092

什么是叔块

叔块是以太坊引进的,顾名思义叔块就是跟自己的父区块指向的父区块相同。

当矿工打包的时候发现有这样的块存在,就把它打包进去。那么这个块就是当前块的叔叔了,就称为叔块,这个起名还是蛮有意思的。

如上图说是,当打包102的时候,发现还有个黄色的101也指向自己(102)的爷爷(100),那么黄色的101就是一个叔块(当然这个是最高级别的叔块,如果打包102的时候还没有黄色的101,打包103的时候才发现黄色的101,那么黄色的101也是会当做区块打包到103内,区别是黄色101区块的生产者获得奖励不同)

为什么要有叔块

比特币里面是没有叔块概念的,叔块是以太坊中引进的,至于为什么要引进叔块的概念,是与以太坊的缩短出块时间有关。

比特币平均出块时间间隔为10分钟,出现叔块的情况概率比较小,当时中本聪设定的这种情况的叔块是做无用功,不会有任何奖励。

但是以太坊为了缩短出块时间到10s出头,那么叔块产生的概率就比较高了,如果类似比特币的设计,会有很多矿工因为生产了叔块而获取不到任何奖励,矿工的积极性会降低,不利于以太坊生态发展,所以V神引入了叔块的概念,这种情况下矿工打包叔块进区块,叔块生产者和打包叔块的矿工都会有一定的奖励。

可以看下V神的这篇文章:https://blog.ethereum.org/2014/07/11/toward-a-12-second-block-time/

叔块的相关规定

看以太坊的wiki:

如果要打包叔块到区块B的话要满足几点:

1 叔块必须是B的第K层祖先,2<= k <= 7

2 叔块不能是B的祖先

3 叔块必须有合法的block header,但是不必是之前验证过的完整的block(没太看懂)

4 叔块必须没有被包进区块过的

叔块的奖励

生成family和ancestors

在打包生成区块的时候,先计算下叔块的family和ancestors    

        for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
		for _, uncle := range ancestor.Uncles() {
			work.family.Add(uncle.Hash())
		}
		work.family.Add(ancestor.Hash())
		work.ancestors.Add(ancestor.Hash())
	}

目的是后续为了验证叔块的合法性

1 拿到当前blockchain中的最新7个块

2 把这7个块以及块里的uncles加入到family map

3 把这7个块加入到ancestors map

打包叔块进区块

        for hash, uncle := range self.possibleUncles {
		if len(uncles) == 2 {
			break
		}
		if err := self.commitUncle(work, uncle.Header()); err != nil {
			log.Trace("Bad uncle found and will be removed", "hash", hash)
			log.Trace(fmt.Sprint(uncle))

			badUncles = append(badUncles, hash)
		} else {
			log.Debug("Committing new uncle to block", "hash", hash)
			uncles = append(uncles, uncle.Header())
		}
	}
func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
	hash := uncle.Hash()
	if work.uncles.Has(hash) {
		return fmt.Errorf("uncle not unique")
	}
	if !work.ancestors.Has(uncle.ParentHash) {
		return fmt.Errorf("uncle's parent unknown (%x)", uncle.ParentHash[0:4])
	}
	if work.family.Has(hash) {
		return fmt.Errorf("uncle already in family (%x)", hash)
	}
	work.uncles.Add(uncle.Hash())
	return nil
}

1 遍历possibleUncles map,这个里面保存着所有的可能的叔块,只有被打包进区块才能成为真正的区块

2 commitUncle里面

    a: 如果已经被加入到uncle了,return

    b: 如果ancestors map内不包含当前uncle的父区块,return

    c: 如果当前family包含该区块,return

最终添加通过的区块到uncle,画个图看下:

    从possibleUncles中筛选到最终的uncle的时候要符合possibleUncles中的祖先要在ancestors map中,

    所以最终只有101-106这6种情况会被打包到区块107中。

3 最多打包两个uncle到区块中

计算区块/叔块奖励

func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
	// Select the correct block reward based on chain progression
	blockReward := FrontierBlockReward
	if config.IsByzantium(header.Number) {
		blockReward = ByzantiumBlockReward
	}
	// Accumulate the rewards for the miner and any included uncles
	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)
	}
	state.AddBalance(header.Coinbase, reward)
}

1 先设置基本的奖励blockReward,默认为5Eth,但是Byzantium版本之后为3Eth,也就是现在的区块奖励为3Eth了

2 计算叔块奖励的公式:

   ((uncleNumer + 8) - headerNumber)*blockReward/8

那么对于打包区块的时候叔块与当前number的差值奖励是不一样的

因为刚开始就定义了ancestors,就是uncle的祖先只能为当前区块以及前7个区块,那么uncleNumber的取值为当前块(不是当前打包的块,是已经加到blockchain的块)以及前6个块

这个图再贴过来吧。比如打包的块107,那么headerNum是107,uncleNumber的取值范围是101-106,所以最终叔块的奖励范围是:

(2/8~7/8)*blockReward,表格看下:

间隔层数报酬比例报酬(Eth)
17/82.625
26/82.25
35/81.875
44/81.5
53/81.125
62/80.75

3 计算区块生产者的奖励,这个矿工打包叔块的原因,是有Eth奖励的

    blockReward/32

这是打包一个叔块的奖励:3Eth*/32,如果打包了两个叔块奖励是:3/16Eth

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值