Rand Protocol
Documentação
Referência

JSON-RPC

Todos os métodos rand_* que o nó oferece - parâmetros, formatos de resultado e erros - além de lotes, das assinaturas WebSocket e do formato de transmissão de transações.

O nó serve JSON-RPC 2.0 sobre HTTP em --rpc (padrão 127.0.0.1:8545) e um WebSocket na mesma porta para subscrições. Desde a v0.6.8, também pode abrir um segundo listener, público (--public-rpc, abaixo). randprotocol_client::RpcClient (Rust) encapsula todos os métodos abaixo. Esta página é a lista de métodos tal como a v0.6.8 (c9c9bd3c), a build que a chain 20 executa, os serve; quando um método existe no código mas está inerte na chain 20, a página o indica.

curl -s http://127.0.0.1:8545 -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"rand_getHead","params":[]}'

O endpoint público

https://rpc.randprotocol.org (o mesmo proxy também está em https://randprotocol.org/api/rpc) encaminha para um nó de arquivo da chain 20 que guarda todos os blocos, para carteiras e páginas sem nó próprio (rand --rpc https://rpc.randprotocol.org …). Aceita apenas HTTP POST, com CORS aberto e sem WebSocket, e é mais restrito que um nó:

  • Uma requisição por chamada. Um lote é recusado com -32600.
  • Uma lista de métodos permitidos: desde 2026-10-01, o mesmo conjunto do listener público do próprio nó (rpc::PUBLIC_METHODS na v0.6.8). Assim, as leituras de estado de programa de que rand program invoke precisa, rand_getAdmitted, as leituras de agregação e as leituras de vesting estão nela, junto com rand_checkTransaction e rand_sendTransaction. rand_mint, rand_importViewingKey, rand_getViewingNotes, rand_removeViewingKey e rand_getPeers não estão, e respondem -32601 method not allowed here sem chegar ao nó: um faucet público é uma superfície de abuso, e uma viewing key só deve ir a um nó que você mesmo opera.
  • Um corpo de requisição de no máximo 12 MiB, que comporta qualquer transferência, ação de token ou deploy, e uma chamada cuja prova chegue a cerca de 3,4 MB (a transação é codificada em hexadecimal, e as provas de bundle e de auth ocupam cerca de 2,85 MB antes da prova da chamada). Uma chamada maior vai para o seu próprio nó. Acima do limite: HTTP 413 e -32600.
  • Por endereço, 1.200 requisições por minuto e 6 por minuto para rand_sendTransaction. Acima disso: HTTP 429 e -32005. O orçamento de leitura é dimensionado para a primeira sincronização de uma carteira, que são várias centenas de requisições numa só rajada (645 na altura 99.000 da chain 18).
  • -32000 upstream unavailable quando o nó por trás não responde.

Todo o resto desta página descreve o próprio nó.

Os dois listeners do nó

Desde a v0.6.8 (audit v6), um nó tem dois listeners JSON-RPC.

  • --rpc <ADDR>, o listener do operador. Todos os métodos, lotes e o WebSocket. Ele identifica um chamador pelo endereço de socket e confia no loopback: os métodos de viewing key respondem apenas ao loopback, e o loopback não é medido. Mantenha-o em 127.0.0.1. Um proxy reverso ou um encaminhamento SSH chega pelo loopback, de modo que, atrás de um deles, todo visitante é o operador: nunca aponte um endpoint público para esta porta.
  • --public-rpc <ADDR>, o listener público, para exatamente esse salto. Serve um conjunto fixo de métodos, as leituras de que uma carteira, um explorador ou uma página precisa, e rand_sendTransaction (rpc::PUBLIC_METHODS). rand_importViewingKey, rand_getViewingNotes, rand_removeViewingKey, rand_mint e rand_getPeers nunca são servidos ali, nem qualquer método adicionado depois até que seja listado; uma chamada assim responde -32000 <method> is not served on this node's public listener. Um lote é -32600, e não há rota de WebSocket. Um único medidor cobre todos os chamadores em conjunto, 600 requisições em rajada e 150 por segundo; acima disso, HTTP 429 com corpo -32000. Os limites por visitante cabem ao proxy, que consegue ver os visitantes. Seus chamadores ocupam no máximo metade dos slots de leitura bloqueante do nó, de modo que o listener do operador nunca fica sem recursos.

Os dois listeners compartilham dois limites de leitura. Uma leitura bloqueante que não retorna em 30 s recebe a resposta -32000 this read took longer than 30 s on this node; retry with a smaller range. rand_getBlocks encerra sua página assim que leu 64 MiB de blocos.

--rpc-viewing-token-file <PATH> coloca um bearer token nos métodos de viewing key de --rpc: a primeira linha do arquivo, com pelo menos 32 caracteres, enviada como Authorization: Bearer <token>. Com ele, o loopback sozinho não basta, e um chamador de qualquer lugar que o apresente é atendido.

Convenções

  • Endereços de validator são strings base58 (32 bytes). Hashes têm 64 caracteres hexadecimais, com ou sem 0x. Os valores shielded — commitments, nullifiers, anchors, raízes de árvore, níveis de witness — são Word8: oito palavras u32 little-endian como 64 caracteres hexadecimais minúsculos.
  • Os endereços shielded são rand1 + base58, 1.667 caracteres. Um parâmetro com mais de 2.000 caracteres é recusado pelo tamanho antes de ser analisado.
  • Todo valor u64 é uma string decimal ("1500000000" = 1,5 RAND; 1 RAND = 10⁹ unidades): unidades de RAND ou de token, estado da chain ou campo próprio de uma transação decodificada. Um número JSON não é um inteiro exato acima de 2⁵³, e a oferta de um token de 9 casas decimais ultrapassa isso em algumas dezenas de milhões de unidades. Veja a nota datada abaixo para o que isso mudou.
  • Índices, nonces, alturas, índices de folha, views, comprimentos, decimais e contadores de dias (mint_day) nunca são valores monetários e são inteiros JSON em todo o documento.
  • Toda requisição deve conter um membro id. Um objeto sem ele é uma notificação e é recusado com -32600; um "id": null explícito é uma requisição normal.
  • Não há método de saldo nem método de conta. Uma carteira calcula seu saldo varrendo rand_getCommitments e rand_getNullifiers com a sua viewing key. rand_getBalance, rand_getAccount e rand_getAssetBalance respondem -32601.

Mudança incompatível, 2026-09-20 (chain 14): todo valor é uma string decimal

Antes da chain 14, os valores dentro de uma transação decodificada eram inteiros JSON. Essa exceção acabou. Estes campos passaram de números JSON para strings decimais, sem nenhuma outra mudança de significado ou de posição:

  • bundle.fee, em tx de rand_getTransaction e em transactions[] de rand_getBlockByHeight / rand_getBlockByHash;
  • action.amount para kind = mint, bond, unbond, withdraw, bridge_attest (os mesmos três métodos);
  • action.amount e action.relayer_fee para kind = bridge_burn (os mesmos três métodos);
  • locked nas linhas de rand_getAssets e de rand_getBridgeState.assets[].

Um cliente que leia qualquer um deles como número deve passar a analisar uma string. O campo aggregation.subsidy_base de rand_status (apenas em chains com agregação) tornou-se string na mesma mudança. Todos os outros valores já eram strings: rand_getSupply, rand_getEmission, rand_getValidators, as notes de visualização e todos os campos introduzidos com a chain 14 — os burn_a e burn_r do bundle, as ofertas dos tokens, o locked de cada backing, mint_cap_per_day e minted_today, registration_fee, e o amount de token_mint, token_burn e register_token (initial_amount, initial.amount).

Lotes

Um corpo POST pode ser um array de no máximo 20 objetos de requisição, respondido por um array do mesmo comprimento na ordem das requisições, erros incluídos. As requisições são executadas uma após a outra. Um array vazio, um array com mais de 20 elementos, ou um corpo que não seja nem objeto nem array resulta em um único -32600 com id nulo. O corpo inteiro continua limitado pelo limite de corpo de requisição do nó, dimensionado para uma transação com prova: um lote de duas chamadas rand_sendTransaction com prova é recusado com 413. Use lotes para leituras, não para envios com prova.

Chain e nó

rand_chainId

Params []. Resultado: o id da chain (inteiro); 20 na testnet.

rand_tokenInfo

Params []. Resultado { "symbol": "RAND", "decimals": 9 }.

rand_getHead

Params []. Resultado { "height": 1998, "hash": "…", "view": 2251 }. view é a view de consenso atual do nó, que corre à frente da altura quando as views expiram por timeout.

rand_status (alias rand_syncStatus)

Params []. Resultado:

{
  "height": 1998, "head_hash": "…", "view": 2251, "high_qc_view": 2250,
  "syncing": false, "sync_target": 1998,
  "sync_inflight_age_ms": null, "sync_failures": 0, "sync_late_batches": 0,
  "peer_count": 26, "connected_peers": 26, "reserved_peers": 25, "ws_clients": 0, "refused_cache": 0,
  "verify_queue": 0, "mempool_size": 0,
  "is_validator": true, "active_validator": true, "faucet": true, "confidential": true,
  "testnet": true, "fri_profile": "production", "programs": 10, "viewing_keys": 0,
  "notes": 197, "nullifiers": 160, "tree_root": "72b9…1197", "hc_bundle": "60af…3fce", "hc_auth": "1e4e…39c1",
  "binding_domain": 1,
  "address": "5TAofR…", "peer_id": "12D3KooW…",
  "gas_prices": { "gas_price": "100", "byte_price": "800" }
}

is_validator: este nó possui uma chave de validator; active_validator: essa chave está no conjunto que executa a época atual. reserved_peers (v0.6.8) conta os peers admitidos além do limite de conexões de entrada: os bootstraps, qualquer --reserved-peer e cada identidade de validator aprendida a partir de um vínculo de peer assinado, cada um uma só vez; num nó da frota, deve chegar ao número de validators no prazo de um minuto após o início. viewing_keys é quantas viewing keys o nó mantém em memória para varredura no próprio nó. verify_queue é o número de transações à espera de um dos quatro workers de verificação de provas (64 de profundidade no máximo). hc_bundle é o guest de bundle contra o qual as provas desta chain são feitas e hc_auth o guest de auth que o seu genesis fixa (autorização dividida, desde a chain 17), ou null numa chain sem um; um nó cuja build discorde de qualquer um dos dois recusa-se a iniciar. testnet e binding_domain são os campos de genesis de mesmo nome, como rand_getLimits os serve. gas_prices são os preços de gas atuais do ledger da ponta, atualizados a cada commit, como strings decimais; null numa chain sem seção gas. Os preços da chain 20 são dinâmicos e variam por bloco conforme o preenchimento, nunca abaixo dos pisos de 100 e 800 e nunca acima dos tetos de 10.000 e 80.000; por isso, leia-os aqui ou em rand_getLimits e não os fixe no código. O objeto também traz um objeto aggregation (seu subsidy_base é uma string decimal, o restante são inteiros), que aparece todo zerado numa chain sem seção aggregation, como é a chain 20.

O objeto também traz disk_free_bytes (um número) e disk_low, além do par de retenção: prune_floor, a menor altura que este nó ainda mantém (0 num nó de arquivo), e prune_history_secs, a janela que um nó iniciado com --prune-history mantém (null quando mantém tudo). Na chain 20, como na chain 19, 24 dos 26 validators mantêm 24 horas de blocos; os dois nós de arquivo mantêm todos. Veja Nós podados.

rand_getPeers

Params []. Resultado: um array de { "peer_id": "12D3KooW…", "addrs": ["/ip4/…/tcp/30303"], "connected_secs": 1241 }.

rand_getBlockByHeight / rand_getBlockByHash

Params [height] ou [hash]. Resultado null se desconhecido; caso contrário:

{
  "hash": "647b…", "height": 50, "view": 92, "parent": "2d41…",
  "proposer": "3v3VBJ…", "timestamp_ms": 1788000123456,
  "tx_root": "0000…", "state_root": "a1b2…", "justify_view": 91,
  "tx_count": 0, "transactions": [ ]
}

Somente blocos confirmados são servidos. transactions tem o mesmo formato que o tx de rand_getTransaction. Um bloco também traz sealed, e cada uma de suas transações traz sealed_by; eles valem false e null em uma chain sem agregação.

rand_getBlocks

Parâmetros [from_height, to_height]. Resultado: cabeçalhos de bloco, do mais antigo ao mais recente, no máximo 1.024 a partir de from_height (128 em um nó anterior a 2026-09-24): os campos de rand_getBlockByHeight sem transactions. Um intervalo maior que o limite, ou além da cabeça da chain, é truncado, não recusado, e desde a v0.6.8 uma página também termina assim que leu 64 MiB de blocos; continue a partir da última altura retornada. -32602 quando to_height é menor que from_height.

Desde a v0.6.8, todo cabeçalho também traz public_notes: as transações bridge_attest, token_mint e register_token do bloco e, em uma chain com taxas de bridge, suas transações bridge_burn, como [{ "hash", "raw" }] (a codificação que rand_getRawTransaction serve); vazio para todos os outros blocos. Uma burn é servida com suas provas esvaziadas e "proofs_stripped": true; seu hash é o id real da transação. A primeira sincronização de uma carteira lê essas páginas e não precisa de mais nada para reconstruir as notas públicas.

rand_getFinality

Parâmetros [height] ou [hash]. Resultado, um entre { "status": "committed", "height", "hash" }, { "status": "certified", "height", "hash", "qc_view" }, { "status": "proposed", "height", "hash" }, { "status": "unknown" }. Uma altura é verificada apenas contra a chain confirmada, portanto responde committed ou unknown; um hash também pode retornar certified (na árvore não confirmada da réplica, com um quorum certificate) ou proposed (na árvore, sem um).

rand_getProposer

Parâmetros [view] ou [from_view, to_view], no máximo 64 views. Resultado { "epoch": 3, "proposers": [ { "view": 2251, "proposer": "2nRdFC…" } ] }: o líder de cada view sob o conjunto de validadores atual, não o conjunto que operava naquela view historicamente. -32602 para um intervalo invertido ou com mais de 64 views.

rand_getVersion

Parâmetros []. Resultado { "version", "git_sha", "chain_id", "hc_bundle", "hc_auth", "fri_profile" }. version é a versão do crate do workspace; git_sha é o hash do commit capturado na compilação, com -dirty acrescentado quando arquivos rastreados diferiam, ou "unknown". hc_auth é o guest de autenticação do genesis, como em rand_status, ou null. O endpoint público em 2026-10-01, na chain 20:

{ "version": "0.6.8", "git_sha": "c9c9bd3c1903aa4cc5833b7ab8c62fc3e6942017", "chain_id": 20,
  "hc_bundle": "60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce",
  "hc_auth": "1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1",
  "fri_profile": "production" }

rand_getGenesisHash

Parâmetros []. Resultado: o hash do genesis em hexadecimal; "6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135" na chain 20 (o da chain 19 era a3defc93…228a). Um chain id sozinho não distingue dois cortes de chain; este distingue. Na chain 20 ele também faz parte de todo binding de transação e de toda mensagem de ação assinada (binding_domain: 1, veja rand_getLimits).

rand_getHealth

Parâmetros []. Resultado, um entre { "status": "disk_low", "free_bytes": "3221225472" }, { "status": "ok" }, { "status": "syncing", "behind": 412 }, { "status": "behind", "behind": 30 }. disk_low tem precedência sobre todos os demais, quando o espaço livre no sistema de arquivos do diretório de dados é inferior a quatro vezes o --min-free-disk-mb do nó (padrão 1024, ou seja, menos de 4 GB); free_bytes é uma string decimal. ok quando sync_target - height é no máximo 2 e nenhuma requisição de lote de sincronização está pendente; syncing enquanto há uma; behind quando o nó não está sincronizando e o atraso continua acima de 2.

rand_getMempoolInfo

Parâmetros []. Resultado { "count": 2, "bytes": 2611200, "oldest_ms": 1450, "max_count": 10000 }. bytes soma o comprimento codificado de cada transação no pool; oldest_ms é null quando o pool está vazio. Desde a v0.6.8, o pool também tem um limite em bytes, de oito vezes o max_block_bytes do genesis (160 MiB na chain 20): acima dele, uma transação que paga mais acima de seu piso por KiB desloca a mais barata, e uma que paga menos ou o mesmo é recusada com mempool full. As ações de governança passam pelos dois limites.

Envio

rand_sendTransaction

Parâmetros [hex], em que hex é bincode(Transaction). Resultado: o hash da transação. O nó valida na ordem de admissão (Transações), coloca no pool e propaga por gossip. Os erros são -32000 com o motivo: nullifier already spent, anchor is not one of the last 1024 roots, time 12 is outside [1500, 2524] (ambas as janelas são o proof_window_blocks do genesis, 1.024 na chain 20; 256 nas chains até a 19), fee 1000000 below minimum 2000000, the bundle's digest is not what its proof published, invalid bundle proof: …, unknown program …, already in mempool, conflicts with a pending transaction over <nullifier>, faucet is disabled on this chain; para um invoke, cell <key> is no longer what this transition read (um veredito de estado: leia a célula de novo e prove outra vez) ou the vault holds … of asset … and the transition pays …; para um Bond de registro sob admissão por voto, validator … has not been admitted by the validator set's vote (staking.admission_by_vote); ask the validators for an AdmitValidator first; para um bundle que não cabe no genesis da chain 20, envelope is 1348 bytes, this chain requires exactly 1860, this chain requires an auth proof on every bundle (genesis hc_auth), the auth proof publishes a different commitment than the bundle's auth_commit, auth proof: …, bundle proof declares gas limit …, this chain requires exactly 20479, non-canonical proof: … — re-prove with an up-to-date wallet; para as ações de bridge, bridge: attestation already consumed, the attestation names a different recipient, the attestation deposits under asset 2, and the transaction names 1, the bundle burns 399, not the 400 the action declares; para um bundle que carrega uma burn que sua ação não pode carregar, the bundle burns asset 2 on an action that burns no token, a burn of 5 is not allowed on this action ou RAND burned through burn_a (5); a RAND burn goes through burn_r; para o estado da bridge, bridge minting is paused, mint cap … per backing per day, already paused, not paused, wrong pause nonce, wrong list nonce, chain N has no registered emitter; para o registro de tokens, wrong mint nonce e wrong token index. Aceitação não é confirmação: consulte rand_getTransaction ou rand_getTransactionStatus.

Uma transação maior que o limite de bloco da chain (max_block_bytes de rand_getLimits) é recusada com -32000, citando os dois tamanhos, antes de chegar ao mempool. O corpo da requisição é limitado a 2 × (2 × max_proof_bytes + 4 × 2048 + max_call_envelope_bytes + 16,384 + 64 KiB) + 256 KiB, calculado a partir do genesis na inicialização: 8.867.840 bytes em uma chain padrão e 17.350.656 nos limites da chain 20, o mesmo das chains 17 a 19 (34.127.872 nas chains 13 a 15, cujo limite de prova era 8 MiB). 4 × 2048 são os quatro envelopes do bundle no limite de envelope. Um corpo acima disso gera -32600, citando o limite.

Somente -32000 (a admissão a recusou) e -32602 (não pôde ser decodificada) são um veredito sobre a transação. Qualquer outra falha, inclusive -32603, deixa seu destino desconhecido: o nó coloca a transação no pool e a propaga por gossip antes de responder, de modo que um nó que pare nessa janela pode ter admitido o que nunca respondeu. O randprotocol_client trata um envio como recusado somente nesses dois códigos.

rand_getTransactionStatus

Parâmetros [[hash, …]], de 1 a 64 hashes. Resultado: uma entrada por hash, em ordem:

[ { "hash": "…", "status": "committed", "height": 1998, "index": 0 },
  { "hash": "…", "status": "pending" },
  { "hash": "…", "status": "rejected", "reason": "bad mint signature" },
  { "hash": "…", "status": "unknown" } ]

Ordem de consulta por hash: confirmada (armazenamento), pendente (o mempool), rejeitada (o cache de recusadas que o refused_cache de rand_status contabiliza), caso contrário unknown. rejected cobre apenas recusas sobre os bytes da própria transação, que nenhum bloco posterior pode alterar: uma prova inválida, um digest de bundle que não é o que sua prova publicou, uma assinatura de mint inválida, o chain id errado, uma parte grande demais, um nullifier ou compromisso repetido dentro da transação, um envelope de tamanho errado, uma prova de autenticação ausente ou divergente, um bundle ou prova de autenticação que declara o limite de gas errado. Uma recusa que depende do estado do nó naquele momento — um nullifier gasto, uma âncora ou time fora da janela, uma taxa abaixo do piso (que na chain 20 acompanha os preços de gas), um programa desconhecido, um nonce de registro, uma leitura obsoleta de invoke — não é lembrada e retorna unknown. -32602 para uma lista vazia ou com mais de 64 hashes.

rand_mint (faucet da testnet)

Parâmetros [address] ou [address, amount]; address é um endereço rand1…, amount é uma string de unidades de no máximo 100000000000 (100 RAND, o padrão). Resultado: o hash da transação de mint. Somente em uma chain cujo genesis tenha "faucet": true; caso contrário, -32000 faucet is disabled on this chain. Um observador responde faucet mints are signed by validators; ask a validator node.

Em uma chain cujo genesis define staking.faucet_recipients, como o da chain 20 (16 carteiras), somente as carteiras listadas podem receber: um mint para qualquer outro endereço é recusado com the faucet may not mint to this recipient (not in staking.faucet_recipients). O genesis da chain 20 também define staking.faucet_minters (18 chaves de validador): somente uma chave listada pode assinar um mint. O faucet também tem um orçamento por época, staking.faucet_budget_per_epoch (10.000 RAND por época de 1.000 blocos na chain 20); um mint acima dele é recusado com FaucetBudgetExhausted, um veredito de estado que retorna unknown assim que sai do pool.

O faucet tem limite de taxa por processo do nó: oito mints em sequência, recarregando à razão de um por segundo. Além disso, a chamada responde faucet is rate limited on this node (8 mints back to back, refilling at 1/s); try again shortly. Uma enxurrada no faucet não consegue, portanto, encher o pool antes de um PauseMints da bridge, que, como as outras três ações de governança da bridge, também é isento da recusa mempool full do pool e é ordenado primeiro no bloco.

Desde a chain 14, um mint é aberto: a ação Mint carrega pk, time e r da nota ao lado de cm e amount, a admissão recalcula o compromisso e recusa um cm que não abra para esses valores (the mint's commitment does not open to its published note and amount), e o minter assina os sete campos sob o domínio rand-mint-2; na chain 20 (binding_domain: 1), sob rand-mint-3, com o hash de gênese em primeiro lugar. O dono e o valor de uma nota do faucet são, portanto, públicos, como o pagamento de um withdraw. Os parâmetros de rand_mint não mudaram.

rand_estimateFee

Params [spec], um entre {"kind":"bundle"}, {"kind":"deploy","words":n,"public_words":m}, {"kind":"call","tier":t,"bytes":b,"gas":g}, com t em 10, 12, 14, 16, 18, 20. Resultado: a taxa mínima em unidades, como string. {"kind":"bundle"} é "1000000". public_words (opcional, padrão 0) é pago por palavra, como o código, de modo que a taxa é a taxa de deploy de n + m palavras. bytes (opcional, padrão 0) é o tamanho da prova da chamada somado ao tamanho do envelope de sua entrada.

Como uma chamada é precificada depende de gas_metering em rand_getLimits:

  • "circuit", uma chain com seção gas própria, como é a chain 20. gas é o limite de gas que a prova da chamada declara, e é obrigatório: sem ele a chamada responde -32602 under the gas section a call estimate needs its gas. A resposta é 1,000,000 + gas_price × gas + byte_price × ⌈bytes / 1024⌉ aos preços vigentes no tip, os que rand_getLimits serve. Aos preços mínimos da chain 20, de 100 e 800, uma chamada que declara 20.479 de gas com 1.300.000 bytes de prova e envelope custa "4063900". Os preços mudam a cada bloco, então estime perto do envio.
  • "header", uma política de gas no nível do nó em uma chain sem a seção. A especificação da chamada aceita keccak_log_height e sha256_log_height (opcionais, padrão 0, cada um de 0 a 40, caso contrário -32602), as alturas das tabelas de hash que o cabeçalho da prova declara, e a resposta é o maior valor entre o piso de tier do ledger e o piso de gas desse cabeçalho. Sob uma seção gas, as duas alturas são aceitas e ignoradas.
  • null, nenhum dos dois. Apenas a tabela de tiers do ledger: até a franquia gratuita (2.097.152 + 18.432 bytes), uma chamada custa a taxa do seu tier; cada KiB acima dela, contando um KiB parcial como inteiro, soma 1.000 unidades.

Desde a v0.6.8, {"kind":"invoke", …, "created_cells": c} precifica um invoke de RPL-2: todos os campos de uma especificação de chamada, mais created_cells (opcional, padrão 0, no máximo max_writes, caso contrário -32602), as células que a transição criaria. Cada uma soma o cell_fee da chain (rand_getLimits.program_state). Quem chama as conta: uma escrita de valor não nulo em uma célula que rand_getProgramCell lê como zeros. Na chain 20, a chamada acima com duas células criadas custa "24063900". Em uma chain sem seção program_state, o kind resulta em -32602.

Taxas traz a tabela.

O pool

rand_getTreeInfo

Params []. Resultado { "next_index": 41, "root": "6b1d…c4", "nullifiers": 12 }: a contagem de folhas, a raiz atual, quantas notas foram gastas.

rand_getCommitments

Params [from_index] ou [from_index, limit]. Resultado: uma página de folhas a partir de from_index, das mais antigas às mais recentes, no máximo 1.000 linhas, por maior que seja limit.

[ { "index": 40, "cm": "2a9f…07", "height": 37,
    "envelope": { "kem_ct": "b41c…", "to_receiver": "77e0…", "to_sender": "0c31…", "body": "9dd2…" } } ]

rand_getNullifiers

Params [from_height] ou [from_height, limit]. Resultado: todo nullifier publicado a partir dessa altura, com o mesmo teto de 1.000 linhas. Uma página pode parar no meio de uma altura; pagine de volta até a maior altura vista.

[ { "height": 37, "nullifier": "8c04…d1" }, { "height": 41, "nullifier": "12be…9a" } ]

rand_getCompactBlocks

Params [from_height, to_height], ambos obrigatórios. Resultado: uma linha por bloco, das mais antigas às mais recentes, com o que uma light wallet precisa e nada além:

[ { "height": 192, "hash": "63f6…08", "timestamp_ms": 1788000123456,
    "commitments": [],
    "transactions": [
      { "hash": "4f2c…e7",
        "commitments": [ { "index": 40, "cm": "2a9f…07", "envelope": { "kem_ct": "…", "to_receiver": "…", "to_sender": "…", "body": "…" } } ],
        "nullifiers": ["8c04…d1", "5e77…20", "03aa…6f", "e19b…42"] } ] } ]

Toda transação que carrega um bundle possui aqui quatro notas e quatro nullifiers — seus quatro slots, inclusive os slots dummy, que nenhum leitor distingue dos reais (apenas a primeira linha de compromisso do exemplo é mostrada). Desde a v0.6.8, algumas possuem mais notas, depois dessas quatro: um invoke possui uma nota por pagamento, pays e depois mints, cada uma com o envelope próprio do pagamento, de modo que o beneficiário a encontra por tentativa de decifração; em uma chain com taxas de bridge, como é a chain 20, um bridge_burn possui sua nota de taxa do tesouro, e um bridge_attest possui sua nota de taxa depois de seu depósito. O envelope de uma nota de taxa é vazio, selado para ninguém: a wallet do tesouro reconstrói a nota a partir dos campos públicos da transação.

No máximo 128 blocos por chamada (um intervalo maior é limitado) e, depois do primeiro bloco — sempre servido inteiro, 1.000 notas; retome a partir do último height retornado mais um. O array commitments no nível do bloco contém os depósitos de gênese na altura 0 e é vazio nas demais; as notas derivadas de um Withdraw e de um BridgeAttest aparecem sob a respectiva transação. -32602 para um intervalo invertido ou um limite ausente.

rand_getAnchor

Params [] para o head, ou [height]. Resultado { "height": 192, "root": "6b1d…c4" }, ou -32001 para uma altura sem âncora registrada. Só as raízes de fim de bloco são âncoras. O nó pode responder por uma altura antiga, mas a âncora de um bundle só é admissível se for uma das últimas proof_window_blocks raízes: 1.024 na chain 20, 256 nas chains até a 19. Construa contra o head.

rand_getWitness

Params [index]. Resultado null além do fim da árvore, senão o caminho de Merkle dessa folha, da folha para cima, exatamente 32 níveis, com a raiz atual da árvore:

{ "index": 40, "root": "6b1d…c4", "path": ["0000…00", "f2a1…3b", "…"] }

A leitura mais cara que o nó serve (ele reconstrói a árvore completa de profundidade 32) e a única requisição que revela algo sobre quem chama. Um nó executa no máximo duas reconstruções de árvore por vez, rand_getWitness e rand_getWitnesses somadas; uma requisição que espera mais de 10 s por uma vaga é recusada com -32000 witness builds are busy on this node; retry shortly.

rand_getWitnesses

Params [[index, …]], de 1 a 32 índices de folha. Resultado { "root": "…", "witnesses": [ { "index": 7, "path": ["…"] }, { "index": 9, "path": null } ] }: rand_getWitness aplicado a várias folhas em uma única construção da árvore, de modo que uma wallet que prova várias notas paga a reconstrução uma só vez. Um índice além do fim da árvore resulta em path: null nessa entrada. -32602 para uma lista vazia ou mais de 32 índices.

Chaves de visualização e divulgação

rand_importViewingKey

Params [viewing_key] ou [viewing_key, rescan_from_height], a chave em 64 caracteres hexadecimais. Resultado { "imported": true, "rescan_from_height": 0, "viewing_keys": 3 }. O nó mantém a chave somente em memória: no máximo 64 por nó, apagadas na reinicialização; uma chave já mantida não tem efeito ("imported": false). A importação nunca varre; a varredura é conduzida pelo próximo método. -32602 para uma chave malformada; -32000 na 65ª chave.

Os três métodos de chave de visualização respondem somente a quem chama via loopback e recusam qualquer outro com -32000, a menos que o nó rode com --rpc-viewing-open atrás de algo que autentique. rand_removeViewingKey ([viewing_key] → { "removed": bool, "viewing_keys": n }) libera uma vaga e zera a chave na memória. O registro é indexado por um id unidirecional da chave, blake3("rand-viewing-registry-id-1" ‖ nk), nunca pela chave em si, de modo que a importação é a única cópia de longa duração e a remoção a apaga. O texto JSON da própria requisição e as cópias transitórias que a tentativa de decifração produz não são apagados.

rand_getViewingNotes

Params [viewing_key] ou [viewing_key, from_index, limit] (limit com padrão e máximo de 1.000). Cada chamada avança a varredura da chave em até 10.000 folhas e depois serve a página:

{ "scanned_index": 10041, "next_index": 10041, "complete": true,
  "notes": [
    { "index": 40, "cm": "2a9f…07", "height": 37, "role": "received",
      "note": { "pk": "…", "from": "…", "amount": "1500000000", "asset": 0, "time": 5, "memo": "coffee" },
      "nullifier": "8c04…d1", "spent": false },
    { "index": 43, "cm": "b310…88", "height": 39, "role": "sent",
      "note": { "pk": "…", "from": "…", "amount": "25000000", "asset": 0, "time": 9, "memo": null },
      "nullifier": null, "spent": null } ] }

role é received (o envelope abriu como receptor e a nota nomeia o pk da chave) ou sent (aberto pela chave de visualização de saída). O memo da nota é o memo cifrado do remetente, texto UTF-8 de no máximo 510 bytes, ou null quando não há nenhum ou seu campo abriu malformado; um memo malformado nunca custa a nota ao beneficiário. Um memo é texto de qualquer pessoa: exiba-o como não confiável. -32001 para uma chave que este nó não importou.

rand_checkTransaction

Params [hash, key], key uma TxKey por transação em 64 caracteres hexadecimais. Resultado null para um hash desconhecido, senão o que a chave divulga:

{ "tx": "4f2c…e7", "height": 192,
  "disclosed": [ { "output": "bundle:0", "cm": "2a9f…07", "index": 40,
                   "note": { "pk": "…", "from": "…", "amount": "1500000000", "asset": 0, "time": 5, "memo": "invoice 7" } } ] }

Sem estado: a chave é descartada com a chamada. output é bundle:0 … bundle:3 para os quatro slots de saída do bundle (slots 0–1 as saídas de ativo privado, slots 2–3 as saídas de RAND, incluindo os fictícios), deposit para o envelope de depósito de uma atestação de bridge, token_mint para a nota de um TokenMint, initial_mint para a emissão inicial de um RegisterToken, mint:0 para o único envelope de uma emissão do faucet ou (v0.6.8) payout:0 … payout:3 para as notas que um invoke pagou, numeradas pela posição na transição, primeiro pays e depois mints; asset_bundle:* deixou de existir com o segundo bundle. Em uma chain com taxas de bridge, deposit abre o depósito líquido, o valor bruto menos a taxa. A note divulgada traz o seu asset: esta chamada, com a chave sob a qual o remetente selou, é o único ponto em que o RPC revela qual ativo uma transferência movimentou. Traz também o memo, como faz rand_getViewingNotes: a chave que abre a nota abre o memo, a partir do mesmo corpo selado. Uma chave errada retorna { "disclosed": [] }, indistinguível de uma transação que não divulga nada. Os envelopes de um withdraw e de uma alocação de gênese não são testados: são selados dentro do nó sob chaves descartadas de imediato, de modo que não existe TxKey para eles. O envelope de uma emissão do faucet é testado: o destinatário recupera a chave por meio da metade KEM do envelope (rand tx-key).

Transações

rand_getTransaction

Parâmetros [hash]. Resultado null até ser confirmada e, depois:

{
  "height": 192, "index": 0, "block_hash": "63f6…08",
  "tx": {
    "hash": "4f2c…e7", "chain_id": 20,
    "bundle": { "anchor": "6b1d…c4",
                "nullifiers": ["8c04…d1", "5e77…20", "03aa…6f", "e19b…42"],
                "commitments": ["2a9f…07", "b310…88", "77c1…0e", "5d20…b3"],
                "fee": "1000000", "burn_a": "0", "burn_r": "0", "burn_asset": 0, "time": 5,
                "proof_len": 1490435, "envelope_len": [1860, 1860, 1860, 1860],
                "auth_commit": "9217…ee9e", "auth_proof_bytes": 1361161 },
    "action": { "kind": "none" }
  }
}

bundle é null nas ações sem bundle. As provas e os envelopes são informados apenas pelo tamanho. envelope_len é 1.860 em todos os slots na chain 20, cuja gênese fixa o envelope da nota nesse tamanho (envelope_bytes em rand_getLimits); era 1.348 nas chains 14 a 17. auth_commit e auth_proof_bytes pertencem à autorização dividida (desde a chain 17): o compromisso público c = H(AUTH, nk, salt) que a prova do bundle e a prova de autorização publicam, e o tamanho da prova de autorização. Em uma chain sem hc_auth, valem zeros e 0.

bundle é o bundle de ativo oculto (desde a chain 14): quatro slots de entrada e quatro de saída, portanto sempre quatro nullifiers, quatro commitments e quatro envelope_len, incluindo os fictícios. Toda transação carrega no máximo um; não há segundo bundle. Ele não tem campo asset: os slots 0–1 carregam um ativo privado e os slots 2–3, RAND, e nada de público diz qual ativo os slots 0–1 movimentaram. Uma transferência de RAND e uma transferência de qualquer token RPL são ambas "kind": "none", com burn_a, burn_r e burn_asset todos em 0: a mesma forma, campo a campo. Não existe o tipo token_transfer. Os três campos de burn são a única declaração pública do bundle sobre valor que sai do pool:

  • burn_a / burn_asset — uma quantidade do ativo privado queimada e qual é esse ativo. Diferente de zero em um token_burn ou um bridge_burn, onde equivalem ao amount e ao asset da ação, e em um invoke cujo inflow é deposit ou burn.
  • burn_r — RAND queimado. Diferente de zero em um bond (igual ao seu amount), em um register_aggregator e em um invoke que deposita RAND no cofre do programa.
  • fee — a taxa em RAND, sempre proveniente dos slots 2–3.

Representação das ações (todo amount, relayer_fee e initial_amount é uma string decimal; os valores de um token estão nas unidades do próprio token, não nas de RAND):

tipocampos
none—
mintcm, amount, minter (validator em base58)
deployprogram, words, public_words_len
callprogram, proof_len, input_envelope_len (null quando a chamada não traz nenhum)
bondvalidator, amount, registered
unbondvalidator, amount, nonce
withdrawvalidator, amount, nonce, time
bridge_attestattestation_len, recipient, asset, asset_index, amount, time, r, commitment, pq_signers (os índices em pq_guardians dos guardiões cossignatários; as assinaturas de 2.420 bytes não são exibidas). asset_index, amount e commitment são null em uma rotação do conjunto de guardiões. r é derivado, blake3("rand-deposit-r-1" ‖ mu), sobre o digest que os guardiões assinaram. Desde a v0.6.8, também deposit_amount (a nota do depositante: amount, o valor bruto que os guardiões assinaram, menos a taxa de bridge) e fee_note ({ amount, asset, time, r, commitment }, a nota do tesouro sem o seu proprietário, ou null sem taxas de bridge); commitment é a folha do depósito líquido
bridge_burnasset, amount, relayer_fee, to_chain, token (o lastro que está sendo resgatado), to. Um bundle carrega o burn inteiro: o seu burn_asset e o seu burn_a são o asset e o amount da ação. Desde a v0.6.8, também release_amount (o que o corpo assinado libera, amount menos a taxa de bridge) e fee_note, como em uma atestação
register_tokenname, symbol, decimals, authority ("none", "key", "bridge" ou "program"), index, initial_amount, initial ({ amount, recipient, time, r } ou null)
token_mintasset, amount, recipient, time, r, nonce
set_authorityasset, nonce, new_authority (base58, ou null em caso de renúncia)
token_burnasset, amount; o burn_asset / burn_a do bundle os repetem
pause_mintsnonce; sem bundle e sem taxa, assinada pela chave de pausa da gênese
unpause_mintsnonce, pq_signers; sem bundle e sem taxa
register_bridged_tokenname, symbol, salt, chain, token, decimals (os decimais de origem do primeiro lastro), nonce, asset_id, pq_signers
list_backingtoken_index, chain, token, decimals, nonce, pq_signers
rotate_pq_guardiansnew_pq_guardians, nonce (o rotation_nonce consumido), pq_signers (índices no conjunto PQ anterior à rotação); sem bundle e sem taxa, apenas em chains de bridge com rules_v2
rotate_pause_keynew_pause_key, nonce, pq_signers; o mesmo
rotate_pq_guardians_v2, rotate_pause_key_v2v0.6.8: os campos da v1, mais possession_signatures (uma contagem) na forma PQ. Sem bundle e sem taxa; obrigatórias em uma chain cuja bridge.rotation de gênese define needs_possession, como a da chain 20. A rotação entra em vigor delay_secs depois (86.400 s na chain 20)
cancel_rotationv0.6.8: rotation_kind ("pq_guardians" ou "pause_key"), nonce; assinada pela chave de pausa atual, descarta uma rotação pendente
admit_validatorv0.6.8: candidate (endereço), candidate_key (hex), voters (endereços). Sem bundle e sem taxa: o voto do conjunto de validators para permitir o registro de uma nova chave, em uma chain com staking.admission_by_vote, como é a chain 20
slash_equivocationv0.6.8: offender, view, first e second ({ hash, height }); apenas em chains com staking.slashing, o que não é o caso da chain 20
invokev0.6.8, RPL-2: os campos de uma chamada (program, proof_len, input_envelope_len) e a sua transition (abaixo). Apenas em chains com uma seção program_state, como é a chain 20
register_aggregator, unbond_aggregator, withdraw_aggregator, slash_aggregator, aggregateos seus campos públicos; apenas em chains com agregação
claim_vested, revoke_vesting, bond_vested, unbond_vestedentry (hex), amount (unvested em uma revogação), nonce; time em um claim ou uma revogação; validator e registers em um bond; desde a v0.6.8, signers em uma revogação (as posições dos seus signatários em revokers da entrada). Sem bundle; apenas em chains com uma seção vesting na gênese, o que não é o caso da chain 20

O registro e as emissões de um token são públicos, como é um depósito de bridge: cada palavra de uma nota emitida está na ação (o seu from é o MINT_FROM fixo da chain), de modo que o destinatário reconstrói a nota a partir desses campos sem decifrar nada. As strings de tipo bridge_attest, token_mint, register_token e invoke são aquelas em que se baseia a varredura da carteira, e estão fixadas por um teste.

Um invoke na altura 3.079 da chain 20, que leu uma célula, a excluiu e pagou duas notas a partir do cofre:

{ "kind": "invoke", "program": "aaaf…4b21", "proof_len": 1433874, "input_envelope_len": null,
  "transition": {
    "reads":  [{ "key": "0100…fa98", "value": "0000000004000000…00000000" }],
    "writes": [{ "key": "0100…fa98", "value": "0000000000000000000000000000000000000000000000000000000000000000" }],
    "inflow": "none",
    "pays":  [{ "asset": 0, "amount": "1000000000", "recipient": "rand1…", "time": 3027, "r": "87e6…9a67", "cm": "2555…6487" },
              { "asset": 4, "amount": "2000000000", "recipient": "rand1…", "time": 3027, "r": "b833…f390", "cm": "2b70…f204" }],
    "mints": [] } }

Tudo isso é público por concepção. reads são as células que o programa leu, com os valores lidos: a prova foi feita contra elas, e o ledger recusa a transação a menos que ainda sejam válidos. writes são as células que ele escreveu; um valor escrito de 64 zeros exclui a célula. Uma chave ou um valor de célula é um Word8. O que entrou é do bundle: burn_r é o RAND depositado no cofre do programa, e burn_a de burn_asset é o token que inflow nomeia, deposit no cofre ou burn (o token do próprio programa), none quando burn_a é 0. O que saiu é uma nota calculada pela chain por pagamento, pays a partir do cofre e depois mints de um token cuja autoridade de emissão é este programa. Cada palavra de cada nota está aqui sob os nomes de campo de um token_mint; time é o do bundle, cm a folha que a chain acrescentou, e o from da nota é o PROGRAM_FROM fixo da chain. As oito palavras de saída do programa estão no recibo, como as de uma chamada.

Nenhuma resposta de transferência traz remetente, destinatário, nonce, valor ou ativo: esse campo não existe em uma transferência armazenada.

rand_getRawTransaction

Parâmetros [hash]. Resultado: a transação confirmada completa em hex bincode, incluindo os bytes da prova — o que um aggregator precisa e que rand_getTransaction nunca exibe.

Programas e recibos

rand_getProgram

Parâmetros [program_id]. Resultado null ou { "id", "base_pc", "words_len", "code_hash", "deployed_at", "public_words_len", "public_digest" }. Sem campo deployer: um deploy é pago por um bundle. public_words_len é o tamanho da entrada pública do programa definida no deploy (0 se não houver); public_digest é o seu digest, o valor contra o qual a prova de cada chamada é verificada, ou null se não houver.

rand_getProgramCode

Parâmetros [program_id]. Resultado null ou { "base_pc": 0, "words": [ … ] }.

rand_getProgramPublic

Parâmetros [program_id]. Resultado: as palavras públicas do programa definidas no momento do deploy, como uma única string hex, cada palavra nos seus 4 bytes em little-endian (8 dígitos hex por palavra): [1, 2, 0xdeadbeef] é "0100000002000000efbeadde". "" para um programa implantado sem entrada pública, null para um id que nenhum programa possui. Uma wallet que prova uma chamada passa essas palavras ao prover; o ledger confere o compromisso da prova com o public_digest do programa.

rand_getProgramCell

v0.6.8, RPL-2. Parâmetros [program_id, key], a chave uma Word8 em 64 hex (com ou sem 0x). Resultado { "key": "<64 hex>", "value": "<64 hex>" }. Uma célula que o programa nunca escreveu, ou na qual escreveu zeros (o que a apaga), é lida como 64 zeros, a única codificação de “ausente”; o mesmo vale para qualquer chave de um programa que ninguém implantou, pois a existência do programa não é verificada. { "enabled": false } numa chain sem seção program_state. Uma célula é pública por projeto: é isso que uma wallet lê para montar os reads de um invoke.

rand_getProgramCells

v0.6.8. Parâmetros [program_id, { "after": "<64 hex>" | null, "limit": n }], com o objeto opcional. Resultado { "cells": [{ "key", "value" }, …], "next": "<64 hex>" | null }: as células do programa em ordem de chave (uma comparação sem sinal das oito palavras), começando depois de after, no máximo limit delas (limitado ao intervalo de 1 a 1.000). next é a última chave servida quando há mais células; passe-a de volta como after. É null na última página. Um programa sem células responde { "cells": [], "next": null }; { "enabled": false } sem a seção.

rand_getProgramVault

v0.6.8. Parâmetros [program_id]. Resultado [{ "asset": 0, "amount": "123" }, …], em ordem crescente de índice de ativo (0 é RAND, todos os outros índices são os do registro de tokens), valores como strings decimais nas unidades do próprio ativo. Uma linha com zero não existe, portanto um cofre vazio, e um programa que ninguém implantou, é []. { "enabled": false } sem a seção. O valor entra em um cofre pelo bundle de um invoke (burn_r, e burn_a de burn_asset quando o inflow é deposit) e sai dele como as notes que os pays da transição nomeiam.

rand_getLimits

Parâmetros []. Resultado: o que uma wallet precisa do genesis da chain para montar uma transação: os cinco limites de chamada, o tamanho do envelope da note, a chave da v0.6, o guest de autenticação, os termos de gas e, desde a v0.6.8, os campos do genesis do audit-v6 e os limites do estado de programa. Na chain 20:

{ "max_program_words": 65535, "max_proof_bytes": 4194304, "max_block_bytes": 20971520,
  "max_call_envelope_bytes": 65536, "max_program_public_words": 32768,
  "envelope_bytes": 1860, "hardening_v6": true,
  "hc_auth": "1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1",
  "gas_metering": "circuit", "gas_price": "100", "byte_price": "800",
  "bundle_gas_limit": 20479, "adjust_bps": 1250,
  "max_gas_price": "10000", "max_byte_price": "80000", "byte_load": "paying",
  "admission_by_vote": true, "testnet": true, "slashing": null, "binding_domain": 1,
  "proof_window_blocks": 1024,
  "program_state": { "cell_fee": "10000000", "max_reads": 8, "max_writes": 8, "max_payouts": 4 } }

Um genesis sem os cinco campos de limite (chain 12) recebe 4096, 2097152, 4194304, 18432 e 0. max_proof_bytes era 8.388.608 nas chains 13 a 15.

fieldmeaning
envelope_bytes1860 quando o genesis fixa todo envelope que cria notes exatamente nesse comprimento, o formato com memo; null num genesis sem o campo (chains 14 a 17), onde a wallet sela o envelope de 1.348 bytes sem memo. Não existe outro valor
hardening_v6true quando o genesis executa as regras de validade da v0.6. A wallet então prova uma chamada sobre a entrada pública do programa seguida do call binding da transação, e não apenas sobre a entrada pública: as notes do bundle de taxa são escolhidas primeiro, a chamada é provada em segundo lugar, o bundle por último. Uma chain com a flag recusa a prova antiga, uma chain sem ela recusa a nova
hc_autho guest de autenticação que o genesis fixa, em hex, ou null. Se definido, hc_bundle é o bundle guest v3 e todo bundle traz auth_commit e uma prova de autenticação: a wallet entrega ao bundle guest nk e um salt novo, e prova o guest de autenticação sobre a chave de gasto
gas_metering"circuit" numa chain cujo genesis tem uma seção gas (o medidor dentro do circuito); "header" numa chain sem ela quando o nó executa sua própria política de gas (--gas-price, --byte-price); null sem nenhuma das duas
gas_price, byte_priceunidades por gas, e unidades por KiB do envelope de prova e entrada de uma chamada, como strings decimais. Sob uma seção gas são estado de consenso e iguais em todos os nós: com gas.dynamic, como na chain 20, os preços atuais do topo da chain, que se movem a cada bloco conforme a ocupação, nunca caem abaixo dos pisos do genesis (100 e 800) e nunca sobem acima dos tetos; sem ela, os preços fixos da seção. Sem uma seção são a política do próprio nó, e dois nós podem responder de forma diferente
bundle_gas_limito gas fixo que toda prova de bundle deve declarar, vindo da seção gas do genesis; null sem ela
adjust_bpso maior movimento de preço em um bloco do controlador dinâmico, em pontos-base; null numa chain sem gas.dynamic
max_gas_price, max_byte_pricev0.6.8: os tetos sobre os quais o controlador nunca eleva um preço, strings decimais; "10000" e "80000" na chain 20, null onde o genesis não define nenhum (chains 18 e 19)
byte_loadv0.6.8: "paying" quando apenas o envelope de prova e entrada de uma chamada move byte_price, de modo que um bloco de transferências não move nenhum, como na chain 20; null onde os bytes de toda transação contam (chains 18 e 19)
admission_by_votev0.6.8: se um bond que registra uma nova chave de validator exige antes o voto do conjunto de validators (rand_getAdmitted); true na chain 20
testnetv0.6.8: o marcador testnet do genesis, que permite que um faucet conviva com uma seção de bridge; true na chain 20, false em toda chain anterior
slashingv0.6.8: { "equivocation_bps", "jail_epochs" }, o que custa uma equivocação do líder, ou null; null na chain 20
binding_domainv0.6.8: 0 onde o binding de uma transação e toda mensagem de ação assinada vinculam apenas o id da chain (chains 14 a 19), 1 onde carregam também o hash do genesis, de modo que uma prova ou assinatura feita para uma chain não é válida em nenhuma outra (chain 20). Uma wallet decide qual forma provar pelo id da chain, nunca por esta resposta: a wallet rand da v0.6.8 dá às chains de id 14 a 19 a forma com o id da chain e a todos os outros ids a forma vinculada ao genesis, e lê isto apenas para recusar cedo. Uma wallet anterior à v0.6.8 não consegue enviar na chain 20
proof_window_blocksv0.6.8: quão antigo, em blocos, o anchor de um bundle pode ser e quão atrás da altura seu time pode estar, uma janela para ambos; 1024 na chain 20, null (256) nas chains até a 19. Uma wallet com um prover lento ou delegado lê isto para saber quanto tempo uma prova pode levar
program_statev0.6.8, RPL-2: a seção program_state do genesis e seus limites de invoke, ou null, caso em que todo invoke é recusado e nenhum token de programa pode ser registrado. cell_fee são as unidades de RAND (uma string decimal) que o piso de taxa de um invoke ganha por célula que cria, a escrita de um valor não zero numa célula que é lida como zeros; reescrever, apagar ou escrever zeros não custa nada. max_reads, max_writes e max_payouts (pays e mints juntos) são limites rígidos. Na prática, a regra do segmento é a que limita primeiro: as palavras de contexto da transição (11 + 16 por leitura ou escrita + 3 por payout) devem caber ao lado da entrada pública do programa e das 8 palavras de binding sem fazer crescer a tabela pública da zkVM; para um programa sem entrada pública essa tabela tem 128 linhas, o que deixa 119 palavras de contexto

Um nó anterior a um campo responde sem ele. Nada nesta resposta é autenticado, portanto uma wallet não aceita envelope_bytes apenas pela palavra do nó: a wallet rand sela o envelope legado nas chains de id 14 a 17 seja qual for a resposta do nó, e outros clientes devem fazer o mesmo.

rand_getReceipt

Parâmetros [tx_hash]. Resultado null até a chamada ser confirmada, depois { "tx", "program", "tier": 14, "outputs": [1, 0, 25, 0, 0, 0, 0, 0], "height": 17, "index": 0, "h_in": "9c0e…7f", "h_pub": null }. Sem campo effect. h_pub é o digest da entrada pública do programa definida no deploy, contra a qual a prova da chamada foi verificada, null para um programa sem ela. Um invoke (v0.6.8) tem o recibo de uma chamada, e rand_getReceipts e o tópico receipts o carregam sem alteração.

rand_getReceipts

Parâmetros [program_id, from_height, to_height, limit?]. Resultado { "receipts": [ … ], "next_height": 2051 }: os recibos de program_id com from_height <= height <= to_height, por altura e depois por índice, cada um exatamente o objeto de rand_getReceipt. limit tem como padrão 256, que também é seu teto, e nunca divide uma altura: depois que uma página contém limit recibos, ela ainda serve o restante daquela altura. next_height é a primeira altura não servida, ou null quando to_height encerrou a página. -32602 para to_height abaixo de from_height.

rand_getCallEnvelope

Parâmetros [tx_hash]. Resultado null, ou { "tx", "h_in", "kem_ct", "to_sender", "to_auditor", "body" } em hex — a transcrição de entrada selada da chamada, servida literalmente; o nó não guarda nenhuma chave que a abra. null quando a chamada não publicou nenhuma (--no-envelope), a transação não é uma chamada, ou não há recibo.

Staking e oferta

rand_getValidators

Parâmetros []. Resultado: uma linha por entrada do registro, em ordem de endereço, valores como strings decimais:

[{ "address": "…", "stake": "1000000000000",
   "pending": [{ "release_epoch": 41, "amount": "5000000000" }],
   "rewards": "4000000", "payout": "rand1…", "nonce": 3, "active": true, "jailed_until": null }]

jailed_until (v0.6.8) é a primeira época em que uma chave penalizada (slashed) pode voltar a um conjunto (18446744073709551615 para sempre), null quando não está em jail. A chain 20 não tem staking.slashing, portanto ali é sempre null.

rand_getAdmitted

v0.6.8. Parâmetros []. Resultado { "admission_by_vote": true, "max": 256, "admitted": ["<address>", …] }: as chaves que o conjunto de validadores aprovou por voto com um AdmitValidator e que ainda não se registraram, em ordem de endereço. Em uma chain cuja gênese define staking.admission_by_vote, como a da chain 20, um Bond que registra uma chave nova precisa estar entre elas. max é quantas o ledger guarda de uma vez. Em uma chain sem a flag, admission_by_vote é false, a lista é sempre vazia e o registro dispensa voto. A chain 20 respondeu "admitted": [] em 2026-10-01.

rand_getEpoch

Parâmetros []. Resultado { "epoch": 41, "epoch_blocks": 1000, "next_set": ["…", "…"] }; next_set é uma projeção.

rand_getSupply

Parâmetros []. Resultado:

{ "height": 1998,
  "genesis_deposited": "…", "genesis_staked": "…", "faucet_minted": "…",
  "faucet_epoch": "…", "faucet_minted_in_epoch": "…",
  "withdraw_deposited": "…", "fees_paid": "…", "burned": "…",
  "subsidised": "…", "sealed_blocks": "…", "aggregator_bonds": "…", "slashed": "…",
  "registration_fees_burned": "…",
  "vesting_issued": "…", "vesting_released": "…", "vesting_in_register": "…", "vesting_locked": "…",
  "program_rand_out": "…", "program_rand_held": "…",
  "pool_value": "…", "register_total": "…", "total_supply": "…", "invariant_holds": true }

subsidised, sealed_blocks, aggregator_bonds e slashed só se movem em uma chain de agregação. faucet_epoch e faucet_minted_in_epoch são o contador por época do faucet em relação a staking.faucet_budget_per_epoch (estado de consenso na chain 20). Os quatro campos vesting_* são os contadores do vesting da gênese, todos "0" em uma chain sem seção vesting, caso da chain 20. program_rand_out e program_rand_held (v0.6.8, RPL-2; "0" sem seção program_state) são o RAND que as invocações pagaram dos cofres de programa como notas (lado do pool, dentro de pool_value) e o que os cofres ainda guardam (lado do registrador, dentro de total_supply); ele entrou pelo burn_r de uma invocação, portanto está dentro de burned no lado do pool. registration_fees_burned é Σ das taxas de registro de token queimadas segundo o tokens.burn_registration_fee da gênese, que a chain 20 define; invariant_holds o subtrai, junto com slashed, do que a chain emitiu. Oferta explica a identidade.

rand_getEmission

Parâmetros []. Resultado { "inflation": "0", "subsidy": null, "faucet": true }. inflation é um "0" fixo. subsidy é o cronograma de agregação de blocos (current, base, halving_blocks, sealed_blocks, next_halving_at) e é null em uma chain sem seção aggregation, caso da chain 20. faucet espelha rand_status.

Bridge

Todos os quatro respondem em qualquer chain; em uma chain sem seção bridge, o estado é { "enabled": false } e o registro é []. A gênese da chain 20 tem uma: o conjunto de guardiões 1 (guardian_set_index 1) com oito guardiões, oito guardiões PQ, uma chave de pausa, burn_sequence 13 na gênese, um piso contra replay (min_inbound_sequence 3 para as chains de origem 2, 3 e 4, e 7 para a chain de origem 5), rules_v2 da bridge com um teto global de cunhagem de 4,000 zUSD por janela de 24 horas somando todos os lastros, e dois grupos novos na v0.6.8: rotation (a rotação de guardiões PQ ou da chave de pausa exige prova de posse pelas novas chaves e entra em vigor 86,400 s depois de confirmada) e fees (10 bps de cada depósito e 10 bps de cada queima, mantidos na Rand como uma nota de zUSD para um endereço de tesouraria). A chain 19 tinha burn_sequence 8, pisos 1 e 4, e nenhum dos dois grupos. Sua seção tokens tem uma registration_fee de 1 RAND (queimada), um mint_cap_per_day por lastro de 10000000000000 (100,000 zUSD com oito casas decimais) e lista o próprio zUSD: trazido da chain 14 na gênese, mesmo id de ativo, índice 1, sete lastros.

rand_getBridgeState

Parâmetros []. Resultado { "enabled": false }, ou:

{
  "enabled": true,
  "emitter": "01…",
  "emitters": { "2": "02…" },
  "guardian_set_index": 0,
  "guardians": ["aabb…"],
  "pq_guardians": ["…"],
  "mint_paused": false,
  "pause_nonce": 0,
  "list_nonce": 0,
  "pause_key": "…",
  "registration_fee": "1000000000",
  "burn_sequence": 1,
  "rotation_nonce": 0,
  "rules_v2": { "global_mint_cap_per_window": "…", "cap_window_secs": 86400,
                "global_minted_in_window": "…", "global_mint_headroom": "…" },
  "min_inbound_sequence": { "2": 2, "3": 2, "4": 2, "5": 2 },
  "rotation_rules": { "delay_secs": 86400, "needs_possession": true },
  "pending_rotations": [],
  "fees": { "mint_bps": 10, "burn_bps": 10, "recipient": "rand1…" },
  "assets": [ … ]
}
camposignificado
emitterendereço do emissor de saída desta chain, 32 bytes em hex
emittersid da chain de origem → o endereço do emissor confiável ali
guardiansos endereços de 20 bytes do conjunto atual, em hex
pq_guardianso conjunto PQ: chaves públicas Dilithium2 (1,312 bytes), em hex, alinhadas por índice com o conjunto atual de guardiões (conjunto 1 na chain 20). Todo BridgeAttest leva um quórum de co-assinaturas dele. Uma rotação do conjunto de guardiões nunca o move; só um rotate_pq_guardians o faz, em uma chain com rules_v2
mint_pausedenquanto for true, todo attest de transferência é recusado com bridge minting is paused; queimas e rotações continuam abertas
pause_nonceo que a próxima pausa ou despausa deve carregar; ambas o incrementam
list_nonceo que o próximo register_bridged_token ou list_backing deve carregar; ambos o incrementam
pause_keya única chave Dilithium2 que pode pausar a cunhagem, em hex. Ela só pode pausar: despausar exige o quórum de guardiões PQ
registration_feeo que um RegisterBridgedToken deve além da base do bundle, em unidades de RAND, uma string decimal
burn_sequencemensagens de saída emitidas até agora
rotation_nonceo que o próximo rotate_pq_guardians / rotate_pause_key deve carregar
rules_v2o teto global de cunhagem e sua janela móvel, ou null em uma chain sem as regras v2 da bridge. Sob elas, o teto por lastro também é uma janela móvel, e uma listagem é recusada enquanto a cunhagem está pausada. Desde a v0.6.8 também traz global_minted_in_window e global_mint_headroom, strings decimais
min_inbound_sequenceo piso de replay da gênese: id da chain de origem → a menor sequência que uma transferência dessa chain pode carregar, números simples; null em uma chain sem piso (chain 15 e anteriores). Um bridge_attest abaixo dele é recusado com BelowReplayFloor, um veredito permanente. Um relayer o lê para descartar um lock que a chain da qual esta foi derivada já cunhou
rotation_rulesv0.6.8: { "delay_secs", "needs_possession" } vindo do bridge.rotation da gênese, ou null. Sob ele, uma rotação é a ação _v2, carregando as assinaturas de posse das novas chaves, e espera delay_secs antes de entrar em vigor
pending_rotationsv0.6.8: rotações confirmadas e ainda não em vigor, cada uma { "kind": "pq_guardians", "new_pq_guardians", "effective_at_secs" } ou { "kind": "pause_key", "new_pause_key", "effective_at_secs" }; null sem rotation_rules. Um cancel_rotation assinado pela chave de pausa atual descarta uma
feesv0.6.8: { "mint_bps", "burn_bps", "recipient" } vindo do bridge.fees da gênese, ou null (chains 14 a 19). A chain retém essa fração de cada depósito e de cada queima, arredondada para baixo até uma unidade inteira de liberação do lastro, como uma nota de zUSD para recipient. Um depósito credita o valor bruto menos a taxa; o corpo assinado de uma queima libera seu valor menos a taxa. Uma carteira o lê para calcular o valor do próprio depósito e, quando é recipient, para reconstruir suas notas de taxa
assetsas linhas de rand_getAssets

Sem saldos: o valor que passa pela bridge são notas. Não existe mais next_index: um token da bridge é listado, sob um índice que seu registro já fixou, antes de poder ser depositado, então não resta índice a prever. Leia o índice de um token listado em assets ou rand_getTokens.

rand_getAssets

Parâmetros []. Resultado: o registro de ativos da bridge, em ordem crescente de índice, ou []:

[{ "index": 1, "chain": 2, "token": "aaaa…", "asset_id": "…", "decimals": 6, "locked": "600",
   "mint_cap_per_day": "10000000000000", "minted_today": "1000", "mint_day": 20350,
   "minted_in_window": "1000", "mint_window_secs": 86400, "mint_headroom": "390000000000" }]

Desde a v0.6.8, toda linha de lastro, aqui e em qualquer lugar onde lastros são servidos (rand_getBridgeState.assets, os backings de rand_getToken, rand_getTokens e rand_getTokenSupply), traz minted_in_window (uma string decimal) e mint_window_secs, ambos null em uma chain com contador diário, e mint_headroom: o maior depósito nesse lastro que os tetos admitem no tempo de bloco do topo da chain, o teto por lastro menos o que ele já cunhou e, sob as regras v2, no máximo o que resta da janela de todo o registro. Leia mint_headroom, não mint_cap_per_day − minted_today, que ignora o teto global. Sob as regras v2, como na chain 20, minted_today é a contagem da janela móvel, a medida contra a qual o teto por lastro é verificado; a descrição do contador diário abaixo é a da chain 14.

Uma linha por lastro (moeda de origem), então um token com sete lastros são sete linhas sob um mesmo index. index é a palavra asset que uma nota desse ativo carrega; o índice 0 é RAND e nunca está no registro. decimals são as casas decimais de origem do lastro. locked, mint_cap_per_day e minted_today são strings decimais nas unidades de oito casas do próprio token, nunca as do RAND; mint_day é um inteiro simples, um número de dia UTC. mint_cap_per_day é o tokens.mint_cap_per_day da gênese, o máximo que um lastro pode cunhar por dia UTC do tempo de bloco. minted_today é o que o lastro cunhou em mint_day, o dia UTC (timestamp_ms / 86,400,000) do bloco do topo da chain, de modo que um contador deixado de um dia anterior lê "0" quando o topo cruza a meia-noite. Um depósito acima do teto é recusado com MintCapExceeded e passa a ser admissível no dia seguinte. chain e token são a identidade de rede sobre a qual os guardiões assinam; asset_id é o blake3 dos dois, o que rand_bridgeAssetId calcula.

rand_bridgeAssetId

Parâmetros [token_chain, token_address] (inteiro, 32 bytes em hex). Resultado: o id do ativo, 64 caracteres hex. Aritmética pura.

rand_getBridgeBurn

Parâmetros [sequence]. Resultado null ou { "sequence": 0, "body_hex": "…", "digest": "…", "tx": "…", "height": 2, "amount": "…", "release_amount": "…", "fee": "…" }.

Os três últimos são da v0.6.8, em toda chain, como strings decimais nas unidades de oito casas do token. release_amount é o valor que o corpo assinado carrega, lido do próprio body_hex: o que o contrato de origem libera, e do qual paga a taxa do relayer do corpo. fee é a taxa de bridge que a chain reteve como nota de tesouraria, e amount o que o bundle queimou, release_amount + fee. Sem bridge.fees (chains 14 a 19), fee é "0". A sequência 13 na chain 20, uma queima de 0.999 zUSD: "amount": "99900000", "fee": "99900", "release_amount": "99800100".

Tokens (RPL)

O registro de tokens RPL: todo token, da bridge e nativo. Tokens explica o padrão.

rand_getTokens

Parâmetros [from_index, limit], ambos opcionais (0 e 1000; limit é limitado a 1,000). Resultado: o registro em ordem crescente de índice a partir de from_index, lido por intervalo a partir desse índice:

{ "enabled": true, "registration_fee": "1000000000", "next_index": 3, "max_tokens": 4096,
  "burn_registration_fee": true, "bound_note_value": true,
  "tokens": [
    { "index": 2, "id": "<64 hex>", "id_text": "rpl1…", "name": "Test Coin", "symbol": "TST",
      "decimals": 6,
      "authority": { "kind": "key", "key": "<Dilithium2 key, hex>", "address": "<base58>" },
      "mint_nonce": 1, "total_supply": "5700", "registered_at": 3 }
  ] }

Em uma cadeia sem a seção tokens: { "enabled": false, "tokens": [] }. index é a palavra asset que uma nota do token carrega (0 é RAND e nunca aparece na lista). id é o id de ativo do token e id_text a sua forma textual com checksum: bech32m, HRP rpl, sobre os 32 bytes do id, 62 caracteres. authority é um dos seguintes:

kindoutros campos
none— (oferta fixa, ou renunciada)
keykey, address
bridgebackings: [{ "chain", "token", "decimals", "locked", "mint_cap_per_day", "minted_today", "mint_day" }], os campos de rand_getAssets, uma linha por lastro
programprogram

As ofertas, locked, mint_cap_per_day, minted_today e registration_fee são strings decimais (unidades de RAND para registration_fee, unidades do token para as demais); next_index, mint_day e max_tokens são números. max_tokens é o limite de gênese do registro (4.096 na cadeia 20; null quando não há limite), a partir do qual um registro é recusado com RegistryFull. burn_registration_fee indica se a taxa de um registro é queimada em vez de paga ao proponente; bound_note_value indica se uma emissão ou um depósito igual ou superior a 2⁶³ é uma regra de validade (a admissão recusa um desses em toda cadeia, de qualquer modo). Os três estão definidos na cadeia 20. Uma página menor que limit é a última.

Uma autoridade program ({ "kind": "program", "program": "<id>" }) só pode ser registrada em uma cadeia com a seção program_state, como é a cadeia 20 (v0.6.8): o token começa com oferta zero, e apenas as invocações desse programa o emitem ou o queimam.

Uma carteira resolve o id de um token por esta listagem, nunca por rand_getToken: o ativo de uma transferência é privado na cadeia, e ler o registro inteiro custa o mesmo, qualquer que seja o token pretendido.

rand_getToken

Parâmetros [token]: um índice do registro (um número ou uma string decimal), o id de 64 caracteres hexadecimais (com ou sem 0x, em qualquer caixa) ou a forma textual rpl1… (toda em minúsculas ou toda em maiúsculas). Resultado: a linha de rand_getTokens desse token, ou null. Um id malformado — checksum inválido, outro HRP, tamanho errado, caixa mista, não hexadecimal — resulta em -32602, de modo que um erro de digitação nunca leva a outro token. Uma consulta por token informa ao nó qual token interessa a quem consulta; serve a exploradores e a leituras pontuais.

rand_getTokenSupply

Parâmetros [token], nas mesmas formas. Resultado null, ou:

{ "total_supply": "600",
  "backings": [{ "chain": 2, "token": "<32 bytes hex>", "decimals": 6, "locked": "600",
                 "mint_cap_per_day": "10000000000000", "minted_today": "1000", "mint_day": 20350 }] }

backings é vazio para um token nativo; para um token com ponte, os valores de locked somam total_supply. Vale a mesma observação de privacidade de rand_getToken.

Agregação de blocos (não ativa na cadeia 20)

Estes métodos existem no nó para cadeias cuja gênese traz uma seção aggregation. Na cadeia 20 o registro está vazio e nada jamais é aberto.

métodoparâmetrosresultado
rand_getAggregate[hash]covers, aggregator, subsidy, proving_share, n e height do agregado que sela; null para qualquer outra transação
rand_getAggregators[]o registro de agregadores: address, bond, payout, nonce, unbonding por linha
rand_getUnsealed[from, limit]{ "bundles": [{ "hash", "height", "excess" }], "next_from" }, os pacotes que um agregador ainda pode cobrir

Um Aggregate é enviado por rand_sendTransaction, como todo o resto.

Vesting de gênese (não ativo na cadeia 20)

Estes métodos existem no nó para cadeias cuja gênese traz uma seção vesting. Nenhuma cadeia a tem ainda: na cadeia 20, cada um responde { "enabled": false }. O endpoint público os encaminha desde 2026-10-01.

métodoparâmetrosresultado
rand_getVesting[id] ou [id, at_ms], o id de 64 caracteres hexadecimais da entradaa entrada: sua classe, beneficiário, cronograma (amount, start_ms, cliff_ms, linear_ms, step_ms), o que foi resgatado, revogado e vinculado (bonded), e vested_now, claimable_now, unvested_now em as_of_ms (por padrão, o horário do bloco mais recente); null para um id desconhecido. Desde a v0.6.8, uma entrada revogável lista revokers, o threshold deles que uma revogação exige e o treasury que uma revogação paga (substituem o revoker único), e a entrada traz revoke_nonce e locked_now
rand_getVestingSummary[]{ "enabled": true, "height", "as_of_ms", "entries", "issued", "released", "locked", "classes": [ … ] }: totais por classe, sem chave nem titular
rand_getVestingSchedule[from_ms, to_ms, step_ms], no máximo 1.000 pontos{ "enabled": true, "issued", "points": [{ "t_ms", "locked" }] }: o total bloqueado do registro ao longo do tempo

Os valores são strings decimais. As quatro ações de vesting são enviadas por rand_sendTransaction.

Assinaturas (WebSocket)

ws://127.0.0.1:8545/ ou /ws. O socket atende apenas rand_subscribe e rand_unsubscribe e responde -32601 a qualquer outra coisa. Três tópicos, fluxos independentes, sem promessa de ordem entre eles:

  • newHeads — no formato de rand_getHead, enviado uma vez por bloco confirmado, em ordem, inclusive durante a sincronização. view aqui é a view do próprio bloco.
  • receipts ou receipts <program_id> — uma notificação por bloco confirmado que traga ao menos um recibo de chamada correspondente: { "height", "hash", "receipts": [ … ] }, cada recibo no formato de rand_getReceipt.
  • transaction <hash> — uma notificação, após a qual o nó remove a assinatura: { "status": "committed", "height", "index" }, ou { "status": "rejected", "reason" } para uma recusa sobre os bytes da própria transação (o limite que rand_getTransactionStatus tem). Uma recusa que depende do estado nunca é anunciada, portanto combine com um timeout.
{ "jsonrpc": "2.0", "id": 1, "method": "rand_subscribe",   "params": ["newHeads"] }
{ "jsonrpc": "2.0", "id": 2, "method": "rand_unsubscribe", "params": ["1"] }
{ "jsonrpc": "2.0", "id": 3, "method": "rand_subscribe",   "params": ["receipts", "<program_id>"] }
{ "jsonrpc": "2.0", "id": 4, "method": "rand_subscribe",   "params": ["transaction", "<hash>"] }

{ "jsonrpc": "2.0", "id": 1, "result": "1" }
{ "jsonrpc": "2.0", "id": 2, "result": true }
{ "jsonrpc": "2.0", "method": "rand_subscription",
  "params": { "subscription": "1", "result": { "height": 1998, "hash": "…", "view": 2251 } } }

Limites: 64 conexões por nó (a 65ª é recusada no upgrade com 503), 8 assinaturas por conexão, 64 KiB por frame do cliente, um ping a cada 30 s respondido em até 5 s e 256 entradas de fila pendente por fluxo — um assinante mais atrasado em um fluxo que ele escuta é encerrado com o código 1008, não colocado em buffer; reconecte e preencha a lacuna com rand_getCompactBlocks (heads), rand_getReceipts (recibos) ou rand_getTransactionStatus (uma transação). Um GET / simples, sem cabeçalhos de upgrade, responde 400.

Erros

códigosignificado
-32601método desconhecido (inclusive os métodos de conta aposentados)
-32602parâmetro inválido ou ausente
-32000rejeitado: uma transação que a mempool recusou, uma chamada de faucet limitada por taxa, uma construção de witness que esperou mais de 10 s, uma leitura acima de 30 s, um método que o listener público não atende ou uma assinatura acima do limite
-32001objeto referenciado não encontrado
-32010podado: uma altura abaixo do piso de retenção deste nó; data.floor o informa (veja abaixo)
-32603erro interno
-32600requisição inválida: corpo acima do limite de tamanho, não JSON, um lote malformado ou uma notificação
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32000, "message": "…" } }

Para rand_sendTransaction, apenas -32000 e -32602 são um veredito sobre a transação; após qualquer outro código, seu destino é desconhecido (veja rand_sendTransaction).

Nós podados: erro -32010

Um nó iniciado com --prune-history <window> guarda o ledger inteiro (notas, nullifiers, âncoras, o registro), mas apenas os últimos <window> de blocos, transações e recibos; rand_status.prune_floor é a menor altura que ele ainda mantém. Na cadeia 20, 24 dos 26 validadores executam --prune-history 24h; os dois nós de arquivo rodam sem a flag e guardam todos os blocos, e o endpoint público encaminha para um deles.

  • Por altura, abaixo do piso (exceto a gênese): rand_getBlockByHeight, rand_getFinality por altura e um intervalo de rand_getBlocks, rand_getCompactBlocks ou rand_getReceipts que chegue abaixo dele respondem -32010 pruned: height h is below this node's retention floor f com data: { "floor": f }. Consulte um nó de arquivo. [0, 0] ainda serve a gênese.
  • Por hash: rand_getBlockByHash, rand_getReceipt, rand_getRawTransaction, rand_getCallEnvelope e rand_getAggregate respondem null para um hash podado, como para um que nunca existiu; só um nó de arquivo distingue os dois casos. rand_getTransaction e rand_checkTransaction também respondem null, e -32010 somente quando sobrevive uma linha de localização que nomeia uma altura abaixo do piso. rand_getTransactionStatus acrescenta floor a cada entrada unknown em um nó podado.
  • A varredura da carteira não é afetada: rand_getCommitments, rand_getNullifiers, rand_getAnchor e os métodos de witness leem famílias que nunca são podadas.

A transação no fio

Transaction { chain_id: u64, bundle: Option<Bundle>, action: Action }

Bundle {                                        // the hidden-asset bundle (since chain 14)
  anchor: Word8, nullifiers: [Word8; 4], commitments: [Word8; 4],
  fee: u64, burn_a: u64, burn_r: u64, burn_asset: u32, time: u32,
  envelopes: [Envelope; 4], proof: Vec<u8>,
  auth_commit: Word8, auth_proof: Vec<u8>,      // since chain 17 (v0.6.3): split authorisation's c and
}                                               //   its proof; zeros and empty without hc_auth
Envelope { kem_ct: Vec<u8>, to_receiver: Vec<u8>, to_sender: Vec<u8>, body: Vec<u8> }

Action::None
Action::Mint { cm: Word8, pk: Word8, time: u32, r: Word8, envelope: Envelope, amount: u64,
               minter: PublicKey, signature: Signature }
Action::Deploy { base_pc: u32, words: Vec<u32>, public: Vec<u32> }
Action::Call { program: Hash, proof: Vec<u8>, input_envelope: Option<CallEnvelope> }
Action::Bond { validator: Address, amount: u64, registration: Option<Registration> }
Action::Unbond { validator: Address, amount: u64, nonce: u64, signature: Signature }
Action::Withdraw { validator: Address, amount: u64, nonce: u64, time: u32, r: Word8,
                   envelope: Envelope, signature: Signature }
Action::BridgeAttest { attestation: Vec<u8>, recipient: ShieldedAddress, r: Word8, time: u32,
                       asset: u32, envelope: Envelope, pq_signatures: Vec<PqSignature> }
Action::BridgeBurn { asset: u32, amount: u64, relayer_fee: u64, to_chain: u16,
                     token: [u8; 32], to: [u8; 32] }
// the five aggregation variants sit here in the enum's declared order
Action::RegisterToken { name: String, symbol: String, decimals: u8, authority: MintAuthority,
                        initial: Option<InitialMint>, salt: [u8; 32], index: u32 }
Action::TokenMint { asset: u32, amount: u64, recipient: ShieldedAddress, r: Word8, time: u32,
                    envelope: Envelope, nonce: u64, signature: Signature }
Action::SetAuthority { asset: u32, new: Option<PublicKey>, nonce: u64, signature: Signature }
Action::TokenBurn { asset: u32, amount: u64 }
Action::PauseMints { nonce: u64, signature: Signature }               // bundle-less, fee-less
Action::UnpauseMints { nonce: u64, pq_signatures: Vec<PqSignature> }  // bundle-less
Action::RegisterBridgedToken { name: String, symbol: String, salt: [u8; 32], chain: u16,
                               token: [u8; 32], decimals: u8, nonce: u64,
                               pq_signatures: Vec<PqSignature> }
Action::ListBacking { token_index: u32, chain: u16, token: [u8; 32], decimals: u8, nonce: u64,
                      pq_signatures: Vec<PqSignature> }
Action::RotatePqGuardians { new_pq_guardians: Vec<PublicKey>, nonce: u64,
                            pq_signatures: Vec<PqSignature> }         // bundle-less, fee-less
Action::RotatePauseKey { new_pause_key: PublicKey, nonce: u64,
                         pq_signatures: Vec<PqSignature> }            // bundle-less, fee-less
// the four vesting variants (ClaimVested, RevokeVesting, BondVested, UnbondVested) follow, tags 24 to 27;
// since v0.6.8 RevokeVesting carries `signatures: Vec<RevokerSignature>` in place of one `signature`
Action::AdmitValidator { candidate: PublicKey, signatures: Vec<(PublicKey, Signature)> }   // tag 28, v0.6.8
Action::SlashEquivocation { first: Box<SignedHeader>, second: Box<SignedHeader> }         // tag 29
Action::RotatePqGuardiansV2 { new_pq_guardians: Vec<PublicKey>, possession: Vec<Vec<u8>>,
                              nonce: u64, pq_signatures: Vec<PqSignature> }                // tag 30
Action::RotatePauseKeyV2 { new_pause_key: PublicKey, possession: Vec<u8>, nonce: u64,
                           pq_signatures: Vec<PqSignature> }                               // tag 31
Action::CancelRotation { kind: u8, nonce: u64, signature: Signature }                      // tag 32
Action::Invoke { program: Hash, proof: Vec<u8>, input_envelope: Option<CallEnvelope>,
                 transition: Transition }                                                  // tag 33, RPL-2

MintAuthority = None | Key(PublicKey) | Bridge { backings: Vec<Backing> } | Program(Hash)
InitialMint { amount: u64, recipient: ShieldedAddress, r: Word8, time: u32, envelope: Envelope }
Transition { reads: Vec<Cell>, writes: Vec<Cell>, inflow: Inflow, pays: Vec<Payout>, mints: Vec<Payout> }
Cell { key: Word8, value: Word8 }               // keys strictly ascending in each list
Inflow = None | Deposit | Burn                  // what the bundle's burn_a of burn_asset is to the program
Payout { asset: u32, amount: u64, recipient: ShieldedAddress, r: Word8, envelope: Envelope }
Registration { public_key: PublicKey, payout: ShieldedAddress, signature: Signature }
CallEnvelope { kem_ct: Vec<u8>, to_sender: Vec<u8>, to_auditor: Vec<u8>, body: Vec<u8> }
PqSignature { index: u8, signature: Vec<u8> }   // one guardian's Dilithium2 co-signature, by set index

Configuração padrão do bincode: inteiros de largura fixa, prefixos de comprimento de 8 bytes, tags de enum u32 na ordem de declaração. As cinco variantes de agregação vêm depois de BridgeBurn e antes de RegisterToken no enum (Transações); a cadeia 20 nunca as admite, nem as quatro variantes de vesting nem SlashEquivocation, mas um codificador que fixa os números das tags no código ainda precisa contá-las.

Os dois últimos campos do bundle chegaram com a v0.6.3 e a cadeia 17. O bincode é posicional, de modo que um codificador escrito para a cadeia 16 ou anterior não produz uma transação que esta cadeia decodifique, e todo id de transação mudou junto: o domínio do id agora é rand-txid-3, que vincula auth_commit e o digest da prova de autenticação. Um cliente que recalcula ids localmente precisa acompanhar a mudança. Na cadeia 20, todo bundle traz uma prova de autenticação, seja autoprovada ou delegada. A v0.6.8 não altera nada no layout de Transaction nem de Bundle; ela acrescenta as ações 28 a 33.

Toda transação carrega no máximo um bundle. Um Bond carrega um bundle cujo burn_r é igual ao seu amount, com burn_a e burn_asset em 0. Um BridgeBurn ou um TokenBurn queima por meio do bundle: burn_asset deve ser o asset da ação (nunca 0), burn_a o amount da ação e burn_r 0, enquanto fee é pago em RAND a partir dos slots 2–3. Qualquer outra ação não queima nenhum token, e RAND só é queimado por meio de burn_r: um bundle com burn_asset 0 e burn_a diferente de zero é recusado em todos os casos. O r de um BridgeAttest é derivado, não escolhido: a admissão exige blake3("rand-deposit-r-1" ‖ mu) sobre o digest que os guardians assinaram e recusa qualquer outro valor (WrongDepositBlinding, uma recusa permanente). Um token com bridge é listado — no genesis, ou por um RegisterBridgedToken / ListBacking — antes que qualquer atestação dele seja admissível; a atestação de uma moeda não listada é recusada com UnlistedToken.

Toda prova de bundle é feita sobre a transação em que viaja, e verificada contra ela: a transação inteira com suas provas zeradas, vinculada ao chain id e, na chain 20 (binding_domain: 1), ao hash do genesis, sob tags novas. Nas chains 14 a 19 a vinculação era apenas o chain id, de modo que uma prova feita para a chain 19 não é verificada na chain 20, e uma carteira anterior à v0.6.8 não consegue enviar transações lá. Nas chains 18 a 20, um bundle sem suas duas provas é codificado em 7.936 bytes, e uma transação de transferência sem elas, em 7.949 (5.848 e 5.861 nas chains 14 a 16, com envelopes de 1.348 bytes e sem campos de autenticação). Uma transferência na rede ocupa cerca de 2,85 MB no perfil de produção, quase tudo prova: uma prova de bundle de cerca de 1,49 MB e uma prova de autenticação de cerca de 1,36 MB. Antes da autorização dividida, ocupava cerca de 1,43 MB.

Última verificação em relação ao commit c0878c3f do fullnode (chain 21) em 2026-10-12. Onde o código e esta página divergirem, o código está certo; avise-nos.