Rand Protocol
Dokumentacja
Programy RISC-V

Transpiler Ethereum

evm2rv tłumaczy bajtkod uruchomieniowy EVM na RISC-V ISA sieci Rand - czym jest, model zaufania i jego zabezpieczenie kodu, obsługiwane opkody i prekompilacje oraz miejsca, w których zgłasza pułapkę, zmierzone wartości oraz pełny przykład tokena ERC-20: od Solidity przez solc --bin-runtime po wyniki zgodne z interpreterem EVM słowo w słowo.

evm2rv przyjmuje bajtkod uruchomieniowy EVM, czyli wynik solc --bin-runtime, i zamienia go na program Rand. Generuje kod w C, a rand-guest build kompiluje go do obrazu RV32IM. Obraz przyjmuje ten sam wektor wejściowy co gość interpretera EVM w Rand, evm.bin, i publikuje te same osiem słów wyjściowych. Kontrakt wykonuje natywnie, zamiast interpretować go opkod po opkodzie. Ta strona pokazuje całą ścieżkę na przykładzie ERC-20.

Czym jest

wejścieuruchomieniowy bajtkod EVM, jako tekst szesnastkowy (.hex) lub surowe bajty
wyjściecrate z powłoką w C; rand-guest build zamienia go w kontener obrazu
gdzie działapoza łańcuchem, na maszynie programisty; łańcuch widzi tylko obraz
z czym musi się zgadzaćstatus, osiem słów wyjściowych i gas_used z evm.bin
repozytoriumevm2rv/ w repozytorium circuits
przypięty toolchainRust 1.98.1, clang 23.1.1, crate cc 1.4.6

Translator przyjmuje kod uruchomieniowy, nie kod tworzący. Dowód obejmuje jedno wywołanie wdrożonego kontraktu, więc konstruktor nigdy się nie wykonuje. Stan, który zapisałby konstruktor, wchodzi natomiast w skład stanu początkowego, jako świadectwa składowania (storage witnesses).

Istnieją dwa etapy translacji. Oba dają te same wyniki i ten sam gaz; każdy jest osobnym programem z własnym hc.

etapflagaco robi
pierwszy--stage 1każdy opkod na stosie w pamięci
drugi--stage 2, domyślnysłowa stosu każdego bloku w zmiennych lokalnych C, stałe obliczane podczas translacji

Wektor wejściowy jest taki jak w interpreterze: kod, calldata, wywołujący i pozostałe słowa środowiska, limit gazu, korzeń stanu początkowego oraz jedno świadectwo składowania na każdy slot, którego dotyka wywołanie. Wyjściami są out[0], czyli status (1 – powodzenie, 0 – revert, 2 – wyjątkowe zatrzymanie), oraz out[1..8], skrót EVM_OUT obejmujący skrót kodu, oba korzenie stanu, dane zwrotne i logi.

Model zaufania

Weryfikator sprawdza przetłumaczony kontrakt w dwóch krokach.

  1. hc == translate(bytecode). Uruchom evm2rv ponownie na opublikowanym bajtkodzie z tym samym --stage i --chain-id, zbuduj ponownie przypiętym toolchainem i porównaj hc. Wygenerowany crate przypina cc dokładnie i zawiera własny Cargo.lock.
  2. Strażnik kodu wiąże hc z bajtkodem. Przetłumaczona logika jest skompilowana w obrazie, ale CODECOPY i CODESIZE czytają kod z wektora wejściowego. Bez kontroli ten sam hc mógłby działać na bajtach kodu wybranych przez wywołującego. Dlatego contract.c zawiera skrót Poseidon2 źródłowego bajtkodu (jego długości i bajtów), a powłoka hashuje kod z wektora wejściowego w ten sam sposób, zanim wykona się jakikolwiek przetłumaczony kod. Inny kod jest odrzucany: status 2, gas_used 0, zatrzymanie OutOfBounds.

Skrót EVM_OUT wiąże też keccak256 kodu, tak jak w interpreterze. Łańcuch nie zapisuje źródłowego bajtkodu ani jego skrótu. Aby inni mogli sprawdzić hc, opublikuj bajtkod albo kod źródłowy Solidity i dokładną wersję solc.

Strażnik kosztuje 1 008 cykli przy transferze. Kod różniący się od źródła jednym bajtem jest odrzucany w 30 418 cyklach na etapie drugim (poziom 16).

Zakres i to, co przerywa wykonanie

Opkody. Zestaw Shanghai. Kompiluj z --evm-version shanghai: nowsze cele emitują MCOPY i inne opkody Cancun, które przerywają wykonanie.

Opkody środowiska:

opkodtranslacja
ADDRESS, CALLER, CALLVALUE, CALLDATASIZE, CODESIZEz wektora wejściowego, tak jak czyta je interpreter
CHAINIDwartość --chain-id, wpisana na stałe podczas translacji, więc hc ją wiąże; wymagana, gdy kod zawiera CHAINID
ORIGINrówny CALLER (jedno wywołanie, brak przekaźnika)
GASPRICE, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, SELFBALANCE, BASEFEE, BLOCKHASHprzerywają wykonanie (status 2), tak jak w interpreterze

Dziewięć opkodów kontekstu bloku przerywa wykonanie, dopóki nie powstanie projekt ich wiązania z blokiem. Prywatne wejście nie może przenosić faktu o bloku, ponieważ weryfikator nie może otworzyć H_IN. Do czasu podjęcia tej decyzji kontrakt odczytujący czas lub numer bloku (na przykład termin ważności permitu) przerywa wykonanie.

Wywołania. CALL, CALLCODE, DELEGATECALL i STATICCALL uruchamiają prekompilację, gdy celem jest adres od 1 do 9. Każdy inny cel przerywa wykonanie. Niezerowa wartość w CALL lub CALLCODE przerywa wykonanie: nie ma modelu sald.

Prekompilacje. Wszystkie dziewięć działa programowo. Niektóre są dziś zbyt wolne, by je udowodnić, ponieważ dowód mieści co najwyżej 2²⁰ wierszy:

prekompilacjawektorcyklemieści się w 2²⁰
1 ecrecoverValidKey14 510 525nie
2 sha256”abc” / 200 bajtów2 791 / 5 289tak
3 ripemd160”abc”12 195tak
4 identity100 bajtów4 498tak
5 modexpnagydani-1-square / -1-pow0x10001122 332 / 874 548tak
5 modexpeip_example1 (256 bitów)11 170 118nie
5 modexpnagydani-5-pow0x10001 (1 024 bajty)55 076 950nie
6 bn256 addchfast1978 262tak, ledwo
7 bn256 mulchfast13 060 669nie
8 bn256 pairing1 para / 2 pary1 853 656 212 / 2 019 000 469nie
9 blake2f12 rund14 493tak, do około 1 800 rund

Podstawa i moduł w modexp są ograniczone do 1 024 bajtów każde.

Akceptowane rozbieżności. Status, osiem słów i gas_used muszą się zgadzać. Akceptowane są trzy różnice: rodzaj zatrzymania może się różnić (gaz statyczny jest naliczany na początku każdego bloku, więc OutOfGas i inne zatrzymanie mogą się zamienić; oba oznaczają status 2 przy zużyciu całego gazu); translacja implementuje CHAINID, ORIGIN i wywołania prekompilacji, które interpreter przerywa; a strażnik kodu odrzuca kod inny niż jego źródło.

Liczby

Wywołania ERC-20 z wbudowanym strażnikiem kodu. Cykle z rand-guest run; poziom w nawiasie.

wywołanieinterpreter (evm.bin)etap pierwszyetap drugi (domyślny)
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)
programsłowahc
evm.bin, interpreter18 0097e1aea2b…854c08
ERC-20, etap pierwszy15 8049cdb79e7…2fd048c8
ERC-20, etap drugi11 686a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6

Etap drugi wykonuje te trzy wywołania w 54,5%, 56,2% i 55,0% cykli interpretera. Transfer pozostaje na poziomie 18: jego 66 235 cykli plus 3 155 wierszy skrótu daje 69 390 wierszy, czyli 3 855 ponad 65 535 z poziomu 16.

Około 60% transferu na etapie drugim (około 39 928 cykli) to uprząż wspólna dla obu obrazów: dekodowanie wejścia, weryfikacja świadectw składowania, wywołania keccak256 w ABI i skrót wyjściowy. Żadna praca translacji nie schodzi poniżej tej podłogi.

Przewodnik: ERC-20, od Solidity do zgodnych wyjść

Każde polecenie uruchamia się z katalogu głównego kopii circuits na 7ef3220, z toolchainem z Wdrożenie programu w Rust i clang 23.1.1 z Wdrożenie programu RISC-V. Długie wyjście jest obcięte w miejscach oznaczonych ….

0. Zbuduj narzędzia

(cd evm2rv && cargo +1.98.1 build --release)
(cd rand-guest && cargo +1.98.1 build --release)

1. Skompiluj Solidity do bajtkodu uruchomieniowego

Kontraktem jest zatwierdzony guests-compiled/evm/contracts/ERC20.sol: samodzielny ERC-20 z układem składowania z OpenZeppelin v4, pragma solidity 0.8.37. Użyj dokładnie solc 0.8.37; inna wersja optymalizuje inaczej i daje inny bajtkod.

wydaniev0.8.37 z github.com/ethereum/solidity/releases
plik dla macOSsolc-macos, sha256 a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821
plik dla Linuksasolc-static-linux, z tego samego wydania
$ 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

Ostatni wiersz to bajtkod uruchomieniowy, 1 296 bajtów. Jest identyczny bajt w bajt z zatwierdzonym guests-compiled/evm/contracts/erc20.runtime.hex; SOLC=$PWD/solc bash guests-compiled/evm/contracts/build.sh sprawdza to i wypisuje contracts: erc20.runtime.hex reproduces.

Flagi mają znaczenie:

  • --bin-runtime: kod wdrożony, nie kod tworzący.
  • --evm-version shanghai: domyślny cel dla 0.8.37 emituje MCOPY, który przerywa wykonanie.
  • --optimize --optimize-runs 200: profil dla wdrożonego kontraktu.

2. Przetłumacz

$ 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 musi wskazywać wewnątrz kopii circuits. Bez niego evm2rv tylko analizuje kod.
  • Każdy opkod przerywający wykonanie zostałby tu wymieniony jako ostrzeżenie, wraz z jego pc.
  • Ta sesja została zarejestrowana z --chain-id 12. Ten ERC-20 nie zawiera CHAINID, więc --chain-id nie zmienia jego hc. Kontrakt odczytujący CHAINID wymaga tej flagi; ustaw ją na łańcuch, w którym będziesz wdrażać (--chain-id 19 dla działającego łańcucha).

contract.c kończy się skrótem strażnika kodu:

const uint32_t *evm_code_digest(void) {
    static const uint32_t d[8] = {0xf679280fu, 0x86c10e83u, 0x7e8f1f39u, 0xa2377de3u, 0x8a2e282fu, 0xc54cad42u, 0xddfaf009u, 0x7d28a8afu};
    return d;
}

3. Zbuduj obraz

Domyślny limit to 4 096 słów, więc przekaż --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

To jest opublikowany hc etapu drugiego. Nazwa crate’a nie ma na niego wpływu.

4. Zbuduj wektor wejściowy i uruchom transfer

Przykład erc20_vector wypisuje wektory testu zgodności jako słowa wejściowe: transfer (ALICE wysyła BOB 250 ze swoich 1 000), approve (ALICE pozwala BOB wydać 5) i transferFrom (BOB przenosi 100 z 1 000 ALICE przy przydziale 300). Dla własnego kontraktu zbuduj EvmCall w Rust w ten sam sposób; przykład jest wzorcem.

$ (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. Porównaj z interpreterem

To samo wejście w gościu interpretera:

$ 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

And the interpreter run natively on the host, the tests’ oracle: → Oraz interpreter uruchomiony natywnie na hoście, wyrocznia dla testów:

$ (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

Sprawdzenie w jednym poleceniu:

$ 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

Powtórz kroki 4 i 5 dla approve i transferFrom; oba dają identyczne słowa. cd evm2rv && cargo +1.98.1 test --release uruchamia je oraz pięć dalszych wektorów w obu etapach, a także sprawdza gas_used (70 testów oraz 2 pominięte dowody).

przetłumaczony (etap drugi)interpreter (evm.bin)
osiem słów wyjściowychidentyczneidentyczne
cykle, transfer66 235121 638
poziom1818
słowa programu11 68618 009

6. Wdrożenie

rand program deploy evm2rv/target/mytoken/image.bin

Portfel wypisuje identyfikator programu, liczbę słów i hc, a następnie sprawdza limit łańcucha, zanim wygeneruje jakikolwiek dowód. Obraz ma 11 686 słów, więc wymaga łańcucha, którego genesis ustawia max_program_words na co najmniej 11 686. Łańcuch 12 działał z domyślną wartością 4 096, więc wdrożenie zostało tam odrzucone. Łańcuch 13, łańcuch wersji v0.4, ustawił max_program_words na 65 535 i każdy kolejny łańcuch zachowuje tę wartość. Łańcuch 20, aktualny łańcuch (genesis 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135), zachowuje także limity bloku, koperty wywołania i danych publicznych z łańcucha 13, a limit dowodu zmniejsza o połowę do 4 MiB (4 194 304 bajtów, od łańcucha 17; łańcuchy od 13 do 16 ustawiały 8 MiB). Limit słów nie jest już jedyną bramką. Genesis łańcucha 20 ustawia hardening_v6, a przy nim wdrożenie programu o większej liczbie słów, niż może pomieścić wywołanie przy limicie wywołania poziomu 14, jest nieprawidłowe (ProgramUncallable): co najwyżej 8 180 słów bez danych publicznych. Ten obraz ma 11 686 słów, więc łańcuch 20 odrzuca wdrożenie i odrzuciłby też wywołania: każde wywołanie ERC-20 generuje dowód na poziomie 16 lub 18, powyżej limitu wywołania poziomu 14 (krok 7). Agregacja bloków jest na łańcuchu 20 wyłączona (jego genesis nie ma sekcji aggregation); jego węzły startowe są wymienione w Uruchamianie walidatora. Opłata za wdrożenie wynosi 0.001 + 0.0001 × 11,686 = 1,1696 RAND, czyli tyle, ile zapłaciło wdrożenie w łańcuchu 13 opisane poniżej.

To wdrożenie odbyło się w łańcuchu 13 w dniu 2026-09-19, gdy łańcuch 13 był aktualnym łańcuchem (produkcyjny profil FRI, genesis 8123ccac1883a45750e4df6964fb7cd3f0b321798cde4c0ef406a0293939ece3), z genesisowego portfela shielded-1. Każdy kolejny łańcuch (od 14 do 19) został uruchomiony od nowa, bez programów łańcucha 13, a obraz nie został w żadnym z nich wdrożony ponownie, więc poniższa transakcja i wysokość należą do łańcucha 13 i nie wyświetlają się już w eksploratorze. Identyfikator programu jest skrótem samych base_pc i słów, więc ten sam obraz dostaje ten sam identyfikator w każdym łańcuchu, który dopuszcza wdrożenie. Wyjście portfela, z pominiętymi liniami postępu (…):

$ rand program deploy <image.bin>
program id: f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d (11686 words, hc 92aefea0951c31a717574962aeb70e10a37012a7d035d48e8713c36df68feae0)
…
proved in 92.2s: tier 14, 1419655 bytes
submitted deploy c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
…
identyfikator programuf074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d
obraz11 686 słów; hc a0feae92… w zapisie rand-guest, 92aefea0… w zapisie portfela
pakiet opłaty (pakiet 2-in-2-out łańcucha 13)poziom 14, 1 419 655 bajtów, dowód w 92,2 s
transakcja wdrożenia (łańcuch 13)c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
zatwierdzona na wysokości (łańcuch 13)381

Od łańcucha 14 pakietem płacącym jest jeden pakiet 4-in-4-out z ukrytym aktywem, który niesie każda transakcja, udowodniony względem wiązania transakcji. Nadal jest to poziom 14: około 100 s i około 1,42 MB przy profilu produkcyjnym w łańcuchach 14 i 15. Od łańcucha 17 pakiet niesie także dowód uwierzytelnienia poziomu 10 (podzielona autoryzacja), więc w łańcuchach 18 i 19 pakiet opłaty transakcji to około 1,49 MB dowodu pakietu i około 1,37 MB dowodu uwierzytelnienia.

7. Wywołanie

Wywołanie transferu niesie wektor 921 słów jako dane prywatne, mieszczący się w limicie danych wejściowych w każdym łańcuchu (domyślnie 4 295 słów, 16 071 w łańcuchu 20), i żadnych słów publicznych. Nie można go przesłać do łańcucha 20: program nie może tam zostać wdrożony (krok 6), transfer generuje dowód na poziomie 18, a od fullnode v0.5.6 (2026-09-25) węzeł odrzuca każdy dowód wywołania powyżej poziomu 14 z błędem CallTierTooHigh, zanim zbuduje klucz weryfikatora. Poniższe polecenie generuje dowód lokalnie, a łańcuch odrzuca wynik; pomiary dotyczą dowodów poza łańcuchem. rand call przyjmuje każde słowo jako powtarzane --input:

rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d \
    $(for w in $(cat evm2rv/target/transfer.words); do printf -- '--input %s ' "$w"; done)

Teraz zmierzone. Dowód poziomu 18 został przerwany na 48-gigabajtowym laptopie przy 24,7 GB, ale na 128-gigabajtowym droplecie (m-16vcpu-128gb) przetłumaczone wywołanie transfer zostało udowodnione: szczytowe RSS 85,0 GB, 3 230,5 s (53,8 min), dowód o rozmiarze 811 600 bajtów. Został zweryfikowany w 101,4 s na droplecie oraz w 50,2 s przy 3,66 GB RSS na 48-gigabajtowym laptopie z procesorem Apple silicon (pamięć do generowania dowodów). Przy płaskim harmonogramie poziomów księgi, czyli regule w łańcuchach bez sekcji gas (do łańcucha 17), opłata za wywołanie na poziomie 18 wynosiła 0,0024 RAND. Łańcuchy 18 i 19 wyceniają wywołanie według zadeklarowanego limitu gazu i jego bajtów, przy cenach genesis 100 jednostek za gaz i 800 za KiB, i nie dopuszczają żadnego wywołania powyżej poziomu 14.

Wywołanie w łańcuchu 13, 2026-09-19

Wywołanie approve(BOB, 5) (649 słów prywatnych, poziom 16) odbyło się w łańcuchu 13 w dniu 2026-09-19, gdy był on aktualnym łańcuchem, z profilem produkcyjnym FRI, z tego samego portfela. Żadne wywołanie nie zostało wykonane w żadnym późniejszym łańcuchu, w którym program nie jest wdrożony, a łańcuch 20 odrzuca ten dowód wywołania poziomu 16 (CallTierTooHigh). Wyjście portfela, z pominiętymi liniami postępu (…):

$ 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
…
dowód wywołaniapoziom 16, 3 412 405 bajtów, dowód w 388,7 s
pakiet opłaty (pakiet 2-in-2-out łańcucha 13)poziom 14, 1 420 423 bajtów, dowód w 96,0 s
zapieczętowana koperta2 700 bajtów
transakcja wywołania (łańcuch 13)279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7
zakotwiczona na / zatwierdzona nawysokość 802 / wysokość 919
opłata0,00357 RAND
potwierdzenie h_pubnull
wyjścia potwierdzeniarówne ośmiu słowom interpretera dla tego samego wektora
czas rzeczywisty, szczytowe RSS622,8 s, 22,9 GB, na 48-gigabajtowym laptopie serii M
  • Dowód produkcyjny ma 3 412 405 bajtów, więc przekracza limit dowodu łańcucha 12 wynoszący 2 MiB. Łańcuch 12 nie mógł przyjąć tego wywołania; limit 8 MiB łańcucha 13 mógł. Łańcuchy od 14 do 16 zachowały ten sam limit, a łańcuchy od 17 do 20 ustawiają 4 MiB (4 194 304 bajtów), w który dowód tego rozmiaru nadal się mieści. Od v0.5.6 węzeł odrzuca wywołanie ze względu na jego poziom, zanim spojrzy na jego rozmiar.
  • Opłata obejmuje składnik bajtowy harmonogramu łańcucha 13: dowód 3,41 MB przekracza bezpłatny limit 2 MiB + 18 432 bajtów. Od łańcucha 18 każde wywołanie płaci za KiB od bajtu 0.

Osiem słów potwierdzenia to te z kroku 4. Łańcuch nie przechowuje stanu EVM: wywołujący dostarcza korzeń stanu początkowego i świadectwa pamięci, a korzeń stanu końcowego znajduje się wewnątrz skrótu EVM_OUT.

Limity

  • Brak kontekstu bloku. Dziewięć opkodów kontekstu bloku kończy się pułapką (trap), dopóki nie powstanie projekt wiązania z blokiem.
  • Brak transferów wartości. CALL z niezerową wartością kończy się pułapką. Wywołania kontraktów innych niż prekompilaty również kończą się pułapką.
  • ecrecover, bn256 mul, parowanie i duże modexp nie mogą być dziś udowodnione. Każde przekracza limit warstwy 2²⁰ wierszy; potrzebują tablic koprocesora.
  • Brak stanu EVM w łańcuchu. Wywołanie to jeden dowód dla jednego przebiegu; stan przenosi wywołujący.
  • Ani wdrożenie, ani żadne wywołanie ERC-20 nie jest dopuszczalne w chain 20. W ramach hardening_v6 chain 20 wdrożenie większej liczby słów, niż może pomieścić wywołanie warstwy 14, jest nieprawidłowe (ProgramUncallable; maksymalnie 8 180 słów), a obraz ma 11 686. Od fullnode v0.5.6 dowód wywołania musi należeć do warstwy 14 lub niższej (CallTierTooHigh); approve jest dowodzone w warstwie 16, a transfer i transferFrom w warstwie 18. Ta sama kontrola ogranicza tablice skrótów, które wywołanie może zadeklarować: 2¹² wierszy Keccak (128 permutacji) i 2¹³ wierszy SHA-256 (128 kompresji). Wywołania nadal dają się udowodnić poza łańcuchem, jak poniżej.
  • Indeks pamięci masowej ma głębokość 32 bitów. evm-core umieszcza liść pamięci kontraktu według górnych 32 bitów keccak256(slot), więc slot kolidujący z wybranym kosztuje około 2³² skrótów Keccak do znalezienia, a dopóki przechowuje on niezerową wartość, wybrany slot jest zamrożony (bez fałszerstwa i bez utraty wartości). Jest to uśpione: evm.bin ma 18 009 słów, a wywołanie na limicie warstwy 14 mieści co najwyżej 8 184, więc żaden runtime EVM nie jest wywoływalny w żadnym łańcuchu. Plik docs/confidential.md w fullnode odnotowuje ten warunek wstępny obok limitu wywołań (audyt v6, ZKV-6; na main od 2026-09-30, po tagu v0.6.7): zanim łańcuch zniesie limit wywołań warstwy 14 lub dopuści runtime EVM na tyle mały, by dało się go wywołać, indeks pamięci masowej musi zostać pogłębiony, a evm.bin ponownie przypięty.
  • Udowodnione. Dowód transferu etapu pierwszego (warstwa 18) został zabity przez SIGKILL na laptopie z 48 GB przy 24,7 GB po 1 016 s, ale wywołanie transfer etapu drugiego zostało udowodnione na droplecie z 128 GB (m-16vcpu-128gb): szczytowe RSS 85,0 GB, 3 230,5 s (53,8 min), dowód o rozmiarze 811 600 bajtów, zweryfikowany w 101,4 s (droplet) i 50,2 s przy 3,66 GB RSS (laptop 48 GB). Dowód transferu dla evm.bin interpretera był bardzo zbliżony: 85,5 GB, 3 143,3 s (52,4 min), dowód 805 108 bajtów — a oba dowody mają identyczne publiczne słowa wyjściowe, co potwierdza zgodność na prawdziwym proverze. approve (warstwa 16, przetłumaczony) jest znacznie tańszy: 21,7 GB, 786,7 s (13,1 min), dowód 798 930 bajtów. Translacja obniża koszt dowodzenia tylko wtedy, gdy przenosi wywołanie do mniejszej warstwy.
  • Łańcuch nie zapisuje bytecode’u. Opublikuj go, aby inni mogli odbudować hc.

Ostatnio zweryfikowano względem commitu fullnode c0878c3f (łańcuch 21) dnia 2026-10-12, a także circuits `7ef3220` (`evm2rv/README.md`, `guests-compiled/evm/contracts/SOLC.md`, `docs/superpowers/specs/2026-09-18-evm-to-rv32-translator-design.md`); the walkthrough re-run on 2026-09-19 with solc 0.8.37. Jeśli kod i ta strona się różnią, rację ma kod; prosimy o zgłoszenie.