在以太坊这个庞大的去中心化应用生态中,账户余额是衡量用户资产、驱动智能合约交互的核心要素,这些看似简单的“余额数字”究竟是如何在以太坊区块链上被存储、管理和查询的呢?理解以太坊账户余额的存储机制,是深入掌握以太坊工作原理的关键一步。

我们需要知道以太坊存在两种不同类型的账户,它们的存储方式和结构截然不同:
关键区别:EOA 的余额直接存储在账户本身的状态中,而合约账户的余额也存储在其状态中,但其状态还包括了存储的变量(存储在 storage 中)和代码。
无论是 EOA 还是合约账户,其核心状态信息都记录在以太坊的状态树(State Trie)中,具体来说是每个账户的状态对象中,一个账户的状态对象大致包含以下字段:

nonce:
balance:这就是我们关心的账户余额! 它以 Wei 为单位(1 ETH = 10^18 Wei)。balance 是一个整数,直接存储在账户状态对象中。storageRoot(仅合约账户):指向一个存储树的根哈希,该树存储了合约账户的所有持久化变量(即 storage 中的数据),EOA 没有这个字段,或者说其 storageRoot 为空。codeHash:存储账户关联代码的 Keccak-256 哈希值,对于 EOA,其 codeHash 是一个空字符串的哈希值;对于合约账户,是其代码的哈希值。账户余额 balance 是账户状态对象的一个直接组成部分,它存储在以太坊的状态树(也称为账户状态树 Account State Trie)的叶子节点中,状态树的键是账户地址,值就是上述的状态对象。

以太坊使用一种称为 Merkle Patricia Trie (MPT) 的数据结构来组织账户状态和合约存储,这种结构具有以下优点:
对于账户余额的存储:
balance 字段直接存储着余额值(一个整数)。当一笔交易向某个账户转账时(调用 transfer 函数或直接发送 ETH),本质上就是修改了目标账户状态对象中的 balance 字段:将原值加上转账金额(扣除矿工费等后),这个修改会反映在状态树中,并最终导致状态根哈希的改变,从而被打包进新的区块中。
查询余额:
balance 字段。更新余额:
balance 字段。balance 减去交易金额和矿工费。balance 加上交易金额。fallback 或 receive 函数,如果存在)。this.balance (Solidity 0.4.0 及以前) 或 address(this).balance (Solidity 0.5.0 及以后) 来查询自身余额。balance 是账户状态的一部分,存储在状态树中,修改它会产生状态变更成本(Gas),而合约执行时的局部变量存储在内存(Memory)中,读取和写入内存的成本远低于状态存储,但内存是临时性的,合约执行结束后即被销毁。