区块链NFT投资,BTC/USDT/CGPAY,虚拟加密货币交易行情分析平台
深入理解以太坊二层方案 Arbitrum 技术架构
百款NFT链游免费玩 | 数字货币支付图解教程 | 区块链游戏获利技巧 |
简单来说,Arbitrum 在 Layer 2 实现了 AVM 虚拟机,在虚拟机上再模拟 EVM 执行环境。
推荐阅读:《》
Arbitrum 是 Layer2 Rollup 的一种方案。和 Optimism 类似,状态的终局性采用「挑战」(challenge) 机制进行保证。Optimism 的挑战方法是将某个交易完全在 Layer1 模拟执行,判断交易执行后的状态是否正确。这种方法需要在 Layer 1 模拟 EVM 的执行环境,相对复杂。Arbitrum 的挑战相对轻便一些,在 Layer1 执行某个操作(AVM),确定该操作执行是否正确。Arbitrum 介绍文档中提到,整个挑战需要大概 500 字节的数据和 9w 左右的 gas。为了这种轻便的挑战机制,Arbitrum 实现了 AVM 虚拟机,并在 AVM 虚拟机中实现了 EVM 的执行。AVM 虚拟机的优势在于底层结构方便状态证明。
Arbitrum 的开发者 详细介绍了 Arbitrum 架构和设计。对 AVM 以及 L1/L2 交互细节感兴趣的小伙伴可以耐心地查看「Inside Arbitrum」章节。
整体框架
Arbitrum 的开发者文档给出了各个模块关系:
Arbitrum 的系统主要由三部分组成(图中的右部分,从下到上):EthBridge,AVM 执行环境和 ArbOS。EthBridge 主要实现了 inbox/outbox 管理以及 Rollup 协议。EthBridge 实现在 Layer1。ArbOS 在 AVM 虚拟机上执行 EVM。简单的说,Arbitrum 在 Layer2 实现了 AVM 虚拟机,在虚拟机上再模拟 EVM 执行环境。用 AVM 再模拟 EVM 的原因是 AVM 的状态更好表达,便于 Layer1 进行挑战。
EthBridge 和 AVM 执行环境对应的
ArbOS 对应的
这个模块关系图太过笼统,再细分一下:
EthBridge 主要实现了三部分功能:inbox,outbox 以及 Rollup 协议。inbox 中「存放」交易信息,这些交易信息会「同步」到 ArbOS 并执行。outbox 中「存放」从 L2 到 L1 的交易,主要是 withdrawl 交易。Rollup 协议主要是 L2 的状态保存以及挑战。特别注意的是,Arbitrum 的所有的交易都是先提交到 L1,再到 ArbOS 执行。ArbOS 除了对外的一些接口外,主要实现了 EVM 模拟器。整个模拟器实现在 AVM 之上。整个 EVM 模拟器采用 mini 语言实现,Arbitrum 实现了 AVM 上的 mini 语言编译器。简单的说,Arbitrum 定义了新的硬件(machine)和指令集,并实现了一种上层语言 mini。通过 mini 语言,Arbitrum 实现了 EVM 模拟器,可以执行相应交易。
AVM State
因为所有的交易都是在 AVM 执行,交易的执行状态可以用 AVM 状态表示。AVM 相关实现的代码在 arbitrum/packages/arb-avm-cpp 中。
AVM 的状态由 PC,Stack,Register 等状态组成。AVM 的状态是这些状态的 hash 值拼接后的 hash 结果。
AVM 使用 c++实现,AVM 表示的逻辑实现在 MachineStateKeys 类的 machineHash 函数(machinestate.cpp)中。AVM 的特别之处就是除了执行外,还能较方便的表达(证明)执行状态。深入理解 AVM 的基本数据结构,AVM 的基本的数据类型包括:
using value = std::variant<Tuple, uint256_t, CodePointStub, HashPreImage, Buffer>; enum ValueTypes { NUM, CODEPT, HASH_PRE_IMAGE, TUPLE, BUFFER = 12, CODE_POINT_STUB = 13 };
uint256_t - 整数类型
CodePoint - 当前代码指令表示
Tuple - 元组,由 8 个 Value 组成。元组中的某个元素依然可以是元组
Buffer - 数组,最长为 2^64
HashPreImage - 固定的 hash 类型,hashValue = hash(value, prevHashValue)
每种数据类型除了数据表示外,还能非常方便地计算其 hash 值作为状态。详细看看 CodePoint 和 Tuple 基本数据类型。
CodePoint
CodePoint 类型将多个操作「捆绑」在一起,每个 CodePoint 除了记录当前的 Operation 外,还包括前一个 CodePoint 的 hash 信息。这样所有的 Operation 可以串连起来,当前的 CodePoint 除了能表达当前的 Operation 外,还能明确 Operation 的依赖关系。CodePoint 的类型定义在:packages/arb-avm-cpp/avm_values/include/avm_values/codepoint.hpp。
struct CodePoint { Operation op; uint256_t nextHash; CodePoint(Operation op_, uint256_t nextHash_) : op(op_), nextHash(nextHash_) {} bool isError() const { return nextHash == 0 && op == Operation{static_cast(0)}; } };
Tuple
Tuple 类型由 RawTuple 实现。RawTuple 是由一组 value 组成。Tuple 限制最多 8 个 value。
struct RawTuple { HashPreImage cachedPreImage; std::vector data; bool deferredHashing = true; RawTuple() : cachedPreImage({}, 0), deferredHashing(true) {} };
Tuple 的类型定义在:packages/arb-avm-cpp/avm_values/include/avm_values/tuple.hpp。
在理解了基础类型的基础上,DataStack 可以由一系列 Tuple 实现:
总结一下,AVM 中的 PC,Stack,Register 等等的状态都能通过 hash 结果表示。AVM 整个状态由这些 hash 值的拼接数据的 hash 表示。
Rollup Challenge
在提交到 L1 的状态有分歧时,挑战双方(Asserter 和 Challenger)先将状态分割,找出「分歧点」。明确分歧点后,挑战双方都可提供执行环境,L1 执行相关操作确定之前提交的状态是否正确。L1 的挑战处理逻辑实现在 arb-bridge-eth/contracts/challenge/Challenge.sol。整个挑战机制有超时机制保证,为了突出核心流程,简化流程如下图所示:
挑战者通过 initializeChallenge 函数发起挑战。接下来挑战者 (Challenger) 和应战者 (Asserter) 通过 bisectExecution 确定不可再分割的「分歧点」。在确定分歧点后,挑战者通过 oneStepProveExecution 函数确定 Assert 之前提交的状态是否正确。
initializeChallenge
function initializeChallenge( IOneStepProof[] calldata_executors, address_resultReceiver, bytes32_executionHash, uint256_maxMessageCount, address_asserter, address_challenger, uint256_asserterTimeLeft, uint256_challengerTimeLeft, IBridge_bridge ) external override { ... asserter =_asserter; challenger =_challenger; ... turn = Turn.Challenger; challengeState =_executionHash; ... }
initializeChallenge 确定挑战者和应战者,并确定需要挑战的状态(存储在 challengeState)。challengeState 是由一个和多个 bisectionChunk 状态 hash 组成的 merkle 树树根:
整个执行过程可以分割成多个小过程,每个小过程 (bisection) 由起始和结束的 gas 和状态来表示。
turn 用来记录交互顺序。turn = Turn.Challenger 表明在初始化挑战后,首先由 Challenger 发起分歧点分割。
bisectExecution
bisectExecution 挑选之前分割片段,并如可能将片段进行再次分割:
bisectExecution 的函数定义如下:
function bisectExecution( bytes32[] calldata_merkleNodes, uint256_merkleRoute, uint256_challengedSegmentStart, uint256_challengedSegmentLength, bytes32_oldEndHash, uint256_gasUsedBefore, bytes32_assertionRest, bytes32[] calldata_chainHashes ) external onlyOnTurn {
_chainHashes 是再次分割点的状态。如果需要再次分割,需要满足分割点的个数规定:
uint256 private constant EXECUTION_BISECTION_DEGREE = 400; require( _chainHashes.length == bisectionDegree(_challengedSegmentLength, EXECUTION_BISECTION_DEGREE) + 1, "CUT_COUNT" );
简单的说,每次分割,必须分割成 400 份。
_oldEndHash 是用来验证状态这次分割的分割片段是上一次分割中的某个。需要检查分割的有效性:
require(_chainHashes[_chainHashes.length - 1] !=_oldEndHash, "SAME_END"); require( _chainHashes[0] == ChallengeLib.assertionHash(_gasUsedBefore,_assertionRest), "segment pre-fields" ); require(_chainHashes[0] != UNREACHABLE_ASSERTION, "UNREACHABLE_START"); require( _gasUsedBefore <_challengedSegmentStart.add(_challengedSegmentLength), "invalid segment length" );
起始状态正确。这次分割不能超出上次分割范围,并且最后一个状态和上一个分割的结束状态不一样。
bytes32 bisectionHash = ChallengeLib.bisectionChunkHash( _challengedSegmentStart, _challengedSegmentLength, _chainHashes[0], _oldEndHash ); verifySegmentProof(bisectionHash,_merkleNodes,_merkleRoute);
通过 merkle 树的路径检查确定起始状态和结束状态是上一次某个分割。
updateBisectionRoot(_chainHashes,_challengedSegmentStart,_challengedSegmentLength);
更新细分分割对应的 challengeState。
oneStepProveExecution
当不能分割后,挑战者提供初始状态(证明),并由 L1 进行相应的计算。计算的结果应该和提供的 _oldEndHash 不一致。不一致说明挑战者成功证明了之前的计算结果不对。
(uint64 gasUsed, uint256 totalMessagesRead, bytes32[4] memory proofFields) = executors[prover].executeStep( bridge, _initialMessagesRead, [_initialSendAcc,_initialLogAcc], _executionProof, _bufferProof );
通过 executeStep 计算出正确的结束状态。executeStep 实现在 packages/arb-bridge-eth/contracts/arch/OneStepProofCommon.sol 中。核心是 executeOp 函数,针对当前的 context 读取 op,执行并更新状态。感兴趣的小伙伴可以自行查看。
rootHash = ChallengeLib.bisectionChunkHash( _challengedSegmentStart, _challengedSegmentLength, oneStepProofExecutionBefore( _initialMessagesRead, _initialSendAcc, _initialLogAcc, _initialState, proofFields ), _oldEndHash ); } verifySegmentProof(rootHash,_merkleNodes,_merkleRoute);
确定初始状态和结束状态是上一次挑战状态中的某个分割。初始状态由提供的证明(proof)计算获得。
require( _oldEndHash != oneStepProofExecutionAfter( _initialSendAcc, _initialLogAcc, _initialState, gasUsed, totalMessagesRead, proofFields ), "WRONG_END" );
确认 _oldEndHash 和计算获得结束状态不一样。不一样才说明之前提交的结束状态是错误的。
_currentWin();
计算完成后,确定胜利方。
总结
Arbitrum 是 Layer2 Rollup 的一种方案。采用挑战机制确定 Rollup 状态的终局性。为了引入轻便挑战机制,Arbitrum 定义了 AVM,一种可以方便证明执行状态的虚拟机,并设计了 mini 语言和编译器。在 AVM 上模拟了 EVM 的执行环境,兼容 EVM。挑战时将执行过程进行 400 分分割,由 L1 执行少量指令确定状态是否正确。
百款NFT链游免费玩 | 数字货币支付图解教程 | 区块链游戏获利技巧 |
相关文章
热门推荐
- 解析波卡平行链插槽拍卖参与方式及潜在影响
- 俄罗斯国家杜马一读通过俄罗斯大选候选人披露其加...
- 可编程基础设施将成为现有金融体系的补充
- TrustBase 将于今日 21:00 上线于火币生态链建立的...
- 专注高端加密艺术市场的 NFT 平台
- L2 扩容方案 zkSync 2.0 公开三项资产安全保护措施...
- DAOSquare 将于 5 月 23 日进行 Balancer LBP
- 内蒙古等多地矿场被清退,比特币系统会受影响吗?...
- Darwinia Crab 发布 Kusama 卡槽竞拍计划
- Terra 生态稳定币 UST 出现脱锚征兆,到底发生了什...
- 刚刚为第三支基金募得 1.25 亿美元的 1confirmatio...
- Gitcoin 推出治理代币 GTC,你领到了多少回溯空投?
- 短期抛售未改变比特币的基本面
- Richest的数字货币投资学习日记和空投整理 | 区块...
- Arbitrum、Optimism 与 Polygon
- 以太坊波动率指数交易平台 volmex.finance 将于 6 ...
最新文章
- 关税不确定性将于 4 月 2 日消除,但涨跌难测
- 川普将于周三宣布「对等关税」,市场屏息以待
- BitMEX 前执行长 Arthur Hayes 、共同创办人等 4 ...
- 马斯克澄清「美国政府无意采用狗狗币」!浇熄市场...
- 币托「消费即投资」再加一!携凯基银行推首张「点...
- 遏制内线交易、打击诈欺!日本拟将「加密货币」列...
- FTX 预告 5 月 30 启动大额还款!比特币赔掉 80% ...
- 「8 千枚比特币」沉睡多年突苏醒!加密货币市场将...
- LUNA 、 UST 崩盘近 3 年终于等到!Terraform Labs...
- 以太坊「Pectra 升级」暂定 4 月 30 日实施,尚待...
- 「120 亿美元比特币选择权」将到期,会冲击市场吗...
- 吉卜力风暴席卷加密市场!币安 Alpha 率先上架 2 ...
- 巨鲸大户「2 周狂扫 110 亿美元比特币」,市场信心...
- 全球首个去中心化私募融资平台 - AIX,重塑投资未来!
- 怀俄明州跑全美第一!州长预期最快 7 月推稳定币、...
- Hoodi 测试网升级「彩排成功」!以太坊 Pectra 升...