evm2rv 接收 EVM 运行时字节码(即 solc --bin-runtime 的输出),并将其转换为 Rand 程序。它生成 C 代码,再由 rand-guest build 将 C 代码编译为 RV32IM 镜像。该镜像与 Rand 的 EVM 解释器 guest(evm.bin)使用相同的输入向量,并发布相同的八个输出字。它以原生方式运行合约,而不是逐条操作码地解释执行。本页展示 ERC-20 的完整流程。
它是什么
| 输入 | EVM 运行时字节码,十六进制文本(.hex)或原始字节 |
| 输出 | 一个 C shim crate;rand-guest build 将其构建为镜像容器 |
| 运行位置 | 链下,在开发者的机器上;链上只能看到镜像 |
| 必须匹配的内容 | evm.bin 的状态、八个输出字和 gas_used |
| 代码仓库 | circuits 仓库中的 evm2rv/ |
| 固定的工具链 | Rust 1.98.1、clang 23.1.1、cc crate 1.4.6 |
转译器处理的是运行时代码,而非创建代码。一次证明只覆盖对已部署合约的一次调用,因此构造函数不会运行。构造函数本应写入的状态则作为前置状态的一部分,以存储见证的形式提供。
转译分为两个阶段。两者给出相同的结果和 gas;每个阶段都是各自独立的程序,有各自的 hc。
| 阶段 | 标志 | 作用 |
|---|---|---|
| 一 | --stage 1 | 每个操作码都基于内存栈实现 |
| 二 | --stage 2,默认 | 每个基本块的栈字放入 C 局部变量,常量在转译时折叠 |
输入向量与解释器的相同:代码、calldata、调用者及其他环境字、gas 上限、前置状态根,以及调用所涉及的每个存储槽对应的一个存储见证。输出为 out[0],即状态(1 表示成功,0 表示回滚,2 表示异常停机),以及 out[1..8],即对代码哈希、两个状态根、返回数据和日志计算的 EVM_OUT 摘要。
信任模型
验证者分两步检查转译后的合约。
hc == translate(bytecode)。 使用相同的--stage和--chain-id,对已发布的字节码重新运行evm2rv,用固定的工具链重新构建,并比较hc。生成的 crate 精确固定了cc的版本,并自带Cargo.lock。- 代码守卫将
hc与字节码绑定。 转译后的逻辑被编译进镜像,但CODECOPY和CODESIZE读取的是输入向量中的代码。若无检查,同一个hc可能在调用者选定的代码字节上运行。因此contract.c携带源字节码的 Poseidon2 摘要(其长度和字节),shim 在运行任何转译代码之前,以同样的方式对输入向量中的代码做哈希。其他代码会被拒绝:状态 2,gas_used为 0,停机原因OutOfBounds。
EVM_OUT 摘要同样绑定代码的 keccak256,与解释器的做法相同。链上不记录源字节码或其哈希。若要让他人核对 hc,请发布字节码,或者发布 Solidity 源码及确切的 solc 构建。
在 transfer 上,守卫耗费 1,008 个周期。与源代码相差一个字节的代码,在阶段二以 30,418 个周期被拒绝(tier 16)。
覆盖范围与会触发陷阱的情况
操作码。 Shanghai 指令集。请使用 --evm-version shanghai 编译:较新的目标会生成 MCOPY 及其他 Cancun 操作码,这些操作码会触发陷阱。
环境操作码:
| 操作码 | 转译方式 |
|---|---|
ADDRESS、CALLER、CALLVALUE、CALLDATASIZE、CODESIZE | 取自输入向量,与解释器的读取方式相同 |
CHAINID | 取 --chain-id 的值,在转译时固化,因此 hc 绑定该值;代码包含 CHAINID 时必须提供 |
ORIGIN | 等于 CALLER(一次调用,没有中继者) |
GASPRICE、COINBASE、TIMESTAMP、NUMBER、PREVRANDAO、GASLIMIT、SELFBALANCE、BASEFEE、BLOCKHASH | 触发陷阱(状态 2),与解释器相同 |
这九个区块上下文操作码会触发陷阱,直到有将它们绑定到区块的设计为止。私有输入无法携带区块事实,因为验证者无法打开 H_IN。在做出该决定之前,读取时间或区块号的合约(例如 permit 的截止时间)会触发陷阱。
调用。 当目标为地址 1 至 9 时,CALL、CALLCODE、DELEGATECALL 和 STATICCALL 运行预编译合约。任何其他目标都会触发陷阱。CALL 或 CALLCODE 带非零 value 会触发陷阱:没有余额模型。
预编译合约。 九个预编译均以软件方式运行。由于一次证明最多容纳 2²⁰ 行,有些目前过慢,无法证明:
| 预编译 | 向量 | 周期数 | 是否容纳于 2²⁰ |
|---|---|---|---|
| 1 ecrecover | ValidKey | 14,510,525 | 否 |
| 2 sha256 | ”abc” / 200 bytes | 2,791 / 5,289 | 是 |
| 3 ripemd160 | ”abc” | 12,195 | 是 |
| 4 identity | 100 bytes | 4,498 | 是 |
| 5 modexp | nagydani-1-square / -1-pow0x10001 | 122,332 / 874,548 | 是 |
| 5 modexp | eip_example1 (256-bit) | 11,170,118 | 否 |
| 5 modexp | nagydani-5-pow0x10001 (1,024-byte) | 55,076,950 | 否 |
| 6 bn256 add | chfast1 | 978,262 | 是,刚好 |
| 7 bn256 mul | chfast1 | 3,060,669 | 否 |
| 8 bn256 pairing | 1 pair / 2 pairs | 1,853,656,212 / 2,019,000,469 | 否 |
| 9 blake2f | 12 rounds | 14,493 | 是,最多约 1,800 轮 |
modexp 的底数和模数各自上限为 1,024 字节。
可接受的差异。 状态、八个字和 gas_used 必须一致。有三处差异是可接受的:停机的种类可能不同(静态 gas 在每个基本块的开头扣除,因此 OutOfGas 与另一种停机可能互换;两者都是状态 2 且耗尽全部 gas);转译实现了 CHAINID、ORIGIN 和预编译调用,而解释器对这些会触发陷阱;以及代码守卫会拒绝源代码以外的代码。
数据
带有代码守卫的 ERC-20 调用。周期数来自 rand-guest run;括号内为 tier。
| 调用 | 解释器(evm.bin) | 阶段一 | 阶段二(默认) |
|---|---|---|---|
transfer(BOB, 250) | 121,638 (18) | 80,211 (18) | 66,235 (18) |
approve(BOB, 5) | 85,645 (18) | 56,261 (16) | 48,119 (16) |
transferFrom(ALICE, BOB, 100) | 161,434 (18) | 110,074 (18) | 88,824 (18) |
| 程序 | 字数 | hc |
|---|---|---|
evm.bin,解释器 | 18,009 | 7e1aea2b…854c08 |
| ERC-20,阶段一 | 15,804 | 9cdb79e7…2fd048c8 |
| ERC-20,阶段二 | 11,686 | a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6 |
阶段二运行这三个调用,分别只用解释器周期数的 54.5%、56.2% 和 55.0%。transfer 仍停留在 tier 18:其 66,235 个周期加上 3,155 行摘要,共 69,390 行,比 tier 16 的 65,535 多出 3,855 行。
阶段二 transfer 中约 60%(约 39,928 个周期)是两个镜像共有的框架开销:解码输入、验证存储见证、ABI 的 keccak256 调用以及输出摘要。任何转译工作都无法降到这一下限以下。
演练:ERC-20,从 Solidity 到输出一致
每条命令都在 7ef3220 版本的 circuits 检出目录根部运行,工具链来自 Deploy a Rust program,clang 23.1.1 来自 Deploy a RISC-V program。较长的输出在标有 … 处截断。
0. 构建工具
(cd evm2rv && cargo +1.98.1 build --release)
(cd rand-guest && cargo +1.98.1 build --release)
1. 将 Solidity 编译为运行时字节码
合约是已提交的 guests-compiled/evm/contracts/ERC20.sol:一个自包含的 ERC-20,采用 OpenZeppelin v4 的存储布局,pragma solidity 0.8.37。请严格使用 solc 0.8.37;其他版本的优化方式不同,会生成不同的字节码。
| 发行版本 | v0.8.37,来自 github.com/ethereum/solidity/releases |
| macOS 资源 | solc-macos,sha256 a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821 |
| Linux 资源 | solc-static-linux,来自同一发行版本 |
$ curl -sSL -o solc https://github.com/ethereum/solidity/releases/download/v0.8.37/solc-macos
$ shasum -a 256 solc
a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821 solc
$ chmod +x solc && ./solc --version
solc, the solidity compiler commandline interface
Version: 0.8.37+commit.f401782d.Darwin.appleclang
$ (cd guests-compiled/evm && ../../solc --optimize --optimize-runs 200 --evm-version shanghai \
--bin-runtime contracts/ERC20.sol) | tee solc.out
======= contracts/ERC20.sol:ERC20 =======
Binary of the runtime part:
608060405234801561000f575f5ffd5b5060043610610060575f3560e01c8063095ea7b31461006457806318160ddd1461008c57806323b872dd1461…
$ tail -1 solc.out > evm2rv/target/mytoken.hex
最后一行是运行时字节码,共 1,296 字节。它与已提交的 guests-compiled/evm/contracts/erc20.runtime.hex 逐字节相同;SOLC=$PWD/solc bash guests-compiled/evm/contracts/build.sh 会检查这一点,并打印 contracts: erc20.runtime.hex reproduces。
这些标志很重要:
--bin-runtime:已部署的代码,而非创建代码。--evm-version shanghai:0.8.37 的默认目标会生成MCOPY,它会触发陷阱。--optimize --optimize-runs 200:面向已部署合约的配置。
2. 转译
$ evm2rv/target/release/evm2rv evm2rv/target/mytoken.hex --out evm2rv/target/mytoken --chain-id 12
1296 code bytes: 74 blocks, 798 opcodes, 51 jumpdests (stage 2)
CHAINID is the constant 12
no trapping opcodes present
wrote evm2rv/target/mytoken (crate mytoken): contract.c, Cargo.toml, Cargo.lock, build.rs, src/main.rs, shim.ld
--out必须位于 circuits 检出目录之内。没有它,evm2rv只分析代码。- 任何会触发陷阱的操作码都会在此作为警告列出,并附带其 pc。
- 此次会话以
--chain-id 12捕获。这个 ERC-20 不含CHAINID,因此--chain-id不会改变它的hc。读取CHAINID的合约必须提供该标志;请将其设为你将要部署的链(对于在线链,使用--chain-id 19)。
contract.c 以代码守卫的摘要结尾:
const uint32_t *evm_code_digest(void) {
static const uint32_t d[8] = {0xf679280fu, 0x86c10e83u, 0x7e8f1f39u, 0xa2377de3u, 0x8a2e282fu, 0xc54cad42u, 0xddfaf009u, 0x7d28a8afu};
return d;
}
3. 构建镜像
默认上限为 4,096 个字,因此请传入 --max-words 65535。
$ rand-guest/target/release/rand-guest build evm2rv/target/mytoken --max-words 65535
…
11686 words against a cap of 65535 (fits); 0 ecall(s) with a non-static a7
OK
wrote evm2rv/target/mytoken/image.bin and its .sha256 (11686 words, hc a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6, program id f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d)
$ rand-guest/target/release/rand-guest info evm2rv/target/mytoken/image.bin
form: image container
text 11147 words at 0x10000; data 408 words (205 non-zero) at 0x1ae2c; prologue 539 words; program 11686 words from base_pc 0xf794
hc a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6
program id f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d
11686 words against a cap of 4096: does not fit
这就是已发布的阶段二 hc。crate 名称不会影响它。
4. 构建输入向量并运行 transfer
erc20_vector 示例会将一致性测试的向量打印为输入字:transfer(ALICE 从其 1,000 中向 BOB 发送 250)、approve(ALICE 允许 BOB 花费 5)和 transferFrom(BOB 在额度为 300 的授权下,从 ALICE 的 1,000 中转移 100)。对于你自己的合约,请以同样方式在 Rust 中构建 EvmCall;该示例就是模板。
$ (cd evm2rv && cargo +1.98.1 run -q --release --example erc20_vector -- transfer > target/transfer.words)
921 input words
$ rand-guest/target/release/rand-guest run evm2rv/target/mytoken/image.bin --input $(cat evm2rv/target/transfer.words)
out[0] = 1
out[1] = 513227413
out[2] = 3087537901
out[3] = 995619457
out[4] = 4004100029
out[5] = 234390638
out[6] = 3262201797
out[7] = 3842361427
cycles 66235
tier 18
5. 与解释器比较
同一输入在解释器 guest 上运行:
$ rand-guest/target/release/rand-guest run guests-compiled/bin/evm.bin --input $(cat evm2rv/target/transfer.words)
out[0] = 1
out[1] = 513227413
out[2] = 3087537901
out[3] = 995619457
out[4] = 4004100029
out[5] = 234390638
out[6] = 3262201797
out[7] = 3842361427
cycles 121638
tier 18
以及在主机上原生运行的解释器,即测试的预言机(oracle):
$ (cd evm2rv && cargo +1.98.1 run -q --release --example erc20_vector -- transfer --expected)
out[0] = 1
out[1] = 513227413
…
out[7] = 3842361427
interpreter (native): status 1, Return, gas_used 29956
作为一条命令的检查:
$ diff <(rand-guest/target/release/rand-guest run evm2rv/target/mytoken/image.bin --input $(cat evm2rv/target/transfer.words) | grep '^out') \
<(rand-guest/target/release/rand-guest run guests-compiled/bin/evm.bin --input $(cat evm2rv/target/transfer.words) | grep '^out') \
&& echo "the eight words are identical"
the eight words are identical
对 approve 和 transferFrom 重复第 4 步和第 5 步;两者给出的字数组完全相同。cd evm2rv && cargo +1.98.1 test --release 会运行这些测试,以及另外五组向量,两个阶段均包含在内,并且还会检查 gas_used(70 个测试,外加 2 个被忽略的证明)。
| 转译后(第二阶段) | 解释器(evm.bin) | |
|---|---|---|
| 八个输出字 | 相同 | 相同 |
| 周期数,transfer | 66,235 | 121,638 |
| 层级 | 18 | 18 |
| 程序字数 | 11,686 | 18,009 |
6. 部署
rand program deploy evm2rv/target/mytoken/image.bin
钱包会打印程序 id、字数和 hc,然后在生成任何证明之前检查链的上限。该镜像为 11,686 个字,因此需要一条创世块将 max_program_words 设置为至少 11,686 的链。链 12 采用默认值 4,096,所以部署在那里被拒绝。链 13,即 v0.4 链,将 max_program_words 设置为 65,535,此后的每条链都保持这一取值。链 20 是当前运行的链(创世哈希 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135),它同样沿用链 13 的区块、调用信封和公开输入限制,并将证明大小上限减半至 4 MiB(4,194,304 字节,自链 17 起;链 13 至 16 设为 8 MiB)。字数上限不再是唯一的门槛。链 20 的创世块设置了 hardening_v6,在此设置下,若部署的程序字数超过一次调用在 tier-14 调用上限下所能容纳的数量,则该部署无效(ProgramUncallable):在没有公开输入时最多为 8,180 个字。该镜像为 11,686 个字,因此链 20 会拒绝此次部署,同样也会拒绝相应的调用:每一次 ERC-20 调用都在层级 16 或 18 上生成证明,高于 tier-14 调用上限(第 7 步)。链 20 上的区块聚合处于关闭状态(其创世块没有 aggregation 部分);其引导节点列于运行验证者。部署费用为 0.001 + 0.0001 × 11,686 = 1.1696 RAND,即下文链 13 上的部署所支付的费用。
此次部署于 2026-09-19 在链 13 上运行,当时链 13 是运行中的链(生产 FRI 配置,创世哈希 8123ccac1883a45750e4df6964fb7cd3f0b321798cde4c0ef406a0293939ece3),使用创世钱包 shielded-1。此后的每条链(14 至 19)都是作为不含链 13 程序的全新链启动的,该镜像也未在其中任何一条链上重新部署,因此下面的交易和高度属于链 13,已无法在浏览器中解析。程序 id 仅是 base_pc 与字的哈希,所以同一镜像在任何接受该部署的链上都会得到相同的 id。钱包的输出,其中进度行已省略(…):
$ rand program deploy <image.bin>
program id: f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d (11686 words, hc 92aefea0951c31a717574962aeb70e10a37012a7d035d48e8713c36df68feae0)
…
proved in 92.2s: tier 14, 1419655 bytes
submitted deploy c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
…
| 程序 id | f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d |
| 镜像 | 11,686 个字;在 rand-guest 的写法中为 hc a0feae92…,在钱包的写法中为 92aefea0… |
| 费用捆绑包(链 13 的 2 入 2 出捆绑包) | tier 14,1,419,655 字节,证明耗时 92.2 秒 |
| 部署交易(链 13) | c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0 |
| 提交高度(链 13) | 381 |
自链 14 起,支付费用的捆绑包是每笔交易都携带的那个 4 入 4 出的隐藏资产捆绑包,针对该交易的绑定值生成证明。它仍为 tier 14:在链 14 和 15 上,生产配置下约 100 秒、约 1.42 MB。自链 17 起,捆绑包还携带一个 tier-10 的授权证明(拆分授权),因此在链 18 和 19 上,一笔交易的费用捆绑包约包含 1.49 MB 的捆绑包证明和约 1.37 MB 的授权证明。
7. 调用
一次转账调用将 921 个字的向量作为私有输入,低于任何链上的输入上限(默认为 4,295 个字,链 20 上为 16,071 个字),且没有公开字。它无法提交到链 20: 程序无法在那里部署(第 6 步),转账在 tier 18 上生成证明,而且自 fullnode v0.5.6(2026-09-25)起,节点会在构建验证密钥之前,以 CallTierTooHigh 拒绝任何高于 tier 14 的调用证明。下面的命令在本地生成证明,链会拒绝其结果;这些测量数据是链下证明。rand call 将每个字作为重复的 --input 传入:
rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d \
$(for w in $(cat evm2rv/target/transfer.words); do printf -- '--input %s ' "$w"; done)
以下为实测结果。一个 tier-18 证明在 48 GB 笔记本上于 24.7 GB 时被终止,但在 128 GB 的 droplet(m-16vcpu-128gb)上,转译后的 transfer 调用完成了证明:峰值 RSS 为 85.0 GB,耗时 3,230.5 秒(53.8 分钟),证明大小为 811,600 字节。它在 droplet 上的验证耗时为 101.4 秒,在 48 GB 的 Apple 芯片笔记本上为 50.2 秒、RSS 为 3.66 GB(证明内存)。在账本的固定层级费率表下(即没有 gas 部分的链上的规则,直至链 17),tier 18 的调用费用为 0.0024 RAND。链 18 和 19 则按调用声明的 gas 上限及其字节数定价,按创世价格为每 gas 100 个单位、每 KiB 800 个单位,并且不接受任何高于 tier 14 的调用。
2026-09-19 链 13 上的调用
approve(BOB, 5) 调用(649 个私有字,tier 16)于 2026-09-19 在链 13 上运行,当时它是运行中的链,采用生产 FRI 配置,使用同一钱包。此后的任何链上都没有发起过调用,因为程序未在其中部署,而且链 20 会拒绝这个 tier-16 调用证明(CallTierTooHigh)。钱包的输出,其中进度行已省略(…):
$ rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d --input <w0> --input <w1> … # the 649 words of approve(BOB, 5)
…
proved in 388.7s: tier 16, 3412405 bytes, outputs [1, 942495465, 790002515, 1351749335, 1059083501, 2923046783, 2814575942, 696258848]
…
proved in 96.0s: tier 14, 1420423 bytes
submitted call 279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7
…
| 调用证明 | tier 16,3,412,405 字节,证明耗时 388.7 秒 |
| 费用捆绑包(链 13 的 2 入 2 出捆绑包) | tier 14,1,420,423 字节,证明耗时 96.0 秒 |
| 密封信封 | 2,700 字节 |
| 调用交易(链 13) | 279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7 |
| 锚定高度 / 提交高度 | 高度 802 / 高度 919 |
| 费用 | 0.00357 RAND |
回执 h_pub | null |
| 回执输出 | 与解释器对同一向量给出的八个字相同 |
| 耗时,峰值 RSS | 622.8 秒,22.9 GB,在 48 GB 的 M 系列笔记本上 |
- 生产环境的证明为 3,412,405 字节,超过了链 12 的 2 MiB 证明上限。链 12 无法接受这次调用;链 13 的 8 MiB 上限则可以。链 14 至 16 保持相同的上限,链 17 至 20 设为 4 MiB(4,194,304 字节),这个大小的证明仍然在其范围内。自 v0.5.6 起,节点会先根据调用的层级拒绝它,然后才查看其大小。
- 该费用包含链 13 费率表中的字节项:3.41 MB 的证明超过了 2 MiB + 18,432 字节的免费额度。自链 18 起,每次调用从第 0 字节起就按每 KiB 计费。
回执的八个字就是第 4 步中的那些。链不保存 EVM 状态:调用方提供前状态根和存储见证,后状态根包含在 EVM_OUT 摘要之中。
限制
- 无区块上下文。 在区块绑定设计出现之前,九个区块上下文操作码均会陷入陷阱(trap)。
- 不支持价值转移。 携带非零价值的
CALL会陷入陷阱。对预编译合约之外的合约发起的调用同样会陷入陷阱。 - 目前无法证明 ecrecover、bn256 mul、配对运算和大数 modexp。 它们各自都超出 2²⁰ 行的层级上限,需要协处理器表。
- 链上没有 EVM 状态。 一次调用是对一次运行的一份证明,状态由调用方携带。
- 在 chain 20 上,部署与任何 ERC-20 调用均不被接受。 在 chain 20 的
hardening_v6下,部署的字数若超过 tier-14 调用所能容纳的数量即为无效(ProgramUncallable;至多 8,180 个字),而该镜像为 11,686 个字。自 fullnode v0.5.6 起,调用证明必须在 tier 14 或以下(CallTierTooHigh);approve在 tier 16 上证明,transfer与transferFrom在 tier 18 上证明。同一项检查还限制了一次调用可声明的哈希表:2¹² 行 Keccak(128 次置换)和 2¹³ 行 SHA-256(128 次压缩)。如下所述,这些调用仍可在链下证明。 - 存储索引只有 32 位深。
evm-core按keccak256(slot)的高 32 位放置合约存储叶子,因此与选定槽位发生冲突的槽位,需要约 2³² 次 Keccak 哈希才能找到;而只要该槽位持有非零值,选定的槽位就会被冻结(既无法伪造,也不会丢失价值)。这一问题目前处于休眠状态:evm.bin为 18,009 个字,而处于 tier-14 上限的调用至多容纳 8,184 个字,因此在任何链上都没有可调用的 EVM 运行时。fullnode 的docs/confidential.md在调用上限旁记录了这一前提条件(审计 v6,ZKV-6;自 2026-09-30 起位于main,在 v0.6.7 标签之后):在某条链取消 tier-14 调用上限、或接纳小到可被调用的 EVM 运行时之前,必须加深存储索引并重新固定evm.bin。 - 已证明。 第一阶段的 transfer 证明(tier 18)在一台 48 GB 笔记本上运行 1,016 s、内存达 24.7 GB 时被 SIGKILL 终止,但第二阶段的
transfer调用在一台 128 GB 的 droplet(m-16vcpu-128gb)上完成了证明:峰值 RSS 85.0 GB,3,230.5 s(53.8 min),证明大小 811,600 字节,验证耗时为 101.4 s(droplet)和 50.2 s、RSS 3.66 GB(48 GB 笔记本)。解释器的evm.bintransfer 证明与之高度吻合:85.5 GB,3,143.3 s(52.4 min),证明大小 805,108 字节——两份证明携带完全相同的公开输出字,在真实证明器上确认了一致性。approve(tier 16,经转译)的开销要低得多:21.7 GB,786.7 s(13.1 min),证明大小 798,930 字节。只有当转译使一次调用落入更小的层级时,才会降低证明成本。 - 链上不记录字节码。 请公开发布字节码,以便他人重建
hc。