源码
GitHub地址 https://github.com/TTCECO/gttc
目录
基于以太坊go-ethereum的DPOS实现(一)源码及测试运行
基于以太坊go-ethereum的DPOS实现(二)简要说明
基于以太坊go-ethereum的DPOS实现(三)创世块
基于以太坊go-ethereum的DPOS实现(四)共识接口
基于以太坊go-ethereum的DPOS实现(五)定时出块
基于以太坊go-ethereum的DPOS实现(六)代表选择
共识接口
在go-ethereum中添加一种共识机制,最方便的方式是实现consensus.go中Engine接口所定义的方法。
// Engine is an algorithm agnostic consensus engine.
type Engine interface {
// Author retrieves the Ethereum address of the account that minted the given
// block, which may be different from the header's coinbase if a consensus
// engine is based on signatures.
Author(header *types.Header) (common.Address, error)
// VerifyHeader checks whether a header conforms to the consensus rules of a
// given engine. Verifying the seal may be done optionally here, or explicitly
// via the VerifySeal method.
VerifyHeader(chain ChainReader, header *types.Header, seal bool) error
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
// concurrently. The method returns a quit channel to abort the operations and
// a results channel to retrieve the async verifications (the order is that of
// the input slice).
VerifyHeaders(chain ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error)
// VerifyUncles verifies that the given block's uncles conform to the consensus
// rules of a given engine.
VerifyUncles(chain ChainReader, block *types.Block) error
// VerifySeal checks whether the crypto seal on a header is valid according to
// the consensus rules of the given engine.
VerifySeal(chain ChainReader, header *types.Header) error
// Prepare initializes the consensus fields of a block header according to the
// rules of a particular engine. The changes are executed inline.
Prepare(chain ChainReader, header *types.Header) error
// Finalize runs any post-transaction state modifications (e.g. block rewards)
// and assembles the final block.
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error)
// Seal generates a new block for the given input block with the local miner's
// seal place on top.
Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error)
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have.
CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int
// APIs returns the RPC APIs this consensus engine provides.
APIs(chain ChainReader) []rpc.API
}
在本篇及接下来的几篇关于DPOS实现的文章中,所有的叙述都是围绕着这些方法的实现展开的,所以在这里先对这些方法做下说明。
Author
// Author retrieves the Ethereum address of the account that minted the given
// block, which may be different from the header's coinbase if a consensus
// engine is based on signatures.
Author(header *types.Header) (common.Address, error)
对于以太坊的POW共识来说Author返回的就是header.coinbase的地址,可以认为是矿工地址或受益人的地址,这个地址并不需要用签名来证明。但对于DPOS共识机制来说,必须证明出块地址必须是当前有权限出块的地址,所以在alien当中,Author的返回值是根据签名计算而来的,方式和clique中的完全相同。
VerifyHeader & VerifyHeaders
// VerifyHeader checks whether a header conforms to the consensus rules of a
// given engine. Verifying the seal may be done optionally here, or explicitly
// via the VerifySeal method.
VerifyHeader(chain ChainReader, header *types.Header, seal bool) error
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
// concurrently. The method returns a quit channel to abort the operations and
// a results channel to retrieve the async verifications (the order is that of
// the input slice).
VerifyHeaders(chain ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error)
这两个方法都是用来验证头部信息的,可以调用同一个方法实现,其中验证的内容会单独一篇叙述。
VerifyUncles
// VerifyUncles verifies that the given block's uncles conform to the consensus
// rules of a given engine.
VerifyUncles(chain ChainReader, block *types.Block) error
叔块(Uncles)在DPOS共识当中没有意义,所以可以直接返回nil,也可以验证如果叔块存在则报错,需要注意的是挖矿奖金的计算处也不需要计算叔块。
VerifySeal
// VerifySeal checks whether the crypto seal on a header is valid according to
// the consensus rules of the given engine.
VerifySeal(chain ChainReader, header *types.Header) error
注释中叙述的很清晰,但是在开发过程中,因为几个Verify方法会逐层调用,所以具体功能上的区分并不清晰。
Prepare
// Prepare initializes the consensus fields of a block header according to the
// rules of a particular engine. The changes are executed inline.
Prepare(chain ChainReader, header *types.Header) error
在DPOS共识当中,如果启动后还未达到genesisTimestamp中所定义的首轮开始的出块时间,则等待。
Finalize
// Finalize runs any post-transaction state modifications (e.g. block rewards)
// and assembles the final block.
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error)
Finalize是DPOS实现中非常重要的一个方法,除了计算header.extra中签名的部分以外,几乎所有的数据的计算和组装都在这个方法中完成。比如获取代表投票,提议,表决等的交易及根据快照所做的计算入出块顺序确认等。
Seal
// Seal generates a new block for the given input block with the local miner's
// seal place on top.
Seal(chain ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error)
DPOS实现中,Seal方法根据已经unlock的账户信息,在header.extra中为block添加签名。
CalcDifficulty
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have.
CalcDifficulty(chain ChainReader, time uint64, parent *types.Header) *big.Int
直接设置为1,DPOS不需要工作量证明。
APIs
// APIs returns the RPC APIs this consensus engine provides.
APIs(chain ChainReader) []rpc.API
对外提供的rpc接口定义。
下一节 基于以太坊go-ethereum的DPOS实现(五)定时出块