evm2rv بایتکد زماناجرای EVM، یعنی خروجی solc --bin-runtime، را میگیرد و به یک برنامهٔ Rand تبدیل میکند. خروجی آن کد C است و rand-guest build این کد C را به یک ایمیج RV32IM کامپایل میکند. این ایمیج همان بردار ورودیِ guest مفسر EVM در Rand، یعنی evm.bin، را میپذیرد و همان هشت کلمهٔ خروجی را منتشر میکند. قرارداد را بهجای تفسیر opcode به opcode، بهصورت بومی اجرا میکند. این صفحه کل مسیر را روی یک ERC-20 نشان میدهد.
چیستی آن
| ورودی | بایتکد زماناجرای EVM، بهصورت متن hex (.hex) یا بایتهای خام |
| خروجی | یک crate شیم C؛ rand-guest build آن را به یک کانتینر ایمیج تبدیل میکند |
| محل اجرا | خارج از زنجیره، روی دستگاه توسعهدهنده؛ زنجیره فقط ایمیج را میبیند |
| آنچه باید با آن مطابقت داشته باشد | وضعیت، هشت کلمهٔ خروجی و gas_used در evm.bin |
| مخزن | evm2rv/ در مخزن circuits |
| زنجیرهٔ ابزار پینشده | Rust 1.98.1، clang 23.1.1، crate با نام cc نسخهٔ 1.4.6 |
مترجم کد زماناجرا را میگیرد، نه کد ایجاد را. اثبات یک فراخوانی از قراردادِ مستقرشده را پوشش میدهد، پس سازنده (constructor) هرگز اجرا نمیشود. حالتی که سازنده مینوشت، در عوض بهصورت شاهدهای storage بخشی از پیشحالت (pre-state) است.
ترجمه دو مرحله دارد. هر دو نتایج و gas یکسانی میدهند؛ هرکدام برنامهای جداگانه با hc خودش است.
| مرحله | پرچم | کار آن |
|---|---|---|
| یک | --stage 1 | هر opcode روی یک پشتهٔ مبتنی بر حافظه |
| دو | --stage 2، پیشفرض | کلمات پشتهٔ هر بلوک در متغیرهای محلی C، با ثابتهایی که هنگام ترجمه تا میشوند |
بردار ورودی همان بردار مفسر است: کد، calldata، فراخواننده و دیگر کلمات محیطی، سقف gas، ریشهٔ پیشحالت، و یک شاهد storage برای هر slot که فراخوانی به آن دست میزند. خروجیها عبارتاند از out[0]، وضعیت (1 موفقیت، 0 revert، 2 توقف استثنایی)، و out[1..8]، چکیدهٔ EVM_OUT روی هش کد، هر دو ریشهٔ حالت، دادههای بازگشتی و لاگها.
مدل اعتماد
verifier یک قرارداد ترجمهشده را در دو گام بررسی میکند.
hc == translate(bytecode).evm2rvرا روی بایتکد منتشرشده با همان--stageو--chain-idدوباره اجرا کنید، با زنجیرهٔ ابزار پینشده دوباره بسازید وhcرا مقایسه کنید. crate تولیدشدهccرا دقیقاً پین میکند وCargo.lockخودش را دارد.- محافظ کد،
hcرا به بایتکد پیوند میدهد. منطق ترجمهشده درون ایمیج کامپایل شده است، اماCODECOPYوCODESIZEکدِ موجود در بردار ورودی را میخوانند. بدون بررسی، یکhcمیتوانست با بایتهای کدی که فراخواننده انتخاب کرده اجرا شود. بنابراینcontract.cیک چکیدهٔ Poseidon2 از بایتکد مبدأ (طول و بایتهای آن) را در خود دارد و شیم، پیش از اجرای هر کد ترجمهشده، کدِ بردار ورودی را به همان روش هش میکند. هر کد دیگری رد میشود: وضعیت 2،gas_usedبرابر 0، توقفOutOfBounds.
چکیدهٔ EVM_OUT نیز مانند چکیدهٔ مفسر، keccak256 کد را در خود پیوند میدهد. زنجیره بایتکد مبدأ یا هش آن را ثبت نمیکند. برای اینکه دیگران بتوانند hc را بررسی کنند، بایتکد را منتشر کنید، یا کد منبع Solidity و نسخهٔ دقیق solc را.
محافظ روی transfer مبلغ 1,008 چرخه هزینه دارد. کدی که یک بایت با مبدأ تفاوت داشته باشد، در مرحلهٔ دو با 30,418 چرخه رد میشود (tier 16).
پوشش و آنچه trap میشود
Opcodeها. مجموعهٔ Shanghai. با --evm-version shanghai کامپایل کنید: هدفهای جدیدتر MCOPY و دیگر opcodeهای Cancun را تولید میکنند که trap میشوند.
Opcodeهای محیطی:
| opcode | ترجمه |
|---|---|
ADDRESS، CALLER، CALLVALUE، CALLDATASIZE، CODESIZE | از بردار ورودی، همانطور که مفسر آنها را میخواند |
CHAINID | مقدار --chain-id، که هنگام ترجمه درون کد نشانده میشود و در نتیجه hc آن را پیوند میدهد؛ اگر کد شامل CHAINID باشد الزامی است |
ORIGIN | برابر CALLER است (یک فراخوانی، بدون relayer) |
GASPRICE، COINBASE، TIMESTAMP، NUMBER، PREVRANDAO، GASLIMIT، SELFBALANCE، BASEFEE، BLOCKHASH | trap میشوند (وضعیت 2)، همانطور که در مفسر |
نُه opcode بافتار بلوک تا زمانی که طرحی برای پیوند دادن آنها به یک بلوک وجود نداشته باشد، trap میشوند. یک ورودی خصوصی نمیتواند حقیقتی دربارهٔ بلوک را حمل کند، زیرا verifier نمیتواند H_IN را باز کند. تا زمانی که این تصمیم گرفته نشده، قراردادی که زمان یا شمارهٔ بلوک را بخواند (برای مثال مهلت یک permit) trap میشود.
فراخوانیها. CALL، CALLCODE، DELEGATECALL و STATICCALL وقتی مقصد آدرس 1 تا 9 باشد یک precompile را اجرا میکنند. هر مقصد دیگری trap میشود. مقدار غیرصفر در CALL یا CALLCODE trap میشود: مدل موجودی وجود ندارد.
Precompileها. هر نُه مورد بهصورت نرمافزاری اجرا میشوند. برخی امروز برای اثباتشدن بیشازحد کندند، زیرا یک اثبات حداکثر 2²⁰ سطر دارد:
| precompile | بردار | چرخهها | در 2²⁰ جا میشود |
|---|---|---|---|
| 1 ecrecover | ValidKey | 14,510,525 | خیر |
| 2 sha256 | ”abc” / 200 بایت | 2,791 / 5,289 | بله |
| 3 ripemd160 | ”abc” | 12,195 | بله |
| 4 identity | 100 بایت | 4,498 | بله |
| 5 modexp | nagydani-1-square / -1-pow0x10001 | 122,332 / 874,548 | بله |
| 5 modexp | eip_example1 (256 بیتی) | 11,170,118 | خیر |
| 5 modexp | nagydani-5-pow0x10001 (1,024 بایتی) | 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 دور | 14,493 | بله، تا حدود 1,800 دور |
پایه و مدول modexp هرکدام حداکثر 1,024 بایت هستند.
واگراییهای پذیرفتهشده. وضعیت، هشت کلمه و gas_used باید مطابقت داشته باشند. سه تفاوت پذیرفته شده است: نوع توقف ممکن است متفاوت باشد (gas ایستا در ابتدای هر بلوک کسر میشود، پس OutOfGas و توقفی دیگر ممکن است جابهجا شوند؛ هر دو وضعیت 2 با مصرف کل gas هستند)؛ ترجمه CHAINID، ORIGIN و فراخوانی precompileها را پیاده میکند، در حالی که مفسر آنها را trap میکند؛ و محافظ کد، کدی غیر از مبدأ خود را رد میکند.
اعداد
فراخوانیهای 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 سطر، یعنی 3,855 بیش از 65,535 سطر tier 16.
حدود 60٪ از یک transfer در مرحلهٔ دو (حدود 39,928 چرخه) مربوط به harnessی است که هر دو ایمیج در آن مشترکاند: رمزگشایی ورودی، راستیآزمایی شاهدهای storage، فراخوانیهای keccak256 مربوط به ABI و چکیدهٔ خروجی. هیچ کار ترجمهای کمتر از این کف نمیرود.
راهنمای گامبهگام: یک ERC-20، از Solidity تا خروجیهای منطبق
هر دستور از ریشهٔ یک checkout از circuits در 7ef3220 اجرا میشود، با زنجیرهٔ ابزار 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 مستقل با چیدمان storage مربوط به 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را تولید میکند که trap میشود.--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باید درون یک checkout از circuits باشد. بدون آن،evm2rvفقط کد را تحلیل میکند.- هر opcode که trap شود، اینجا بهصورت یک هشدار همراه با pc آن فهرست میشد.
- این نشست با
--chain-id 12ثبت شده است. این ERC-20 دستورCHAINIDندارد، پس--chain-idhcآن را تغییر نمیدهد. قراردادی که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 مبلغ 250 از 1,000 خود را برای BOB میفرستد)، approve (ALICE به BOB اجازهٔ خرج 5 را میدهد) و transferFrom (BOB مبلغ 100 از 1,000 ALICE را در برابر مجوز 300 جابهجا میکند). برای قرارداد خودتان، یک EvmCall را به همین شیوه در Rust بسازید؛ این مثال الگوی کار است.
$ (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
و مفسّری که بهصورت بومی روی میزبان اجرا میشود، یعنی مرجع صحت آزمونها:
$ (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 تکرار کنید؛ هر دو کلمات یکسان میدهند. cd evm2rv && cargo +1.98.1 test --release اینها و پنج بردار دیگر را در هر دو مرحله اجرا میکند و gas_used را هم بررسی میکند (۷۰ آزمون، بهعلاوهٔ ۲ اثبات نادیدهگرفتهشده).
| ترجمهشده (مرحلهٔ دوم) | مفسّر (evm.bin) | |
|---|---|---|
| هشت کلمهٔ خروجی | یکسان | یکسان |
| چرخهها، transfer | 66,235 | 121,638 |
| رده | 18 | 18 |
| کلمات برنامه | 11,686 | 18,009 |
6. استقرار
rand program deploy evm2rv/target/mytoken/image.bin
کیف پول شناسهٔ برنامه، تعداد کلمات و hc را چاپ میکند و پیش از اثبات هر چیز، سقف زنجیره را بررسی میکند. تصویر برنامه ۱۱٬۶۸۶ کلمه است، پس به زنجیرهای نیاز دارد که جنسیس آن 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 را تنظیم میکند و بر پایهٔ آن، استقرار برنامهای با کلمات بیشتر از آنچه یک فراخوانی در سقف فراخوانی ردهٔ 14 میتواند در خود جا دهد نامعتبر است (ProgramUncallable): حداکثر 8,180 کلمه بدون ورودی عمومی. این تصویر 11,686 کلمه است، پس زنجیرهٔ 20 استقرار را رد میکند و فراخوانیها را هم رد میکرد: هر فراخوانی ERC-20 در ردهٔ 16 یا 18 اثبات میشود که بالاتر از سقف فراخوانی ردهٔ 14 است (گام ۷). تجمیع بلوک در زنجیرهٔ 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 هستند و دیگر در کاوشگر یافت نمیشوند. شناسهٔ برنامه تنها هش base_pc و کلمات است، پس همان تصویر روی هر زنجیرهای که استقرار را بپذیرد همان شناسه را میگیرد. خروجی کیف پول، با خطوط پیشرفت حذفشده (…):
$ rand program deploy <image.bin>
program id: f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d (11686 words, hc 92aefea0951c31a717574962aeb70e10a37012a7d035d48e8713c36df68feae0)
…
proved in 92.2s: tier 14, 1419655 bytes
submitted deploy c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
…
| شناسهٔ برنامه | f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d |
| تصویر | 11,686 کلمه؛ hc a0feae92… به املای rand-guest، 92aefea0… به املای کیف پول |
| بستهٔ کارمزد (بستهٔ ۲ ورودی ۲ خروجی زنجیرهٔ 13) | رده 14، 1,419,655 بایت، اثباتشده در 92.2 s |
| تراکنش استقرار (زنجیرهٔ 13) | c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0 |
| ثبتشده در ارتفاع (زنجیرهٔ 13) | 381 |
از زنجیرهٔ 14، بستهٔ پرداختکننده همان بستهٔ دارایی پنهان ۴ ورودی ۴ خروجی است که هر تراکنش حمل میکند و در برابر binding تراکنش اثبات میشود. هنوز ردهٔ 14 است: در پروفایل تولیدی روی زنجیرههای 14 و 15 حدود 100 s و حدود 1.42 MB. از زنجیرهٔ 17، هر بسته یک اثبات احراز هویت ردهٔ 10 هم (احراز هویت تقسیمشده) حمل میکند، پس در زنجیرههای 18 و 19 بستهٔ کارمزد یک تراکنش حدود 1.49 MB اثبات بسته و حدود 1.37 MB اثبات احراز هویت است.
7. فراخوانی
یک فراخوانی transfer بردار ۹۲۱ کلمهای را بهصورت ورودیهای خصوصی حمل میکند، زیر سقف ورودی در هر زنجیره (بهطور پیشفرض 4,295 کلمه، در زنجیرهٔ 20 برابر 16,071) و هیچ کلمهٔ عمومی ندارد. این فراخوانی را نمیتوان به زنجیرهٔ 20 ارسال کرد: برنامه در آنجا قابل استقرار نیست (گام ۶)، transfer در ردهٔ 18 اثبات میشود و از fullnode v0.5.6 (2026-09-25) هر گره هر اثبات فراخوانی بالاتر از ردهٔ 14 را با CallTierTooHigh رد میکند، پیش از آنکه کلید تأییدکننده بسازد. دستور زیر بهصورت محلی اثبات میکند و زنجیره نتیجه را رد میکند؛ اندازهگیریها اثباتهای خارج از زنجیره هستند. rand call هر کلمه را بهصورت یک --input تکرارشونده میگیرد:
rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d \
$(for w in $(cat evm2rv/target/transfer.words); do printf -- '--input %s ' "$w"; done)
اکنون اندازهگیری شده است. یک اثبات ردهٔ 18 روی لپتاپ 48 GB در 24.7 GB متوقف شد، اما روی droplet با 128 GB (m-16vcpu-128gb) فراخوانی transfer ترجمهشده اثبات شد: اوج RSS برابر 85.0 GB، زمان 3,230.5 s (53.8 min) و اثبات 811,600 بایتی. تأیید آن روی droplet در 101.4 s و روی لپتاپ Apple-silicon با 48 GB در 50.2 s با 3.66 GB RSS انجام شد (حافظهٔ اثبات). بر اساس جدول ردههای ثابت دفتر کل، قاعدهای که در زنجیرههای بدون بخش gas (تا زنجیرهٔ 17) برقرار است، کارمزد فراخوانی در ردهٔ 18 برابر 0.0024 RAND بود. زنجیرههای 18 و 19 در عوض فراخوانی را بر پایهٔ سقف گاز اعلامشده و بایتهایش قیمتگذاری میکنند، با قیمتهای جنسیس 100 واحد به ازای هر گاز و 800 به ازای هر KiB، و هیچ فراخوانی بالاتر از ردهٔ 14 را نمیپذیرند.
فراخوانی روی زنجیرهٔ 13، 2026-09-19
فراخوانی approve(BOB, 5) (649 کلمهٔ خصوصی، ردهٔ 16) در 2026-09-19 روی زنجیرهٔ 13 اجرا شد، هنگامی که زنجیرهٔ زنده بود، با پروفایل FRI تولیدی، از همان کیف پول. روی هیچ زنجیرهٔ بعدی، که برنامه در آن مستقر نیست، فراخوانی انجام نشده است و زنجیرهٔ 20 این اثبات فراخوانی ردهٔ 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
…
| اثبات فراخوانی | رده 16، 3,412,405 بایت، اثباتشده در 388.7 s |
| بستهٔ کارمزد (بستهٔ ۲ ورودی ۲ خروجی زنجیرهٔ 13) | رده 14، 1,420,423 بایت، اثباتشده در 96.0 s |
| پاکت مهرومومشده | 2,700 بایت |
| تراکنش فراخوانی (زنجیرهٔ 13) | 279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7 |
| لنگرشده در / ثبتشده در | ارتفاع 802 / ارتفاع 919 |
| کارمزد | 0.00357 RAND |
رسید h_pub | null |
| خروجیهای رسید | برابر با هشت کلمهٔ مفسّر برای همان بردار |
| زمان کل، اوج RSS | 622.8 s، 22.9 GB، روی لپتاپ M-series با 48 GB |
- اثبات تولیدی 3,412,405 بایت است، بیش از سقف اثبات 2 MiB زنجیرهٔ 12. زنجیرهٔ 12 نمیتوانست این فراخوانی را بپذیرد؛ سقف 8 MiB زنجیرهٔ 13 پذیرفت. زنجیرههای 14 تا 16 همان سقف را نگه داشتند و زنجیرههای 17 تا 20 آن را 4 MiB (4,194,304 بایت) گذاشتند که اثباتی با این اندازه هنوز زیر آن جا میشود. از v0.5.6، گره فراخوانی را بهخاطر ردهاش پیش از بررسی اندازهاش رد میکند.
- کارمزد شامل جملهٔ بایتیِ جدول زنجیرهٔ 13 است: اثبات 3.41 MB بالاتر از سهمیهٔ رایگان 2 MiB + 18,432 بایت است. از زنجیرهٔ 18، هر فراخوانی از بایت 0 به ازای هر KiB میپردازد.
هشت کلمهٔ رسید همانهایی هستند که در گام ۴ آمدهاند. زنجیره هیچ وضعیت EVM را نگه نمیدارد: فراخوانکننده ریشهٔ پیشوضعیت و شاهدهای ذخیرهسازی را فراهم میکند و ریشهٔ پسوضعیت درون خلاصهٔ EVM_OUT است.
محدودیتها
- بدون زمینهٔ بلاک. نُه opcode مربوط به زمینهٔ بلاک تا زمانی که طرحی برای اتصال به بلاک وجود نداشته باشد، trap میشوند.
- بدون انتقال مقدار.
CALLبا مقدار غیرصفر trap میشود. فراخوانی قراردادهایی غیر از precompileها نیز trap میشود. - ecrecover، ضرب bn256، pairing و modexp بزرگ امروز قابل اثبات نیستند. هر کدام از سقف ۲²⁰ سطر در هر tier فراتر میروند؛ این عملیات به جدولهای coprocessor نیاز دارند.
- هیچ وضعیت EVM روی زنجیره نیست. هر فراخوانی یک اثبات روی یک اجراست؛ وضعیت را فراخواننده با خود حمل میکند.
- نه استقرار و نه هیچ فراخوانی ERC-20 روی chain 20 پذیرفتنی نیست. تحت
hardening_v6در chain 20، استقرار با تعداد کلمات بیشتر از آنچه یک فراخوانی tier-14 میتواند در خود جای دهد نامعتبر است (ProgramUncallable؛ حداکثر ۸٬۱۸۰ کلمه)، و اندازهٔ image برابر ۱۱٬۶۸۶ است. از fullnode v0.5.6 به بعد، اثبات یک فراخوانی باید در tier 14 یا پایینتر باشد (CallTierTooHigh)؛approveدر tier 16 وtransferوtransferFromدر tier 18 اثبات میشوند. همین بررسی، جدولهای هشی را که یک فراخوانی میتواند اعلام کند نیز محدود میکند: ۲¹² سطر Keccak (۱۲۸ جایگشت) و ۲¹³ سطر SHA-256 (۱۲۸ تابع فشردهسازی). این فراخوانیها همچنان خارج از زنجیره اثبات میشوند، مطابق توضیح زیر. - شاخص ذخیرهسازی ۳۲ بیت عمق دارد.
evm-coreیک برگ ذخیرهسازی قرارداد را با ۳۲ بیت بالایkeccak256(slot)جای میدهد؛ بنابراین یافتن slotی که با slot انتخابشده برخورد کند حدود ۲³² هش Keccak هزینه دارد، و تا زمانی که آن slot مقداری غیرصفر دارد، slot انتخابشده منجمد میماند (نه جعلی در کار است و نه مقداری از دست میرود). این مسئله فعلاً خفته است:evm.binبرابر ۱۸٬۰۰۹ کلمه است و یک فراخوانی در سقف tier-14 حداکثر ۸٬۱۸۴ کلمه را در خود جای میدهد، پس هیچ runtime از EVM روی هیچ زنجیرهای قابل فراخوانی نیست. فایلdocs/confidential.mdدر fullnode پیششرط را در کنار سقف فراخوانی ثبت کرده است (audit v6، ZKV-6؛ از ۲۰۲۶-۰۹-۳۰ رویmainاست، پس از تگ v0.6.7): پیش از آنکه زنجیرهای سقف فراخوانی tier-14 را بردارد یا runtime ای از EVM را که به اندازهٔ کافی کوچک باشد تا فراخوانی شود بپذیرد، باید شاخص ذخیرهسازی عمیقتر شود وevm.binدوباره pin شود. - اثباتشده. اثبات انتقال مرحلهٔ اول (tier 18) روی یک لپتاپ ۴۸ گیگابایتی پس از ۱٬۰۱۶ ثانیه در ۲۴٫۷ گیگابایت با SIGKILL متوقف شد، اما فراخوانی
transferمرحلهٔ دوم روی یک droplet با ۱۲۸ گیگابایت (m-16vcpu-128gb) اثبات شد: اوج RSS برابر ۸۵٫۰ گیگابایت، ۳٬۲۳۰٫۵ ثانیه (۵۳٫۸ دقیقه)، اثباتی ۸۱۱٬۶۰۰ بایتی، که در ۱۰۱٫۴ ثانیه (droplet) و در ۵۰٫۲ ثانیه با RSS برابر ۳٫۶۶ گیگابایت (لپتاپ ۴۸ گیگابایتی) تأیید شد. اثبات انتقال باevm.binمفسر نیز بسیار نزدیک بود: ۸۵٫۵ گیگابایت، ۳٬۱۴۳٫۳ ثانیه (۵۲٫۴ دقیقه)، اثباتی ۸۰۵٬۱۰۸ بایتی — و این دو اثبات کلمات خروجی عمومی یکسانی دارند که تطابق را روی prover واقعی تأیید میکند.approve(tier 16، ترجمهشده) بسیار ارزانتر است: ۲۱٫۷ گیگابایت، ۷۸۶٫۷ ثانیه (۱۳٫۱ دقیقه)، اثباتی ۷۹۸٬۹۳۰ بایتی. ترجمه تنها زمانی هزینهٔ اثبات را کاهش میدهد که یک فراخوانی را به tier کوچکتری ببرد. - زنجیره بایتکد را ثبت نمیکند. آن را منتشر کنید تا دیگران بتوانند
hcرا بازسازی کنند.