Repository navigation
fix(arc): charge PQ precompile gas before copying its byte arguments - #256
Merged
Merged
Conversation
Port circlefin/arc-node#486 (arc-node v0.8.1). The PQ precompile decoded and copied vk, message and sig before charging base and message gas, so a call with zero gas still allocated and copied every argument; aliasing the three offsets to one array tripled that work. Tokenize and type-check first (same checks as abi_decode_raw_validate, arguments stay borrowed), charge gas, then detokenize. Results are unchanged: detokenize cannot fail, so only the time of the copy moves.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
上游 arc-node v0.8.1(circlefin/arc-node#486,相对 v0.8.0 只有这一处改动)修复了 PQ 预编译(
0x1800…0004,SLH-DSA-SHA2-128s 验签)的资源消耗问题:原实现先用abi_decode_raw_validate把vk、message、sig三个 bytes 参数拷贝出来,再扣 base gas 和 message gas。leafage 的移植版arc/precompile/pq.rs是同样的顺序。于是 gas 为 0 或不足的调用也会先分配并拷贝全部参数,然后才因 gas 不足退出。三个 offset 可以指向同一段数据,这时拷贝量是输入长度的 3 倍。
PrecompilesMap::run把 calldata 以借用方式传给预编译(as_bytes_local),EVM 层不拷贝,所以这份工作量只由预编译自己的解码产生。合约可以在一笔调用里用 0 gas 反复调用这个预编译,每次只付约 100 gas 的调用开销,eth_call / simulateTransactions / estimateGas 都能触发。修改
按上游的做法拆开解码:
abi::decode_sequence+type_check:只读 offset 和长度并做边界检查,参数仍借用输入,不拷贝;detokenize:gas 已付,再拷贝参数。返回结果不变:
abi_decode_raw_validate就是decode_sequence_with_config(validate=true)→type_check→detokenize;validate 不开 strict 时,解码过程和默认配置一样,所以第 1 步的成功/失败与原来完全相同。detokenize不会失败,挪到扣 gas 之后只改变拷贝的时机。验证
pq_aliased_input_reverts_or_runs_out_of_gas_at_each_charge:三个 offset 指向同一段数据(长度 0 / 32 / 4096),在 gas 为 0、base gas − 1、全额 − 1 时都是PrecompileOOG;全额时 revert,gas 等于 base + message gas,revert 信息分别为 vk 长度错误或 sig 长度错误。该测试在修复前后都通过,用来固定结果不变。pq_zero_gas_call_does_not_copy_byte_arguments:1 MiB 数据被三个 offset 共用,gas=0 调用期间本线程分配量须小于 1 MiB。为此在 chains crate 的测试二进制里加了一个只按当前线程计数的 global allocator(所有操作原样转给System),不受并行测试影响。pq.rs换回 main 版本,测试保留):pq_zero_gas_call_does_not_copy_byte_arguments失败,gas=0 的一次调用分配 3,151,864 字节(3 × 1 MiB 参数拷贝,加约 6 KB EVM 开销);结果固定测试和原有两个 PQ 测试通过。cargo test --locked -p leafage-evm-chains -p leafage-evm-rpc全部通过:chains lib 575 通过 / 4 ignored,arc_db_error2/2,b20_gas6/6,rpc lib 93/93,rpc 集成测试全部通过。rustfmt --check、git diff --check通过。不在本 PR
Writer(Chaintable/arc-node v0.8.0-ct.4)的
crates/pq-precompile/src/lib.rs也是修复前的顺序,需要单独合入上游 v0.8.1。