Rand Protocol
Documentazione
Riferimento

JSON-RPC

Tutti i metodi rand_* che il nodo espone - parametri, formati dei risultati ed errori - oltre ai batch, alle sottoscrizioni WebSocket e al formato di trasmissione delle transazioni.

Il nodo serve JSON-RPC 2.0 su HTTP su --rpc (predefinito 127.0.0.1:8545) e un WebSocket sulla stessa porta per le sottoscrizioni. Dalla v0.6.8 può aprire anche un secondo listener pubblico (--public-rpc, sotto). randprotocol_client::RpcClient (Rust) incapsula ogni metodo qui sotto. Questa pagina è l’elenco dei metodi così come li serve la v0.6.8 (c9c9bd3c), la build su cui gira la chain 20; dove un metodo esiste nel codice ma è inattivo sulla chain 20, lo dice.

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

L’endpoint pubblico

https://rpc.randprotocol.org (lo stesso proxy è raggiungibile anche su https://randprotocol.org/api/rpc) inoltra a un nodo archivio della chain 20 che conserva ogni blocco, per wallet e pagine privi di un nodo proprio (rand --rpc https://rpc.randprotocol.org …). Accetta solo HTTP POST, con CORS aperto e senza WebSocket, ed è più ristretto di un nodo:

  • Una richiesta per chiamata. Un batch viene rifiutato con -32600.
  • Una allowlist di metodi: dal 2026-10-01 è lo stesso insieme del listener pubblico del nodo (rpc::PUBLIC_METHODS nella v0.6.8), quindi vi rientrano le letture dello stato dei programmi di cui rand program invoke ha bisogno, rand_getAdmitted, le letture di aggregazione e quelle di vesting, insieme a rand_checkTransaction e rand_sendTransaction. rand_mint, rand_importViewingKey, rand_getViewingNotes, rand_removeViewingKey e rand_getPeers non vi rientrano e rispondono -32601 method not allowed here senza raggiungere il nodo: un faucet pubblico è una superficie di abuso, e una viewing key dovrebbe andare solo a un nodo gestito da te.
  • Un corpo della richiesta di al massimo 12 MiB, che contiene qualsiasi trasferimento, azione su token o deploy e una chiamata la cui proof arriva a circa 3,4 MB (la transazione è codificata in esadecimale, e le proof del bundle e dell’auth occupano circa 2,85 MB prima di quella della chiamata). Una chiamata più grande va al tuo nodo. Oltre il limite: HTTP 413 e -32600.
  • Per indirizzo, 1.200 richieste al minuto e 6 al minuto per rand_sendTransaction. Oltre il limite: HTTP 429 e -32005. Il budget di lettura è dimensionato sulla prima sincronizzazione di un wallet, che consiste in diverse centinaia di richieste in un’unica raffica (645 all’altezza 99.000 della chain 18).
  • -32000 upstream unavailable quando il nodo dietro il proxy non risponde.

Tutto il resto di questa pagina descrive il nodo stesso.

I due listener del nodo

Dalla v0.6.8 (audit v6) un nodo ha due listener JSON-RPC.

  • --rpc <ADDR>, il listener dell’operatore. Ogni metodo, i batch e il WebSocket. Identifica un chiamante dal suo indirizzo di socket e si fida del loopback: i metodi delle viewing key rispondono solo al loopback, e il loopback non è soggetto a limiti. Tienilo su 127.0.0.1. Un reverse proxy o un inoltro SSH arriva dal loopback, quindi dietro uno di essi ogni visitatore è l’operatore: non puntare mai un endpoint pubblico a questa porta.
  • --public-rpc <ADDR>, il listener pubblico, pensato proprio per quel passaggio. Serve un insieme fisso di metodi, le letture di cui un wallet, un explorer o una pagina hanno bisogno e rand_sendTransaction (rpc::PUBLIC_METHODS). rand_importViewingKey, rand_getViewingNotes, rand_removeViewingKey, rand_mint e rand_getPeers non vi sono mai serviti, e nemmeno lo è un metodo aggiunto in seguito finché non viene inserito nell’elenco; una simile chiamata risponde -32000 <method> is not served on this node's public listener. Un batch dà -32600 e non esiste alcuna route WebSocket. Un unico contatore copre tutti i chiamanti insieme, 600 richieste in una raffica e 150 al secondo; oltre, HTTP 429 con un corpo -32000. I limiti per visitatore spettano al proxy, che i visitatori li vede. I suoi chiamanti occupano al massimo metà degli slot di lettura bloccante del nodo, così il listener dell’operatore non resta mai a corto di risorse.

Entrambi i listener condividono due limiti di lettura. Una lettura bloccante che non è tornata entro 30 s riceve -32000 this read took longer than 30 s on this node; retry with a smaller range. rand_getBlocks chiude la propria pagina una volta letti 64 MiB di blocchi.

--rpc-viewing-token-file <PATH> pone un bearer token sui metodi delle viewing key di --rpc: la prima riga del file, di almeno 32 caratteri, inviata come Authorization: Bearer <token>. Con esso il solo loopback non basta, e viene servito un chiamante da qualsiasi luogo che lo presenti.

Convenzioni

  • Gli indirizzi dei validator sono stringhe base58 (32 byte). Gli hash sono 64 caratteri esadecimali, con o senza 0x. I valori shielded — commitment, nullifier, anchor, radici dell’albero, livelli dei witness — sono Word8: otto parole u32 little-endian come 64 caratteri esadecimali minuscoli.
  • Gli indirizzi shielded sono rand1 + base58, 1.667 caratteri. Un parametro più lungo di 2.000 caratteri viene rifiutato in base alla lunghezza prima di essere analizzato.
  • Ogni importo u64 è una stringa decimale ("1500000000" = 1,5 RAND; 1 RAND = 10⁹ unità): unità di RAND o unità di token, stato della chain o campo proprio di una transazione decodificata. Un numero JSON non è un intero esatto oltre 2⁵³, e l’offerta di un token a 9 decimali supera quella soglia a poche decine di milioni di unità. Vedi la nota datata più sotto per ciò che questo ha cambiato.
  • Indici, nonce, altezze, indici di foglia, view, lunghezze, decimali e contatori di giorni (mint_day) non sono mai importi e sono ovunque interi JSON.
  • Ogni richiesta deve contenere un membro id. Un oggetto che ne è privo è una notifica e viene rifiutato con -32600; un "id": null esplicito è una richiesta normale.
  • Non esiste alcun metodo per il saldo né per l’account. Un wallet calcola il proprio saldo scansionando rand_getCommitments e rand_getNullifiers con la sua viewing key. rand_getBalance, rand_getAccount e rand_getAssetBalance rispondono -32601.

Modifica incompatibile, 2026-09-20 (chain 14): ogni importo è una stringa decimale

Prima della chain 14, gli importi all’interno di una transazione decodificata erano interi JSON. Quell’eccezione non esiste più. Questi campi sono passati da numeri JSON a stringhe decimali, senza altre modifiche al loro significato o alla loro posizione:

  • bundle.fee, in tx di rand_getTransaction e in transactions[] di rand_getBlockByHeight / rand_getBlockByHash;
  • action.amount per kind = mint, bond, unbond, withdraw, bridge_attest (gli stessi tre metodi);
  • action.amount e action.relayer_fee per kind = bridge_burn (gli stessi tre metodi);
  • locked nelle righe di rand_getAssets e di rand_getBridgeState.assets[].

Un client che legge uno qualsiasi di questi come numero deve analizzare invece una stringa. aggregation.subsidy_base di rand_status (solo chain con aggregazione) è diventato una stringa con la stessa modifica. Ogni altro importo era già una stringa: rand_getSupply, rand_getEmission, rand_getValidators, le note di visualizzazione e ogni campo introdotto con la chain 14 — i burn_a e burn_r del bundle, le offerte dei token, il locked di ciascun backing, mint_cap_per_day e minted_today, registration_fee, e l’amount di token_mint, token_burn e register_token (initial_amount, initial.amount).

Batch

Il corpo di una POST può essere un array di al massimo 20 oggetti richiesta, a cui si risponde con un array della stessa lunghezza nell’ordine delle richieste, errori inclusi. Le richieste vengono eseguite una dopo l’altra. Un array vuoto, un array con più di 20 elementi o un corpo che non è né un oggetto né un array dà un singolo -32600 con id nullo. L’intero corpo resta comunque limitato dal limite di dimensione del corpo della richiesta del nodo, dimensionato per una transazione con proof: un batch di due chiamate rand_sendTransaction con proof viene rifiutato con 413. Metti in batch le letture, non gli invii con proof.

Chain e nodo

rand_chainId

Parametri []. Risultato: l’id della chain (intero); 20 sulla testnet.

rand_tokenInfo

Parametri []. Risultato { "symbol": "RAND", "decimals": 9 }.

rand_getHead

Parametri []. Risultato { "height": 1998, "hash": "…", "view": 2251 }. view è la view di consenso corrente del nodo, che precede l’altezza quando le view scadono.

rand_status (alias rand_syncStatus)

Parametri []. Risultato:

{
  "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: questo nodo detiene una chiave di validator; active_validator: quella chiave fa parte dell’insieme che esegue l’epoca corrente. reserved_peers (v0.6.8) conta i peer ammessi oltre il limite di connessioni in ingresso: i bootstrap, ogni --reserved-peer e ogni identità di validator appresa da un peer binding firmato, ciascuno una volta; su un nodo della flotta dovrebbe raggiungere il numero di validator entro un minuto dall’avvio. viewing_keys è il numero di viewing key che il nodo tiene in memoria per la scansione lato nodo. verify_queue è il numero di transazioni in attesa di uno dei quattro worker di verifica delle proof (al massimo 64 in coda). hc_bundle è il guest del bundle rispetto al quale sono le proof di questa chain e hc_auth il guest di auth fissato dal suo genesis (autorizzazione separata, dalla chain 17), oppure null su una chain che ne è priva; un nodo la cui build non concorda con l’uno o con l’altro rifiuta di avviarsi. testnet e binding_domain sono i campi di genesis omonimi, come li serve rand_getLimits. gas_prices sono i prezzi del gas correnti del tip ledger, aggiornati a ogni commit, come stringhe decimali; null su una chain priva di una sezione gas. I prezzi della chain 20 sono dinamici e si muovono a ogni blocco in base al riempimento, mai sotto i minimi di 100 e 800 e mai sopra i massimi di 10.000 e 80.000, quindi leggili qui o in rand_getLimits e non fissarli nel codice. L’oggetto contiene anche un oggetto aggregation (il suo subsidy_base è una stringa decimale, il resto interi), che legge tutti zeri su una chain priva di una sezione aggregation, come lo è la chain 20.

L’oggetto contiene inoltre disk_free_bytes (un numero) e disk_low, e la coppia di conservazione: prune_floor, l’altezza più bassa che questo nodo detiene ancora (0 su un archivio), e prune_history_secs, la finestra che conserva un nodo avviato con --prune-history (null quando conserva tutto). Sulla chain 20, come sulla chain 19, 24 dei 26 validator conservano 24 ore di blocchi; i due archivi li conservano tutti. Vedi Nodi con pruning.

rand_getPeers

Parametri []. Risultato: un array di { "peer_id": "12D3KooW…", "addrs": ["/ip4/…/tcp/30303"], "connected_secs": 1241 }.

rand_getBlockByHeight / rand_getBlockByHash

Parametri [height] o [hash]. Risultato null se sconosciuto, altrimenti:

{
  "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": [ ]
}

Solo i blocchi sottoposti a commit vengono serviti. transactions ha la stessa struttura del campo tx di rand_getTransaction. Un blocco riporta anche sealed, e ciascuna delle sue transazioni sealed_by; su una chain senza aggregazione valgono rispettivamente false e null.

rand_getBlocks

Parametri [from_height, to_height]. Risultato: intestazioni di blocco, dalla più vecchia, al massimo 1.024 a partire da from_height (128 su un nodo precedente al 2026-09-24): i campi di rand_getBlockByHeight senza transactions. Un intervallo più ampio del limite, o oltre la testa della chain, viene troncato e non rifiutato; dalla v0.6.8 una pagina termina inoltre quando ha letto 64 MiB di blocchi; si prosegue dall’ultima altezza restituita. -32602 se to_height è inferiore a from_height.

Dalla v0.6.8 ogni intestazione riporta anche public_notes: le transazioni bridge_attest, token_mint e register_token del blocco e, su una chain con commissioni di bridge, le sue transazioni bridge_burn, nella forma [{ "hash", "raw" }] (la codifica che serve rand_getRawTransaction); vuoto per ogni altro blocco. Un burn viene servito con le prove svuotate e "proofs_stripped": true; il suo hash è l’id reale della transazione. La prima sincronizzazione di un wallet legge queste pagine e non ha bisogno d’altro per ricostruire le note pubbliche.

rand_getFinality

Parametri [height] oppure [hash]. Risultato, uno tra { "status": "committed", "height", "hash" }, { "status": "certified", "height", "hash", "qc_view" }, { "status": "proposed", "height", "hash" }, { "status": "unknown" }. Un’altezza viene verificata solo rispetto alla chain sottoposta a commit, quindi risponde committed oppure unknown; un hash può risultare anche certified (nell’albero non ancora sottoposto a commit della replica, con un quorum certificate) o proposed (nell’albero, senza quorum certificate).

rand_getProposer

Parametri [view] oppure [from_view, to_view], al massimo 64 view. Risultato { "epoch": 3, "proposers": [ { "view": 2251, "proposer": "2nRdFC…" } ] }: il leader di ciascuna view secondo l’insieme di validator corrente, non quello che era in carica in quella view in passato. -32602 per un intervallo invertito o per più di 64 view.

rand_getVersion

Parametri []. Risultato { "version", "git_sha", "chain_id", "hc_bundle", "hc_auth", "fri_profile" }. version è la versione del crate del workspace; git_sha l’hash del commit acquisito in fase di build, con -dirty aggiunto se i file tracciati differivano, oppure "unknown". hc_auth è la guest di autenticazione del genesis, come in rand_status, oppure null. L’endpoint pubblico il 2026-10-01, sulla chain 20:

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

rand_getGenesisHash

Parametri []. Risultato: l’hash del genesis in esadecimale; "6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135" sulla chain 20 (quello della chain 19 era a3defc93…228a). Un chain id da solo non distingue due tagli della chain; questo sì. Sulla chain 20 fa inoltre parte di ogni binding di transazione e di ogni messaggio di azione firmato (binding_domain: 1, vedi rand_getLimits).

rand_getHealth

Parametri []. Risultato, uno tra { "status": "disk_low", "free_bytes": "3221225472" }, { "status": "ok" }, { "status": "syncing", "behind": 412 }, { "status": "behind", "behind": 30 }. disk_low ha la precedenza su tutto il resto, quando lo spazio libero sul filesystem della directory dei dati è inferiore a quattro volte il valore di --min-free-disk-mb del nodo (predefinito 1024, quindi sotto i 4 GB); free_bytes è una stringa decimale. ok quando sync_target - height è al massimo 2 e nessuna richiesta di batch di sincronizzazione è in sospeso; syncing finché ne è in sospeso una; behind quando il nodo non sta sincronizzando e il ritardo è ancora superiore a 2.

rand_getMempoolInfo

Parametri []. Risultato { "count": 2, "bytes": 2611200, "oldest_ms": 1450, "max_count": 10000 }. bytes somma la lunghezza codificata di ogni transazione nel pool; oldest_ms è null quando il pool è vuoto. Dalla v0.6.8 il pool ha anche un limite in byte, pari a otto volte il max_block_bytes del genesis (160 MiB sulla chain 20): oltre il limite, una transazione che paga di più sopra la propria soglia minima per KiB sostituisce la più economica, mentre una che paga meno o lo stesso viene rifiutata con mempool full. Le azioni di governance rispettano entrambi i limiti.

Invio

rand_sendTransaction

Parametri [hex], dove hex è bincode(Transaction). Risultato: l’hash della transazione. Il nodo valida secondo l’ordine di ammissione (Transazioni), la inserisce nel pool e la diffonde in gossip. Gli errori sono -32000 con il motivo: nullifier already spent, anchor is not one of the last 1024 roots, time 12 is outside [1500, 2524] (entrambe le finestre sono il proof_window_blocks del genesis, 1.024 sulla chain 20; 256 sulle chain fino alla 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; per un invoke, cell <key> is no longer what this transition read (un verdetto di stato: rileggere la cella e produrre di nuovo la prova) oppure the vault holds … of asset … and the transition pays …; per un Bond di registrazione soggetto ad ammissione per voto, validator … has not been admitted by the validator set's vote (staking.admission_by_vote); ask the validators for an AdmitValidator first; per un bundle non conforme al genesis della 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; per le azioni di 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; per un bundle che brucia ciò che la sua azione non può bruciare, the bundle burns asset 2 on an action that burns no token, a burn of 5 is not allowed on this action oppure RAND burned through burn_a (5); a RAND burn goes through burn_r; per lo stato del 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; per il registro dei token, wrong mint nonce e wrong token index. L’accettazione non equivale al commit: si interroga rand_getTransaction oppure rand_getTransactionStatus.

Una transazione più grande del limite di blocco della chain (max_block_bytes da rand_getLimits) viene rifiutata con -32000, con l’indicazione di entrambe le dimensioni, prima di arrivare al mempool. Il corpo della richiesta è limitato a 2 × (2 × max_proof_bytes + 4 × 2048 + max_call_envelope_bytes + 16,384 + 64 KiB) + 256 KiB, calcolato dal genesis all’avvio: 8.867.840 byte su una chain predefinita e 17.350.656 con i limiti della chain 20, come per le chain da 17 a 19 (34.127.872 sulle chain da 13 a 15, il cui limite di prova era 8 MiB). 4 × 2048 sono le quattro envelope del bundle al limite di envelope. Un corpo oltre il limite dà -32600, con l’indicazione del limite.

Solo -32000 (l’ammissione l’ha rifiutata) e -32602 (non è stato possibile decodificarla) costituiscono un verdetto sulla transazione. Qualsiasi altro errore, -32603 compreso, lascia il suo destino ignoto: il nodo inserisce nel pool e diffonde in gossip una transazione prima di rispondere, quindi un nodo che si ferma in quella finestra può aver ammesso ciò di cui non ha mai dato riscontro. randprotocol_client considera un invio rifiutato solo con questi due codici.

rand_getTransactionStatus

Parametri [[hash, …]], da 1 a 64 hash. Risultato: una voce per hash, nell’ordine:

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

Ordine di ricerca per ogni hash: committed (storage), pending (il mempool), rejected (la cache dei rifiutati che rand_status conta in refused_cache), altrimenti unknown. rejected copre solo i rifiuti che riguardano i byte della transazione stessa, che nessun blocco successivo può cambiare: una prova non valida, un digest del bundle diverso da quello pubblicato dalla sua prova, una firma di mint errata, il chain id sbagliato, una parte di dimensioni eccessive, un nullifier o un commitment ripetuto all’interno della transazione, un’envelope di dimensione errata, una prova di autenticazione mancante o non corrispondente, un bundle o una prova di autenticazione che dichiara un gas limit errato. Un rifiuto che dipende dallo stato del nodo in quel momento — un nullifier già speso, un’ancora o un time fuori dalla finestra, una commissione sotto la soglia minima (che sulla chain 20 si muove con i prezzi del gas), un programma sconosciuto, un nonce di registro, una lettura invoke obsoleta — non viene ricordato e risulta unknown. -32602 per un elenco vuoto o per più di 64 hash.

rand_mint (faucet testnet)

Parametri [address] oppure [address, amount]; address è un indirizzo rand1…, amount una stringa di unità pari al massimo a 100000000000 (100 RAND, il valore predefinito). Risultato: l’hash della transazione di mint. Solo su una chain il cui genesis ha "faucet": true; altrimenti -32000 faucet is disabled on this chain. Un observer risponde faucet mints are signed by validators; ask a validator node.

Su una chain il cui genesis imposta staking.faucet_recipients, come fa quello della chain 20 (16 wallet), possono essere pagati solo i wallet elencati: un mint verso qualsiasi altro indirizzo viene rifiutato con the faucet may not mint to this recipient (not in staking.faucet_recipients). Il genesis della chain 20 imposta anche staking.faucet_minters (18 chiavi di validator): solo una chiave elencata può firmare un mint. Il faucet ha inoltre un budget per epoch, staking.faucet_budget_per_epoch (10.000 RAND per epoch di 1.000 blocchi sulla chain 20); un mint oltre il budget viene rifiutato con FaucetBudgetExhausted, un verdetto di stato che risulta unknown una volta uscito dal pool.

Il faucet è soggetto a un limite di frequenza per processo del nodo: otto mint consecutivi, con ricarica di uno al secondo. Oltre il limite la chiamata risponde faucet is rate limited on this node (8 mints back to back, refilling at 1/s); try again shortly. Un flood sul faucet non può quindi riempire il pool prima di un PauseMints del bridge, il quale, come le altre tre azioni di governance del bridge, è inoltre esente dal rifiuto mempool full del pool e ordinato per primo in un blocco.

Dalla chain 14 un mint è aperto: l’azione Mint porta pk, time e r della nota accanto a cm e amount, l’ammissione ricalcola l’impegno e rifiuta un cm che non si apre su di essi (the mint's commitment does not open to its published note and amount), e il minter firma tutti e sette i campi con il dominio rand-mint-2; sulla chain 20 (binding_domain: 1) con rand-mint-3, con l’hash del genesis per primo. Il proprietario e l’importo di una nota del faucet sono quindi pubblici, come lo è il pagamento di un withdraw. I parametri di rand_mint restano invariati.

rand_estimateFee

Parametri [spec], uno tra {"kind":"bundle"}, {"kind":"deploy","words":n,"public_words":m}, {"kind":"call","tier":t,"bytes":b,"gas":g} con t in 10, 12, 14, 16, 18, 20. Risultato: la commissione minima in unità, come stringa. {"kind":"bundle"} è "1000000". public_words (facoltativo, predefinito 0) si paga per parola come il codice, quindi la commissione è quella di deploy di n + m parole. bytes (facoltativo, predefinito 0) è la lunghezza della prova della chiamata più la lunghezza della sua busta di input.

Il prezzo di una chiamata dipende da gas_metering di rand_getLimits:

  • "circuit", una chain con una propria sezione gas, come la chain 20. gas è il limite di gas dichiarato dalla prova della chiamata ed è obbligatorio: senza di esso la chiamata risponde -32602 under the gas section a call estimate needs its gas. La risposta è 1,000,000 + gas_price × gas + byte_price × ⌈bytes / 1024⌉ ai prezzi correnti del tip, quelli serviti da rand_getLimits. Ai prezzi minimi della chain 20, 100 e 800, una chiamata che dichiara 20,479 di gas con 1,300,000 byte di prova e busta costa "4063900". I prezzi cambiano a ogni blocco, quindi conviene stimare a ridosso dell’invio.
  • "header", una politica di gas a livello di nodo su una chain senza la sezione. La specifica della chiamata accetta keccak_log_height e sha256_log_height (facoltativi, predefinito 0, ciascuno da 0 a 40, altrimenti -32602), le altezze delle tabelle di hash dichiarate nell’header della prova, e la risposta è il maggiore tra il minimo del tier del ledger e il minimo di gas di quell’header. Con una sezione gas le due altezze sono accettate e non usate.
  • null, nessuno dei due. Solo la tabella dei tier del ledger: entro la quota gratuita (2,097,152 + 18,432 byte) una chiamata costa la commissione del proprio tier; ogni KiB oltre la quota, contando come intero un KiB parziale, aggiunge 1,000 unità.

Dalla v0.6.8, {"kind":"invoke", …, "created_cells": c} stima il prezzo di un invoke RPL-2: ogni campo della specifica di una chiamata, più created_cells (facoltativo, predefinito 0, al massimo max_writes, altrimenti -32602), le celle che la transizione creerebbe. Ognuna aggiunge il cell_fee della chain (rand_getLimits.program_state). Le celle le conta il chiamante: una scrittura di un valore diverso da zero in una cella che rand_getProgramCell legge come zeri. Sulla chain 20, la chiamata precedente con due celle create costa "24063900". Su una chain senza sezione program_state il tipo risponde -32602.

Commissioni contiene la tabella.

Il pool

rand_getTreeInfo

Parametri []. Risultato { "next_index": 41, "root": "6b1d…c4", "nullifiers": 12 }: il numero di foglie, la radice corrente, quante note sono state spese.

rand_getCommitments

Parametri [from_index] o [from_index, limit]. Risultato: una pagina di foglie a partire da from_index, dalla più vecchia, al massimo 1,000 righe per quanto grande sia limit.

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

rand_getNullifiers

Parametri [from_height] o [from_height, limit]. Risultato: ogni nullifier pubblicato da quell’altezza in poi, con lo stesso limite di 1,000 righe. Una pagina può interrompersi all’interno di un’altezza; risali all’altezza più alta vista.

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

rand_getCompactBlocks

Parametri [from_height, to_height], entrambi obbligatori. Risultato: una riga per blocco, dal più vecchio, con ciò che serve a un wallet leggero e nient’altro:

[ { "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"] } ] } ]

Ogni transazione che porta un bundle possiede qui quattro note e quattro nullifier: i suoi quattro slot, compresi quelli fittizi, che nessun lettore distingue da quelli reali (dell’esempio è mostrata solo la prima riga di commitment). Dalla v0.6.8 alcune possiedono più note, dopo quelle quattro: un invoke possiede una nota per ogni pagamento, prima pays poi mints, ciascuna con la busta propria del pagamento, così che il beneficiario la trovi con la decifratura per tentativi; su una chain con commissioni del bridge, come la chain 20, un bridge_burn possiede la propria nota di commissione per la tesoreria, e un bridge_attest possiede la propria nota di commissione dopo il suo deposito. La busta di una nota di commissione è vuota, sigillata per nessuno: il wallet della tesoreria ricostruisce la nota a partire dai campi pubblici della transazione.

Al massimo 128 blocchi per chiamata (un intervallo più ampio viene ridotto) e, dopo il primo blocco, servito sempre per intero, 1,000 note; riprendi dall’ultimo height restituito più uno. L’array commitments a livello di blocco contiene i depositi del genesis all’altezza 0 ed è vuoto altrove; le note derivate da un Withdraw e da un BridgeAttest compaiono sotto la rispettiva transazione. -32602 per un intervallo invertito o un estremo mancante.

rand_getAnchor

Parametri [] per la testa, oppure [height]. Risultato { "height": 192, "root": "6b1d…c4" }, oppure -32001 per un’altezza senza ancora registrata. Sono ancore solo le radici di fine blocco. Il nodo può rispondere per un’altezza vecchia, ma l’ancora di un bundle è ammissibile solo se è una delle ultime proof_window_blocks radici: 1,024 sulla chain 20, 256 sulle chain fino alla 19. Costruisci sulla testa.

rand_getWitness

Parametri [index]. Risultato null oltre la fine dell’albero, altrimenti il percorso di Merkle di quella foglia, dalla foglia in su, esattamente 32 livelli, con la radice corrente dell’albero:

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

La lettura più costosa che il nodo serve (ricostruisce l’intero albero di profondità 32) e l’unica richiesta che rivela qualcosa sul chiamante. Un nodo esegue al massimo due ricostruzioni dell’albero alla volta, rand_getWitness e rand_getWitnesses insieme; una richiesta che attende più di 10 s per uno slot viene rifiutata con -32000 witness builds are busy on this node; retry shortly.

rand_getWitnesses

Parametri [[index, …]], da 1 a 32 indici di foglia. Risultato { "root": "…", "witnesses": [ { "index": 7, "path": ["…"] }, { "index": 9, "path": null } ] }: rand_getWitness applicato a molte foglie in un’unica costruzione dell’albero, così un wallet che prova più note paga la ricostruzione una volta sola. Un indice oltre la fine dell’albero dà path: null per quella voce. -32602 per una lista vuota o con più di 32 indici.

Chiavi di visualizzazione e divulgazione

rand_importViewingKey

Parametri [viewing_key] o [viewing_key, rescan_from_height], la chiave come 64 caratteri esadecimali. Risultato { "imported": true, "rescan_from_height": 0, "viewing_keys": 3 }. Il nodo conserva la chiave solo in memoria: al massimo 64 per nodo, cancellate al riavvio; una chiave già presente è un’operazione nulla ("imported": false). L’importazione non esegue mai la scansione; la scansione è guidata dal metodo successivo. -32602 per una chiave malformata; -32000 alla 65ª chiave.

I tre metodi delle chiavi di visualizzazione rispondono solo a un chiamante loopback e rifiutano chiunque altro con -32000, a meno che il nodo non sia avviato con --rpc-viewing-open dietro qualcosa che autentichi. rand_removeViewingKey ([viewing_key] → { "removed": bool, "viewing_keys": n }) libera uno slot e azzera la chiave. Il registro è indicizzato da un id unidirezionale della chiave, blake3("rand-viewing-registry-id-1" ‖ nk), mai dalla chiave stessa, così l’importazione è l’unica copia di lunga durata e la rimozione la cancella. Il testo JSON della richiesta e le copie transitorie prodotte dalla decifratura per tentativi non vengono cancellati.

rand_getViewingNotes

Parametri [viewing_key] o [viewing_key, from_index, limit] (limit predefinito e massimo 1,000). Ogni chiamata fa avanzare la scansione della chiave di al massimo 10,000 foglie, poi serve la pagina:

{ "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 (la busta si è aperta come destinatario e la nota riporta il pk della chiave) oppure sent (aperta tramite la chiave di visualizzazione in uscita). Il memo della nota è il memo cifrato del mittente, testo UTF-8 di al massimo 510 byte, oppure null quando non c’è o quando il suo campo si è aperto malformato; un memo malformato non costa mai al beneficiario la nota. Un memo è testo di chiunque: mostralo come non attendibile. -32001 per una chiave che questo nodo non ha importato.

rand_checkTransaction

Parametri [hash, key], con key una TxKey per transazione come 64 caratteri esadecimali. Risultato null per un hash sconosciuto, altrimenti ciò che la chiave rivela:

{ "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" } } ] }

Stateless: la chiave viene scartata insieme alla chiamata. output è bundle:0 … bundle:3 per i quattro slot di output del bundle (slot 0–1 gli output dell’asset privato, slot 2–3 gli output RAND, dummy inclusi), deposit per la busta di deposito di un’attestazione bridge, token_mint per la nota di un TokenMint, initial_mint per il mint iniziale di un RegisterToken, mint:0 per l’unica busta di un mint del faucet, oppure (v0.6.8) payout:0 … payout:3 per le note pagate da un invoke, numerate secondo la loro posizione nella transizione, prima pays poi mints; asset_bundle:* non esiste più con il secondo bundle. Su una chain con commissioni bridge, deposit apre il deposito netto, cioè il lordo meno la commissione. La note rivelata riporta il proprio asset: questa chiamata, con la chiave con cui il mittente ha sigillato, è l’unico punto in cui l’RPC rivela quale asset ha spostato un trasferimento. Riporta anche il memo, come fa rand_getViewingNotes: la chiave che apre la nota apre il memo, dallo stesso corpo sigillato. Una chiave errata restituisce { "disclosed": [] }, indistinguibile da una transazione che non rivela nulla. Le buste di un withdraw e di un’alloc di genesi non vengono provate: sono sigillate all’interno del nodo con chiavi scartate subito, quindi non esiste alcuna TxKey per esse. Quella di un mint del faucet viene provata: il suo destinatario recupera la chiave tramite la metà KEM della busta (rand tx-key).

Transazioni

rand_getTransaction

Parametri [hash]. Risultato null finché non è confermata, poi:

{
  "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 nelle azioni senza bundle. Le prove e le buste sono riportate solo come lunghezza. envelope_len è 1,860 per ogni slot sulla chain 20, il cui genesi fissa a quella dimensione la busta della nota (envelope_bytes in rand_getLimits); era 1,348 sulle chain da 14 a 17. auth_commit e auth_proof_bytes appartengono all’autorizzazione divisa (dalla chain 17): l’impegno pubblico c = H(AUTH, nk, salt) che la prova del bundle e la prova di autorizzazione pubblicano entrambe, e la lunghezza della prova di autorizzazione. Su una chain senza hc_auth sono zeri e 0.

bundle è il bundle ad asset nascosto (dalla chain 14): quattro slot di input e quattro slot di output, quindi sempre quattro nullifiers, quattro commitments e quattro envelope_len, dummy inclusi. Ogni transazione ne porta al massimo uno; non esiste un secondo bundle. Non ha alcun campo asset: gli slot 0–1 portano un asset privato e gli slot 2–3 RAND, e nulla di pubblico dice quale asset abbiano spostato gli slot 0–1. Un trasferimento di RAND e un trasferimento di qualsiasi token RPL sono entrambi "kind": "none" con burn_a, burn_r e burn_asset tutti a 0 — la stessa forma, campo per campo. Non esiste un kind token_transfer. I tre campi di burn sono l’unica dichiarazione pubblica del bundle sul valore che esce dal pool:

  • burn_a / burn_asset — una quantità dell’asset privato bruciata, e quale asset. Diversa da zero su un token_burn o un bridge_burn, dove sono uguali ad amount e asset dell’azione, e su un invoke il cui inflow è deposit o burn.
  • burn_r — RAND bruciati. Diverso da zero su un bond (pari al suo amount), un register_aggregator e un invoke che deposita RAND nel vault del programma.
  • fee — la commissione in RAND, sempre dagli slot 2–3.

Rappresentazione delle azioni (ogni amount, relayer_fee e initial_amount è una stringa decimale; gli importi di un token sono nelle sue unità, non in quelle di RAND):

kindcampi
none—
mintcm, amount, minter (validatore in base58)
deployprogram, words, public_words_len
callprogram, proof_len, input_envelope_len (null quando la chiamata non ne porta)
bondvalidator, amount, registered
unbondvalidator, amount, nonce
withdrawvalidator, amount, nonce, time
bridge_attestattestation_len, recipient, asset, asset_index, amount, time, r, commitment, pq_signers (gli indici dei guardiani co-firmatari in pq_guardians; le firme da 2,420 byte non sono riportate). asset_index, amount e commitment sono null per una rotazione dell’insieme dei guardiani. r è derivato, blake3("rand-deposit-r-1" ‖ mu) sul digest firmato dai guardiani. Dalla v0.6.8 anche deposit_amount (la nota del depositante: amount, il lordo firmato dai guardiani, meno la commissione bridge) e fee_note ({ amount, asset, time, r, commitment }, la nota della tesoreria senza il suo proprietario, oppure null senza commissioni bridge); commitment è la foglia del deposito netto
bridge_burnasset, amount, relayer_fee, to_chain, token (il backing riscattato), to. Un solo bundle porta l’intero burn: i suoi burn_asset e burn_a sono asset e amount dell’azione. Dalla v0.6.8 anche release_amount (ciò che il corpo firmato rilascia, amount meno la commissione bridge) e fee_note, come in un’attestazione
register_tokenname, symbol, decimals, authority ("none", "key", "bridge" o "program"), index, initial_amount, initial ({ amount, recipient, time, r } o null)
token_mintasset, amount, recipient, time, r, nonce
set_authorityasset, nonce, new_authority (base58, oppure null per una rinuncia)
token_burnasset, amount; i burn_asset / burn_a del bundle li ripetono
pause_mintsnonce; senza bundle e senza commissione, firmato dalla chiave di pausa del genesi
unpause_mintsnonce, pq_signers; senza bundle e senza commissione
register_bridged_tokenname, symbol, salt, chain, token, decimals (i decimali sorgente del primo backing), nonce, asset_id, pq_signers
list_backingtoken_index, chain, token, decimals, nonce, pq_signers
rotate_pq_guardiansnew_pq_guardians, nonce (il rotation_nonce consumato), pq_signers (indici nell’insieme PQ prima della rotazione); senza bundle e senza commissione, solo chain bridge rules_v2
rotate_pause_keynew_pause_key, nonce, pq_signers; lo stesso
rotate_pq_guardians_v2, rotate_pause_key_v2v0.6.8: i campi della v1, più possession_signatures (un conteggio) sulla forma PQ. Senza bundle e senza commissione; obbligatorie su una chain il cui genesi bridge.rotation imposta needs_possession, come quello della chain 20. La rotazione ha effetto delay_secs più tardi (86,400 s sulla chain 20)
cancel_rotationv0.6.8: rotation_kind ("pq_guardians" o "pause_key"), nonce; firmato dalla chiave di pausa corrente, annulla una rotazione in sospeso
admit_validatorv0.6.8: candidate (indirizzo), candidate_key (hex), voters (indirizzi). Senza bundle e senza commissione: il voto dell’insieme dei validatori per consentire la registrazione di una nuova chiave, su una chain con staking.admission_by_vote, come lo è la chain 20
slash_equivocationv0.6.8: offender, view, first e second ({ hash, height }); solo chain con staking.slashing, cosa che la chain 20 non è
invokev0.6.8, RPL-2: i campi di una chiamata (program, proof_len, input_envelope_len) e la sua transition (sotto). Solo chain con una sezione program_state, come lo è la chain 20
register_aggregator, unbond_aggregator, withdraw_aggregator, slash_aggregator, aggregatei loro campi pubblici; solo chain con aggregazione
claim_vested, revoke_vesting, bond_vested, unbond_vestedentry (hex), amount (unvested su una revoca), nonce; time su un claim o una revoca; validator e registers su un bond; dalla v0.6.8 signers su una revoca (le posizioni dei suoi firmatari tra i revokers della voce). Senza bundle; solo chain con una sezione vesting nel genesi, cosa che la chain 20 non è

La registrazione e i mint di un token sono pubblici, come un deposito bridge: ogni parola di una nota coniata è nell’azione (il suo from è il MINT_FROM fisso della chain), quindi un destinatario ricostruisce la nota da questi campi senza decifrare nulla. Le stringhe di kind bridge_attest, token_mint, register_token e invoke sono ciò su cui si basa la scansione del wallet e sono fissate da un test.

Un invoke all’altezza 3,079 della chain 20, che ha letto una cella, l’ha eliminata e ha pagato due note dal vault:

{ "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": [] } }

Tutto questo è pubblico per progetto. reads sono le celle lette dal programma, con i valori letti: la prova è stata prodotta rispetto a essi e il ledger rifiuta la transazione se non valgono più. writes sono le celle che ha scritto; un valore scritto di 64 zeri elimina la cella. Una chiave o un valore di cella è un Word8. Ciò che è entrato è del bundle: burn_r sono i RAND depositati nel vault del programma, e burn_a di burn_asset è il token che inflow nomina, deposit nel vault o burn (il token del programma stesso), none quando burn_a è 0. Ciò che è uscito è una nota calcolata dalla chain per ogni payout, prima pays dal vault, poi mints di un token la cui autorità di mint è questo programma. Ogni parola di ciascuna nota è qui con i nomi di campo di un token_mint; time è quello del bundle, cm la foglia che la chain ha aggiunto, e il from della nota è il PROGRAM_FROM fisso della chain. Le otto parole di output del programma sono sulla ricevuta, come quelle di una chiamata.

Nessuna risposta di un trasferimento riporta mittente, destinatario, nonce, importo o asset: un tale campo non esiste in un trasferimento memorizzato.

rand_getRawTransaction

Parametri [hash]. Risultato: la transazione confermata completa come hex bincode, byte della prova inclusi — ciò di cui un aggregatore ha bisogno e che rand_getTransaction non riporta mai.

Programmi e ricevute

rand_getProgram

Parametri [program_id]. Risultato null oppure { "id", "base_pc", "words_len", "code_hash", "deployed_at", "public_words_len", "public_digest" }. Nessun campo deployer: un deploy è pagato da un bundle. public_words_len è la lunghezza dell’input pubblico del programma al momento del deploy (0 se assente); public_digest è il suo digest, il valore rispetto al quale è verificata la prova di ogni chiamata, oppure null se assente.

rand_getProgramCode

Parametri [program_id]. Risultato null oppure { "base_pc": 0, "words": [ … ] }.

rand_getProgramPublic

Parametri [program_id]. Risultato: le parole pubbliche del programma fissate al deploy, come un’unica stringa esadecimale, con ogni parola nei suoi 4 byte little-endian (8 cifre esadecimali a parola): [1, 2, 0xdeadbeef] è "0100000002000000efbeadde". "" per un programma di cui è stato fatto il deploy senza input pubblico, null per un id che nessun programma ha. Un wallet che produce la prova di una chiamata passa queste parole al prover; il ledger verifica l’impegno della prova rispetto al public_digest del programma.

rand_getProgramCell

v0.6.8, RPL-2. Parametri [program_id, key], con la chiave come Word8 in 64 cifre esadecimali (con o senza 0x). Risultato { "key": "<64 hex>", "value": "<64 hex>" }. Una cella che il programma non ha mai scritto, o in cui ha scritto zeri (il che la elimina), si legge come 64 zeri, l’unica codifica di «assente»; vale lo stesso per qualsiasi chiave di un programma di cui nessuno ha fatto il deploy, poiché l’esistenza del programma non viene verificata. { "enabled": false } su una chain senza una sezione program_state. Una cella è pubblica per progetto: è ciò che un wallet legge per costruire i reads di un invoke.

rand_getProgramCells

v0.6.8. Parametri [program_id, { "after": "<64 hex>" | null, "limit": n }], con l’oggetto facoltativo. Risultato { "cells": [{ "key", "value" }, …], "next": "<64 hex>" | null }: le celle del programma in ordine di chiave (un confronto senza segno delle otto parole), a partire da dopo after, al massimo limit (limitato a un valore da 1 a 1.000). next è l’ultima chiave servita quando ne seguono altre; la si ripassa come after. È null nell’ultima pagina. Un programma senza celle risponde { "cells": [], "next": null }; { "enabled": false } senza la sezione.

rand_getProgramVault

v0.6.8. Parametri [program_id]. Risultato [{ "asset": 0, "amount": "123" }, …], in ordine crescente di indice dell’asset (0 è RAND, ogni altro indice è quello del registro dei token), con gli importi come stringhe decimali nelle unità proprie dell’asset. Una riga a zero non esiste, quindi un vault vuoto, e un programma di cui nessuno ha fatto il deploy, è []. { "enabled": false } senza la sezione. Il valore entra in un vault attraverso il bundle di un invoke (burn_r, e burn_a di burn_asset quando l’inflow è deposit) e ne esce come le note che i pays della transizione indicano.

rand_getLimits

Parametri []. Risultato: ciò di cui un wallet ha bisogno dal genesis della chain per costruire una transazione: i cinque limiti di chiamata, la dimensione dell’envelope delle note, l’interruttore v0.6, l’auth guest, i termini del gas e, dalla v0.6.8, i campi del genesis audit-v6 e i limiti dello stato dei programmi. Sulla 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 } }

Un genesis privo dei cinque campi dei limiti (chain 12) ottiene 4096, 2097152, 4194304, 18432 e 0. max_proof_bytes era 8.388.608 sulle chain da 13 a 15.

fieldmeaning
envelope_bytes1860 quando il genesis fissa ogni envelope che crea note esattamente a quella lunghezza, il formato che porta il memo; null su un genesis privo del campo (chain da 14 a 17), dove un wallet sigilla l’envelope da 1.348 byte senza memo. Non esiste alcun altro valore
hardening_v6true quando il genesis applica le regole di validità v0.6. Un wallet allora produce la prova di una chiamata sull’input pubblico del programma seguito dal call binding della transazione, non sul solo input pubblico: prima si scelgono le note del bundle delle commissioni, poi si produce la prova della chiamata, per ultimo il bundle. Una chain con il flag rifiuta la vecchia prova, una chain senza di esso la nuova
hc_authl’auth guest che il genesis fissa, in esadecimale, oppure null. Se è impostato, hc_bundle è il bundle guest v3 e ogni bundle porta auth_commit e una prova di autenticazione: il wallet fornisce al bundle guest nk e un salt nuovo, e produce la prova dell’auth guest sulla chiave di spesa
gas_metering"circuit" su una chain il cui genesis ha una sezione gas (il contatore nel circuito); "header" su una chain che ne è priva quando il nodo applica una propria politica del gas (--gas-price, --byte-price); null in assenza di entrambe
gas_price, byte_priceunità per gas, e unità per KiB della prova e dell’envelope di input di una chiamata, come stringhe decimali. Sotto una sezione gas sono stato di consenso e identici su ogni nodo: con gas.dynamic, come sulla chain 20, i prezzi correnti del tip, che si muovono a ogni blocco in base al riempimento, non scendono mai sotto i minimi del genesis (100 e 800) e non salgono mai oltre i massimi; senza di esso, i prezzi fissi della sezione. Senza una sezione sono la politica propria di quel nodo, e due nodi possono rispondere in modo diverso
bundle_gas_limitil gas fisso che ogni prova di bundle deve dichiarare, dalla sezione gas del genesis; null senza di essa
adjust_bpsil massimo spostamento di prezzo in un blocco del controller dinamico, in punti base; null su una chain senza gas.dynamic
max_gas_price, max_byte_pricev0.6.8: i massimi oltre i quali il controller non porta mai un prezzo, come stringhe decimali; "10000" e "80000" sulla chain 20, null dove il genesis non ne fissa (chain 18 e 19)
byte_loadv0.6.8: "paying" quando solo la prova e l’envelope di input di una chiamata muovono byte_price, così che un blocco di trasferimenti non ne muova alcuno, come sulla chain 20; null dove contano i byte di ogni transazione (chain 18 e 19)
admission_by_votev0.6.8: se un bond che registra una nuova chiave di validatore richiede prima il voto dell’insieme dei validatori (rand_getAdmitted); true sulla chain 20
testnetv0.6.8: il marcatore testnet del genesis, che consente a un faucet di affiancare una sezione bridge; true sulla chain 20, false su ogni chain precedente
slashingv0.6.8: { "equivocation_bps", "jail_epochs" }, ciò che costa l’equivocazione di un leader, oppure null; null sulla chain 20
binding_domainv0.6.8: 0 dove il binding di una transazione e ogni messaggio di azione firmato legano il solo id della chain (chain da 14 a 19), 1 dove portano anche l’hash del genesis, così che una prova o una firma prodotta per una chain non si verifichi su nessun’altra (chain 20). Un wallet decide quale forma provare in base all’id della chain, mai in base a questa risposta: il wallet rand v0.6.8 dà alle chain con id da 14 a 19 la forma con l’id della chain e a ogni altro id la forma legata al genesis, e legge questo campo solo per rifiutare in anticipo. Un wallet precedente alla v0.6.8 non può inviare sulla chain 20
proof_window_blocksv0.6.8: quanto può essere vecchio, in blocchi, l’anchor di un bundle e quanto può restare indietro rispetto all’altezza il suo time, una sola finestra per entrambi; 1024 sulla chain 20, null (256) sulle chain fino alla 19. Un wallet con un prover lento o delegato lo legge per sapere quanto tempo può richiedere una prova
program_statev0.6.8, RPL-2: la sezione program_state del genesis e i suoi limiti per gli invoke, oppure null, nel qual caso ogni invoke è rifiutato e nessun token di programma può essere registrato. cell_fee è la quantità di unità RAND (una stringa decimale) di cui cresce il minimo di commissione di un invoke per ogni cella che crea, ossia una scrittura di un valore non nullo in una cella che si legge come zeri; riscrivere, eliminare o scrivere zeri non costa nulla. max_reads, max_writes e max_payouts (pays e mints insieme) sono limiti rigidi. In pratica vale prima la regola del segmento: le parole di contesto della transizione (11 + 16 per lettura o scrittura + 3 per pagamento) devono stare accanto all’input pubblico del programma e alle 8 parole di binding senza far crescere la tabella pubblica della zkVM; per un programma senza input pubblico quella tabella è di 128 righe, il che lascia 119 parole di contesto

Un nodo precedente a un campo risponde senza di esso. Nulla in questa risposta è autenticato, perciò un wallet non accetta envelope_bytes sulla sola parola del nodo: il wallet rand sigilla l’envelope legacy sulle chain con id da 14 a 17 qualunque cosa risponda il nodo, e gli altri client dovrebbero fare lo stesso.

rand_getReceipt

Parametri [tx_hash]. Risultato null finché la chiamata non è confermata, poi { "tx", "program", "tier": 14, "outputs": [1, 0, 25, 0, 0, 0, 0, 0], "height": 17, "index": 0, "h_in": "9c0e…7f", "h_pub": null }. Nessun campo effect. h_pub è il digest dell’input pubblico del programma, fissato al deploy, rispetto al quale è stata verificata la prova della chiamata, null per un programma che ne è privo. Un invoke (v0.6.8) ha la ricevuta di una chiamata, e rand_getReceipts e il topic receipts la riportano invariata.

rand_getReceipts

Parametri [program_id, from_height, to_height, limit?]. Risultato { "receipts": [ … ], "next_height": 2051 }: le ricevute di program_id con from_height <= height <= to_height, per altezza e poi per indice, ciascuna esattamente l’oggetto di rand_getReceipt. limit ha come valore predefinito e massimo 256 e non divide mai un’altezza: quando una pagina contiene limit ricevute, serve comunque tutte le restanti di quell’altezza. next_height è la prima altezza non servita, oppure null quando to_height ha concluso la pagina. -32602 per to_height inferiore a from_height.

rand_getCallEnvelope

Parametri [tx_hash]. Risultato null, oppure { "tx", "h_in", "kem_ct", "to_sender", "to_auditor", "body" } in esadecimale — la trascrizione sigillata dell’input della chiamata, servita così com’è; il nodo non possiede alcuna chiave che la apra. null quando la chiamata non ne ha pubblicata una (--no-envelope), la transazione non è una chiamata, o non esiste una ricevuta.

Staking e supply

rand_getValidators

Parametri []. Risultato: una riga per ogni voce del registro, in ordine di indirizzo, con gli importi come stringhe decimali:

[{ "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) è la prima epoca in cui una chiave penalizzata con slashing può tornare a far parte di un insieme (18446744073709551615 per sempre), null quando non è in jail. La chain 20 non ha staking.slashing, quindi lì è sempre null.

rand_getAdmitted

v0.6.8. Parametri []. Risultato { "admission_by_vote": true, "max": 256, "admitted": ["<address>", …] }: le chiavi che l’insieme dei validatori ha ammesso con un AdmitValidator e che non si sono ancora registrate, in ordine di indirizzo. Su una chain il cui genesis imposta staking.admission_by_vote, come quello della chain 20, un Bond che registra una nuova chiave deve essere tra queste. max è il numero di chiavi che il ledger contiene in un dato momento. Su una chain senza il flag admission_by_vote vale false, l’elenco è sempre vuoto e una registrazione non richiede alcun voto. La chain 20 ha risposto "admitted": [] il 2026-10-01.

rand_getEpoch

Parametri []. Risultato { "epoch": 41, "epoch_blocks": 1000, "next_set": ["…", "…"] }; next_set è una proiezione.

rand_getSupply

Parametri []. Risultato:

{ "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 si muovono solo su una chain con aggregazione. faucet_epoch e faucet_minted_in_epoch sono il contatore per epoca del faucet rispetto a staking.faucet_budget_per_epoch (stato di consenso sulla chain 20). I quattro campi vesting_* sono i contatori del vesting del genesis, tutti "0" su una chain senza una sezione vesting, come la chain 20. program_rand_out e program_rand_held (v0.6.8, RPL-2; "0" senza una sezione program_state) sono i RAND che gli invoke hanno pagato dai vault dei programmi come note (lato pool, dentro pool_value) e quelli che i vault ancora detengono (lato registro, dentro total_supply); sono entrati tramite il burn_r di un invoke, quindi sono dentro burned sul lato pool. registration_fees_burned è la Σ delle commissioni di registrazione dei token bruciate in base al tokens.burn_registration_fee del genesis, che la chain 20 imposta; invariant_holds la sottrae, insieme a slashed, da ciò che la chain ha emesso. Supply spiega l’identità.

rand_getEmission

Parametri []. Risultato { "inflation": "0", "subsidy": null, "faucet": true }. inflation è un "0" fisso. subsidy è il programma di sussidio per l’aggregazione dei blocchi (current, base, halving_blocks, sealed_blocks, next_halving_at) e vale null su una chain senza una sezione aggregation, come la chain 20. faucet rispecchia rand_status.

Bridge

Tutti e quattro rispondono su qualsiasi chain; su una chain senza una sezione bridge lo stato è { "enabled": false } e il registro è []. Il genesis della chain 20 ne ha una: il guardian set 1 (guardian_set_index 1) con otto guardiani, otto guardiani PQ, una chiave di pausa, burn_sequence 13 al genesis, una soglia anti-replay (min_inbound_sequence 3 per le chain di origine 2, 3 e 4, e 7 per la chain di origine 5), le rules_v2 del bridge con un limite globale di mint di 4.000 zUSD per finestra di 24 ore su tutti i backing, e due gruppi nuovi nella v0.6.8: rotation (la rotazione di un guardiano PQ o della chiave di pausa richiede la prova di possesso da parte delle nuove chiavi ed entra in vigore 86.400 s dopo il commit) e fees (10 bps di ogni deposito e 10 bps di ogni burn, trattenuti su Rand come nota zUSD a un indirizzo di tesoreria). La chain 19 aveva burn_sequence 8, soglie di 1 e 4, e nessuno dei due gruppi. La sua sezione tokens ha una registration_fee di 1 RAND (bruciata), un mint_cap_per_day per backing di 10000000000000 (100.000 zUSD con otto decimali) ed elenca zUSD stesso: riportato dalla chain 14 al genesis, stesso asset id, indice 1, sette backing.

rand_getBridgeState

Parametri []. Risultato { "enabled": false }, oppure:

{
  "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": [ … ]
}
camposignificato
emitterl’indirizzo dell’emitter in uscita di questa chain, 32 byte in esadecimale
emittersid della chain di origine → l’indirizzo dell’emitter considerato attendibile lì
guardiansgli indirizzi da 20 byte dell’insieme corrente, in esadecimale
pq_guardiansl’insieme PQ: chiavi pubbliche Dilithium2 (1.312 byte), in esadecimale, allineate per indice all’insieme di guardiani corrente (l’insieme 1 sulla chain 20). Ogni BridgeAttest porta un quorum di cofirme di questo insieme. Una rotazione del guardian set non lo sposta mai; lo fa solo una rotate_pq_guardians, su una chain con rules_v2
mint_pausedfinché vale true ogni attest di trasferimento viene rifiutato con bridge minting is paused; burn e rotazioni restano aperti
pause_nonceciò che deve portare la prossima pausa o riattivazione; entrambe lo incrementano
list_nonceciò che deve portare la prossima register_bridged_token o list_backing; entrambe lo incrementano
pause_keyl’unica chiave Dilithium2 che può mettere in pausa il minting, in esadecimale. Può solo mettere in pausa: una riattivazione richiede il quorum dei guardiani PQ
registration_feeciò che una RegisterBridgedToken deve oltre la base del bundle, in unità RAND, come stringa decimale
burn_sequencemessaggi in uscita emessi finora
rotation_nonceciò che deve portare la prossima rotate_pq_guardians / rotate_pause_key
rules_v2il limite globale di mint e la sua finestra mobile, oppure null su una chain senza le regole del bridge v2. Con esse anche il limite per backing è una finestra mobile, e un listing viene rifiutato mentre il minting è in pausa. Dalla v0.6.8 porta anche global_minted_in_window e global_mint_headroom, stringhe decimali
min_inbound_sequencela soglia anti-replay del genesis: id della chain di origine → la sequenza più bassa che un trasferimento da quella chain può portare, numeri semplici; null su una chain che non ne ha una (chain 15 e precedenti). Un bridge_attest sotto la soglia viene rifiutato con BelowReplayFloor, un verdetto permanente. Un relayer la legge per scartare un lock che la chain da cui questa è stata ricavata ha già mintato
rotation_rulesv0.6.8: { "delay_secs", "needs_possession" } dal bridge.rotation del genesis, oppure null. Con esse una rotazione è l’azione _v2, che porta le firme di possesso delle nuove chiavi, e attende delay_secs prima di entrare in vigore
pending_rotationsv0.6.8: rotazioni confermate e non ancora in vigore, ciascuna { "kind": "pq_guardians", "new_pq_guardians", "effective_at_secs" } oppure { "kind": "pause_key", "new_pause_key", "effective_at_secs" }; null senza rotation_rules. Una cancel_rotation firmata dalla chiave di pausa corrente ne annulla una
feesv0.6.8: { "mint_bps", "burn_bps", "recipient" } dal bridge.fees del genesis, oppure null (chain da 14 a 19). La chain trattiene quella quota di ogni deposito e di ogni burn, arrotondata per difetto a un’unità intera di rilascio del backing, come nota zUSD a recipient. Un deposito accredita il lordo meno la commissione; il corpo firmato di un burn rilascia il suo importo meno la commissione. Un wallet la legge per valutare il proprio deposito e, quando è recipient, per ricostruire le proprie note di commissione
assetsle righe di rand_getAssets

Nessun saldo: il valore trasferito tramite bridge è fatto di note. Non esiste più alcun next_index: un token bridged viene elencato, con un indice che la sua registrazione ha già fissato, prima di poter essere depositato, quindi non resta alcun indice da prevedere. Leggi l’indice di un token elencato da assets o da rand_getTokens.

rand_getAssets

Parametri []. Risultato: il registro degli asset del bridge, in ordine crescente di indice, oppure []:

[{ "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" }]

Dalla v0.6.8 ogni riga di backing, qui e ovunque i backing vengano serviti (rand_getBridgeState.assets, i backings di rand_getToken, rand_getTokens e rand_getTokenSupply), porta minted_in_window (una stringa decimale) e mint_window_secs, entrambi null su una chain con contatore giornaliero, e mint_headroom: il deposito più grande verso quel backing che i limiti ammettono al block time della testa, cioè il limite per backing meno quanto ha già mintato e, con le regole v2, non più di quanto resta alla finestra dell’intero registro. Leggi mint_headroom, non mint_cap_per_day − minted_today, che ignora il limite globale. Con le regole v2, come sulla chain 20, minted_today è il conteggio della finestra mobile, la cifra rispetto alla quale viene controllato il limite per backing; la descrizione del contatore giornaliero qui sotto è quella della chain 14.

Una riga per backing (moneta di origine), quindi un token con sette backing occupa sette righe sotto un solo index. index è la parola asset che porta una nota di quell’asset; l’indice 0 è RAND e non compare mai nel registro. decimals sono i decimali di origine del backing. locked, mint_cap_per_day e minted_today sono stringhe decimali nelle unità a otto decimali proprie del token, mai quelle di RAND; mint_day è un intero semplice, un numero di giorno UTC. mint_cap_per_day è il tokens.mint_cap_per_day del genesis, il massimo che un backing può mintare per giorno UTC del block time. minted_today è quanto il backing ha mintato in mint_day, il giorno UTC (timestamp_ms / 86,400,000) del blocco di testa, quindi un contatore rimasto da un giorno precedente vale "0" una volta che la testa supera la mezzanotte. Un deposito oltre il limite viene rifiutato con MintCapExceeded e diventa ammissibile il giorno successivo. chain e token sono l’identità sul wire su cui firmano i guardiani; asset_id è il blake3 dei due, ciò che calcola rand_bridgeAssetId.

rand_bridgeAssetId

Parametri [token_chain, token_address] (intero, 32 byte in esadecimale). Risultato: l’asset id, 64 caratteri esadecimali. Pura aritmetica.

rand_getBridgeBurn

Parametri [sequence]. Risultato null oppure { "sequence": 0, "body_hex": "…", "digest": "…", "tx": "…", "height": 2, "amount": "…", "release_amount": "…", "fee": "…" }.

Gli ultimi tre sono della v0.6.8, su ogni chain, come stringhe decimali nelle unità a otto decimali del token. release_amount è l’importo che porta il corpo firmato, letto dallo stesso body_hex: ciò che il contratto di origine rilascia, e da cui paga la commissione del relayer del corpo. fee è la commissione del bridge che la chain ha trattenuto come nota di tesoreria, e amount ciò che il bundle ha bruciato, release_amount + fee. Senza bridge.fees (chain da 14 a 19) fee vale "0". La sequenza 13 sulla chain 20, un burn di 0,999 zUSD: "amount": "99900000", "fee": "99900", "release_amount": "99800100".

Token (RPL)

Il registro dei token RPL: ogni token, bridged e nativo. Tokens spiega lo standard.

rand_getTokens

Parametri [from_index, limit], entrambi opzionali (0 e 1000; limit viene limitato a 1.000). Risultato: il registro in ordine crescente di indice a partire da from_index, letto per intervallo da quell’indice:

{ "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 }
  ] }

On a chain without a tokens section: { "enabled": false, "tokens": [] }. index è la parola asset che una nota del token porta con sé (0 è RAND e non è mai elencato). id è l’asset id del token e id_text la sua forma testuale con checksum: bech32m, HRP rpl, sui 32 byte dell’id, 62 caratteri. authority è uno tra:

kindaltri campi
none— (offerta fissa, o rinunciata)
keykey, address
bridgebackings: [{ "chain", "token", "decimals", "locked", "mint_cap_per_day", "minted_today", "mint_day" }], i campi di rand_getAssets, una riga per ogni backing
programprogram

Le offerte, locked, mint_cap_per_day, minted_today e registration_fee sono stringhe decimali (unità RAND per registration_fee, unità del token per le altre); next_index, mint_day e max_tokens sono numeri. max_tokens è il limite del registro fissato al genesis (4.096 sulla chain 20; null se assente), oltre il quale una registrazione viene rifiutata con RegistryFull. burn_registration_fee indica se la commissione di una registrazione viene bruciata anziché versata al proposer; bound_note_value indica se un mint o un deposito pari o superiore a 2⁶³ è una regola di validità (l’ammissione ne rifiuta comunque uno su ogni chain). Tutti e tre sono impostati sulla chain 20. Una pagina più corta di limit è l’ultima.

Un’authority program ({ "kind": "program", "program": "<id>" }) è registrabile solo su una chain con una sezione program_state, come lo è la chain 20 (v0.6.8): il token parte con offerta zero e solo gli invoke di quel programma lo coniano o lo bruciano.

Un wallet risolve l’id di un token tramite questo elenco, mai tramite rand_getToken: l’asset di un trasferimento è privato on-chain, e leggere l’intero registro costa lo stesso, qualunque sia il token cercato.

rand_getToken

Parametri [token]: un indice di registro (un numero o una stringa decimale), l’id di 64 caratteri esadecimali (con o senza 0x, in qualunque combinazione di maiuscole e minuscole) o la forma testuale rpl1… (tutta minuscola o tutta maiuscola). Risultato: la riga di rand_getTokens di quel token, oppure null. Un id malformato — checksum errato, altro HRP, lunghezza sbagliata, maiuscole e minuscole miste, non esadecimale — dà -32602, così un errore di battitura non diventa mai un altro token. Una ricerca per singolo token dice al nodo quale token interessa a chi chiama; serve a explorer e a letture occasionali.

rand_getTokenSupply

Parametri [token], nelle stesse forme. Risultato null, oppure:

{ "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 è vuoto per un token nativo; per uno bridged gli importi locked sommano a total_supply. Vale la stessa nota sulla privacy di rand_getToken.

Aggregazione dei blocchi (non attiva sulla chain 20)

Esistono nel nodo per le chain il cui genesis contiene una sezione aggregation. Sulla chain 20 il registro è vuoto e nulla viene mai dissigillato.

metodoparametririsultato
rand_getAggregate[hash]covers, aggregator, subsidy, proving_share, n, height dell’aggregato che sigilla; null per qualunque altra transazione
rand_getAggregators[]il registro degli aggregator: address, bond, payout, nonce, unbonding per riga
rand_getUnsealed[from, limit]{ "bundles": [{ "hash", "height", "excess" }], "next_from" }, i bundle che un aggregator può ancora coprire

Un Aggregate si invia tramite rand_sendTransaction come ogni altra cosa.

Vesting al genesis (non attivo sulla chain 20)

Esistono nel nodo per le chain il cui genesis contiene una sezione vesting. Nessuna chain ne ha ancora una: sulla chain 20 ciascuno risponde { "enabled": false }. L’endpoint pubblico li inoltra dal 2026-10-01.

metodoparametririsultato
rand_getVesting[id] oppure [id, at_ms], l’id esadecimale di 64 caratteri della vocela voce: la sua classe, il beneficiario, il piano (amount, start_ms, cliff_ms, linear_ms, step_ms), quanto è stato reclamato, revocato e vincolato, e vested_now, claimable_now, unvested_now a as_of_ms (per impostazione predefinita l’ora del blocco di testa); null per un id sconosciuto. Dalla v0.6.8 una voce revocabile elenca revokers, la threshold di essi che una revoca richiede e la treasury a cui una revoca paga (sostituiscono il singolo revoker), e la voce porta revoke_nonce e locked_now
rand_getVestingSummary[]{ "enabled": true, "height", "as_of_ms", "entries", "issued", "released", "locked", "classes": [ … ] }: totali per classe, senza chiave né proprietario
rand_getVestingSchedule[from_ms, to_ms, step_ms], al massimo 1.000 punti{ "enabled": true, "issued", "points": [{ "t_ms", "locked" }] }: il totale bloccato del registro nel tempo

Gli importi sono stringhe decimali. Le quattro azioni di vesting si inviano tramite rand_sendTransaction.

Sottoscrizioni (WebSocket)

ws://127.0.0.1:8545/ oppure /ws. Il socket serve solo rand_subscribe e rand_unsubscribe e risponde -32601 a qualunque altra cosa. Tre topic, flussi indipendenti senza alcuna promessa di ordinamento tra loro:

  • newHeads — nella forma di rand_getHead, inviato una volta per ogni blocco committed, in ordine, anche durante la sincronizzazione. Qui view è la view propria del blocco.
  • receipts oppure receipts <program_id> — una notifica per ogni blocco committed che contiene almeno una ricevuta di chiamata corrispondente: { "height", "hash", "receipts": [ … ] }, ogni ricevuta nella forma di rand_getReceipt.
  • transaction <hash> — una notifica, poi il nodo rimuove la sottoscrizione: { "status": "committed", "height", "index" }, oppure { "status": "rejected", "reason" } per un rifiuto riguardante i byte stessi della transazione (il limite che ha rand_getTransactionStatus). Un rifiuto dipendente dallo stato non viene mai annunciato, quindi va abbinato a un 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 } } }

Limiti: 64 connessioni per nodo (la 65ª viene rifiutata all’upgrade con 503), 8 sottoscrizioni per connessione, 64 KiB per frame del client, un ping ogni 30 s con risposta entro 5 s e 256 voci di backlog per flusso — un sottoscrittore troppo indietro su un flusso che ascolta viene chiuso con il codice 1008, non messo in buffer; riconnettiti e colma il vuoto con rand_getCompactBlocks (head), rand_getReceipts (ricevute) o rand_getTransactionStatus (una transazione). Un semplice GET / senza header di upgrade risponde 400.

Errori

codicesignificato
-32601metodo sconosciuto (inclusi i metodi account ritirati)
-32602parametro non valido o mancante
-32000rifiutato: una transazione che la mempool ha rifiutato, una chiamata al faucet soggetta a rate limit, una costruzione di witness che ha atteso oltre 10 s, una lettura oltre 30 s, un metodo che il listener pubblico non serve, o una sottoscrizione oltre il limite
-32001oggetto referenziato non trovato
-32010pruned: un’altezza inferiore alla soglia di conservazione di questo nodo; data.floor la indica (vedi sotto)
-32603errore interno
-32600richiesta non valida: corpo oltre il limite di dimensione, non JSON, un batch malformato o una notifica
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32000, "message": "…" } }

Per rand_sendTransaction, solo -32000 e -32602 sono un verdetto sulla transazione; dopo qualunque altro codice il suo destino è ignoto (vedi rand_sendTransaction).

Nodi con pruning: errore -32010

Un nodo avviato con --prune-history <window> conserva l’intero ledger (note, nullifier, anchor, il registro) ma solo gli ultimi <window> di blocchi, transazioni e ricevute; rand_status.prune_floor è l’altezza più bassa che ancora detiene. Sulla chain 20, 24 dei 26 validator eseguono --prune-history 24h; i due archivi funzionano senza il flag e conservano ogni blocco, e l’endpoint pubblico inoltra a uno di essi.

  • Per altezza, sotto la soglia (genesis escluso): rand_getBlockByHeight, rand_getFinality per altezza e un intervallo di rand_getBlocks, rand_getCompactBlocks o rand_getReceipts che scende sotto la soglia rispondono -32010 pruned: height h is below this node's retention floor f con data: { "floor": f }. Interroga un archivio. [0, 0] serve ancora il genesis.
  • Per hash: rand_getBlockByHash, rand_getReceipt, rand_getRawTransaction, rand_getCallEnvelope e rand_getAggregate rispondono null per un hash eliminato dal pruning, come per uno mai esistito; solo un archivio sa distinguere i due casi. Anche rand_getTransaction e rand_checkTransaction rispondono null, e -32010 solo quando sopravvive una riga di posizione che indica un’altezza sotto la soglia. rand_getTransactionStatus aggiunge floor a ogni voce unknown su un nodo con pruning.
  • La scansione del wallet non è influenzata: rand_getCommitments, rand_getNullifiers, rand_getAnchor e i metodi di witness leggono famiglie che non vengono mai eliminate dal pruning.

La transazione sul wire

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

Configurazione predefinita di bincode: interi a larghezza fissa, prefissi di lunghezza a 8 byte, tag enum u32 nell’ordine di dichiarazione. Le cinque varianti di aggregazione seguono BridgeBurn e precedono RegisterToken nell’enum (Transazioni); la chain 20 non le ammette mai, né le quattro varianti di vesting né SlashEquivocation, ma un encoder che codifica i numeri dei tag in modo fisso deve comunque contarle.

Gli ultimi due campi del bundle sono arrivati con la v0.6.3 e la chain 17. bincode è posizionale, quindi un encoder scritto per la chain 16 o precedente non produce una transazione che questa chain decodifica, e con essi è cambiato ogni id di transazione: il dominio dell’id è ora rand-txid-3, che vincola auth_commit e il digest della prova di autenticazione. Un client che ricalcola gli id in locale deve adeguarsi. Sulla chain 20 ogni bundle porta una prova di autenticazione, auto-dimostrata o delegata che sia. La v0.6.8 non cambia nulla nel layout di Transaction o Bundle; aggiunge le azioni da 28 a 33.

Ogni transazione porta al massimo un bundle. Un Bond porta un bundle il cui burn_r è uguale al suo amount, con burn_a e burn_asset pari a 0. Un BridgeBurn o un TokenBurn brucia attraverso il bundle: burn_asset deve essere l’asset dell’azione (mai 0), burn_a l’amount dell’azione e burn_r 0, mentre fee paga in RAND dagli slot 2–3. Ogni altra azione non brucia alcun token, e RAND viene bruciato esclusivamente tramite burn_r: un bundle con burn_asset 0 e burn_a diverso da zero viene rifiutato ovunque. L’r di un BridgeAttest è derivato, non scelto: l’ammissione richiede blake3("rand-deposit-r-1" ‖ mu) calcolato sul digest firmato dai guardiani e rifiuta qualsiasi altro valore (WrongDepositBlinding, un rifiuto permanente). Un token bridged è elencato — al genesis, oppure tramite un RegisterBridgedToken / ListBacking — prima che qualsiasi sua attestazione sia ammissibile; l’attestazione di una moneta non elencata viene rifiutata con UnlistedToken.

Ogni prova del bundle è costruita su, e verificata rispetto a, la transazione in cui viaggia: l’intera transazione con le sue prove azzerate, vincolata al chain id e, sulla chain 20 (binding_domain: 1), all’hash del genesis, con tag nuovi. Sulle chain da 14 a 19 il vincolo era il solo chain id, quindi una prova costruita per la chain 19 non viene verificata sulla chain 20, e un wallet precedente alla v0.6.8 non può inviare lì. Sulle chain da 18 a 20 un bundle privo delle sue due prove si codifica in 7.936 byte e una transazione di trasferimento priva delle prove in 7.949 (5.848 e 5.861 sulle chain da 14 a 16, con envelope da 1.348 byte e senza campi di autenticazione). Un trasferimento sulla rete pesa circa 2,85 MB al profilo di produzione, quasi interamente prova: una prova del bundle di circa 1,49 MB e una prova di autenticazione di circa 1,36 MB. Prima della split authorisation era di circa 1,43 MB.

Ultima verifica rispetto al commit c0878c3f del fullnode (chain 21) il 2026-10-12. Dove il codice e questa pagina non concordano, ha ragione il codice; segnalacelo.