1 存储整体结构
2 区块
区块分为两部分,即区块头和区块体。
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。
区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。
3 区块头
区块头的结构如下图所示
-
stateRoot
世界状态树的根节点哈希值(在所有交易被执行后)。 -
transactionsRoot
交易树根节点的哈希值。这棵树包含了区块体的所有交易。 -
receiptsRoot
每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
其中交易树和收据树是Merkle树,状态树是Merkle Patricia Tree.
三棵树求取根哈希,可以得到区块头中的StateRoot,TransactionsRoot,ReceiptsRoot三个字段。这样就建立了交易和区块头字段的映射。当其他用户收到块,根据块里的交易可以计算出收据和状态,计算三个根哈希后和区块头的三个字段进行验证,判断这是否为合法的块。
4 世界状态
以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。账户分为两种:
-
外部账户(Externally owned account)
被私钥控制且没有任何代码与之关联。一个外部账户可以创建交易,来发送消息给另一个外部账户或合约账户,以此来触发转账交易和智能合约的调用、创建 -
合约账户(Contract account)
被它们的合约代码控制且有代码与之关联。合约账户不可以自己发起一个交易,只能被外部账户调用。 -
nonce
从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作. -
balance
此账号所拥有的以太币数量。 -
storageRoot
账户存储树的根节点哈希值。 -
codeHash
对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户此处留空。
账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。可以理解为保存Solidity智能合约中的状态变量值。
多个区块的MPT树共享了账户状态,子块状态树和父块状态树的差别在于它指向了在子区块中被改变了的账户。这样节省了总的存储空间,方便了块的回滚操作。例如某个智能合约账户中,智能合约的变量值由29改变成了45。
5 交易数据
外部账户可以创建交易,用自己的私钥进行签名之发送消息给另一个外部账户或合约账户。两个外部账户之间传送的消息即为转账操作。从外部账户到合约账户的消息会**合约账户的代码,执行各种操作,也就是我们常说的调用智能合约。可以通过向0地址发起交易来创建合约账户。交易包含以下主要字段:
- Type:交易的类型,ContractCreation(创建合约)还是MessageCall(调用合约或转账)
- Nonce: 发送地址的交易计数
- Value: 向目标账户发送的金额
- ReceiveAddress:接受方地址
- GasPrice:为交易付出的Gas价格
- Gas:为交易付出的Gas
- Data:交易的附加数据
- VRS:交易签名结构体
6 收据数据
账户创建交易并向其它节点广播后,会被其它节点执行并放入准备打包的区块。在这个过程中会生成一个收据。收据的主要字段有:
- blockHash: 交易所在块的哈希值
- blockNumber: 交易在块的序号
- transactionHash: 交易的哈希值
- transactionIndex: 交易在块中的序号
- from: 发送者地址
- to: 接受者地址,为空时候表示创建合约
- cumulativeGasUsed: 执行完此交易时候,块内消耗的总的gas值
- gasUsed:本交易所消耗的gas
- contractAddress: 当此交易为创建合约时,表示所创建合约的地址,否则为空
- logs: 此交易的日志
7 总结
总体而言,以太坊有四种前缀树:
- 世界状态树包括了从地址到账户状态之间的映射。 世界状态树的根节点哈希值由区块保存(在 stateRoot 字段),它标示了区块创建时的当前状态。整个网络中只有一个世界状态树。
- 账户存储树保存了与某一智能合约相关的数据信息。由账户状态保存账户存储树的根节点哈希值(在 storageRoot 字段)。每个账户都有一个账户存储树。
- 交易树包含了一个区块中的所有交易信息。由区块头(在 transactionsRoot 区域)保存交易树的根节点哈希值。每个区块都有一棵交易树。
- 交易收据树包含了一个区块中所有交易的收据信息。同样由区块头(在 receiptsRoot 区域)保存交易收据树的根节点哈希值;每个区块都有对应的交易收据树。
8 参考
https://zhuanlan.zhihu.com/p/30922425
https://www.cnblogs.com/ccbupt/p/11468791.html