Rand Protocol
Dokumentation
RISC-V-Programme

Der Ethereum-Transpiler

evm2rv übersetzt EVM-Runtime-Bytecode in die RISC-V ISA von Rand – was er ist, das Vertrauensmodell und seine Code-Absicherung, die abgedeckten Opcodes und Precompiles und wo er abbricht, die gemessenen Zahlen sowie eine vollständige ERC-20-Schritt-für-Schritt-Anleitung von Solidity über solc --bin-runtime bis zu Ausgaben, die mit dem EVM-Interpreter Wort für Wort übereinstimmen.

evm2rv nimmt EVM-Runtime-Bytecode, die Ausgabe von solc --bin-runtime, und macht daraus ein Rand-Programm. Es schreibt C, und rand-guest build kompiliert das C zu einem RV32IM-Image. Das Image nimmt denselben Eingabevektor entgegen wie der EVM-Interpreter-Guest von Rand, evm.bin, und veröffentlicht dieselben acht Ausgabewörter. Es führt den Contract nativ aus, statt ihn Opcode für Opcode zu interpretieren. Diese Seite zeigt den gesamten Weg an einem ERC-20.

Was es ist

EingabeEVM-Runtime-Bytecode, als Hex-Text (.hex) oder als Rohbytes
Ausgabeein C-Shim-Crate; rand-guest build macht daraus einen Image-Container
Ausführungsortoff chain, auf dem Rechner des Entwicklers; die Chain sieht nur das Image
Was übereinstimmen mussStatus, acht Ausgabewörter und gas_used von evm.bin
Repositoryevm2rv/ im circuits-Repository
festgelegte ToolchainRust 1.98.1, clang 23.1.1, das cc-Crate 1.4.6

Der Übersetzer nimmt Runtime-Code, nicht Creation-Code. Ein Beweis deckt einen Aufruf eines bereitgestellten Contracts ab, der Konstruktor läuft also nie. Der Zustand, den der Konstruktor schreiben würde, ist stattdessen Teil des Vorzustands, in Form von Storage-Witnesses.

Es gibt zwei Übersetzungsstufen. Beide liefern dieselben Ergebnisse und dasselbe Gas; jede ist ein eigenes Programm mit eigenem hc.

StufeFlagWas sie tut
eins--stage 1jeden Opcode über einen Speicher-Stack
zwei--stage 2, der Standarddie Stack-Wörter jedes Blocks in lokalen C-Variablen, Konstanten bei der Übersetzung gefaltet

Der Eingabevektor ist der des Interpreters: der Code, die Calldata, der Aufrufer und weitere Umgebungswörter, das Gaslimit, die Pre-State-Root und ein Storage-Witness pro Slot, den der Aufruf berührt. Die Ausgaben sind out[0], der Status (1 Erfolg, 0 Revert, 2 außergewöhnlicher Halt), und out[1..8], der EVM_OUT-Digest über den Code-Hash, beide State-Roots, die Rückgabedaten und die Logs.

Vertrauensmodell

Ein Verifier prüft einen übersetzten Contract in zwei Schritten.

  1. hc == translate(bytecode). evm2rv mit demselben --stage und --chain-id erneut auf den veröffentlichten Bytecode anwenden, mit der festgelegten Toolchain neu bauen und hc vergleichen. Das generierte Crate legt cc exakt fest und bringt sein eigenes Cargo.lock mit.
  2. Der Code-Guard bindet hc an den Bytecode. Die übersetzte Logik ist in das Image einkompiliert, aber CODECOPY und CODESIZE lesen den Code im Eingabevektor. Ohne Prüfung könnte ein hc mit Code-Bytes laufen, die der Aufrufer gewählt hat. Deshalb enthält contract.c einen Poseidon2-Digest des Quell-Bytecodes (seiner Länge und seiner Bytes), und das Shim hasht den Code des Eingabevektors auf dieselbe Weise, bevor übersetzter Code läuft. Anderer Code wird abgewiesen: Status 2, gas_used 0, Halt OutOfBounds.

Der EVM_OUT-Digest bindet außerdem keccak256 des Codes, wie der des Interpreters. Die Chain speichert weder den Quell-Bytecode noch dessen Hash. Damit andere hc prüfen können, veröffentlichen Sie den Bytecode oder den Solidity-Quellcode und den exakten solc-Build.

Der Guard kostet beim Transfer 1.008 Zyklen. Code, der sich um ein Byte von der Quelle unterscheidet, wird auf Stufe zwei in 30.418 Zyklen abgewiesen (Tier 16).

Abdeckung und was abbricht

Opcodes. Der Shanghai-Satz. Kompilieren Sie mit --evm-version shanghai: Neuere Ziele erzeugen MCOPY und andere Cancun-Opcodes, die abbrechen.

Umgebungs-Opcodes:

OpcodeÜbersetzung
ADDRESS, CALLER, CALLVALUE, CALLDATASIZE, CODESIZEaus dem Eingabevektor, wie der Interpreter sie liest
CHAINIDder Wert von --chain-id, bei der Übersetzung eingebacken, sodass hc ihn bindet; erforderlich, wenn der Code CHAINID enthält
ORIGINentspricht CALLER (ein Aufruf, kein Relayer)
GASPRICE, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, SELFBALANCE, BASEFEE, BLOCKHASHAbbruch (Status 2), wie im Interpreter

Die neun Block-Kontext-Opcodes brechen ab, bis es einen Entwurf gibt, sie an einen Block zu binden. Eine private Eingabe kann keinen Blockfakt tragen, weil ein Verifier H_IN nicht öffnen kann. Bis diese Entscheidung getroffen ist, bricht ein Contract ab, der die Zeit oder die Blocknummer liest (zum Beispiel eine Permit-Frist).

Aufrufe. CALL, CALLCODE, DELEGATECALL und STATICCALL führen einen Precompile aus, wenn das Ziel die Adresse 1 bis 9 ist. Jedes andere Ziel bricht ab. Ein Wert ungleich null bei CALL oder CALLCODE bricht ab: Es gibt kein Guthabenmodell.

Precompiles. Alle neun laufen in Software. Einige sind heute zu langsam zum Beweisen, weil ein Beweis höchstens 2²⁰ Zeilen fasst:

PrecompileVektorZyklenpasst in 2²⁰
1 ecrecoverValidKey14.510.525nein
2 sha256„abc“ / 200 Bytes2.791 / 5.289ja
3 ripemd160„abc“12.195ja
4 identity100 Bytes4.498ja
5 modexpnagydani-1-square / -1-pow0x10001122.332 / 874.548ja
5 modexpeip_example1 (256 Bit)11.170.118nein
5 modexpnagydani-5-pow0x10001 (1.024 Bytes)55.076.950nein
6 bn256 addchfast1978.262ja, knapp
7 bn256 mulchfast13.060.669nein
8 bn256 pairing1 pair / 2 pairs1.853.656.212 / 2.019.000.469nein
9 blake2f12 rounds14.493ja, bis etwa 1.800 Runden

Basis und Modulus von modexp sind auf jeweils 1.024 Bytes begrenzt.

Akzeptierte Abweichungen. Status, die acht Wörter und gas_used müssen übereinstimmen. Drei Unterschiede sind akzeptiert: Die Art des Halts kann abweichen (statisches Gas wird am Kopf jedes Blocks berechnet, sodass OutOfGas und ein anderer Halt vertauscht sein können; beide sind Status 2 bei vollständig verbrauchtem Gas); die Übersetzung implementiert CHAINID, ORIGIN und Precompile-Aufrufe, die der Interpreter abbrechen lässt; und der Code-Guard weist anderen Code als seine Quelle ab.

Die Zahlen

ERC-20-Aufrufe, mit eingebautem Code-Guard. Zyklen aus rand-guest run; Tier in Klammern.

AufrufInterpreter (evm.bin)Stufe einsStufe zwei (Standard)
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)
ProgrammWörterhc
evm.bin, der Interpreter18.0097e1aea2b…854c08
ERC-20, Stufe eins15.8049cdb79e7…2fd048c8
ERC-20, Stufe zwei11.686a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6

Stufe zwei führt die drei Aufrufe in 54,5 %, 56,2 % und 55,0 % der Zyklen des Interpreters aus. Der Transfer bleibt auf Tier 18: Seine 66.235 Zyklen plus 3.155 Digest-Zeilen ergeben 69.390 Zeilen, 3.855 über den 65.535 von Tier 16.

Etwa 60 % eines Stufe-zwei-Transfers (etwa 39.928 Zyklen) entfallen auf das Harness, das beide Images teilen: das Dekodieren der Eingabe, das Prüfen der Storage-Witnesses, die keccak256-Aufrufe der ABI und der Ausgabe-Digest. Keine Übersetzungsarbeit geht unter diese Untergrenze.

Walkthrough: ein ERC-20, von Solidity zu übereinstimmenden Ausgaben

Jeder Befehl läuft aus dem Stammverzeichnis eines circuits-Checkouts bei 7ef3220, mit der Toolchain aus Deploy a Rust program und clang 23.1.1 aus Deploy a RISC-V program. Lange Ausgaben sind dort gekürzt, wo … steht.

0. Die Werkzeuge bauen

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

1. Das Solidity zu Runtime-Bytecode kompilieren

Der Contract ist die eingecheckte guests-compiled/evm/contracts/ERC20.sol: ein eigenständiger ERC-20 mit dem Storage-Layout von OpenZeppelin v4, pragma solidity 0.8.37. Verwenden Sie exakt solc 0.8.37; eine andere Version optimiert anders und liefert anderen Bytecode.

Releasev0.8.37 von github.com/ethereum/solidity/releases
macOS-Assetsolc-macos, sha256 a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821
Linux-Assetsolc-static-linux, aus demselben Release
$ 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

Die letzte Zeile ist der Runtime-Bytecode, 1.296 Bytes. Er ist byteidentisch mit der eingecheckten guests-compiled/evm/contracts/erc20.runtime.hex; SOLC=$PWD/solc bash guests-compiled/evm/contracts/build.sh prüft das und gibt contracts: erc20.runtime.hex reproduces aus.

Die Flags sind wichtig:

  • --bin-runtime: der bereitgestellte Code, nicht der Creation-Code.
  • --evm-version shanghai: Das Standardziel von 0.8.37 erzeugt MCOPY, das abbricht.
  • --optimize --optimize-runs 200: ein Profil für bereitgestellte Contracts.

2. Übersetzen

$ 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 muss innerhalb eines circuits-Checkouts liegen. Ohne es analysiert evm2rv den Code nur.
  • Jeder abbrechende Opcode würde hier als Warnung mit seinem pc aufgeführt.
  • Diese Sitzung wurde mit --chain-id 12 aufgezeichnet. Dieser ERC-20 enthält kein CHAINID, daher ändert --chain-id sein hc nicht. Ein Contract, der CHAINID liest, verlangt das Flag; setzen Sie es auf die Chain, auf der Sie bereitstellen (--chain-id 19 für die Live-Chain).

contract.c endet mit dem Digest des Code-Guards:

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

3. Das Image bauen

Die Standardobergrenze liegt bei 4.096 Wörtern, übergeben Sie also --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

Das ist das veröffentlichte hc der Stufe zwei. Der Crate-Name beeinflusst es nicht.

4. Einen Eingabevektor bauen und einen Transfer ausführen

Das Beispiel erc20_vector gibt die Vektoren des Paritätstests als Eingabewörter aus: transfer (ALICE sendet BOB 250 ihrer 1.000), approve (ALICE erlaubt BOB, 5 auszugeben) und transferFrom (BOB bewegt 100 von ALICEs 1.000 gegen ein Allowance von 300). Für Ihren eigenen Contract bauen Sie in Rust auf dieselbe Weise einen EvmCall; das Beispiel ist die Vorlage.

$ (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. Mit dem Interpreter vergleichen

Dieselbe Eingabe auf dem Interpreter-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

Und der Interpreter, nativ auf dem Host ausgeführt, als Orakel der Tests:

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

Die Prüfung als ein Befehl:

$ 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

Wiederholen Sie die Schritte 4 und 5 mit approve und transferFrom; beide liefern identische Wörter. cd evm2rv && cargo +1.98.1 test --release führt diese und fünf weitere Vektoren unter beiden Stufen aus und prüft zusätzlich gas_used (70 Tests, dazu 2 ignorierte Beweise).

übersetzt (Stufe zwei)Interpreter (evm.bin)
acht Ausgabewörteridentischidentisch
Zyklen, transfer66.235121.638
Stufe1818
Programmwörter11.68618.009

6. Deployment

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

Die Wallet gibt die Programm-ID, die Wortzahl und hc aus und prüft die Obergrenze der Chain, bevor sie irgendetwas beweist. Das Image umfasst 11.686 Wörter und braucht daher eine Chain, deren Genesis max_program_words auf mindestens 11.686 setzt. Chain 12 lief mit dem Standardwert 4.096, das Deployment wurde dort also abgelehnt. Chain 13, die v0.4-Chain, setzte max_program_words auf 65.535, und jede Chain seither behält diesen Wert. Chain 20, die aktive Chain (Genesis 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135), behält zudem die Block-, Call-Envelope- und Public-Input-Limits von Chain 13 bei und halbiert die Beweisobergrenze auf 4 MiB (4.194.304 Bytes, seit Chain 17; die Chains 13 bis 16 setzten 8 MiB). Die Wortobergrenze ist nicht mehr die einzige Hürde. Die Genesis von Chain 20 setzt hardening_v6, und unter dieser Einstellung ist ein Deployment mit mehr Programmwörtern, als ein Aufruf bei der Call-Obergrenze von Stufe 14 fassen kann, ungültig (ProgramUncallable): höchstens 8.180 Wörter ohne Public Input. Dieses Image umfasst 11.686 Wörter, daher lehnt Chain 20 das Deployment ab, und sie würde auch die Aufrufe ablehnen: Jeder ERC-20-Aufruf wird auf Stufe 16 oder 18 bewiesen, oberhalb der Call-Obergrenze von Stufe 14 (Schritt 7). Die Block-Aggregation ist auf Chain 20 ausgeschaltet (ihre Genesis hat keinen Abschnitt aggregation); ihre Bootstrap-Knoten sind unter Running a validator aufgeführt. Die Deployment-Gebühr beträgt 0.001 + 0.0001 × 11,686 = 1,1696 RAND, die Gebühr, die das nachfolgende Deployment auf Chain 13 bezahlt hat.

Dieses Deployment lief am 2026-09-19 auf Chain 13, als diese die aktive Chain war (FRI-Profil für den Produktivbetrieb, Genesis 8123ccac1883a45750e4df6964fb7cd3f0b321798cde4c0ef406a0293939ece3), aus der Genesis-Wallet shielded-1. Jede Chain seither (14 bis 19) wurde als frische Chain ohne die Programme von Chain 13 aufgesetzt, und das Image wurde auf keiner davon erneut deployt; die Transaktion und die Höhe unten gehören daher zu Chain 13 und lassen sich im Explorer nicht mehr auflösen. Die Programm-ID ist ein Hash allein aus base_pc und den Wörtern, also erhält dasselbe Image auf jeder Chain, die das Deployment zulässt, dieselbe ID. Die Ausgabe der Wallet, mit ausgelassenen Fortschrittszeilen (…):

$ rand program deploy <image.bin>
program id: f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d (11686 words, hc 92aefea0951c31a717574962aeb70e10a37012a7d035d48e8713c36df68feae0)
…
proved in 92.2s: tier 14, 1419655 bytes
submitted deploy c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
…
Programm-IDf074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d
Image11.686 Wörter; hc a0feae92… in der Schreibweise von rand-guest, 92aefea0… in der der Wallet
Gebühren-Bundle (2-in-2-out-Bundle von Chain 13)Stufe 14, 1.419.655 Bytes, bewiesen in 92,2 s
Deployment-Tx (Chain 13)c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
bestätigt in Höhe (Chain 13)381

Seit Chain 14 ist das zahlende Bundle das eine 4-in-4-out-Bundle mit verborgenem Asset, das jede Transaktion trägt und das gegen das Binding der Transaktion bewiesen wird. Es ist weiterhin Stufe 14: auf den Chains 14 und 15 etwa 100 s und etwa 1,42 MB beim Produktivprofil. Seit Chain 17 trägt ein Bundle außerdem einen Auth-Beweis der Stufe 10 (geteilte Autorisierung); auf den Chains 18 und 19 umfasst das Gebühren-Bundle einer Transaktion daher etwa 1,49 MB Bundle-Beweis und etwa 1,37 MB Auth-Beweis.

7. Aufruf

Ein transfer-Aufruf trägt den Vektor mit 921 Wörtern als private Eingaben, unterhalb der Eingabeobergrenze jeder Chain (standardmäßig 4.295 Wörter, auf Chain 20 16.071), und keine öffentlichen Wörter. Er kann nicht an Chain 20 gesendet werden: Das Programm lässt sich dort nicht deployen (Schritt 6), der transfer wird auf Stufe 18 bewiesen, und seit fullnode v0.5.6 (2026-09-25) lehnt ein Knoten jeden Aufrufbeweis oberhalb von Stufe 14 mit CallTierTooHigh ab, noch bevor er einen Verifier-Schlüssel erzeugt. Der folgende Befehl beweist lokal, und die Chain lehnt das Ergebnis ab; die Messungen sind Off-Chain-Beweise. rand call nimmt jedes Wort als wiederholtes --input:

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

Nun gemessen. Ein Beweis der Stufe 18 wurde auf einem Laptop mit 48 GB bei 24,7 GB abgebrochen, doch auf einem Droplet mit 128 GB (m-16vcpu-128gb) wurde der übersetzte transfer-Aufruf bewiesen: 85,0 GB Spitzen-RSS, 3.230,5 s (53,8 min), ein Beweis von 811.600 Bytes. Er wurde auf dem Droplet in 101,4 s verifiziert und auf einem Apple-Silicon-Laptop mit 48 GB in 50,2 s bei 3,66 GB RSS (Proving-Speicher). Nach dem festen Stufenplan des Ledgers, der Regel auf Chains ohne Abschnitt gas (bis Chain 17), betrug die Aufrufgebühr auf Stufe 18 0,0024 RAND. Die Chains 18 und 19 bepreisen einen Aufruf stattdessen nach seinem deklarierten Gas-Limit und seinen Bytes, bei den Genesis-Preisen 100 Einheiten pro Gas und 800 pro KiB, und lassen keinen Aufruf oberhalb von Stufe 14 zu.

Der Aufruf auf Chain 13, 2026-09-19

Der Aufruf approve(BOB, 5) (649 private Wörter, Stufe 16) lief am 2026-09-19 auf Chain 13, als diese die aktive Chain war, mit dem FRI-Profil für den Produktivbetrieb, aus derselben Wallet. Auf keiner späteren Chain wurde ein Aufruf ausgeführt, da das Programm dort nicht deployt ist, und Chain 20 lehnt diesen Aufrufbeweis der Stufe 16 ab (CallTierTooHigh). Die Ausgabe der Wallet, mit ausgelassenen Fortschrittszeilen (…):

$ 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
…
AufrufbeweisStufe 16, 3.412.405 Bytes, bewiesen in 388,7 s
Gebühren-Bundle (2-in-2-out-Bundle von Chain 13)Stufe 14, 1.420.423 Bytes, bewiesen in 96,0 s
versiegelter Envelope2.700 Bytes
Aufruf-Tx (Chain 13)279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7
verankert in / bestätigt inHöhe 802 / Höhe 919
Gebühr0,00357 RAND
Receipt h_pubnull
Receipt-Ausgabengleich den acht Wörtern des Interpreters für denselben Vektor
Laufzeit, Spitzen-RSS622,8 s, 22,9 GB, auf einem Laptop der M-Serie mit 48 GB
  • Der Produktivbeweis umfasst 3.412.405 Bytes und liegt über der Beweisobergrenze von 2 MiB auf Chain 12. Chain 12 konnte diesen Aufruf nicht annehmen; die Obergrenze von 8 MiB auf Chain 13 schon. Die Chains 14 bis 16 behielten dieselbe Obergrenze, und die Chains 17 bis 20 setzten 4 MiB (4.194.304 Bytes), unter der ein Beweis dieser Größe weiterhin liegt. Seit v0.5.6 lehnt ein Knoten den Aufruf wegen seiner Stufe ab, bevor er dessen Größe prüft.
  • Die Gebühr enthält den Byte-Term des Plans von Chain 13: Der Beweis mit 3,41 MB liegt über dem freien Kontingent von 2 MiB + 18.432 Bytes. Seit Chain 18 zahlt jeder Aufruf ab dem ersten Byte pro KiB.

Die acht Wörter des Receipts sind die aus Schritt 4. Die Chain hält keinen EVM-Zustand: Der Aufrufer liefert die Pre-State-Root und die Storage-Witnesses, und die Post-State-Root steckt im EVM_OUT-Digest.

Grenzen

  • Kein Blockkontext. Die neun Blockkontext-Opcodes lösen einen Trap aus, bis ein Entwurf zur Blockbindung vorliegt.
  • Keine Wertübertragungen. Ein CALL mit einem Wert ungleich null löst einen Trap aus. Aufrufe an andere Contracts als Precompiles lösen einen Trap aus.
  • ecrecover, bn256 mul, das Pairing und große modexp lassen sich heute nicht beweisen. Jede dieser Operationen überschreitet die Obergrenze der Stufe mit 2²⁰ Zeilen; sie benötigen Coprozessor-Tabellen.
  • Kein EVM-Zustand on-chain. Ein Aufruf ist ein Beweis über einen Lauf; der Aufrufer trägt den Zustand.
  • Weder das Deployment noch ein ERC-20-Aufruf ist auf chain 20 zulässig. Unter hardening_v6 von chain 20 ist ein Deployment mit mehr Wörtern, als ein Aufruf der Stufe 14 fassen kann, ungültig (ProgramUncallable; höchstens 8.180 Wörter), und das Image umfasst 11.686. Seit fullnode v0.5.6 muss ein Aufrufbeweis auf Stufe 14 oder darunter liegen (CallTierTooHigh); approve wird auf Stufe 16 bewiesen, transfer und transferFrom auf Stufe 18. Dieselbe Prüfung begrenzt auch die Hash-Tabellen, die ein Aufruf deklarieren darf: 2¹² Keccak-Zeilen (128 Permutationen) und 2¹³ SHA-256-Zeilen (128 Kompressionen). Die Aufrufe lassen sich weiterhin off-chain beweisen, wie unten beschrieben.
  • Der Speicherindex ist 32 Bit tief. evm-core legt ein Contract-Speicherblatt anhand der obersten 32 Bit von keccak256(slot) ab. Ein Slot, der mit einem gewählten kollidiert, kostet daher etwa 2³² Keccak-Hashes, um ihn zu finden, und solange er einen Wert ungleich null hält, ist der gewählte Slot eingefroren (keine Fälschung und kein verlorener Wert). Das ist derzeit ruhend: evm.bin umfasst 18.009 Wörter, und ein Aufruf an der Obergrenze der Stufe 14 fasst höchstens 8.184, sodass auf keiner Chain eine EVM-Runtime aufrufbar ist. Die docs/confidential.md des fullnode hält die Voraussetzung neben der Aufrufobergrenze fest (Audit v6, ZKV-6; auf main seit 2026-09-30, nach dem Tag v0.6.7): Bevor eine Chain die Aufrufobergrenze der Stufe 14 aufhebt oder eine EVM-Runtime zulässt, die klein genug zum Aufrufen ist, muss der Speicherindex vertieft und evm.bin neu festgelegt werden.
  • Bewiesen. Ein Transfer-Beweis der ersten Phase (Stufe 18) wurde auf einem 48-GB-Laptop nach 1.016 s bei 24,7 GB mit SIGKILL beendet, doch der transfer-Aufruf der zweiten Phase wurde auf einem 128-GB-Droplet (m-16vcpu-128gb) bewiesen: 85,0 GB Spitzen-RSS, 3.230,5 s (53,8 min), ein Beweis von 811.600 Byte, verifiziert in 101,4 s (Droplet) und in 50,2 s bei 3,66 GB RSS (48-GB-Laptop). Der Transfer-Beweis des Interpreters mit evm.bin stimmte eng damit überein: 85,5 GB, 3.143,3 s (52,4 min), ein Beweis von 805.108 Byte – und die beiden Beweise tragen identische öffentliche Ausgabewörter, was die Parität auf dem echten Prover bestätigt. approve (Stufe 16, übersetzt) ist deutlich günstiger: 21,7 GB, 786,7 s (13,1 min), ein Beweis von 798.930 Byte. Die Übersetzung senkt die Beweiskosten nur dann, wenn sie einen Aufruf in eine kleinere Stufe verschiebt.
  • Die Chain zeichnet den Bytecode nicht auf. Veröffentlichen Sie ihn, damit andere hc neu bauen können.

Zuletzt geprüft gegen den fullnode-Commit c0878c3f (Chain 21) am 2026-10-12 und 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. Wo Code und diese Seite voneinander abweichen, hat der Code recht; sagen Sie uns Bescheid.