为什么 Solana 可以查询代币的 Holder 列表,以太坊不可以?

💡 原文中文,约9600字,阅读约需23分钟。
📝

内容提要

文章从 Solana 可查询 Token Holder、以太坊不可查询入手,指出根源在于状态模型差异:ERC-20 余额存储在合约内部 mapping 中,无法枚举;SPL 余额则是独立 Token Account,可按 mint 过滤聚合。更深层原因是 Solana 以 Account 为一等公民,交易显式声明读写账户,便于并行调度;以太坊以合约存储为中心,更灵活但依赖链下索引器。

🔎

延伸解读

状态模型差异:从余额存储方式说起

文章指出,ERC-20 余额存储在合约内部的 mapping 中,而 Solidity 的 mapping 不可枚举,因此无法直接列出所有持有者。相反,SPL Token 余额是独立的 Token Account,可按 mint 过滤并聚合。这不仅是接口差异,更是状态组织方式的根本不同:以太坊以合约存储为中心,Solana 以独立账户为状态单元。

并行执行的前提:显式声明状态依赖

Solana 要求交易提前声明读写账户,使运行时能提前检测冲突并并行调度。以太坊则允许合约在执行过程中动态决定访问哪些状态,因此难以提前确定完整的读写集。这导致 Solana 将状态管理复杂性暴露给开发者,而以太坊将复杂性转移至链下索引器和客户端优化。

工程取舍:复杂性被放在不同位置

文章强调,Solana 和以太坊并非简单的好坏之分,而是不同的工程取舍。Solana 用开发复杂性换取运行时的可预测性和并行能力;以太坊则提供更动态、通用的编程环境,但依赖链下基础设施重建业务语义。两者对“区块链应如何组织状态与执行程序”给出了不同答案。

❓

Q&A

为什么 Solana 可以直接查询代币的 Holder 列表,而以太坊不能?

因为 Solana 的 SPL Token 余额存储在独立的 Token Account 中,可以按 mint 过滤并聚合 owner;而以太坊 ERC-20 的余额存储在合约内部的 mapping 中,mapping 不可枚举,无法直接列出所有持有者。

ERC-20 代币的余额在以太坊上是怎么存储的?为什么不能枚举所有持有者?

ERC-20 余额通常存储在合约的 mapping(address => uint256) 中,例如 balances[Alice] = 100。Solidity 的 mapping 不可枚举,EVM 没有原生操作能列出所有 key,因此只能通过 balanceOf 查询单个地址的余额,无法直接获取所有持有者。

Solana 的 Token Account 和以太坊的 ERC-20 余额在数据模型上有什么本质区别?

Solana 的 Token 余额是独立的 Token Account,每个 Account 包含 mint、owner 和 amount,可以按 mint 过滤并聚合 owner 得到 Holder 列表;而 ERC-20 余额是合约内部 Storage 中的一个值,不是独立对象,无法从链上状态直接枚举。

Solana 为什么要把状态拆成大量独立 Account?

为了支持并行执行。Solana 要求交易提前声明要读写的 Account,Runtime 可以提前检测冲突并调度并行执行。Account 成为状态分片单位、锁粒度和并行调度单位,因此需要将状态显式拆分为独立 Account。

以太坊依赖链下索引器来获取 Holder 列表,这反映了什么更深层的设计差异?

以太坊以合约为核心,合约内部存储的业务对象(如 Token 余额)对 Runtime 不可见,Runtime 无法理解业务语义,因此需要链下索引器通过扫描事件重建状态。而 Solana 将状态显式表示为 Account,Runtime 能直接理解状态依赖。

Solana 和以太坊在状态模型上的根本分歧是什么?

以太坊是合约中心:合约拥有代码和存储,程序自由组织和访问状态,Runtime 尽量少理解业务语义。Solana 是账户中心:程序与状态分离,状态被拆成大量独立、可寻址、可拥有、可锁定的 Account,程序围绕这些 Account 运行。

🏷️

标签

➡️

继续阅读