Monad简介
Monad是与以太坊兼容的高性能Layer1,Monad实质性推动了区块链去中心化和扩容间博弈的有效边界。
Monad在以下四个方面进行了优化,使区块链的吞吐量达到每秒10,000笔交易(tps):
Monad的优化解决了现有区块链的瓶颈问题,同时为应用程序开发人员(完全兼容EVM字节码)和用户(兼容以太坊RPC API)保留了完全兼容性。因此,丰富的以太坊工具和应用密码学研究可以无缝接入到Monad,同时受益于Monad的高吞吐量和交易规模:
- 应用程序(在以太坊上构建的任何dapp)
- 开发人员工具(如:Hardhat、Apeworx、Foundry)
- 钱包(如:MetaMask)
- 链上分析/索引工具(如:Etherscan、Dune)
Monad客户端以性能为核心,采用C++和Rust语言编写。下文将介绍Monad的主要优化及用户交互。
面向用户的Monad
Monad是与以太坊兼容的高性能Layer1,为用户提供了两全其美的解决方案:可复制性和性能。
从可复制性的角度来看,Monad为以太坊虚拟机(EVM)提供了完整的字节码兼容性,因此在太坊上构建的应用程序无需修改代码即可复制到Monad;并且提供了完整的以太坊RPC兼容性,因此用户可以使用MetaMask或Etherscan等基础设施。
从性能角度来看,Monad拥有10,000tps的吞吐量,即每天10亿笔的交易量,另外Monad拥有按秒计算的出块时间和区块确认时间。这使得Monad能够支持比现有区块链更多的用户高并发交互,同时拥有更低廉的单笔交易成本。
对比以太坊,Monad有什么相似之处?
从用户角度来看,Monad的链上操作与以太坊非常相似。你可以使用熟悉的钱包(如MetaMask)或区块浏览器(如Etherscan)来签署或查看交易,在以太坊上构建的应用程序也可以复制到Monad上,无需修改代码,因此用户可以在Monad上使用最喜欢的以太坊应用程序。Monad中的地址空间与以太坊中的地址空间相同,因此用户可以使用现有的密钥在Monad上创建钱包。
与以太坊一样,Monad也具有linear blocks和区块内linear ordering排序的特点。
与以太坊一样,Monad也是一个由去中心化的验证者维护的权益证明网络。任何人都可以运行一个节点来独立验证交易的执行情况,并且已经采取了大量措施来保持最低的硬件要求。
对比以太坊,Monad有什么不同之处?
Monad通过在以太坊虚拟机中引入并行执行(parallel execution)和超标量流水线(superscalar pipelining)技术,使卓越的性能成为可能。
Parallel execution是指利用多个内核和线程有策略地并行执行交易,同时仍按原始排序提交交易结果。虽然交易在"内部"是并行执行的,但从用户和开发人员的角度来看,它们是串行执行的;一系列交易的结果总是相同的,就像这些交易是一个接一个地执行一样。
Superscalar pipelining是一种将执行单元划分为不同阶段,并且并行执行这些阶段的技术。可以通过以下图例阐明该技术:
当洗四件衣服时,“普通洗衣作业”的策略是在洗第二件衣服之前,完成第一件衣服的洗涤、烘干、折叠和储存;“pipelined洗衣作业”的策略是当第一件衣服洗涤完成进入烘干机时,开始洗涤第二件衣服,通过同时利用多个资源来更有效地完成工作。
Monad引入了pipelining执行技术,以解决现有区块链在状态存储、交易处理和分布式共识中的瓶颈。具体而言,Monad在以下四个方面引入了pipelining技术和其他优化:
- MonadBFT (pipelined HotStuff共识机制,以及更多的研究改进)
- Deferred Execution (在达成共识和执行之间进行pipelining作业,以大幅增加执行预算)
- Parallel Execution
- MonadDb (高性能状态后端)
Monad客户端采用C++和Rust语言编写,它反映了在这些架构上的优化,为去中心化应用程序提供了一个平台,可以真正扩展到全球范围。
你应该关心什么?
去中心化应用程序是中心化服务的替代品,具有若干显著优势:
- 开放式应用程序接口和可组合性:去中心化的应用程序可以被其他去中心化应用程序原子调用,允许开发人员通过堆栈现有组件来构建更复杂的功能。
- 透明性:应用程序的逻辑纯粹通过代码表达,因此任何人都可以审查程序的安全性,状态是透明和可审计的,默认情况下在DeFi中进行开源证明。
- 抗审查和可信中立性: 任何人都可以无需许可地向网络提交交易或上传应用程序。
- 全球覆盖:任何人只要能上网,就能获得重要的金融服务,包括unbanked/underbanked用户。
然而,去中心化应用程序需要廉价、高性能的基础设施,才能达到预期的影响水平。一个拥有100万日活跃用户(DAUs)和每个用户每天进行10笔交易的应用程序,每天需要吞吐1000万笔交易,即100tps。快速浏览一下L2Beat(一个研究EVM兼容的Layer1和Layer2区块链网络吞吐量和去中心化程度的网站)就会发现,目前没有任何EVM区块链支持或接近100tps的吞吐量水平。
Monad极大地提高了与EVM兼容的区块链网络的性能,开创了多项创新,有望在未来几年成为以太坊的标准。
有了Monad,开发人员、用户和研究人员可以采用大量现有的为EVM而构建的应用程序、库和应用密码学研究。
如何使用Monad?
Monad的首个公共测试网将在未来几个月内上线。
届时,用户可以在兼容以太坊的钱包中添加相应的RPC url和ChainId,然后像使用其他兼容以太坊的区块链一样开始使用Monad。在此之前,敬请期待!
面向开发者的Monad
Monad是与以太坊兼容的Layer1区块链,吞吐量为10,000 tps,区块时间为1秒,采用单时隙确定性(single-slot finality)。
Monad对以太坊虚拟机的优化符合上海升级的要求,使用Monad执行环境模拟以太坊历史交易会产生相同的结果。Monad还与以太坊RPC完全兼容,因此用户可以使用MetaMask和Etherscan等熟悉的工具与Monad进行交互。
Monad通过引入以下四项重大创新实现了这些性能的优化:
- MonadBFT (pipelined HotStuff共识机制,以及更多的研究改进)
- Deferred Execution (在达成共识和执行之间进行pipelining作业,以大幅增加执行预算)
- Parallel Execution
- MonadDb (高性能状态后端)
虽然Monad具有并行执行和流水线执行功能,但需要注意的是,Monad中的区块是线性的,交易在每个区块中也是线性排序的。
交易格式
智能合约
Monad支持EVM字节码,与以太坊字节码等效,支持所有操作码(截至上海升级)。
共识机制
相关属性 | 属性描述 |
---|---|
抗51%攻击机制 | 权益证明(PoS) |
委托投票权 | 允许(协议原生) |
共识机制和流水线机制 | MonadBFT是一种基于领导人选举的共识算法,用于在部分同步条件下就交易排序和打包达成一致。广义上,它是HotStuff的衍生算法,并进行了额外的研究优化。
MonadBFT是一种流水线式两阶段BFT算法,在一般情况下具有线性的communication overhead。与大多数BFT算法一样,通信分阶段进行,在每个阶段,领导人向投票者发送签名信息,投票者再发回签名回执。流水线作业允许区块 |
区块时间 | 1秒 |
最终确定性 | 单时隙确定性,一旦2/3的验证者对整块提议投了"支持"票,区块即最终确定。 |
内存池 | 有内存池,交易采用纠删码,并使用broadcast tree进行通信,以提高效率。 |
抵制垃圾交易 | 用户为交易打包进区块(“传输成本”)和交易执行(“执行成本”)付费。 |
共识参与者 | 直接共识参与者对区块提议进行投票,并担任领导人。要成为直接参与者,节点必须至少有 |
交易哈希 | 为提高效率,区块提议仅通过哈希值来引用交易。如果一个节点没有参与交易,它将通过哈希向邻居节点请求交易。 |
延迟执行和燃料成本 | 在Monad中,共识和执行以流水线方式进行。节点在执行正式交易排序(延迟执行)之前,会就该排序达成共识,执行结果并不是达成共识的先决条件。
在区块链中,通常执行是达成共识的先决条件,而执行的时间预算只占区块时间的一小部分。将共识和执行流水线化后,Monad就可以将全部区块时间用于共识和执行。
区块提议由交易哈希有序列表和 |
状态确认 | 最终确定性发生在共识时间,在这一点上,交易的官方排序是神圣的。对于任何全节点来说,结果都是完全确定的,它们通常会在1秒内执行该新块的交易。
状态merkle根的 |
执行机制
每个区块的执行阶段,在该区块达成共识后开始,并允许节点继续就后续区块达成共识。
并行执行
交易是按线性顺序排列的,执行作业是得出串行执行交易列表后的状态,最简单的方法就是一个接一个地执行交易。我们能做得更好吗?可以!
Monad采用并行执行:
- 执行器是执行交易的虚拟机,Monad可并行运行多个执行器。
- 执行器接收一笔交易并产生一个结果,结果是该笔交易的输入和输出列表,其中输入是执行过程SLOAD的(ContractAddress、Slot、Value)元组,输出是交易结果SSTORE的(ContractAddress、Slot、Value)元组。
- 结果最初在待处理状态下产生,然后按照交易的原始排序提交,当结果提交时,其输出会更新当前状态。在结果提交时,Monad会检查其输入是否仍与当前状态匹配,如果不匹配,Monad会重新安排交易。由于采用了并发控制,Monad能确保生成与串行执行交易相同的结果。
- 当交易被重新安排时,许多或全部需要的输入都已被缓存,因此重新执行的成本通常相对较低。需要注意的是,在重新执行时,交易可能会生成与上次执行不同的输入集。
MonadDb:高性能状态后端
所有交易的活动状态都存储在MonadDb中,MonadDb是由固态硬盘(SSD)组成的存储后端,专为存储merkle trie数据而优化。该数据更新是分批进行的,因此可以提高merkle根的更新效率。
MonadDb实现了内存缓存,并使用asio实现了高效的异步读写。节点至少配置32GB内存,以获得最佳性能。
与以太坊的比较:用户角度
相关属性 | Ethereum | Monad |
---|---|---|
每秒交易量(合约调用和转账) | ~10次 | ~10,000次 |
区块时间 | 12秒 | 1秒 |
最终确定性 | 2 epochs (12-18分钟) | 单时隙确定性 (1秒) |
字节码标准 | EVM (上海升级) | EVM (上海升级) |
RPC API | ||
密码学 | ECDSA | ECDSA |
账户 | ECDSA算法中,keccak-256公钥的最后20个字节 | ECDSA算法中,keccak-256公钥的最后20个字节 |
共识机制 | Gasper (Casper-FFG finality gadget + LMD-GHOST fork-choice rule) | MonadBFT (pipelined HotStuff 以及更多的研究优化) |
内存池 | 有 | 有 |
交易排序 | Leader's discretion (实际:PBS) | Leader's discretion (默认方案:PGA) |
抗51%攻击机制 | PoS | PoS |
投票权委托 | 不允许,需通过LSTs实现 | 允许 |
硬件要求 (全节点) | 4核 CPU 16GB 内存 1TB 固态硬盘 25Mbit/s 带宽 | 16核 CPU 32GB 内存 2TB 固态硬盘 100Mbit/s 带宽 |
技术讨论
相关概念
流水线技术(Pipelining)
Pipelining技术是一种实现并行化的技术,它将事务拆分成一系列可并行处理的较小事务。
Pipelining技术用于计算机处理器,致力于提高以相同时钟频率顺序执行一系列指令的吞吐量(处理器中还使用了其他技术来提高吞吐量)。有关指令级并行(ILP)的更多信息,请点击此处。
解释Pipelining技术的一个简单例子:
当洗四件衣服时,“普通洗衣作业”的策略是在洗第二件衣服之前,完成第一件衣服的洗涤、烘干、折叠和储存。“pipelined洗衣作业”的策略是当第一件衣服洗涤完成进入烘干机时,开始洗涤第二件衣服,通过同时利用多个资源来更有效地完成工作。
异步输入/输出(Asynchronous I/O)
Asynchronous I/O是一种输入/输出处理方式,它允许中央处理器在通信进行时继续并发执行。
硬盘和网络比中央处理器慢几个数量级,与启动输入/输出操作并等待结果相比,中央处理器可以在需要数据时立即启动输入/输出操作,并继续执行其他不依赖于输入/输出操作结果的指令。
一些粗略的比较,仅供参考:
硬件 | 延迟时间 | 传输速度 |
---|---|---|
中央处理器(三级缓存) | 10纳秒 | >400 GB/s |
内存 | 100纳秒 | 100 GB/s |
硬盘(NVMe 固态硬盘) | 400纳秒 | 380 MB/s |
网络 | 50-200毫秒 | 1 Gb/s (125 MB/s) |
(由fio报告的2KB随机读取的实际硬盘统计数据 - ~190k IOPS)
幸运的是,固态硬盘驱动器可以并发执行事务,因此CPU可以同时启动多个请求继续执行,然后同时接收多个事务的结果。
某些数据库(如:lmdb/mdbx)使用内存映射存储来读写磁盘,遗憾的是,内存映射存储是由内核(mmap)实现的,而不是异步的,因此在等待事务完成时会阻碍执行。
有关Asynchronous I/O的更多信息,请点击此处。
为什么选择区块链?
“是什么"和”为什么“的简单心智选择。
区块链是不同参与者就以下两件事达成的去中心化协议:
- 交易的官方排序(分类账)。
- 官方全局状态,包括用户账户余额和各种程序的状态。
在以太坊等现代区块链中,交易包括余额转移、创建新程序以及对现有程序的函数调用。到目前为止,所有交易的总结果就是当前状态,这就是为什么(1)的一致性意味着(2)的一致性。
区块链系统有一组协议规则,这些规则描述了当前同步的分布式节点集将如何相互通信,以商定每个节点应该使用的新交易列表。归纳法使节点保持同步:它们从相同的状态开始,同步相同的交易,因此在使用新的交易列表结束时,它们仍然具有一致的状态。(本文将忽略这种节点系统如何达成一致的细节,但你可以参阅Monad共识机制的文档,了解更多)。
共享全局状态用于开发去中心化应用程序——链上程序,即在区块链系统的每个节点上运行的应用程序。去中心化应用程序是一个代码块(以及长期的、特定于应用程序的状态),可以被任何用户调用,用户只需提交指向该应用程序功能的交易即可,区块链中的每个节点都负责正确执行被调用的字节码,重复工作可保证每个节点的诚实。
去中心化应用程序示例
去中心化应用程序可以实现我们可能期望以中心化方式实现的功能,去中心化应用程序的一个非常简单的例子就是虚拟银行(在加密领域通常被称为借贷协议)。
在现实世界中,银行是吸收存款并以较高利率放贷的企业,银行赚取存款和借贷之间的利差。借款人获得贷款,去做一些有经济效益的事情,存款人则从存款中赚取利息,大家都是赢家!
区块链虚拟银行只是一个拥有四种主要功能的应用程序:存款
、取款
、借款
、还款
,每种功能的逻辑主要是记账,以确保正确跟踪存款和贷款:
class VirtualBank:
def deposit(sender, amount):
# transfer amount from sender to myself (the bank)
# do internal bookkeeping to credit the sender
def withdraw(sender, amount):
# ensure the sender had enough on deposit
# do internal bookkeeping to debit the sender
# transfer amount from myself (the bank) to sender
def borrow(sender, amount):
# ...
def repay(sender, amount);
# ...
在以太坊或Monad中,有人可以为这个虚拟银行编写代码并上传,然后任何人都可以利用它进行借贷,与其所在国实体银行相比,区块链虚拟银行服务可能方便得多。
这个简单的例子显示了去中心化应用程序的威力,这里还有其他优势值得一提:
- 开放式应用程序接口/可组合性:去中心化应用程序可被其他去中心化应用程序原子调用,允许开发人员通过堆栈现有组件来构建更复杂的程序功能。
- 透明性:去中心化应用程序的功能逻辑纯粹通过代码实现,因此任何人都可以审查程序的安全性,状态是透明和可审计的,默认情况下在DeFi中进行开源证明。
- 抗审查和可信中立性: 任何人都可以无需许可地向区块链提交交易或上传应用程序。
- 全球覆盖:任何人只要能上网,就能获得重要的金融服务,包括unbanked/underbanked用户。
为什么选择Monad:去中心化+性能
去中心化问题
区块链有几个主要组成部分:
- 共识机制,用于就添加到分类账的交易确认达成一致。
- 执行/存储系统,用于维持区块链活动状态。
在提高这些组件的性能时,可以偷工减料,例如要求所有节点在物理上相互靠近(以节省达成共识的开销),或要求大量使用RAM(以将大部分或全部状态缓存在内存中),但这是以牺牲去中心化为代价的。
而去中心化正是关键所在!
正如”为什么是区块链“章节中所讨论的,去中心化的全局状态共享允许多方协调,同时依赖于单一、共享、客观的真实消息源。去中心化是问题的关键,由一小群节点操作员(或在极端情况下,一个操作员!)维护的区块链将无法拥有去信任化、可信的中立性和抗审查性等特征。
对于任何区块链网络来说,去中心化都应该是主要关注点,提高性能不应以牺牲去中心化为代价。
当下区块链性能瓶颈
以太坊当前的执行限制(1.25M Gas/每秒)设置得比较保守,这样做有几个理由:
- 低效的存储访问模式
- 单线程执行
- 执行时间预算非常有限,因为没有执行就无法达成共识
- 对状态增长的担忧,以及状态增长对未来状态访问成本的影响
Monad通过改进算法和架构来解决这些局限性,开创了多项创新,有望在未来几年成为以太坊的标准。保持高度去中心化,同时进行实质性的性能优化,这是关键的考虑因素。
通过优化解决瓶颈问题
Monad在以下四个主要方面实现了流水线作业并有其他优化,从而使以太坊虚拟机具有卓越的性能,极大地推动了区块链的去中心化和可扩展性博弈的有效边界。下文将介绍这些主要方面的优化:
共识机制
Monad拜占庭容错共识机制(MonadBFT)
流水线式两阶段HotStuff共识机制(Pipelined two-phase HotStuff)
MonadBFT是一种高性能共识机制,用于在拜占庭参与者存在的情况下,在部分同步条件下就交易排序达成一致。它是HotStuff的衍生机制,在Jolteon/DiemBFT/Fast-HotStuff中采用了优化方案,即在领导人超时的情况下,利用二次通信复杂度将三轮共识减少到两轮。
MonadBFT是一种流水线式两阶段BFT算法,具有乐观响应性,在普通情况下通信开销为线性,在超时情况下通信开销为二次方。与大多数BFT算法一样,通信分阶段进行,在每个阶段,领导人向投票者发送签名信息,投票者再向下一位领导人发送签名回执,流水线作业允许区块 k
的法定人数证书(QC)或超时证书(TC)捎带区块 k+1
的提议。
基本情况
相关属性 | 属性描述 |
---|---|
抗51%攻击机制 | 权益证明 (PoS) |
区块时间 | 1秒 |
最终确定性 | 单时隙确定性 |
投票权委托 | 允许 |
内存池
请参阅共享内存池
共识协议
MonadBFT是一种流水线式共识机制,分轮次进行。以下内容提供了对协议的高级直观理解。
按照惯例,假设有 n=3f+1
个节点,其中 f
是拜占庭节点的最大数量, 2f+1
(即 2/3)个节点是非拜占庭节点。在下面的讨论中,我们将所有节点视为具有相同投票权,实际上,所有阈值都可以用投票权而不是节点数来表示。
- 在每一轮中,领导人都会发出一个新的区块,以及上一轮的QC或TC(稍后将详细介绍)。
- 每个验证者都会审查该区块是否符合协议,如果通过,则将签名的”同意"选票发送给下一轮领导人,然后该领导人通过汇总(通过阈值签名)来自
2f+1
个验证者的 "同意"选票,得出QC(法定人数证书)。请注意,这种情况下的消息是线性的:领导人向验证者发送区块,验证者直接向下一轮领导人发送选票。 - 每个验证者在收到第
k+1
轮的QC时(在第k+2
轮领导人的消息中),最终确定第k
轮提出的区块。具体来说:
另外,如果验证者在预先指定的时间内没有收到有效数据块,它就会向所有对等设备广播一个签名的超时消息,该超时消息还包括验证者观察到的最高QC。如果任何验证者积累了 2f+1
个超时消息,它就会将这些消息(同样通过阈值签名)组合成一个TC(超时证书),然后直接发送给下一轮领导人。
第 k
轮的领导人Alice会向所有人发送一个新的区块(同时发送第 k-1
轮的QC或TC。我们忽略这一点,因为它并不重要)。
如果有 2f+1
个验证者通过向Bob(第 k+1
轮的领导人)发送选票来对该区块投同意票,那么 k+1
中的区块将包含第 k
轮的QC。然而,验证者Valerie此时看到第 k
轮的QC并不足以让她知道第 k
轮的区块已被纳入。原因例如:Bob可能是恶意的,他只向Valerie发送了该区块,Valerie所能做的就是对区块 k+1
进行投票,并将她的投票发送给Charlie(第 k+2
轮的领导人)。
如果有 2f+1
个验证者对区块 k+1
投同意票,那么Charlie就会发布 k+1
轮的QC以及 k+2
轮的区块提议。一旦Valerie收到这个区块,她就知道第 k
轮的区块(即Alice的区块)已经最终确定。
假设Bob在第 k+1
轮恶意发送了一个无效的区块提议,或者向少于 2f+1
个验证者发送了该提议,那么至少有 f+1
个验证者会超时,然后触发其他非拜占庭验证者超时,这样至少有一个验证者产生 k+1
轮的TC。然后,Charlie将在他的提议中公布第 k+1
轮的TC(他必须这样做才能提出提议,因为第 k+1
轮没有QC)。
我们把这种提交流程称为2-chain提交规则,因为只要验证者看到2个相邻的被证明块 B
和 B'
,就可以提交 B
及其所有祖先块。
参考资料:
- Maofan Yin, Dahlia Malkhi, Michael K. Reiter, Guy Golan Gueta, and Ittai Abraham. HotStuff: BFT Consensus in the Lens of Blockchain, 2018.
- Mohammad M. Jalalzai, Jianyu Niu, Chen Feng, Fangyu Gai. Fast-HotStuff: A Fast and Resilient HotStuff Protocol, 2020.
- Rati Gelashvili, Lefteris Kokoris-Kogias, Alberto Sonnino, Alexander Spiegelman, and Zhuolun Xiang. Jolteon and ditto: Network-adaptive efficient consensus with asynchronous fallback. arXiv preprint arXiv:2106.10362, 2021.
- The Diem Team. DiemBFT v4: State machine replication in the diem blockchain. 2021.
BLS多重签名
证书(QC和TC)可以在secp256k1 curve上以ECDSA签名向量的形式简单实现,这些证书是明确的,易于构建和验证。但是证书的大小与签名者的数量成线性关系,除了投票信息外,几乎每条共识消息都包含证书,这限制了区块链扩容。
BLS12-381 curve上基于配对的BLS签名有助于解决扩容问题,签名可以逐步聚合成一个签名,验证单个有效的聚合签名就能证明与公钥相关的投票权都已在消息上签名。
BLS签名比ECDSA签名慢得多,出于性能考虑,MonadBFT采用了一种混合签名方案:BLS签名只用于可聚合的消息类型(投票和超时),消息的完整性和真实性仍由ECDSA签名提供。
共享内存池
内存池
待处理的用户交易存储在每个验证者的内存池中,直到它们被包含在最终确认的区块中。待处理交易通过纠删码与其他验证者内存池共享,然后通过广播树进行通信,以提高效率。
交易哈希
MonadBFT是就任意有效负载达成一致的有效方法,然而区块广播仍然是一个重大瓶颈。例如,一个包含10,000笔交易和500个字节交易的区块将达到5MB,这种大小的区块将对验证者节点的带宽提出过高要求。
为了缓解这一问题,区块提议只通过哈希值引用交易,这大大节省了哈希,因为哈希值是32字节。因此所有验证者内存池在对提议进行投票以及提交区块时,都需要在自己的内存池中保存交易。提交给验证者内存池的交易会通过纠删码与其他验证者内存池共享,然后通过广播树进行通信,以提高效率。
延迟执行
Monad区块链的一个新颖之处在于执行与共识分离,采用流水线式共识执行分级机制。
简而言之,共识是Monad节点就交易的官方排序达成一致的过程,而执行则是实际执行这些交易并更新状态的过程。
在Monad共识中,节点就交易的官方排序达成一致,但领导人节点或验证节点都无需执行这些交易。
也就是说,领导人在不知道结果状态根的情况下提出排序,验证节点投票区块的有效性,可以不知道区块中的所有交易执行是否可以回滚。
怎么会这样?为什么Monad会这样做?
这个答案是Monad设计的基石,它使Monad能够大幅提升交易速度,让单体分片区块链扩展到数百万用户。
交错执行 & 共识效率低
在以太坊中,执行是达成共识的先决条件。因此当节点就一个区块达成共识时,它们先要就以下两点达成共识:(1) 该区块中的交易列表;(2) 归集执行该交易列表后所有状态的merkle根。因此领导人在共享提议之前必须执行提议区块中的所有交易,而验证节点在响应投票之前也必须执行这些交易。
在这种模式下,执行的时间预算极为有限,因为它必须执行两次,并留出足够的时间进行多轮跨全局通信以达成共识。另外由于执行过程会限制共识达成,因此必须极其保守地选择Gas限制,以确保即使在最极端的情况下,所有节点上的计算都能在预算范围内完成。
确定的排序意味着状态确定性
这里有一个显而易见却又至关重要的见解:给定一个官方的交易排序,正确的状态就完全确定了,需要执行才能揭示真相,但真相已经确定。
Monad利用了这一见解,取消了节点在达成共识前执行交易的要求。节点协议仅是关于官方排序,每个节点独立执行区块 N
中的交易,同时开始就区块 N+1
达成共识。
这样就可以获得与整个区块时间相对应的Gas预算,因为执行过程只需紧跟共识即可。此外,这种方法对精确计算时间变化的容忍度更高,普遍而言,执行只需紧跟共识即可。
延迟merkle根仍能确保状态机复制
人们可能对上述观点提出的主要反对意见是:
- 如果其中一个节点是恶意的,没有执行共识中指定的确定性交易,会发生什么情况?(例如,它忽略了某些交易,或者只是将状态变量设置为自己选择的任意值)。
- 如果其中一个节点在执行过程中出错,会发生什么情况?
为了解决以上问题,在Monad中,区块提议包含有一个延迟了 D
个区块的merkle根,其中 D
是一个全局参数(目前预计为10)。因为这种延迟的merkle根:
- 在网络就区块
N
达成共识(2/3的多数票)后,意味着网络已同意区块N-D
的官方结果处于遵循merkle根M
的状态,此时轻客户端可以检索全节点,以获得区块N-D
的状态变量值的merkle证明。 - 在区块
N-D
执行中出现错误的任何节点将从区块N
开始脱离共识层,这将触发该类节点回滚到区块N-D-1
的结束状态,重新执行区块N-D
中的交易(希望能实现merkle根匹配),接着重新执行N-D+1
、N-D+2
等区块中的交易。
以太坊的方法是使用共识,以非常严格的方式执行状态机复制:在节点达成共识后,我们知道绝大多数认同官方排序和由该排序产生的状态结果。然而这种严格的方法带来了巨大的代价——极其有限的吞吐量,Monad在此处稍微放宽了,取得了很好的效果。
最终确定性
在MonadBFT中,最终确定性采用单时隙确定性(时间为1秒),对于使用全节点的人来说,执行结果一般会滞后不到1秒。让我们来解读一下这一点:
Monad中的最终确定性采用单时隙确定性(时间为1秒),如果你提交了一笔交易,你将在一个区块后看到该交易的官方排序(在所有其他交易中)。除非网络中的绝大多数人采取恶意行为,否则不存在回滚重新排序的可能性,这使得Monad的最终确定性速度远快于以太坊(2 个epochs,时间为12.8分钟)。
交易的执行结果(成功还是失败?交易后的余额是多少?)通常会在全节点上延迟不到1秒的最终确定性,任何需要快速了解交易结果的人(例如,想要了解交易状态的高频交易员)都可以运行全节点。Monad会最大限度地减少全节点的运行成本,更多信息请参阅硬件要求。
任何人如果想在不运行全节点的情况下安全地查询交易结果,可以运行一个轻客户端,同时用merkle证明查询全节点的余额,在这种情况下,查询将滞后于merkle根(延迟D=10
个区块,即10秒)。请注意,目前大多数用户都是使用软件/浏览器钱包或通过区块浏览器查看区块链状态,此类查询方式均不涉及轻客户端。
有些读者可能会错误地将merkle根(延迟了 D=10
个区块)与最终确定性混为一谈,误以为最终确定性就是10个区块的时间。事实并非如此,官方交易排序是在1个区块后确定的,在此之后,如果没有绝大多数的拜占庭行为,就不会有任何更改。
传输成本和储备金余额
方法与动机
延迟执行的功能非常强大,因为它允许执行和共识并行作业,从而大大增加了执行的时间预算。
一个显而易见的反对意见是:既然共识节点没有最新的状态视图,那么如何防止它们误将已消耗掉所有Gas的账户的交易打包进区块,这将会产生DoS攻击。
为了防止这种情况发生,Monad为区块链上的交易传输设置了成本(即"传输成本")。每个账户将保留一个储备金余额,在交易达成共识时更新,并根据储备金余额收取传输成本。
传输成本
在Monad中,通过区块网络进行交易需要支付费用("传输成本"),这是一项独立于执行成本的费用。
传输成本是防止垃圾交易所必需存在的,费用极低,但反映了利用网络资源的成本。
交易有可能被纳入共识(并被收取传输成本),但相对于指定的Gas限额,假设执行预算不足,在这种情况下,交易在执行时会失败,但仍会收取失败交易的Gas费用。请注意,这与以太坊并无不同:当账户中ETH不足时提交交易,将耗尽ETH并失败。为防止执行交易时出现失败,用户有必要在交易前为账户充值足够多的Gas。
储备金余额
对于每个账户,节点保持同步两个余额:
- 储备金余额,用于支付传输成本
- 执行余额,用于支付交易执行费用
当交易被纳入区块(达成共识)时,传输成本从储备金余额中扣除;当交易执行时,费用从执行余额中扣除(双重费用);在 D
个区块延迟(10秒)后,对储备金余额中的传输成本进行递减操作。
储备金实际上是"待确认"交易的费用预算,它的存在是为了确保区块中只打包了已支付交易费用的交易。你可以认为储备金余额是实时递减的(即在达成共识时),虽然节点对全局状态的洞察是滞后的,但储备金余额总是反映最新的交易费用支出。
预设储备金余额
预设储备金余额是每个账户已设定的参数,默认值预计为传输成本的较大倍数(200 倍),这样用户就可以顺利提交大量待确认交易。
如果用户计划从同一EOA账户发送大量待确认交易,则可通过与嵌入式智能合约交互来更改预设储备金余额。预设储备金余额的更改被视为执行,即只有在延迟期过后才会反映在储备金余额中。
执行机制
并行执行
Monad以并行方式执行交易,乍看起来,这似乎有着与以太坊不同的执行原语。实际并非如此,Monad区块与以太坊区块相同——是一组线性有序的交易集,区块中执行交易的结果在Monad和以太坊中是相同的。
乐观执行
在基础层面上,Monad使用乐观执行,这意味着Monad会在区块中较早的交易完成之前开始执行当前交易。有时(但并不总是),这会导致执行错误。
思考两笔交易(在区块中按此顺序排列):
- 交易1:读取并更新账户A的余额(例如,接收来自账户B的转账)。
- 交易2:仍会读取和更新账户A的余额(例如,向账户C转账)。
如果这些交易是并行执行的,而交易2在交易1完成之前就开始执行,那么它为账户A读取的余额可能与按顺序执行时的余额不同, 这可能导致执行错误。
乐观执行解决这个问题的方法是跟踪交易2执行时的输入,并将其与交易1的输出进行比较。如果两者不同,我们就检测到交易2在执行时使用了错误的数据,此时需要使用正确的数据再次执行。
在Monad并行执行交易的同时,每个交易的更新状态都是按顺序"合并”的,以便检查是否有上述问题出现。
于此相关的计算机科学研究有乐观并发控制(OCC)和软件事务内存(STM)。
乐观执行的影响
在乐观执行的朴素方式中,直到区块中的早期交易完成后,我们才会发现交易需要再次执行。此时,所有早期交易的状态更新都已合并,因此该交易不可能再次因乐观执行而失败。
在执行交易的过程中,有些步骤并不依赖于状态。例如,重复签名是一项昂贵的计算,再次执行交易时,这项工作无需重复。
此外,由于合并失败而再次执行交易时,访问的账户和存储往往不会改变,因为状态仍缓存在内存中,因此这项昂贵的工作不需要重复操作。
执行调度
乐观执行的朴素方式会在处理器有可用资源时尝试开始执行下一笔交易,区块中可能存在相互依赖的长"链“交易,并行执行这些交易会导致大量故障。
提前确定交易之间的依赖关系,可以让Monad只在前序交易完成后才调度交易执行,从而避免资源浪费。Monad采用静态代码分析技术,可以尝试做出这样的预测。在良好状态下,Monad可以提前预测出许多依赖关系;在极端情况下,Monad会退回到朴素执行方式。
未来工作
探索更多避免重复执行交易的方法,并实现它们。
MonadDb
MonadDb是用于存储区块链状态的自定义数据库。
大多数以太坊客户端使用的键值数据库都是以B-Tree(例如LMDB)或LSM-Tree(例如LevelDB和RocksDB)数据结构实现的,然而以太坊却使用Merkle Patricia Trie(MPT)数据结构来存储状态。这是一种次优解决方案,一种数据结构被嵌入到另一种不同类型的数据结构中。为了避免这种情况发生,MonadDb在磁盘和内存中都原生实现了Patricia Trie数据结构。
Monad可以并行执行多笔交易,当一笔交易需要从磁盘读取状态时,系统不应停滞等待前序操作完成,而应启动读取,然后在此期间同步处理另一笔交易。关键在于此操作要求数据库支持异步输入/输出(async i/o),而上述提到的键值数据库缺乏相应的异步输入/输出支持(尽管在这方面有一些改进)。MonadDb充分利用了最新内核支持异步输入/输出(在Linux上是io_uring),这就避免了为了异步执行交易而产生大量内核线程来处理待处理的输入/输出请求。
MonadDb还对输入/输出进行了其他一些优化,例如绕过文件系统,因为文件系统会增加昂贵的开销。
Monad的交易生命周期
交易提交
交易的生命周期开始于用户发起一个已签名的交易并将其提交给RPC节点。
交易通常由应用程序前端准备,然后提交给用户钱包进行签名。大多数钱包都会调用 eth_estimateGas
RPC来预设该笔交易的Gas限额,不过用户也可以在钱包中修改该限额,用户通常还会被要求选择交易的Gas价格,即每单位Gas的本机代币数量。
用户在其钱包中批准签名后,签名交易将通过 eth_sendTransaction
或 eth_sendRawTransaction
API调用提交到RPC节点。
值得注意的是,在Monad中,Gas限额是传输成本Gas和执行成本Gas之和,传输Gas是一个常数。
内存池广播
RPC节点会将待处理交易广播给参与共识的其他Monad节点,待处理交易集也叫"内存池"。有关内存池作业的更多详情,请参阅内存池章节。
出于防止垃圾交易的原因,只有当储备金余额中有足够的Gas时,节点才会将该笔交易添加到其内存池中。
区块打包
MonadBFT采用轮值领导人机制来生成区块,每一轮的领导人都会从待处理交易集中选出一个区块。在将一笔交易打包进区块后,领导人会对储备金余额中的传输成本进行递减操作。
如MonadBFT所述,区块会在网络中广播,该区块的法定人数证书(QC)会在随后一轮共识中广播(即由下一任领导人发出);接收到QC证书后,投票节点会相互发送投票;当一个节点检测到2/3的投票权投同意票时,它就会最终确认该区块。
一旦区块被最终确认,该笔交易就在区块链交易历史上正式"发生"了。由于其排序已确定,因此其真值(即成功还是失败,以及执行后的结果)也就确定了。
本地执行
节点一旦确认一个区块,就会开始执行该区块中的交易。出于效率考虑,交易以并行方式优化执行,由于结果总是按原始排序提交,因此就像串行执行交易一样。
结果查询
用户可以在任何RPC节点上调用 eth_getTransactionByHash
或 eth_getTransactionReceipt
来查询交易结果,RPC节点上的本地执行完成后,将立即返回结果。
其他详细信息
账户
Monad中的账户与以太坊账户相同,使用与以太坊相同的地址空间(ECDSA的20字节地址)。与以太坊账户一样,Monad也分外部账户(EOA)和合约账户。
交易
Monad中的交易格式与以太坊一致,即符合EIP-2718标准,交易使用RLP编码。
支持可选访问列表 (EIP-2930),但不是必需的。
区块和交易的线性
区块仍然是线性的,区块内的交易也是线性的。并行执行仅用于提高效率,绝不会影响一系列交易的真实结果或结束状态。
燃料(Gas)
Gas(或许更明确地命名为 "本币的计算单位")的设置与以太坊相同,每个操作码都需要花费一定量的Gas。在Monad中,每个操作码的Gas成本与以太坊相同,但未来可能会更新。
当用户提交交易时,会在交易中加入Gas限额(该函数调用在交易失败前可消耗的最大Gas数量)和Gas价格(每单位Gas成本,以本币为单位)。
默认Monad客户端中的领导人使用优先Gas竞拍(PGA)提交交易,即按照Gas报价从高到低排序交易,未来可能会有其他的交易排序机制。排序的选择与下游发生的一切无关,有效的排序选择并不包含在Monad协议中。
使用Monad
运行一个节点
硬件要求
运行Monad全节点的硬件要求如下:
- 中央处理器: 16 core CPU
- 内存: 32GB RAM
- 硬盘: 2TB NVMe SSD
- 带宽: 100 Mb/s
在Monad上开发
建议资源
Monad与EVM字节码完全兼容,支持上海升级后的所有操作码和预编译,Monad还保留了标准的以太坊JSON-RPC接口。
因此,以太坊主网的大部分开发资源都适用于Monad,本章节为在以太坊上构建去中心化应用程序的开发者提供了一套最基础的资源。
由于Solidity是以太坊智能合约最常用的语言,因此本章节的资源主要集中在Solidity,包括部分Vyper和Huff的资源。请注意,由于智能合约是可组合的,最初用一种语言编写的合约仍可以调用另一种语言的合约。
集成开发环境(IDE)
- Remix是一款交互式Solidity集成开发环境,它是编码和编译Solidity智能合约最简单快捷的方式,无需安装其他工具。
- VSCode + Solidity extension
Solidity入门教程
- CryptoZombies是在EVM上构建去中心化应用程序的最佳学习教程。它为任何人提供了资源和课程,适用于从零代码编写经验,到希望探索区块链深度开发的所有人员。
- Solidity by Example通过简单的开发示例,循序渐进地介绍相关概念,最适合已有其他语言开发基础经验的人员阅读。
Solidity中级教程
- Solidity Language围绕EVM环境,对智能合约和区块链基础知识进行了详细阐述。除了Solidity Language文档外,它还涵盖了在EVM上编译代码、部署合约的基础知识,以及提供了在EVM上部署合约的相关基本组件。
- Solidity Patterns提供了代码模板库及其用法说明。
- Uniswap V2合约是一个专业而易于理解的智能合约,它提供了一个正在运行中的 Solidity dApp的全局视图,该合约的演示在此处。
- Cookbook.dev提供了一套交互式合约模板示例,具有实时编译、一键部署和人工智能聊天集成功能,可帮助解决代码问题。
- OpenZeppelin 为ERC20、ERC712和ERC1155等常见的以太坊代币部署提供了可定制的合约模板。请注意,它们没有进行Gas优化。
Solidity高级教程
- Solmate资源库和Solady资源库利用Solidity或Yul提供Gas优化合约。
- Yul是Solidity的一种中间语言,一般可视为EVM的内联汇编。它并不完全是纯粹的汇编语言,它提供控制流结构并抽象出堆栈的内部工作,同时仍向开发人员提供原始内存后台。Yul主要面向需要接触EVM原始内存后台的开发人员,以构建高性能、Gas优化的EVM合约代码。
- Huff最接近于EVM汇编,与Yul不同,Huff不提供控制流结构,也不抽象程序堆栈的内部工作。只有对性能最敏感的应用程序才会使用Huff,但它是学习EVM诠释最底层指令的绝佳教学工具。
本地节点
开发人员通常会发现,运行一个修改了参数的以太坊单节点,对交互测试很有帮助:
如何安装相应工具包,并获得本地节点,下一章节将详细介绍。
工具包
开发人员通常会发现,在一个功能齐全的开发框架内构建自己的程序能提高开发效率。开发框架可以组织外部依赖关系(即软件包管理),组织单元测试和集成测试,定义部署程序(针对本地节点、测试网和主网),记录Gas成本等。
以下是两种最常用的Solidity开发工具包:
- Foundry是一个用于开发和测试的Solidity开发框架,Foundry可以管理依赖关系、编译项目、运行测试、部署,并允许用户通过命令行或Solidity脚本与链进行交互,Foundry用户通常使用Solidity语言编写智能合约和测试。
- Hardhat是一个Solidity开发框架,搭配有JavaScript测试框架,它具有与Foundry类似的功能,在Foundry出现之前是EVM开发人员的主要工具链。
与以太坊RPC API交互
去中心化应用程序的前端通常使用JavaScript或Python向RPC节点提交读取或写入查询,这些代码通常被称为 "客户端",因为开发人员可以将区块链大致等同于后台服务器。
以下资源库提供了向RPC节点提交查询或交易的标准方法:
- Python:
- Javascript:
这里是一个创建去中心化应用程序前端的快速示例:create-eth-app。
测试网
Monad测试网将在未来几个月内提供给开发者使用,由于字节码和RPC与EVM兼容,计划在Monad上部署的开发者可以初步使用以太坊的测试网。
更多资源
EVM behavior
EVM behavior规范
- 关于EVM的说明:EVM的直接技术规范和一些behavior示例
- EVM:从Solidity到字节码、内存和存储: Peter Robinson和David Hyland-Wood 90分钟的讲座
- EVM图解:一套用于衡量开发者心智水平的出色图表
- EVM深度挖掘:通往隐形超级编码器之路
操作码参考
evm.codes:操作码参考(包括Gas成本)和用于单步执行字节码的交互式沙盒
Solidity存储布局
EVM允许智能合约将数据存储在32字节的单词("存储槽")中,但复杂数据结构(如列表或映射)则留给更高级的语言来处理,Solidity有一种将变量分配到存储槽的特定方法,如下所述:
Solidity资源
除了 "建议资源 "中提到的资源外,这里还有一些其他资源:
教程
- Ethernaut:通过解谜学习Solidity
最佳实践/模式
测试
- Echidna:模糊测试
- Slither:用于漏洞检测的静态分析
- solidity-coverage:测试Solidity代码覆盖率
智能合约存档
- Smart contract sanctuary:在以太坊上验证智能合约
- EVM函数签名数据库
链上调试
交易反馈与追踪
- Tenderly
- EthTx Transaction Decoder
- https://openchain.xyz/
- Bloxy
- https://github.com/naddison36/tx2uml:生成UML图表的操作系统工具
- https://github.com/apeworx/evm-trace: 追踪工具
合约反编译
- https://oko.palkeo.com/:Panoramix反编译器的托管版本
其他语言
Vyper语言
Vyper是一种流行的EVM编程语言,逻辑上类似于Solidity,语法上类似于Python。
Vyper文档包括Vyper语言的安装、语法、编码示例和编译。
我们鼓励希望获得类似Python体验的典型EVM开发人员使用Vyper作为编程语言,并使用采用Python语言构建的ApeWorx作为测试和部署框架,ApeWorx还允许在分析测试结果时使用典型的Python库,如Pandas。
Vyper和ApeWorx可与Jupyter配合使用,后者提供了一个使用网络浏览器的交互式环境。 有关使用Vyper和Jupyter为EVM开发智能合约的快速指南,请点击此处。
Vyper相关资源
- Vyper示例
- Snekmate:基于Vyper语言的智能合约Gas优化模块库
- Curve contracts:Vyper语言最突出的使用实例
Huff语言
Huff最接近于EVM汇编,与Yul不同,Huff不提供控制流结构,也不抽象程序堆栈的内部工作。只有对性能最敏感的应用程序才会使用Huff,但它是学习EVM诠释最底层指令的绝佳教学工具。
- Huff资源库:提供关于Huff语言的资源