以太坊作为全球领先的智能合约平台,其核心之一便是账户系统,理解以太坊如何管理账户,对于深入把握区块链的工作原理、开发安全的应用程序以及排查问题至关重要,本文将基于以太坊源码,详细探讨账户管理的核心机制,包括账户的类型、结构、存储、以及与之相关的核心数据结构和操作。
账户:以太坊世界的基本单元
在以太坊中,所有状态(余额、代码、存储等)都以账户的形式存在,账户是区块链上状态的基本单位,类似于传统银行系统中的账户,但功能更为强大和复杂,以太坊定义了两种主要的账户类型:
- 外部账户 (Externally Owned Accounts, EOAs):由用户通过私钥控制,没有关联的代码,最常见的EOAs就是普通用户的钱包地址,用于发送交易、支付ETH等。
- 合约账户 (Contract Accounts):由部署的智能代码控制,拥有代码和存储,当EOA向合约账户发送交易或调用其方法时,合约账户的代码会被执行。
账户的核心数据结构:Account与StateAccount
在以太坊的Go源码(主要在core/types和core/state包中)中,账户的定义是理解账户管理的基础。
core/types/account.go - 简化账户模型
// Account represents an Ethereum account.
// It only contains the metadata, the actual state is stored in a trie.
type Account struct {
Nonce uint64
Balance *big.Int
Root common.Hash // Merkle root of the storage trie
CodeHash common.Hash
}
这个Account结构体是账户在状态树(Merkle Patricia Trie)中存储的简化表示,它包含了四个关键字段:
- Nonce:一个计数器,用于防止重放攻击,对于EOA,它代表该账户发送的交易数量;对于合约账户,它代表该账户创建的合约数量。
- Balance:账户持有的以太币数量,以
wei(1 ETH = 10^18 wei)为单位,使用big.Int表示以支持大数。 - Root:一个Merkle Patricia Trie的根哈希,这个 trie 存储了合约账户的持久化数据(即状态变量),对于EOA,这个字段为空。
- CodeHash:账户关联代码的哈希值,对于EOA,这个字段是空字符串的哈希(
c5d2460186f7233c9272727d6c5686c5d2460186f7233c9272727d6c5686c);对于合约账户,是其代码的哈希。
core/state/state_object.go - 内存中的账户对象
当账户被加载到内存中进行操作时,它会表示为StateObject结构体(位于core/state/state_object.go),这个结构体不仅包含了Account的所有信息,还提供了修改和查询账户的方法,以及缓存机制。
// StateObject represents an Ethereum account which is being modified.
type StateObject struct {
address common.Address
addrHash common.Hash // hash of the address
data Account
db *StateDB
// Cache fields
dirty bool
dirtyStorage map[common.Hash]common.Hash
suicide bool
}
