evm2rv recebe bytecode de runtime da EVM, a saída de solc --bin-runtime, e o transforma em um programa Rand. Ele gera C, e rand-guest build compila esse C em uma imagem RV32IM. A imagem recebe o mesmo vetor de entrada que o guest interpretador de EVM da Rand, evm.bin, e publica as mesmas oito palavras de saída. Ela executa o contrato nativamente, em vez de interpretá-lo opcode por opcode. Esta página mostra o caminho completo com um ERC-20.
O que é
| entrada | bytecode de runtime da EVM, como texto hexadecimal (.hex) ou bytes brutos |
| saída | um crate C shim; rand-guest build o transforma em um contêiner de imagem |
| onde executa | fora da cadeia, na máquina do desenvolvedor; a cadeia só vê a imagem |
| o que deve coincidir | o status, as oito palavras de saída e o gas_used de evm.bin |
| repositório | evm2rv/ no repositório de circuitos |
| toolchain fixada | Rust 1.98.1, clang 23.1.1, o crate cc 1.4.6 |
O tradutor recebe código de runtime, não código de criação. Uma prova cobre uma chamada a um contrato já implantado, então o construtor nunca é executado. O estado que o construtor escreveria faz parte, em vez disso, do pré-estado, como testemunhas de armazenamento.
Há dois estágios de tradução. Ambos dão os mesmos resultados e o mesmo gas; cada um é seu próprio programa, com seu próprio hc.
| estágio | flag | o que faz |
|---|---|---|
| um | --stage 1 | cada opcode sobre uma pilha em memória |
| dois | --stage 2, o padrão | as palavras da pilha de cada bloco em variáveis locais de C, constantes resolvidas na tradução |
O vetor de entrada é o do interpretador: o código, o calldata, o chamador e demais palavras de ambiente, o limite de gas, a raiz do pré-estado e uma testemunha de armazenamento por slot tocado pela chamada. As saídas são out[0], o status (1 sucesso, 0 revert, 2 parada excepcional), e out[1..8], o digest EVM_OUT sobre o hash do código, as duas raízes de estado, os dados de retorno e os logs.
Modelo de confiança
Um verificador checa um contrato traduzido em duas etapas.
hc == translate(bytecode). Executeevm2rvnovamente sobre o bytecode publicado, com o mesmo--stagee o mesmo--chain-id, recompile com a toolchain fixada e comparehc. O crate gerado fixacccom exatidão e traz seu próprioCargo.lock.- A guarda de código liga
hcao bytecode. A lógica traduzida é compilada dentro da imagem, masCODECOPYeCODESIZEleem o código do vetor de entrada. Sem uma verificação, um mesmohcpoderia rodar com bytes de código escolhidos pelo chamador. Por issocontract.ctraz um digest Poseidon2 do bytecode de origem (seu comprimento e seus bytes), e o shim calcula o hash do código do vetor de entrada da mesma forma antes de executar qualquer código traduzido. Qualquer outro código é recusado: status 2,gas_used0, paradaOutOfBounds.
O digest EVM_OUT também liga o keccak256 do código, como o do interpretador. A cadeia não registra o bytecode de origem nem o seu hash. Para que outros possam verificar hc, publique o bytecode, ou o código-fonte Solidity e o build exato do solc.
A guarda custa 1.008 ciclos na transferência. Um código que difere em um único byte da origem é recusado em 30.418 ciclos no estágio dois (tier 16).
Cobertura e o que gera trap
Opcodes. O conjunto Shanghai. Compile com --evm-version shanghai: alvos mais novos emitem MCOPY e outros opcodes do Cancun, que geram trap.
Opcodes de ambiente:
| opcode | tradução |
|---|---|
ADDRESS, CALLER, CALLVALUE, CALLDATASIZE, CODESIZE | do vetor de entrada, como o interpretador os lê |
CHAINID | o valor de --chain-id, embutido na tradução, de modo que hc o vincula; obrigatório quando o código contém CHAINID |
ORIGIN | igual a CALLER (uma chamada, sem relayer) |
GASPRICE, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, SELFBALANCE, BASEFEE, BLOCKHASH | trap (status 2), como no interpretador |
Os nove opcodes de contexto de bloco geram trap até que exista um desenho para vinculá-los a um bloco. Uma entrada privada não pode carregar um fato de bloco, porque um verificador não consegue abrir H_IN. Até que essa decisão seja tomada, um contrato que lê a hora ou o número do bloco (um prazo de permit, por exemplo) gera trap.
Chamadas. CALL, CALLCODE, DELEGATECALL e STATICCALL executam um precompile quando o destino é um endereço de 1 a 9. Qualquer outro destino gera trap. Um valor diferente de zero em CALL ou CALLCODE gera trap: não há modelo de saldo.
Precompiles. Os nove rodam em software. Alguns são lentos demais para serem provados hoje, porque uma prova comporta no máximo 2²⁰ linhas:
| precompile | vetor | ciclos | cabe em 2²⁰ |
|---|---|---|---|
| 1 ecrecover | ValidKey | 14.510.525 | não |
| 2 sha256 | ”abc” / 200 bytes | 2.791 / 5.289 | sim |
| 3 ripemd160 | ”abc” | 12.195 | sim |
| 4 identity | 100 bytes | 4.498 | sim |
| 5 modexp | nagydani-1-square / -1-pow0x10001 | 122.332 / 874.548 | sim |
| 5 modexp | eip_example1 (256 bits) | 11.170.118 | não |
| 5 modexp | nagydani-5-pow0x10001 (1.024 bytes) | 55.076.950 | não |
| 6 bn256 add | chfast1 | 978.262 | sim, por pouco |
| 7 bn256 mul | chfast1 | 3.060.669 | não |
| 8 bn256 pairing | 1 par / 2 pares | 1.853.656.212 / 2.019.000.469 | não |
| 9 blake2f | 12 rodadas | 14.493 | sim, até cerca de 1.800 rodadas |
A base e o módulo de modexp são limitados a 1.024 bytes cada.
Divergências aceitas. O status, as oito palavras e o gas_used devem coincidir. Três diferenças são aceitas: o tipo de parada pode diferir (o gas estático é cobrado no início de cada bloco, de modo que OutOfGas e outra parada podem se trocar; ambos são status 2, com todo o gas consumido); a tradução implementa CHAINID, ORIGIN e as chamadas a precompiles, que o interpretador trata como trap; e a guarda de código recusa qualquer código diferente de sua origem.
Os números
Chamadas ERC-20, com a guarda de código incluída. Ciclos obtidos de rand-guest run; tier entre parênteses.
| chamada | interpretador (evm.bin) | estágio um | estágio dois (padrão) |
|---|---|---|---|
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) |
| programa | palavras | hc |
|---|---|---|
evm.bin, o interpretador | 18.009 | 7e1aea2b…854c08 |
| ERC-20, estágio um | 15.804 | 9cdb79e7…2fd048c8 |
| ERC-20, estágio dois | 11.686 | a0feae92a7311c9562495717100eb7aea71270a38ed435d06dc31387e0ea8ff6 |
O estágio dois executa as três chamadas em 54,5%, 56,2% e 55,0% dos ciclos do interpretador. A transferência permanece no tier 18: seus 66.235 ciclos mais 3.155 linhas de digest somam 69.390 linhas, 3.855 acima das 65.535 do tier 16.
Cerca de 60% de uma transferência no estágio dois (cerca de 39.928 ciclos) é o harness que as duas imagens compartilham: decodificar a entrada, verificar as testemunhas de armazenamento, as chamadas keccak256 da ABI e o digest de saída. Nenhum trabalho de tradução desce abaixo desse piso.
Passo a passo: um ERC-20, do Solidity a saídas coincidentes
Todos os comandos são executados a partir da raiz de um checkout do repositório de circuitos em 7ef3220, com a toolchain de Deploy a Rust program e o clang 23.1.1 de Deploy a RISC-V program. Saídas longas são cortadas onde indicado por ….
0. Compile as ferramentas
(cd evm2rv && cargo +1.98.1 build --release)
(cd rand-guest && cargo +1.98.1 build --release)
1. Compile o Solidity para bytecode de runtime
O contrato é o guests-compiled/evm/contracts/ERC20.sol versionado: um ERC-20 autocontido com o layout de armazenamento do OpenZeppelin v4, pragma solidity 0.8.37. Use exatamente o solc 0.8.37; outra versão otimiza de forma diferente e gera bytecode diferente.
| release | v0.8.37 de github.com/ethereum/solidity/releases |
| asset para macOS | solc-macos, sha256 a27396e7732aa52e80ff89ad7bd8a2e46fec2a6dcc4ef20cd16e5e0c502d6821 |
| asset para Linux | solc-static-linux, da mesma 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
A última linha é o bytecode de runtime, com 1.296 bytes. Ele é idêntico, byte a byte, ao guests-compiled/evm/contracts/erc20.runtime.hex versionado; SOLC=$PWD/solc bash guests-compiled/evm/contracts/build.sh verifica isso e imprime contracts: erc20.runtime.hex reproduces.
As flags importam:
--bin-runtime: o código implantado, não o código de criação.--evm-version shanghai: o alvo padrão do 0.8.37 emiteMCOPY, que gera trap.--optimize --optimize-runs 200: um perfil para contratos implantados.
2. Traduza
$ 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
--outdeve estar dentro de um checkout do repositório de circuitos. Sem ele,evm2rvapenas analisa o código.- Qualquer opcode que gerasse trap seria listado aqui como aviso, com seu pc.
- Esta sessão foi capturada com
--chain-id 12. Este ERC-20 não temCHAINID, então--chain-idnão altera seuhc. Um contrato que lêCHAINIDexige a flag; defina-a como a cadeia em que você vai implantar (--chain-id 19para a cadeia em produção).
contract.c termina com o digest da guarda de código:
const uint32_t *evm_code_digest(void) {
static const uint32_t d[8] = {0xf679280fu, 0x86c10e83u, 0x7e8f1f39u, 0xa2377de3u, 0x8a2e282fu, 0xc54cad42u, 0xddfaf009u, 0x7d28a8afu};
return d;
}
3. Construa a imagem
O limite padrão é de 4.096 palavras, então passe --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
Este é o hc publicado do estágio dois. O nome do crate não o afeta.
4. Monte um vetor de entrada e execute uma transferência
O exemplo erc20_vector imprime os vetores do teste de paridade como palavras de entrada: transfer (ALICE envia 250 a BOB, de seus 1.000), approve (ALICE permite que BOB gaste 5) e transferFrom (BOB move 100 dos 1.000 de ALICE, contra uma allowance de 300). Para o seu próprio contrato, monte um EvmCall da mesma forma em Rust; o exemplo é o modelo.
$ (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. Compare com o interpretador
A mesma entrada no guest interpretador:
$ 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
E o interpretador executado nativamente no host, o oráculo dos testes:
$ (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
A verificação em um único comando:
$ 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
Repita os passos 4 e 5 com approve e transferFrom; ambos produzem palavras idênticas. cd evm2rv && cargo +1.98.1 test --release executa estes e mais cinco vetores nos dois estágios, e também verifica gas_used (70 testes, mais 2 provas ignoradas).
| traduzido (segundo estágio) | interpretador (evm.bin) | |
|---|---|---|
| oito palavras de saída | idênticas | idênticas |
| ciclos, transfer | 66,235 | 121,638 |
| tier | 18 | 18 |
| palavras do programa | 11,686 | 18,009 |
6. Deploy
rand program deploy evm2rv/target/mytoken/image.bin
A carteira imprime o id do programa, o número de palavras e hc, e então verifica o limite da chain antes de provar qualquer coisa. A imagem tem 11,686 palavras, então exige uma chain cujo genesis defina max_program_words em pelo menos 11,686. A chain 12 usava o padrão de 4,096, e por isso o deploy foi recusado ali. A chain 13, a chain da v0.4, definiu max_program_words como 65,535, e todas as chains desde então mantêm esse valor. A chain 20, a chain em operação (genesis 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135), mantém também os limites de bloco, de envelope de chamada e de entrada pública da chain 13 e reduz pela metade o limite de prova para 4 MiB (4,194,304 bytes, desde a chain 17; as chains 13 a 16 definiam 8 MiB). O limite de palavras deixou de ser a única barreira. O genesis da chain 20 define hardening_v6, e, sob essa regra, um deploy com mais palavras de programa do que uma chamada comporta no limite de chamada do tier 14 é inválido (ProgramUncallable): no máximo 8,180 palavras, sem entrada pública. Esta imagem tem 11,686 palavras, então a chain 20 recusa o deploy, e recusaria também as chamadas: toda chamada ERC-20 é provada no tier 16 ou 18, acima do limite de chamada do tier 14 (passo 7). A agregação de blocos está desativada na chain 20 (seu genesis não tem seção aggregation); seus nós de bootstrap estão listados em Running a validator. A taxa de deploy é 0.001 + 0.0001 × 11,686 = 1.1696 RAND, a mesma que o deploy na chain 13 abaixo pagou.
Este deploy foi executado na chain 13 em 2026-09-19, quando a chain 13 era a chain em operação (perfil FRI de produção, genesis 8123ccac1883a45750e4df6964fb7cd3f0b321798cde4c0ef406a0293939ece3), a partir da carteira genesis shielded-1. Todas as chains seguintes (14 a 19) foram criadas como chains novas, sem os programas da chain 13, e a imagem não foi reimplantada em nenhuma delas; assim, a transação e a altura abaixo pertencem à chain 13 e já não são resolvidas no explorador. O id do programa é um hash apenas de base_pc e das palavras, de modo que a mesma imagem recebe o mesmo id em qualquer chain que admita o deploy. A saída da carteira, com as linhas de progresso omitidas (…):
$ rand program deploy <image.bin>
program id: f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d (11686 words, hc 92aefea0951c31a717574962aeb70e10a37012a7d035d48e8713c36df68feae0)
…
proved in 92.2s: tier 14, 1419655 bytes
submitted deploy c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0
…
| id do programa | f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d |
| imagem | 11,686 palavras; hc a0feae92… na grafia do rand-guest, 92aefea0… na da carteira |
| pacote de taxa (pacote 2-in-2-out da chain 13) | tier 14, 1,419,655 bytes, provado em 92.2 s |
| tx de deploy (chain 13) | c7a66dc4d9cdb7f9bfc4bde01f618c356e5abad7097e6bf7dc04e2e49c53acd0 |
| confirmada na altura (chain 13) | 381 |
Desde a chain 14, o pacote de pagamento é o único pacote de ativo oculto 4-in-4-out que toda transação carrega, provado contra o binding da transação. Continua no tier 14: cerca de 100 s e cerca de 1.42 MB no perfil de produção nas chains 14 e 15. Desde a chain 17, um pacote também carrega uma prova de autenticação do tier 10 (autorização dividida), de modo que, nas chains 18 e 19, o pacote de taxa de uma transação tem cerca de 1.49 MB de prova do pacote e cerca de 1.37 MB de prova de autenticação.
7. Call
Uma chamada de transferência carrega o vetor de 921 palavras como entradas privadas, dentro do limite de entrada de qualquer chain (4,295 palavras por padrão, 16,071 na chain 20), e nenhuma palavra pública. Ela não pode ser enviada à chain 20: o programa não pode ser implantado ali (passo 6), a transferência é provada no tier 18 e, desde o fullnode v0.5.6 (2026-09-25), um nó recusa qualquer prova de chamada acima do tier 14 com CallTierTooHigh, antes de construir uma chave do verificador. O comando abaixo prova localmente e a chain recusa o resultado; as medições são de provas fora da chain. rand call recebe cada palavra como um --input repetido:
rand call f074c4eb834cf01886a8241b6a2e0caf6e1cee5327fee6cb1a1a37436607280d \
$(for w in $(cat evm2rv/target/transfer.words); do printf -- '--input %s ' "$w"; done)
Agora medido. Uma prova do tier 18 foi interrompida em um laptop de 48 GB a 24.7 GB, mas em um droplet de 128 GB (m-16vcpu-128gb) a chamada transfer traduzida foi provada: 85.0 GB de RSS de pico, 3,230.5 s (53.8 min), uma prova de 811,600 bytes. Ela foi verificada em 101.4 s no droplet e em 50.2 s, com 3.66 GB de RSS, em um laptop Apple-silicon de 48 GB (memória de prova). Sob o cronograma fixo de tiers do ledger, a regra nas chains sem seção gas (até a chain 17), a taxa de chamada no tier 18 era 0.0024 RAND. As chains 18 e 19 precificam uma chamada pelo limite de gas declarado e pelos seus bytes, 100 unidades por gas e 800 por KiB nos preços do genesis, e não admitem nenhuma chamada acima do tier 14.
The call on chain 13, 2026-09-19
A chamada approve(BOB, 5) (649 palavras privadas, tier 16) foi executada na chain 13 em 2026-09-19, quando ela era a chain em operação, com o perfil FRI de produção, a partir da mesma carteira. Nenhuma chamada foi feita em chains posteriores, nas quais o programa não está implantado, e a chain 20 recusa esta prova de chamada do tier 16 (CallTierTooHigh). A saída da carteira, com as linhas de progresso omitidas (…):
$ 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
…
| prova da chamada | tier 16, 3,412,405 bytes, provada em 388.7 s |
| pacote de taxa (pacote 2-in-2-out da chain 13) | tier 14, 1,420,423 bytes, provado em 96.0 s |
| envelope selado | 2,700 bytes |
| tx de chamada (chain 13) | 279e1f62abf3f177ca71b08c633e051c37bc4720118c79ddb00936f036c4bfa7 |
| ancorada em / confirmada em | altura 802 / altura 919 |
| taxa | 0.00357 RAND |
recibo h_pub | null |
| saídas do recibo | iguais às oito palavras do interpretador para o mesmo vetor |
| tempo total, RSS de pico | 622.8 s, 22.9 GB, em um laptop M-series de 48 GB |
- A prova de produção tem 3,412,405 bytes, acima do limite de prova de 2 MiB da chain 12. A chain 12 não poderia aceitar esta chamada; o limite de 8 MiB da chain 13 aceitou. As chains 14 a 16 mantiveram o mesmo limite, e as chains 17 a 20 definem 4 MiB (4,194,304 bytes), dentro do qual uma prova deste tamanho ainda cabe. Desde a v0.5.6, um nó recusa a chamada por causa do tier antes de examinar o tamanho.
- A taxa inclui o termo de bytes do cronograma da chain 13: a prova de 3.41 MB está acima da franquia gratuita de 2 MiB + 18,432 bytes. Desde a chain 18, toda chamada paga por KiB desde o byte 0.
As oito palavras do recibo são as do passo 4. A chain não guarda estado da EVM: o chamador fornece a raiz do estado anterior e as testemunhas de armazenamento, e a raiz do estado posterior está dentro do digest EVM_OUT.
Limits
- Sem contexto de bloco. Os nove opcodes de contexto de bloco geram trap até que exista um desenho de vinculação a blocos.
- Sem transferências de valor. Um
CALLcom valor diferente de zero gera trap. Chamadas a contratos que não sejam precompiles geram trap. - ecrecover, bn256 mul, o pairing e modexp de grande porte não podem ser provados hoje. Cada um excede o limite de 2²⁰ linhas do tier; precisam de tabelas de coprocessador.
- Sem estado da EVM na chain. Uma chamada é uma única prova sobre uma única execução; o chamador carrega o estado.
- Nem o deploy nem qualquer chamada ERC-20 é admissível na chain 20. Sob o
hardening_v6da chain 20, um deploy com mais palavras do que uma chamada de tier 14 comporta é inválido (ProgramUncallable; no máximo 8.180 palavras), e a imagem tem 11.686. Desde o fullnode v0.5.6, a prova de uma chamada deve ser de tier 14 ou inferior (CallTierTooHigh);approveé provado no tier 16,transferetransferFromno tier 18. A mesma verificação limita as tabelas de hash que uma chamada pode declarar: 2¹² linhas de Keccak (128 permutações) e 2¹³ linhas de SHA-256 (128 compressões). As chamadas ainda podem ser provadas fora da chain, como abaixo. - O índice de armazenamento tem 32 bits de profundidade. O
evm-coreposiciona uma folha de armazenamento de contrato pelos 32 bits mais significativos dekeccak256(slot); assim, encontrar um slot que colida com um slot escolhido custa cerca de 2³² hashes Keccak, e, enquanto ele guarda um valor diferente de zero, o slot escolhido fica congelado (sem falsificação e sem perda de valor). Isto está dormente: oevm.bintem 18.009 palavras, e uma chamada no limite do tier 14 comporta no máximo 8.184, de modo que nenhum runtime da EVM pode ser chamado em nenhuma chain. Odocs/confidential.mddo fullnode registra a precondição junto ao limite de chamadas (auditoria v6, ZKV-6; emmaindesde 2026-09-30, após a tag v0.6.7): antes que uma chain suspenda o limite de chamadas do tier 14 ou admita um runtime da EVM pequeno o bastante para ser chamado, o índice de armazenamento deve ser aprofundado e oevm.binfixado novamente. - Provado. Uma prova de transferência de primeira etapa (tier 18) foi encerrada com SIGKILL em um laptop de 48 GB, a 24,7 GB, após 1.016 s, mas a chamada
transferde segunda etapa foi provada em um droplet de 128 GB (m-16vcpu-128gb): 85,0 GB de RSS de pico, 3.230,5 s (53,8 min), uma prova de 811.600 bytes, verificada em 101,4 s (droplet) e em 50,2 s com 3,66 GB de RSS (laptop de 48 GB). A prova de transferência doevm.bindo interpretador ficou muito próxima: 85,5 GB, 3.143,3 s (52,4 min), uma prova de 805.108 bytes — e as duas provas carregam palavras de saída públicas idênticas, o que confirma a paridade no prover real.approve(tier 16, traduzido) é muito mais barato: 21,7 GB, 786,7 s (13,1 min), uma prova de 798.930 bytes. A tradução só reduz o custo de prova quando leva uma chamada a um tier menor. - A chain não registra o bytecode. Publique-o para que outros possam reconstruir o
hc.