资讯动态

Foundry 本地 EVM 回放支持 Celo CIP-64 动态费用交易:类型转换与实现解析

发布时间:2026/9/16 16:44:56 来源:尧图企业网站定制
Foundry 本地 EVM 回放支持 Celo CIP-64 动态费用交易类型转换与实现解析【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry本文基于 .changelog/celo-dynamic-fee-replay.md 记录的变更cast: patch、forge: patch展开Foundry 现已允许将 Celo CIP-64 交易转换为本地 EVM 可回放的形式。文章将结合 crates/evm/core/src/env.rs、crates/evm/networks/src/celo/mod.rs 等源码剖析该能力背后的类型投影逻辑、安全边界与测试验证帮助读者理解 Foundry 如何处理非标准交易类型以及如何在cast run等场景中回放 Celo 链上交易。变更背景为什么需要转换 Celo CIP-64 交易Foundry 的核心工作流之一是把链上真实发生的交易“拉回”本地 EVM 中重新执行一遍——这就是本地 EVM 回放local EVM replay。无论是cast run复现一笔链上交易还是forge在 fork 链上重新执行区块都需要先把 RPC 返回的eth_getTransactionByHash结果转换成 revm 可以执行的TxEnv。Celo 链上存在一种特殊的交易类型由CIP-64Celo Improvement Proposal 64引入的动态费用交易。它本质上是一笔带有 Celo 特性feeCurrency字段的 EIP-1559 交易交易类型号type byte为0x7b。在 crates/evm/networks/src/celo/mod.rs 中Foundry 明确给出了该常量的定义/// Celo dynamic fee transaction type introduced by CIP-64. pub const CELO_DYNAMIC_FEE_TX_TYPE: u8 0x7b;问题在于Alloy 的通用交易解码AnyTxEnvelope并不认识0x7b这种网络私有类型CIP-64 交易会被解码为AnyTxEnvelope::Unknown的未知信封。此前这类交易在回放时会直接转换失败导致cast run无法复现 Celo 链上的真实交易。本次变更正是为了解决这一问题允许 Celo CIP-64 交易被转换为本地 EVM 回放所需的执行环境。核心实现FromAnyRpcTransaction 的 CIP-64 投影转换逻辑位于 crates/evm/core/src/env.rs 的FromAnyRpcTransactiontrait 实现中。该 trait 的职责是把一个AnyRpcTransactionRPC 返回的任意类型交易转换为具体的TxEnv/// Trait for converting an [AnyRpcTransaction] into a specific TxEnv. /// /// Ethereum envelopes delegate to [FromRecoveredTx]. Implementations may also explicitly /// project compatible network-specific envelopes into their execution environment. pub trait FromAnyRpcTransaction: Sized { /// Tries to convert an [AnyRpcTransaction] into Self. fn from_any_rpc_transaction(tx: AnyRpcTransaction) - eyre::ResultSelf; }对于标准以太坊交易EIP-1559、Legacy 等实现直接委托给FromRecoveredTx走常规路径。当交易是AnyTxEnvelope::Unknown且类型号为0x7b时则进入 CIP-64 专属分支。关键代码如下crates/evm/core/src/env.rs// CIP-64 transactions have EIP-1559 execution fields plus a Celo-specific fee currency. // Foundry does not model fee payment in TxEnv, but can replay their EVM payload. Preserve // the custom type so revm does not compare the fee-currency price with the native-CELO // base fee. Keep this projection restricted to active Celo chains so an unrelated network // cannot silently acquire semantics for its own type 0x7b envelope. if let AnyTxEnvelope::Unknown(unknown) *tx.inner.inner unknown.ty() CELO_DYNAMIC_FEE_TX_TYPE matches!( unknown.chain_id().and_then(NamedChain::from_chain_id), Some(NamedChain::Celo | NamedChain::CeloSepolia) ) { return Ok(Self { tx_type: CELO_DYNAMIC_FEE_TX_TYPE, caller: tx.from(), gas_limit: unknown.gas_limit(), gas_price: unknown.max_fee_per_gas(), gas_priority_fee: unknown.max_priority_fee_per_gas(), kind: unknown.kind(), value: unknown.value(), data: unknown.input().clone(), nonce: unknown.nonce(), chain_id: unknown.chain_id(), access_list: unknown.access_list().cloned().unwrap_or_default(), ..Default::default() }); }这段实现的要点值得逐条拆解字段投影CIP-64 交易具备 EIP-1559 的执行字段maxFeePerGas、maxPriorityFeePerGas、accessList等因此可以直接投影为TxEnv的对应字段。gas_price取max_fee_per_gasgas_priority_fee取max_priority_fee_per_gas与 EIP-1559 的语义一致。保留自定义类型号tx_type被显式设置为CELO_DYNAMIC_FEE_TX_TYPE0x7b。源码注释解释了原因——Foundry 的TxEnv并不建模手续费支付fee payment但可以回放 CIP-64 的 EVM 载荷保留原始类型号是为了让 revm 不会把 feeCurrency 的价格与原生 CELO 的 base fee 进行比较。失败即报错如果tx_type不是0x7b或链 ID 不匹配最终会走到eyre::bail!(cannot convert unknown transaction type to TxEnv)转换失败并返回明确错误信息。值得一提的是该 trait 还为 Tempo另一条使用自定义信封类型的网络实现了TempoTxEnv的转换crates/evm/core/src/env.rs其模式与 CIP-64 分支一致从Unknown信封中提取字段并额外读取feeToken。这说明 Foundry 对“未知信封投影”这一能力做了通用化抽象Celo CIP-64 只是其中的一个实例。安全边界为何限定 Celo 与 Celo Sepolia 链 IDCIP-64 转换分支中有一个容易被忽略但至关重要的约束——必须同时匹配链 ID matches!( unknown.chain_id().and_then(NamedChain::from_chain_id), Some(NamedChain::Celo | NamedChain::CeloSepolia) )也就是说仅仅类型号是0x7b还不够交易必须来自 Celo 主网或 Celo Sepolia 测试网投影才会生效。源码注释明确说明了这一设计意图防止无关网络悄无声息地获得对自家0x7b信封的语义解释。因为交易类型号在不同链上可能复用若某个与 Celo 无关的链恰好也使用0x7b作为自己的私有类型直接套用 CIP-64 语义会导致错误的执行结果。这种“类型号 链 ID”双重校验的做法避免了因类型号冲突而引发的跨链语义污染是本次实现中值得借鉴的安全设计模式。测试验证单元测试如何覆盖该能力实现是否可靠测试是最直接的证据。在 crates/evm/core/src/env.rs 中from_any_rpc_transaction_for_celo_dynamic_fee测试构造了一笔完整的 CIP-64 RPC JSON类型0x7b、链 ID0xa4ec即十进制 42220 的 Celo 主网链 ID验证转换结果#[test] fn from_any_rpc_transaction_for_celo_dynamic_fee() { let from Address::with_last_byte(0xAA); let to Address::with_last_byte(0xBB); let fee_currency Address::with_last_byte(0xCC); let json serde_json::json!({ accessList: [], blockHash: B256::ZERO, blockNumber: 0x1, chainId: 0xa4ec, feeCurrency: fee_currency, from: from, gas: 0x5208, gasPrice: 0x3, hash: B256::ZERO, input: 0x1234, maxFeePerGas: 0x3, maxPriorityFeePerGas: 0x1, nonce: 0x2a, r: B256::ZERO, s: B256::ZERO, to: to, transactionIndex: 0x0, type: 0x7b, v: 0x0, value: 0x65, yParity: 0x0 }); // ... 略去非 Celo 链的负向断言 let tx_env TxEnv::from_any_rpc_transaction(any_tx).unwrap(); assert_eq!(tx_env.tx_type, CELO_DYNAMIC_FEE_TX_TYPE); assert_eq!(tx_env.caller, from); assert_eq!(tx_env.nonce, 42); assert_eq!(tx_env.gas_limit, 21000); assert_eq!(tx_env.gas_price, 3); assert_eq!(tx_env.gas_priority_fee, Some(1)); assert_eq!(tx_env.kind, TxKind::Call(to)); assert_eq!(tx_env.value, U256::from(101)); assert_eq!(tx_env.data, Bytes::from_static([0x12, 0x34])); assert_eq!(tx_env.chain_id, Some(42_220)); }该测试覆盖了三层行为正向转换CIP-64 交易的各个字段被正确投影到TxEnv包括tx_type、caller、nonce、gas_limit、gas_price、gas_priority_fee、value、data、chain_id等逐字段断言确认无遗漏。负向边界测试先将chainId改为0x1以太坊主网断言TxEnv::from_any_rpc_transaction(non_celo_tx).is_err()验证了链 ID 限制确实生效。对照组同文件中的from_any_rpc_transaction_for_eth验证标准 EIP-1559 交易走FromRecoveredTx常规路径from_any_rpc_transaction_unknown_envelope_errors则验证未知类型0xFF会报错。CIP-64 分支恰好处于“标准信封可转换”与“完全未知类型不可转换”之间。与回放流程的衔接cast run 中的实际调用转换能力最终要服务于真实的回放流程。以cast run为例其核心执行逻辑在 crates/cast/src/cmd/run.rs 的execute_ordinary中fn execute_ordinary(mut self) - ResultTraceResult { // Decode the target transaction before replaying the block: an envelope this build // cant decode should fail fast. let target_tx_env TxEnvFor::FEN::from_any_rpc_transaction(self.tx)?; let target_index self.target_index()?; self.prepare_target(); // ... self.for_each_prefix_transaction(target_index, |_, tx| { if !is_system_transaction(tx) || replay_system_txes { let tx_env TxEnvFor::FEN::from_any_rpc_transaction(tx).wrap_err_with(|| { format!( Failed to prepare transaction: {:?} in block {}, tx.tx_hash(), block_number ) })?; replay.push((tx.tx_hash(), tx_env)); } Ok(()) })?; let result self.executor.transact_with_ordinary_block_replay( self.evm_env.clone(), target_tx_env, replay, )?; // ... }回放流程对 CIP-64 的支持体现在两个层面目标交易用户指定的那笔交易首先通过from_any_rpc_transaction解码如果解码失败则快速失败fail fast避免后续无效执行。前缀交易目标交易所在区块中位于其之前的交易会被逐一转换为TxEnv并先行回放用于重建目标交易执行前的链上状态。CIP-64 交易作为前缀交易时同样走转换逻辑出错时会附带交易哈希与区块号的上下文信息。换句话说本次变更让cast run不仅能回放 Celo 链上的 CIP-64 目标交易还能在包含 CIP-64 交易的区块中正确重建前缀状态。类似地TxEnvFor::FEN::from_any_rpc_transaction在 crates/evm/core/src/backend/mod.rs 的 fork 后端区块处理中也被广泛复用为 forge 测试在 fork 链上遇到 CIP-64 交易时提供了同样的转换能力。生态支撑Celo 交易回放所需的配套能力CIP-64 交易转换只是 Celo 链上回放的一部分。交易执行过程中Celo 特有的 EVM 语义还需要以下配套支撑它们共同构成 Foundry 的 Celo 支持矩阵Celo transfer 预编译Celo 的 token 二元性token duality体系通过地址0xfd的 transfer 预编译实现原生代币的 ERC20 化转账实现在 crates/evm/networks/src/celo/transfer.rs 中。该预编译接收 96 字节输入from/to/value 各 32 字节固定 gas 成本 9000并会校验余额不足与溢出见 crates/evm/networks/src/celo/transfer.rs。CIP-64 交易如果调用了该预编译回放时依赖这段实现。网络配置挂载预编译的启用与网络配置通过FoundryInspectorExt的get_networks()接入执行器见 crates/evm/core/src/lib.rs即“为 Celo 预编译支持保留的配置”。fork 链上的系统交易处理crates/anvil/tests/it/fork_chains.rs 的注释明确指出fork 链回放需要处理 Orbit 系统交易、Celo CIP-64 交易、OP-stack deposits 等各类链特有交易并说明了链上铸币交易的差异Celo 同时存在 CIP-640x7b与 OP-stack deposits。小结变更的影响范围与使用提示本次变更以cast: patch与forge: patch两个补丁的形式落地核心结论如下能力Celo CIP-640x7b动态费用交易现在可以被FromAnyRpcTransaction转换为本地 EVM 的TxEnv支持在cast run及 fork 后端中进行本地回放。限制转换仅对链 ID 匹配 Celo 主网或 Celo Sepolia 的交易生效非 Celo 网络的0x7b交易仍会报cannot convert unknown transaction type to TxEnv。设计取舍Foundry 不建模 feeCurrency 手续费支付只回放 EVM 载荷并通过保留原始tx_type避免 revm 错误比较 base fee。验证核心转换逻辑有逐字段断言的正向测试与跨链负向测试双重保障。对于在 Celo 链上开发或调试的读者使用cast run tx_hash --rpc-url celo_rpc复现链上交易时CIP-64 交易已可正常转换回放若交易涉及 feeCurrency 计费语义需注意本地回放仅模拟 EVM 执行而非完整结算。本文所涉实现与测试均可在当前仓库对应路径中直接查阅验证。【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价