跳过正文

15. 交易树与收据树

·208 字·1 分钟
Chuck Chan
作者
Chuck Chan
分享技术、思考与生活

交易树与收据树
#

上篇文章中讲了数据结构MPT及状态树,这篇文章再来讲交易树与收据树。交易树与收据树同样基于MPT,分别用于存储区块内的交易信息与交易执行结果,是保证以太坊数据可验证性和透明性的关键组件。二者均与区块一一对应,其根哈希会被记录在区块头中,确保数据不可篡改。

交易树
#

交易树是每个区块内所有交易的结构化存储载体,本质是一棵以交易在区块中的序号为键的 MPT。

其核心作用:

  • 记录区块内所有交易的完整信息,包括发送方、接收方、转账金额、Gas 设置、智能合约调用数据等。
  • 生成交易根哈希并写入区块头,任何人可通过该哈希验证区块内交易是否被篡改,也可通过Merkle Proof快速验证某笔交易是否存在于区块中。

结构特点:

  • 交易的索引(在区块中的序号)会被 RLP 编码后作为 MPT 的键,由于交易序号是连续的数字,其路径前缀共享的概率极低,因此交易树的 MPT 路径压缩特性几乎无法体现,但仍保留 MPT 的密码学验证能力。
  • 与状态树不同,每个区块的交易树仅包含相关的交易,不同区块的交易树不会共享节点。

收据树
#

收据树也叫回执树,存储每笔交易执行后的结果信息,同样是基于 MPT 构建,且与交易树的节点一一对应。

核心作用:

  • 记录交易执行的最终状态,包括交易是否成功、消耗的 Gas 量、智能合约触发的事件日志(Log)、区块哈希与交易哈希关联信息等。
  • 生成收据根哈希写入区块头,为轻节点验证交易执行结果提供依据,比如钱包可通过收据树验证转账是否到账、智能合约事件是否触发。

结构特点:

  • 键为对应交易在区块中的序号,与交易树的键完全一致,保证交易与收据的一一映射。
  • 收据中包含布隆过滤器(Bloom Filter),用于快速检索交易类型、涉及地址等信息,区块头也会聚合所有收据的布隆过滤器,提升全网的事件查询效率。

源码
#

以太坊的客户端比较著名的一个实现**go-ethereum**由go语言实现,下面贴了以太坊Header的源码,还有其他的一些实现细节可以从继续读一下整个源码(有50k+的start)。

// Header represents a block header in the Ethereum blockchain.
type Header struct {
	ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
	UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
	Coinbase    common.Address `json:"miner"`
	Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
	TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
	ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
	Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
	Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
	Number      *big.Int       `json:"number"           gencodec:"required"`
	GasLimit    uint64         `json:"gasLimit"         gencodec:"required"`
	GasUsed     uint64         `json:"gasUsed"          gencodec:"required"`
	Time        uint64         `json:"timestamp"        gencodec:"required"`
	Extra       []byte         `json:"extraData"        gencodec:"required"`
	MixDigest   common.Hash    `json:"mixHash"`
	Nonce       BlockNonce     `json:"nonce"`

	// BaseFee was added by EIP-1559 and is ignored in legacy headers.
	BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`

	// WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers.
	WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"`

	// BlobGasUsed was added by EIP-4844 and is ignored in legacy headers.
	BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"`

	// ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers.
	ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"`

	// ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
	ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`

	// RequestsHash was added by EIP-7685 and is ignored in legacy headers.
	RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"`
}