https://blog.csdn.net/teaspring/article/details/75390210
Root,TxHash和ReceiptHash,分别取自三个MPT类型对象:stateTrie, txTrie, 和receiptTrie的根节点哈希值。用一个32byte的哈希值,来代表一个有若干节点的树形结构(或若干元素的数组),这是为了加密。比如在Block的同步过程中,通过比对收到的TxHash,可以确认数组成员transactions是否同步完整。
三者当中,TxHash和ReceiptHash的生成稍微特殊一点,因为这两的数据来源是数组,而不像stateTrie原本就存在。如何将数组转化成MPT结构?考虑到MPT专门存储[k,v]类型数据,代码里利用了点小技巧:将数组中每个元素的索引作为k,该元素的RLP编码值作为v,组成一个[k,v]键值对作为一个节点,这样所有数组元素作为节点逐个插入一个初始化为空的MPT,形成MPT结构。
在stateTrie,txTrie,receiptTrie这三个MPT结构的产生时间上,receiptTrie 必须在Block的所有交易执行完成才能生成;txTrie 理论上只需tx数组transactions即可,不过依然被限制在所有交易执行完后才生成;最有趣的是stateTrie,由于它存储了所有账户的信息,比如余额,发起交易次数,虚拟机指令数组等等,所以随着每次交易的执行,stateTrie 其实一直在变化,这就使得Root值也在变化中。于是StateDB 定义了一个函数IntermediateRoot(),用来生成那一时刻的Root值:
// core/state/statedb.go
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash
这个函数的返回值,代表了所有账户信息的一个即时状态。
stateRoot生成的大概过程如下
//core/state_processor.go
//交易执行的入口函数
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
=>
p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts)
=>
//core/state/statedb.go
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash
网友评论