
Blockchain was first introduced by Satoshi Nakamoto in the Bitcoin whitepaper as a distributed ledger technology supporting Bitcoin transactions, and over a decade has passed since then. In these years, with the skyrocketing prices of cryptocurrencies, the number of participants in the community has continuously increased, attracting a wealth of professionals from diverse backgrounds to incessantly inject new ideas into the topic of Blockchain. With the continuous influx of new thoughts, the boundaries of blockchain technology have been expanding, gradually evolving into a novel technological field that integrates knowledge from multiple disciplines including databases, distributed systems, cryptography, peer-to-peer networks, compilation principles, static software analysis, crowdsourcing, economics, monetary finance, sociology, and more. Fueled by an unending stream of new technologies and ideas, Blockchain has gradually shifted from a niche decentralized technology community to the mainstream social stage, remaining one of the hottest, most rapidly evolving, and most socially discussed technological topics to date. Influenced by Blockchain's native decentralized philosophy, the vast majority of Blockchain systems are open-source and continuously developed and maintained on GitHub. This presents us with an excellent way to learn Blockchain technology: combining documentation with source code to understand and learn the system's design philosophy and implementation principles.
Blockchain 最早作为支撑 Bitcoin 结算的分布式账本技术,由中本聪在比特币白皮书提出,至今已经过了十几年。在这十几年中,随着加密货币价格的飞涨,社区的参与人数不断的增加,大量的来自不同背景专业人士围绕 Blockchain 这一话题源源不断的注入新的想法。随着新的思想持续的涌入,区块链技术的边界不断的拓展,逐渐成为了融合了数据库,分布式系统,密码学,点对点网络,编译原理,静态软件分析,众包,经济学,货币金融学,社会学等多个学科知识的一个全新技术领域。在源源不断的新技术和新思想的催化下,Blockchain 也逐渐从小众的去中心化技术社区逐渐走向了主流社会的舞台,至今仍是当下最热度最高,技术迭代最快,最能引起社会讨论的技术话题之一。在 Blockchain 原生的 decentralized 的思想的影响下,市面上绝大多数的 Blockchain 系统都是以开源的形式持续在 Github 上开发和维护。这就为我们提供了一种的极好的学习 Blockchain 技术的方式: 结合文档,基于源代码,理解和学习系统的设计思想和实现原理。
从基础建设的角度看,随着网络基础建设的不断完善,网络带宽增加和通信延迟下降的趋势将会持续。伴随着存储技术和分布式算法的不断发展,未来软件系统的运行效率将会持续的提高,并且会逐渐逼近硬件设备的性能极限。这些基础建设的发展为构建大规模去中心化应用带来更大的确定性。在未来的五到十年内,云端服务/去中心化系统的性能以及覆盖场景一定还会有很大的提升。未来的技术世界大概率会是两极分化的。一极是以大型科技公司(i.e, Google,MS,Oracle,Snowflake,and Alibaba)为代表的中心化服务商。另一极就是以 Blockchain 技术作为核心的去中心化的世界。在这个世界中,Ethereum 及其生态系统是当之无愧的领头羊。Ethereum 作为通用型 Public Chain 中的翘楚构建了稳定强大的生态系统。Ethereum 及其生态吸引到了一大批世界上最优秀的工程师和研究人员不断的将新思想,新理念,新技术引入到 Ethereum 及其生态中,并且持续的引领整个 Blockchain 生态系统发展。从计算机技术的发展史上看,优秀的平台化的开源项目,例如 Linux,Android,都拥有持久强大的生命力。由于这类项目的代码经过时间的验证,拥有良好的生态循环,最终会有源源不断的开发人员基于这些项目的代码库来开发全新的应用。Go-Ethereum 作为 Ethereum 的优秀稳健的开源实现,目前已经被广泛的订制,被应用在了多种私有/联盟/Layer-2的场景中(e.g., Quorum, Binance Smart Chain, Scroll, Arbitrum , Optimism)。不管是哪种场景,Ethereum 的相关代码总是位于系统的核心中的核心位置。因此,作为开发人员/研究人员理解 Ethereum 的设计和实现是至关重要的。
一个热门的技术是否热门的标志之一是: 是否有不同视角的作者,在不同的技术发展阶段记录下来的文档资料。目前,对于学习者,不管是探究以加密货币导向(Crypto-based)的 Bitcoin, 还是了解致力于实现通用 Web3 框架(General-Purpose)的 Ethereum,社区中有丰厚的从基础概念的角度的出发的技术文档来讲述它们的基础概念和设计的思想。比如,技术社区有非常多的资料来讲述什么是梅克尔树 (Merkle Hash Tree),什么是梅克尔帕特里夏树 (Merkle Patricia Trie),什么是有向无环图 (Directed acyclic Graph); BFT (Byzantine Fault Tolerance)和 PoW (Proof-Of-Work) 共识算法算法的区别; 以及介绍Blockchain系统为什么可以抵抗双花攻击 (Double-Spending),或者为什么Ethereum会遇到 DAO Attack (Decentralized autonomous organization) 等具体问题。
但是,现有的资料往往对工程实现的细节介绍的不够清晰。对于研究人员和开发人员来说,只了解关键组件的实现细节,或者高度抽象的系统工作流,并不代表着搞清楚 Blockchain 的工作原理。反而很容易在一些关键细节上一头雾水,似懂非懂。比如,当我们谈到 Ethereum 中 Transaction 的生命周期时,翻阅文档时经常会看到类似的说法,“Miner 节点批量地从自己维护的 Transaction pool 中选择一些 Transaction 并打包成一个新的 Block 中”。那么究竟 Miner 是怎么从网络中获取到 Transaction?又是基于什么样的策略从 Transaction pool 中选取多少 Transaction?最终又按照什么样的 Order 把 Transaction 打包进区块中的呢?打包成功的 Block 是怎么交互/传播给其他节点呢?我搜索了大量的文档,发现鲜有文章详细的解释了上述的问题。因此,社区需要一些文章从整体的系统工作流的角度出发,以细粒度的视角对区块链系统中的具体的实现细节进行解析。与数据库系统(Database Management System)相似,Blockchain 系统同样是一个包含网络层,业务逻辑层,任务解析层,存储层的复杂数据管理系统。对它研究同样需要从系统的实现细节出发,从宏观到微观的了解每个执行逻辑的工作流,才能彻底理解和掌握这门技术的秘密。
本系列文章将会从 Ethereum 执行层中具体业务的工作的视角出发,在源码的层面,细粒度地解析以太坊系统中各个模块的实现的细节,以及背后的蕴含的技术和设计思想。Go-ethereum 是以太坊协议的 Go 语言实现版本,目前由以太坊基金会维护。目前除了 Go-ethereum 之外,Ethereum 还有C++, Python,Java, Rust 等基于其他语言实现的版本。由于 Go-ethereum 的代码库在持续的更新,源码分析的文档很难持续追踪最新的代码库。因此,本系列文档目前选择基于 Go-ethereum version 1.10.*(post-merge) 版本首先进行编写。相比于其他的由社区维护的版本,Go-ethereum 的用户数量最多,开发人员最多,版本更新最频繁,issues 的发现和处理都较快。其他语言的 Ethereum 实现版本因为用户与开发人员的数量相对较少,更新频率相对较低,隐藏问题出现的可能性更高。同时 Go 语言语法简单,容易阅读。对于没有 Go 语言开发经验的读者,仍然可以快速的理解代码逻辑。因此我们选择从 Go-ethereum 代码库作为我们的主要学习资料。
在合并 (Merge)之后,以太坊信标链和原有的主链进行了合并。原有的主链节点 (Go-ethereum 节点) 进行了功能缩减,放弃了共识相关的功能,仅作为执行层继续在以太坊的生态中发挥至关重要的作用。例如,交易的执行,状态的维护,数据的存储等基本功能还是由执行层进行维护。因此,作为开发和研究人员,了解 Go-ethereum 代码库仍然是十分有意义的。
关于以太坊细节实现的文档资料相对较少。由于 Ethereum 进行了多次设计上的更新,一些源代码解析的文章中采用的代码已经经历了多次的修改,导致文章丧失了部分的时效性。同时,不少文章在分析细节的时候,浅尝辄止,对一些关键问题没有解析到位。比如,很多的科普文章都提到,在打包新的Block的时候,miner 负责把 a batch of transactions 从 transaction pool 中打包到新的 block 中。那么我们希望读者思考如下的几个问题:
目前的 Blockchain 系统并没有像数据库系统(DBMS)那样统一的形成系统性的方法论。在 Ethereum 中每个不同的模块中都集成了大量的细节。从源码的角度出发可以了解到很多容易被忽视的细节。简单的说,一个完整的区块链系统至少包含以下的模块:
而在具体实现中,由于设计理念,以及 go 语言的特性(没有继承派生关系),Go-ethereum中的模块之间相互调用关系相对复杂。因此,只有通过阅读源码的方式才能更好理解不同模块之间的调用关系,以及业务流程中的关键细节。
阅读源代码是一种漫长的修行。为了方便自检修行的结果,我们将对一个系统的理解程度划分为下面四个等级。
我们希望读者在阅读完本系列之后,对以太坊的理解能够达到 Level 2 - Level 3 的水平。
time.now())对 Transaction.time 进行初始化。Finalise 函数,然后执行Commit函数。 // 向 leveldb 中更新 Storage 数据
func WritePreimages(db ethdb.KeyValueWriter, preimages map[common.Hash][]byte)
// 向 Blockchain 中添加新的 Block,会涉及到 StateDB(Memory)/Trie(Memory)/EthDB(Disk) 的更新
func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) (int, error)
// insertChain 中调用来执行 Block 中的所有的交易
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
// 执行单条 Transaction 的调用
func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error)
// 状态转移函数
func (st *StateTransition) TransitionDb() (*ExecutionResult, error)
// 执行合约内 function
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error)
// opSstore的调用
func (s *StateDB) SetState(addr common.Address, key, value common.Hash)
// 被修改的 state 的值会首先被放在 StateObject 的 dirtyStorage 中,而不是直接添加到 Trie 或者 Disk Database 中。
func (s *stateObject) setState(key, value common.Hash)
// 根据当前的 State Trie 的值来重新计算 State Trie 的 Root,并返回改 Root 的值
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash
// Finalise 当前内存中的 Cache.
func (s *StateDB) Finalise(deleteEmptyObjects bool)
// Commit StateDB 中的 Cache 到内存数据库中
func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error)
// 将 StateObject 中所有的 dirtyStorage 转存到 PendingStorage 中,并清空 dirtyStorage,并给 prefetcher 赋值
func (s *stateObject) finalise(prefetch bool)
// 更新 StorageObject 对应的 Trie, from Pending Storage
func (s *stateObject) updateTrie(db Database) Trie
// 最终获取到新的 StateObject 的 Storage Root
func (t *Trie) hashRoot() (node, node, error)
// 用于在内存数据库中保存 MPT 节点
func (c *committer) store(n node, db *Database) node
// 向 rawdb 对应的数据库写数据(leveldb)
func (db *Database) Commit(node common.Hash, report bool, callback func(common.Hash)) error
本书主要参考了 Go-Ethereum 代码库,Ethereum Yellow Paper,以及 EIP 的具体 Spec。读者可以从下面的链接中找到相关的引用资料。
$ claude mcp add Understanding-Ethereum-Go-version \
-- python -m otcore.mcp_server <graph>