以太坊如何控制区块大小
比特币是通过固定大小控制区块,上限是1M
以太坊采用了完全不同于比特币的做法,使用gaslimit来限制,所以以太坊的区块大小是不固定的
Gaslimit确定
每次开始打包的时候都会确定当前包Gaslimit的大小,以下函数确定大小
func CalcGasLimit(parent *types.Block) uint64 {
// contrib = (parentGasUsed * 3 / 2) / 1024
contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor
// decay = parentGasLimit / 1024 -1
decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1
/*
strategy: gasLimit of block-to-mine is set based on parent's
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
increase it, otherwise lower it (or leave it unchanged if it's right
at that usage) the amount increased/decreased depends on how far away
from parentGasLimit * (2/3) parentGasUsed is.
*/
limit := parent.GasLimit() - decay + contrib
if limit < params.MinGasLimit {
limit = params.MinGasLimit
}
// however, if we're now below the target (TargetGasLimit) we increase the
// limit as much as we can (parentGasLimit / 1024 -1)
if limit < params.TargetGasLimit {
limit = parent.GasLimit() + decay
if limit > params.TargetGasLimit {
limit = params.TargetGasLimit
}
}
return limit
}
其中,targetGasLimit是代码中配置的GenesisGasLimit(现在是4712388)
从代码中的注释描述看意思是当父区块Gas使用量>2/3的时候,会较上次加大gaslimit,反之减小
根据这个公式Gaslimit是会缓慢增加的(当每次使用量都超过2/3的话),从etherscan上也可以看出现在的Gaslimit是800万左右,明显比GenesisGasLimit大了不少了。
公式我就不解释了,自己手动推算一下就能算出来的
区块Gas的使用
在打包区块内每笔交易的时候,会先判断当前区块gas还够不够用
func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address) {
gp := new(core.GasPool).AddGas(env.header.GasLimit)
var coalescedLogs []*types.Log
for {
// If we don't have enough gas for any further transactions then we're done
if gp.Gas() < params.TxGas {
log.Trace("Not enough gas for further transactions", "gp", gp)
break
}
...
}
在这个for循环打包交易的时候,会先判断gp.Gas()是否小于params.TxGas(程序中配置的21000)
gp.Gas()就是计算的区块GasLimit,TxGas是一笔普通转账交易使用的最小Gas。
所以每次打包交易的时候会判断当前区块的Gas余量是否够21000,不够的话就不会打包交易了
那么会不会出现这种情况,区块的Gas使用量大于GasLimit呢,也就是说现在区块的Gas余量大于21000,比如说22000,
但是后面计算交易的时候实际耗费大于22000,导致最终的区块消耗Gas大于GasLimit呢,肯定是不会了
但是代码太多地方了不好挑,大概意思就是:
每次需要消耗gas的时候都会判断Gaslimit是否够用,不够的话会返回Gas不够的错误。比如EVM执行每条指令的时候都会判断gas是否够用,不够就直接返回,然后就打包完成了