El nodo sirve JSON-RPC 2.0 por HTTP en --rpc (por defecto 127.0.0.1:8545), y un WebSocket en el mismo puerto para las suscripciones. Desde v0.6.8 también puede abrir un segundo listener público (--public-rpc, más abajo). randprotocol_client::RpcClient (Rust) envuelve todos los métodos siguientes. Esta página es la lista de métodos tal como la sirve v0.6.8 (c9c9bd3c), la compilación que ejecuta la chain 20; cuando un método existe en el código pero está inactivo en la chain 20, se indica.
curl -s http://127.0.0.1:8545 -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"rand_getHead","params":[]}'
El endpoint público
https://rpc.randprotocol.org (el mismo proxy está también en https://randprotocol.org/api/rpc) reenvía a un nodo de archivo de la chain 20 que conserva todos los bloques, para wallets y páginas que no tienen un nodo propio (rand --rpc https://rpc.randprotocol.org …). Es solo HTTP POST, con CORS abierto y sin WebSocket, y es más acotado que un nodo:
- Una solicitud por llamada. Un lote se rechaza con
-32600. - Una lista de métodos permitidos: desde el 2026-10-01 es el mismo conjunto que el del listener público del propio nodo (
rpc::PUBLIC_METHODSen v0.6.8), de modo que las lecturas del estado de los programas que necesitarand program invoke,rand_getAdmitted, las lecturas de agregación y las lecturas de vesting forman parte de ella, junto conrand_checkTransactionyrand_sendTransaction.rand_mint,rand_importViewingKey,rand_getViewingNotes,rand_removeViewingKeyyrand_getPeersno, y responden-32601method not allowed heresin llegar al nodo: un faucet público es una superficie de abuso, y una viewing key solo debe enviarse a un nodo que usted mismo ejecute. - Un cuerpo de solicitud de 12 MiB como máximo, que admite cualquier transferencia, acción de token o despliegue, y una llamada cuya prueba llegue a unos 3,4 MB (la transacción se codifica en hexadecimal, y sus pruebas de bundle y de auth ocupan unos 2,85 MB antes de la de la llamada). Una llamada mayor debe ir a su propio nodo. Por encima del límite: HTTP 413 y
-32600. - Por dirección, 1.200 solicitudes por minuto, y 6 por minuto para
rand_sendTransaction. Por encima: HTTP 429 y-32005. El presupuesto de lectura está dimensionado para la primera sincronización de una wallet, que son varios cientos de solicitudes en una sola ráfaga (645 a la altura 99.000 de la chain 18). -32000upstream unavailablecuando el nodo que está detrás no responde.
Todo lo demás de esta página describe el nodo en sí.
Los dos listeners del nodo
Desde v0.6.8 (audit v6) un nodo tiene dos listeners JSON-RPC.
--rpc <ADDR>, el listener del operador. Todos los métodos, lotes y el WebSocket. Identifica a quien llama por su dirección de socket y confía en loopback: los métodos de viewing key responden solo a loopback, y loopback no tiene medición. Manténgalo en127.0.0.1. Un proxy inverso o un reenvío SSH llega por loopback, así que detrás de uno cualquier visitante es el operador: nunca apunte un endpoint público a este puerto.--public-rpc <ADDR>, el listener público, para exactamente ese salto. Sirve un conjunto fijo de métodos, las lecturas que necesita una wallet, un explorador o una página, yrand_sendTransaction(rpc::PUBLIC_METHODS).rand_importViewingKey,rand_getViewingNotes,rand_removeViewingKey,rand_mintyrand_getPeersnunca se sirven allí, ni tampoco ningún método añadido más adelante hasta que figure en la lista; una llamada así responde-32000<method> is not served on this node's public listener. Un lote da-32600, y no hay ruta WebSocket. Un único medidor cubre a todos los llamantes en conjunto, 600 solicitudes en una ráfaga y 150 por segundo; superado, HTTP 429 con un cuerpo-32000. Los límites por visitante corresponden al proxy, que sí ve a los visitantes. Sus llamantes ocupan como máximo la mitad de los slots de lectura bloqueante del nodo, de modo que el listener del operador nunca queda desabastecido.
Ambos listeners comparten dos límites de lectura. Una lectura bloqueante que no ha terminado en 30 s recibe -32000 this read took longer than 30 s on this node; retry with a smaller range. rand_getBlocks termina su página cuando ha leído 64 MiB de bloques.
--rpc-viewing-token-file <PATH> pone un bearer token en los métodos de viewing key de --rpc: la primera línea del archivo, de al menos 32 caracteres, enviada como Authorization: Bearer <token>. Con él, loopback por sí solo no basta, y se atiende a cualquier llamante, esté donde esté, que lo presente.
Convenciones
- Las direcciones de validator son cadenas base58 (32 bytes). Los hashes son 64 caracteres hexadecimales, con o sin
0x. Los valores protegidos (shielded) — compromisos, nullifiers, anchors, raíces de árbol, niveles de testigo — sonWord8: ocho palabrasu32little-endian como 64 caracteres hexadecimales en minúscula. - Las direcciones protegidas son
rand1+ base58, 1.667 caracteres. Un parámetro de más de 2.000 caracteres se rechaza por su longitud antes de analizarse. - Todo importe
u64es una cadena decimal ("1500000000"= 1,5 RAND; 1 RAND = 10⁹ unidades): unidades de RAND o unidades de token, estado de la cadena o campo propio de una transacción decodificada. Un número JSON no es un entero exacto más allá de 2⁵³, y la oferta de un token de 9 decimales supera ese valor en unas pocas decenas de millones de unidades. Véase la nota fechada más abajo sobre lo que esto cambió. - Los índices, nonces, alturas, índices de hoja, vistas, longitudes, decimales y contadores de días (
mint_day) nunca son importes y son enteros JSON en todos los casos. - Toda solicitud debe llevar un miembro
id. Un objeto sin él es una notificación y se rechaza con-32600; un"id": nullexplícito es una solicitud normal. - No hay método de saldo ni método de cuenta. Una wallet calcula su saldo escaneando
rand_getCommitmentsyrand_getNullifierscon su viewing key.rand_getBalance,rand_getAccountyrand_getAssetBalanceresponden-32601.
Cambio incompatible, 2026-09-20 (chain 14): todo importe es una cadena decimal
Antes de la chain 14, los importes dentro de una transacción decodificada eran enteros JSON. Esa excepción ha desaparecido. Estos campos pasaron de números JSON a cadenas decimales, sin ningún otro cambio en su significado ni en su posición:
bundle.fee, en eltxderand_getTransactiony entransactions[]derand_getBlockByHeight/rand_getBlockByHash;action.amountparakind=mint,bond,unbond,withdraw,bridge_attest(los mismos tres métodos);action.amountyaction.relayer_feeparakind=bridge_burn(los mismos tres métodos);lockeden las filas derand_getAssetsy derand_getBridgeState.assets[].
Un cliente que lea cualquiera de estos campos como número debe analizar una cadena en su lugar. aggregation.subsidy_base de rand_status (solo en cadenas con agregación) pasó a ser una cadena en el mismo cambio. Todos los demás importes ya eran cadenas: rand_getSupply, rand_getEmission, rand_getValidators, las notas de visualización y todos los campos introducidos con la chain 14 — burn_a y burn_r del bundle, las ofertas de los tokens, el locked de cada respaldo, mint_cap_per_day y minted_today, registration_fee, y el amount de token_mint, token_burn y register_token (initial_amount, initial.amount).
Lotes
El cuerpo de un POST puede ser un arreglo de como máximo 20 objetos de solicitud, al que se responde con un arreglo de la misma longitud en el orden de las solicitudes, errores incluidos. Las solicitudes se ejecutan una tras otra. Un arreglo vacío, un arreglo de más de 20, o un cuerpo que no es ni objeto ni arreglo da un único -32600 con id nulo. El cuerpo completo sigue limitado por el límite de cuerpo de solicitud del nodo, dimensionado para una transacción con prueba: un lote de dos llamadas rand_sendTransaction con prueba se rechaza con 413. Use los lotes para lecturas, no para envíos con prueba.
Cadena y nodo
rand_chainId
Params []. Resultado: el id de la cadena (entero); 20 en la testnet.
rand_tokenInfo
Params []. Resultado { "symbol": "RAND", "decimals": 9 }.
rand_getHead
Params []. Resultado { "height": 1998, "hash": "…", "view": 2251 }. view es la vista de consenso actual del nodo, que va por delante de la altura cuando las vistas expiran.
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 nodo posee una clave de validator; active_validator: esa clave está en el conjunto que ejecuta la época actual. reserved_peers (v0.6.8) cuenta los peers admitidos por encima del límite de conexiones entrantes: los bootstraps, cualquier --reserved-peer y cada identidad de validator conocida a partir de un binding de peer firmado, cada uno una sola vez; en un nodo de la flota debería alcanzar el número de validators en el plazo de un minuto desde el arranque. viewing_keys es el número de viewing keys que el nodo mantiene en memoria para el escaneo del lado del nodo. verify_queue es el número de transacciones que esperan a uno de los cuatro workers de verificación de pruebas (64 de profundidad como máximo). hc_bundle es el guest de bundle contra el que van las pruebas de esta cadena y hc_auth el guest de auth que fija su génesis (autorización dividida, desde la chain 17), o null en una cadena que no lo tiene; un nodo cuya compilación discrepa de cualquiera de los dos se niega a arrancar. testnet y binding_domain son los campos de génesis del mismo nombre, tal como los sirve rand_getLimits. gas_prices son los precios de gas actuales del libro de propinas de la punta, actualizados en cada commit, como cadenas decimales; null en una cadena sin sección gas. Los precios de la chain 20 son dinámicos y se mueven por bloque según su ocupación, nunca por debajo de los pisos de 100 y 800 ni por encima de los techos de 10.000 y 80.000, así que léalos aquí o en rand_getLimits y no los fije en el código. El objeto incluye además un objeto aggregation (su subsidy_base es una cadena decimal, el resto enteros), que lee todo ceros en una cadena sin sección aggregation, como es la chain 20.
El objeto incluye también disk_free_bytes (un número) y disk_low, y el par de retención: prune_floor, la altura más baja que este nodo aún conserva (0 en un archivo), y prune_history_secs, la ventana que mantiene un nodo iniciado con --prune-history (null cuando lo conserva todo). En la chain 20, como en la chain 19, 24 de los 26 validators conservan 24 horas de bloques; los dos nodos de archivo conservan todos. Véase Nodos podados.
rand_getPeers
Params []. Resultado: un arreglo de { "peer_id": "12D3KooW…", "addrs": ["/ip4/…/tcp/30303"], "connected_secs": 1241 }.
rand_getBlockByHeight / rand_getBlockByHash
Params [height] o [hash]. Resultado null si se desconoce, y si no:
{
"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 se sirven los bloques confirmados. transactions tiene la misma forma que el tx de rand_getTransaction. Un bloque también incluye sealed, y cada una de sus transacciones sealed_by; valen false y null en una cadena sin agregación.
rand_getBlocks
Parámetros [from_height, to_height]. Resultado: encabezados de bloque, del más antiguo al más reciente, como máximo 1024 desde from_height (128 en un nodo anterior al 2026-09-24): los campos de rand_getBlockByHeight sin transactions. Un rango más ancho que el límite, o que sobrepasa la cabeza de la cadena, se trunca, no se rechaza, y desde v0.6.8 una página también termina cuando ha leído 64 MiB de bloques; continúe desde la última altura devuelta. -32602 si to_height es menor que from_height.
Desde v0.6.8 cada encabezado incluye además public_notes: las transacciones bridge_attest, token_mint y register_token del bloque y, en una cadena con comisiones de puente, sus transacciones bridge_burn, como [{ "hash", "raw" }] (la codificación que sirve rand_getRawTransaction); vacío en cualquier otro bloque. Una quema se sirve con sus pruebas vaciadas y "proofs_stripped": true; su hash es el identificador real de la transacción. La primera sincronización de una billetera lee estas páginas y no necesita nada más para reconstruir las notas públicas.
rand_getFinality
Parámetros [height] o [hash]. Resultado, uno de { "status": "committed", "height", "hash" }, { "status": "certified", "height", "hash", "qc_view" }, { "status": "proposed", "height", "hash" }, { "status": "unknown" }. Una altura solo se comprueba contra la cadena confirmada, por lo que responde committed o unknown; un hash también puede leerse certified (en el árbol no confirmado de la réplica, con un certificado de quórum) o proposed (en el árbol sin él).
rand_getProposer
Parámetros [view] o [from_view, to_view], como máximo 64 vistas. Resultado { "epoch": 3, "proposers": [ { "view": 2251, "proposer": "2nRdFC…" } ] }: el líder de cada vista según el conjunto de validadores actual, no el que estaba activo en esa vista históricamente. -32602 para un rango invertido o de más de 64 vistas.
rand_getVersion
Parámetros []. Resultado { "version", "git_sha", "chain_id", "hc_bundle", "hc_auth", "fri_profile" }. version es la versión del crate del workspace; git_sha el hash del commit capturado en la compilación, con -dirty añadido si los archivos rastreados diferían, o "unknown". hc_auth es el guest de autenticación del génesis, como en rand_status, o null. El endpoint público el 2026-10-01, en la cadena 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: el hash del génesis en hexadecimal; "6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135" en la cadena 20 (el de la cadena 19 era a3defc93…228a). Un identificador de cadena por sí solo no distingue dos cortes de cadena; esto sí. En la cadena 20 forma además parte de cada vinculación de transacción y de cada mensaje de acción firmado (binding_domain: 1, véase rand_getLimits).
rand_getHealth
Parámetros []. Resultado, uno de { "status": "disk_low", "free_bytes": "3221225472" }, { "status": "ok" }, { "status": "syncing", "behind": 412 }, { "status": "behind", "behind": 30 }. disk_low tiene prioridad sobre todo lo demás, cuando el espacio libre en el sistema de archivos del directorio de datos es inferior a cuatro veces el --min-free-disk-mb del nodo (1024 por defecto, es decir, menos de 4 GB); free_bytes es una cadena decimal. ok cuando sync_target - height es como máximo 2 y no hay ninguna solicitud de lote de sincronización pendiente; syncing mientras hay una; behind cuando el nodo no está sincronizando y el retraso sigue siendo superior a 2.
rand_getMempoolInfo
Parámetros []. Resultado { "count": 2, "bytes": 2611200, "oldest_ms": 1450, "max_count": 10000 }. bytes suma la longitud codificada de cada transacción en el pool; oldest_ms es null cuando el pool está vacío. Desde v0.6.8 el pool también tiene un límite en bytes, de ocho veces el max_block_bytes del génesis (160 MiB en la cadena 20): superado este, una transacción que pague más por encima de su mínimo por KiB desplaza a la más barata, y la que pague menos o lo mismo se rechaza con mempool full. Las acciones de gobernanza pasan ambos límites.
Envío
rand_sendTransaction
Parámetros [hex], donde hex es bincode(Transaction). Resultado: el hash de la transacción. El nodo valida en el orden de admisión (Transacciones), la incorpora al pool y la difunde. Los errores son -32000 con el motivo: nullifier already spent, anchor is not one of the last 1024 roots, time 12 is outside [1500, 2524] (ambas ventanas son el proof_window_blocks del génesis, 1024 en la cadena 20; 256 en las cadenas hasta la 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 un invoke, cell <key> is no longer what this transition read (un veredicto de estado: vuelva a leer la celda y genere la prueba de nuevo) o the vault holds … of asset … and the transition pays …; para un Bond de registro bajo admisión 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 un bundle que no encaja con el génesis de la cadena 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 las acciones de puente 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 un bundle que lleva una quema que su acción no puede llevar, the bundle burns asset 2 on an action that burns no token, a burn of 5 is not allowed on this action o RAND burned through burn_a (5); a RAND burn goes through burn_r; para el estado del puente, 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 el registro de tokens, wrong mint nonce y wrong token index. Aceptación no es confirmación: consulte rand_getTransaction o rand_getTransactionStatus.
Una transacción mayor que el límite de bloque de la cadena (max_block_bytes de rand_getLimits) se rechaza con -32000, indicando ambos tamaños, antes de llegar al mempool. El cuerpo de la solicitud está limitado a 2 × (2 × max_proof_bytes + 4 × 2048 + max_call_envelope_bytes + 16,384 + 64 KiB) + 256 KiB, calculado a partir del génesis al arrancar: 8 867 840 bytes en una cadena por defecto y 17 350 656 con los límites de la cadena 20, igual que las cadenas 17 a 19 (34 127 872 en las cadenas 13 a 15, cuyo límite de prueba era de 8 MiB). 4 × 2048 son los cuatro envelopes del bundle en el límite de envelope. Un cuerpo que lo supere es -32600, indicando el límite.
Solo -32000 (la admisión lo rechazó) y -32602 (no se pudo decodificar) son un veredicto sobre la transacción. Cualquier otro fallo, incluido -32603, deja su destino desconocido: el nodo incorpora al pool y difunde una transacción antes de responder, de modo que un nodo que se detiene en esa ventana puede haber admitido lo que nunca llegó a confirmar. randprotocol_client trata un envío como rechazado solo con esos dos códigos.
rand_getTransactionStatus
Parámetros [[hash, …]], de 1 a 64 hashes. Resultado: una entrada por hash, en orden:
[ { "hash": "…", "status": "committed", "height": 1998, "index": 0 },
{ "hash": "…", "status": "pending" },
{ "hash": "…", "status": "rejected", "reason": "bad mint signature" },
{ "hash": "…", "status": "unknown" } ]
Orden de búsqueda por hash: confirmada (almacenamiento), pendiente (el mempool), rechazada (la caché de rechazos que cuenta el refused_cache de rand_status), y si no, unknown. rejected abarca solo los rechazos relativos a los bytes propios de la transacción, que ningún bloque posterior puede cambiar: una prueba no válida, un digest del bundle que no es el que publicó su prueba, una firma de acuñación incorrecta, un identificador de cadena equivocado, una parte de tamaño excesivo, un nullifier o compromiso repetido dentro de la transacción, un envelope de tamaño incorrecto, una prueba de autenticación ausente o que no coincide, un bundle o una prueba de autenticación que declara un límite de gas incorrecto. Un rechazo que depende del estado del nodo en ese momento —un nullifier ya gastado, un ancla o un time fuera de la ventana, una comisión por debajo del mínimo (que en la cadena 20 varía con los precios del gas), un programa desconocido, un nonce de registro, una lectura obsoleta de invoke— no se recuerda y se lee como unknown. -32602 para una lista vacía o de más de 64 hashes.
rand_mint (faucet de testnet)
Parámetros [address] o [address, amount]; address es una dirección rand1…, amount una cadena de unidades de como máximo 100000000000 (100 RAND, el valor por defecto). Resultado: el hash de la transacción de acuñación. Solo en una cadena cuyo génesis tenga "faucet": true; de lo contrario, -32000 faucet is disabled on this chain. Un observador responde faucet mints are signed by validators; ask a validator node.
En una cadena cuyo génesis define staking.faucet_recipients, como el de la cadena 20 (16 billeteras), solo se puede pagar a las billeteras listadas: una acuñación a cualquier otra dirección se rechaza con the faucet may not mint to this recipient (not in staking.faucet_recipients). El génesis de la cadena 20 también define staking.faucet_minters (18 claves de validador): solo una clave listada puede firmar una acuñación. El faucet también tiene un presupuesto por época, staking.faucet_budget_per_epoch (10 000 RAND por época de 1000 bloques en la cadena 20); una acuñación que lo supere se rechaza con FaucetBudgetExhausted, un veredicto de estado que se lee como unknown una vez que sale del pool.
La faucet tiene un límite de frecuencia por proceso de nodo: ocho acuñaciones seguidas, con una recarga de una por segundo. Superado ese límite, la llamada responde faucet is rate limited on this node (8 mints back to back, refilling at 1/s); try again shortly. Por tanto, una avalancha de peticiones a la faucet no puede llenar el pool antes de un PauseMints del puente, que, como las otras tres acciones de gobernanza del puente, también está exento del rechazo mempool full del pool y se ordena primero en un bloque.
Desde la chain 14, una acuñación es abierta: la acción Mint incluye pk, time y r de la nota junto a cm y amount; la admisión recalcula el compromiso y rechaza un cm que no se abra a esos valores (the mint's commitment does not open to its published note and amount), y el minter firma los siete campos bajo el dominio rand-mint-2; en la chain 20 (binding_domain: 1), bajo rand-mint-3, con el hash de génesis en primer lugar. Por tanto, el propietario y el importe de una nota de la faucet son públicos, igual que el pago de un retiro. Los parámetros de rand_mint no cambian.
rand_estimateFee
Parámetros [spec], con spec igual a {"kind":"bundle"}, {"kind":"deploy","words":n,"public_words":m} o {"kind":"call","tier":t,"bytes":b,"gas":g}, con t en 10, 12, 14, 16, 18, 20. Resultado: la comisión mínima en unidades, como cadena de texto. {"kind":"bundle"} es "1000000". public_words (opcional, 0 por defecto) se paga por palabra, igual que el código, de modo que la comisión es la de un despliegue de n + m palabras. bytes (opcional, 0 por defecto) es la longitud de la prueba de la llamada más la longitud de su envoltorio de entrada.
Cómo se fija el precio de una llamada depende del gas_metering de rand_getLimits:
"circuit", una chain con su propia seccióngas, como la chain 20.gases el límite de gas que declara la prueba de la llamada y es obligatorio: sin él, la llamada responde-32602under the gas section a call estimate needs its gas. El resultado es1,000,000 + gas_price × gas + byte_price × ⌈bytes / 1024⌉a los precios vigentes en la punta de la cadena, los que sirverand_getLimits. Con los precios mínimos de la chain 20, 100 y 800, una llamada que declara 20,479 de gas con 1,300,000 bytes de prueba y envoltorio cuesta"4063900". Los precios cambian en cada bloque, así que conviene estimar justo antes de enviar."header", una política de gas a nivel de nodo en una chain sin la sección. La especificación de la llamada admitekeccak_log_heightysha256_log_height(opcionales, 0 por defecto, cada uno de 0 a 40; de lo contrario,-32602), las alturas de las tablas de hash que declara la cabecera de la prueba, y el resultado es el mayor entre el mínimo de nivel del libro mayor y el mínimo de gas de esa cabecera. Bajo una seccióngas, las dos alturas se aceptan pero no se usan.null, ninguno de los dos. Solo el esquema de niveles del libro mayor: hasta la franquicia gratuita (2,097,152 + 18,432 bytes), una llamada cuesta la comisión de su nivel; cada KiB por encima, contando como entero el KiB parcial, añade 1,000 unidades.
Desde v0.6.8, {"kind":"invoke", …, "created_cells": c} fija el precio de un invoke de RPL-2: todos los campos de una especificación de llamada, más created_cells (opcional, 0 por defecto, como máximo max_writes; de lo contrario, -32602), las celdas que crearía la transición. Cada una añade el cell_fee de la chain (rand_getLimits.program_state). Las cuenta quien llama: una escritura de un valor distinto de cero en una celda que rand_getProgramCell lee como ceros. En la chain 20, la llamada anterior con dos celdas creadas cuesta "24063900". En una chain sin sección program_state, este tipo da -32602.
Comisiones contiene el esquema.
El pool
rand_getTreeInfo
Parámetros []. Resultado { "next_index": 41, "root": "6b1d…c4", "nullifiers": 12 }: el número de hojas, la raíz actual y cuántas notas se han gastado.
rand_getCommitments
Parámetros [from_index] o [from_index, limit]. Resultado: una página de hojas a partir de from_index, de la más antigua a la más reciente, con un máximo de 1,000 filas por grande que sea limit.
[ { "index": 40, "cm": "2a9f…07", "height": 37,
"envelope": { "kem_ct": "b41c…", "to_receiver": "77e0…", "to_sender": "0c31…", "body": "9dd2…" } } ]
rand_getNullifiers
Parámetros [from_height] o [from_height, limit]. Resultado: todos los nullifiers publicados desde esa altura en adelante, con el mismo tope de 1,000 filas. Una página puede detenerse dentro de una altura; retroceda hasta la mayor altura vista.
[ { "height": 37, "nullifier": "8c04…d1" }, { "height": 41, "nullifier": "12be…9a" } ]
rand_getCompactBlocks
Parámetros [from_height, to_height], ambos obligatorios. Resultado: una fila por bloque, de la más antigua a la más reciente, con lo que necesita una wallet ligera y nada más:
[ { "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"] } ] } ]
Cada transacción que lleva un bundle posee aquí cuatro notas y cuatro nullifiers: sus cuatro ranuras, incluidas las ranuras ficticias, que ningún lector puede distinguir de las reales (solo se muestra la primera fila de compromisos del ejemplo). Desde v0.6.8, algunas poseen más notas, después de esas cuatro: un invoke posee una nota por pago, primero pays y luego mints, cada una con el envoltorio propio del pago, de modo que el beneficiario la encuentra mediante descifrado de prueba; en una chain con comisiones de puente, como la chain 20, un bridge_burn posee su nota de comisión de tesorería, y un bridge_attest posee su nota de comisión después de su depósito. El envoltorio de una nota de comisión está vacío, sellado para nadie: la wallet de tesorería reconstruye la nota a partir de los campos públicos de la transacción.
Como máximo 128 bloques por llamada (un rango mayor se recorta) y, después del primer bloque, que siempre se sirve completo, 1,000 notas; continúe desde el último height devuelto más uno. El arreglo commitments a nivel de bloque contiene los depósitos de génesis en la altura 0 y está vacío en las demás; las notas derivadas de un Withdraw y de un BridgeAttest aparecen bajo su transacción. -32602 para un rango invertido o un límite ausente.
rand_getAnchor
Parámetros [] para la cabeza, o [height]. Resultado { "height": 192, "root": "6b1d…c4" }, o -32001 para una altura sin ancla registrada. Solo las raíces de fin de bloque son anclas. El nodo puede responder para una altura antigua, pero el ancla de un bundle solo es admisible si es una de las últimas proof_window_blocks raíces: 1,024 en la chain 20, 256 en las chains hasta la 19. Construya contra la cabeza.
rand_getWitness
Parámetros [index]. Resultado null más allá del final del árbol; en caso contrario, la ruta de Merkle de esa hoja, desde la hoja, exactamente 32 niveles, con la raíz actual del árbol:
{ "index": 40, "root": "6b1d…c4", "path": ["0000…00", "f2a1…3b", "…"] }
Es la lectura más costosa que sirve el nodo (reconstruye el árbol completo de profundidad 32) y la única petición que revela algo sobre quien la hace. Un nodo ejecuta como máximo dos reconstrucciones del árbol a la vez, entre rand_getWitness y rand_getWitnesses juntos; una petición que espera más de 10 s por una ranura se rechaza con -32000 witness builds are busy on this node; retry shortly.
rand_getWitnesses
Parámetros [[index, …]], de 1 a 32 índices de hoja. Resultado { "root": "…", "witnesses": [ { "index": 7, "path": ["…"] }, { "index": 9, "path": null } ] }: rand_getWitness aplicado a muchas hojas en una sola construcción del árbol, de modo que una wallet que prueba varias notas paga la reconstrucción una sola vez. Un índice más allá del final del árbol da path: null en esa entrada. -32602 para una lista vacía o con más de 32 índices.
Claves de visualización y divulgación
rand_importViewingKey
Parámetros [viewing_key] o [viewing_key, rescan_from_height], la clave como 64 caracteres hexadecimales. Resultado { "imported": true, "rescan_from_height": 0, "viewing_keys": 3 }. El nodo guarda la clave solo en memoria: como máximo 64 por nodo, y se borran al reiniciar; una clave que ya está guardada no tiene efecto ("imported": false). La importación nunca escanea; el escaneo lo impulsa el siguiente método. -32602 para una clave mal formada; -32000 en la clave 65.
Los tres métodos de claves de visualización responden solo a un llamante de loopback y rechazan a cualquier otro con -32000, salvo que el nodo se ejecute con --rpc-viewing-open detrás de algo que autentique. rand_removeViewingKey ([viewing_key] → { "removed": bool, "viewing_keys": n }) libera una ranura y pone a cero la clave. El registro se indexa por un identificador unidireccional de la clave, blake3("rand-viewing-registry-id-1" ‖ nk), nunca por la clave misma, de modo que la importación es la única copia de larga duración y la eliminación la borra. El texto JSON de la propia petición y las copias transitorias que hace el descifrado de prueba no se borran.
rand_getViewingNotes
Parámetros [viewing_key] o [viewing_key, from_index, limit] (limit por defecto y máximo: 1,000). Cada llamada avanza el escaneo de la clave hasta 10,000 hojas y luego sirve la 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 es received (el envoltorio se abrió como receptor y la nota nombra el pk de la clave) o sent (se abrió mediante la clave de visualización saliente). El memo de la nota es el memo cifrado del remitente, texto UTF-8 de como máximo 510 bytes, o null cuando no hay ninguno o su campo se abrió mal formado; un memo mal formado nunca le cuesta la nota al beneficiario. Un memo es texto de cualquiera: muéstrelo como no confiable. -32001 para una clave que este nodo no ha importado.
rand_checkTransaction
Parámetros [hash, key], con key una TxKey por transacción como 64 caracteres hexadecimales. Resultado null para un hash desconocido; en caso contrario, lo que revela la clave:
{ "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" } } ] }
Sin estado: la clave se descarta con la llamada. output es bundle:0 … bundle:3 para las cuatro ranuras de salida del bundle (las ranuras 0–1 son las salidas de activo privado, las ranuras 2–3 las salidas de RAND, con los señuelos incluidos), deposit para el sobre de depósito de una atestación de puente, token_mint para la nota de un TokenMint, initial_mint para la emisión inicial de un RegisterToken, mint:0 para el único sobre de una emisión del faucet o (v0.6.8) payout:0 … payout:3 para las notas que pagó un invoke, numeradas según su lugar en la transición, primero pays y luego mints; asset_bundle:* desaparece junto con el segundo bundle. En una cadena con comisiones de puente, deposit abre el depósito neto, es decir, el bruto menos la comisión. La note revelada incluye su asset: esta llamada, con la clave bajo la que la selló el remitente, es el único lugar donde el RPC revela qué activo movió una transferencia. También incluye el memo, igual que rand_getViewingNotes: la clave que abre la nota abre el memo, desde el mismo cuerpo sellado. Una clave incorrecta devuelve { "disclosed": [] }, indistinguible de una transacción que no revela nada. Los sobres de un retiro y de una asignación de génesis no se prueban: se sellan dentro del nodo bajo claves que se descartan de inmediato, de modo que no existe ningún TxKey para ellos. El de una emisión del faucet sí se prueba: su destinatario recupera la clave mediante la mitad KEM del sobre (rand tx-key).
Transacciones
rand_getTransaction
Parámetros [hash]. Resultado null hasta que se confirma y, después:
{
"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 es null en las acciones sin bundle. Las pruebas y los sobres se informan solo por su longitud. envelope_len es 1860 para cada ranura en la cadena 20, cuyo génesis fija el sobre de la nota en ese tamaño (envelope_bytes en rand_getLimits); era 1348 en las cadenas 14 a 17. auth_commit y auth_proof_bytes corresponden a la autorización dividida (desde la cadena 17): el compromiso público c = H(AUTH, nk, salt) que publican tanto la prueba del bundle como la prueba de autorización, y la longitud de la prueba de autorización. En una cadena sin hc_auth son ceros y 0.
bundle es el bundle de activo oculto (desde la cadena 14): cuatro ranuras de entrada y cuatro de salida, de modo que siempre hay cuatro nullifiers, cuatro commitments y cuatro envelope_len, con los señuelos incluidos. Cada transacción lleva como máximo uno; no hay un segundo bundle. No tiene campo asset: las ranuras 0–1 llevan un activo privado y las ranuras 2–3 RAND, y nada público indica qué activo movieron las ranuras 0–1. Una transferencia de RAND y una transferencia de cualquier token RPL son ambas "kind": "none" con burn_a, burn_r y burn_asset todos en 0: la misma forma, campo por campo. No existe un tipo token_transfer. Los tres campos de quema son la única declaración pública del bundle sobre valor que sale del pool:
burn_a/burn_asset: una cantidad del activo privado quemada y cuál es ese activo. Es distinta de cero en untoken_burno unbridge_burn, donde igualan elamounty elassetde la acción, y en uninvokecuyoinflowesdepositoburn.burn_r: RAND quemado. Es distinto de cero en unbond(igual a suamount), unregister_aggregatory uninvokeque deposita RAND en la bóveda del programa.fee: la comisión en RAND, siempre procedente de las ranuras 2–3.
Representación de las acciones (cada amount, relayer_fee e initial_amount es una cadena decimal; las cantidades de un token están en sus propias unidades, no en las de RAND):
| tipo | campos |
|---|---|
none | — |
mint | cm, amount, minter (validator en base58) |
deploy | program, words, public_words_len |
call | program, proof_len, input_envelope_len (null cuando la llamada no lleva ninguno) |
bond | validator, amount, registered |
unbond | validator, amount, nonce |
withdraw | validator, amount, nonce, time |
bridge_attest | attestation_len, recipient, asset, asset_index, amount, time, r, commitment, pq_signers (los índices de los guardianes cofirmantes en pq_guardians; las firmas de 2420 bytes no se muestran). asset_index, amount y commitment son null en una rotación del conjunto de guardianes. r es derivado, blake3("rand-deposit-r-1" ‖ mu) sobre el digest que firmaron los guardianes. Desde v0.6.8 también deposit_amount (la nota del depositante: amount, el bruto que firmaron los guardianes, menos la comisión de puente) y fee_note ({ amount, asset, time, r, commitment }, la nota de la tesorería sin su propietario, o null sin comisiones de puente); commitment es la hoja del depósito neto |
bridge_burn | asset, amount, relayer_fee, to_chain, token (el respaldo que se redime), to. Un bundle lleva toda la quema: sus burn_asset y burn_a son el asset y el amount de la acción. Desde v0.6.8 también release_amount (lo que libera el cuerpo firmado, amount menos la comisión de puente) y fee_note, como en una atestación |
register_token | name, symbol, decimals, authority ("none", "key", "bridge" o "program"), index, initial_amount, initial ({ amount, recipient, time, r } o null) |
token_mint | asset, amount, recipient, time, r, nonce |
set_authority | asset, nonce, new_authority (base58, o null en una renuncia) |
token_burn | asset, amount; los burn_asset / burn_a del bundle los repiten |
pause_mints | nonce; sin bundle y sin comisión, firmada por la clave de pausa del génesis |
unpause_mints | nonce, pq_signers; sin bundle y sin comisión |
register_bridged_token | name, symbol, salt, chain, token, decimals (los decimales de origen del primer respaldo), nonce, asset_id, pq_signers |
list_backing | token_index, chain, token, decimals, nonce, pq_signers |
rotate_pq_guardians | new_pq_guardians, nonce (el rotation_nonce consumido), pq_signers (índices en el conjunto PQ previo a la rotación); sin bundle y sin comisión, solo en cadenas de puente con rules_v2 |
rotate_pause_key | new_pause_key, nonce, pq_signers; lo mismo |
rotate_pq_guardians_v2, rotate_pause_key_v2 | v0.6.8: los campos de v1, más possession_signatures (un recuento) en la forma PQ. Sin bundle y sin comisión; obligatorias en una cadena cuyo bridge.rotation de génesis establece needs_possession, como el de la cadena 20. La rotación surte efecto delay_secs después (86 400 s en la cadena 20) |
cancel_rotation | v0.6.8: rotation_kind ("pq_guardians" o "pause_key"), nonce; firmada por la clave de pausa vigente, descarta una rotación pendiente |
admit_validator | v0.6.8: candidate (dirección), candidate_key (hex), voters (direcciones). Sin bundle y sin comisión: el voto del conjunto de validators para dejar que se registre una nueva clave, en una cadena con staking.admission_by_vote, como es la cadena 20 |
slash_equivocation | v0.6.8: offender, view, first y second ({ hash, height }); solo en cadenas con staking.slashing, que la cadena 20 no tiene |
invoke | v0.6.8, RPL-2: los campos de una llamada (program, proof_len, input_envelope_len) y su transition (más abajo). Solo en cadenas con una sección program_state, como la cadena 20 |
register_aggregator, unbond_aggregator, withdraw_aggregator, slash_aggregator, aggregate | sus campos públicos; solo en cadenas con agregación |
claim_vested, revoke_vesting, bond_vested, unbond_vested | entry (hex), amount (unvested en una revocación), nonce; time en un reclamo o una revocación; validator y registers en un bond; desde v0.6.8 signers en una revocación (las posiciones de sus firmantes en los revokers de la entrada). Sin bundle; solo en cadenas con una sección vesting en el génesis, que la cadena 20 no tiene |
El registro y las emisiones de un token son públicos, igual que un depósito de puente: cada palabra de una nota emitida está en la acción (su from es el MINT_FROM fijo de la cadena), de modo que el destinatario reconstruye la nota a partir de estos campos sin descifrar nada. Las cadenas de tipo bridge_attest, token_mint, register_token e invoke son aquellas en las que se basa el escaneo de la wallet y están fijadas por una prueba.
Un invoke en la altura 3079 de la cadena 20, que leyó una celda, la eliminó y pagó dos notas desde la bóveda:
{ "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": [] } }
Todo ello es público por diseño. reads son las celdas que leyó el programa, con los valores que leyó: la prueba se hizo contra ellos y el ledger rechaza la transacción a menos que sigan vigentes. writes son las celdas que escribió; un valor escrito de 64 ceros elimina la celda. La clave o el valor de una celda es un Word8. Lo que entró es del bundle: burn_r es RAND depositado en la bóveda del programa, y burn_a de burn_asset es el token que nombra inflow, deposit en la bóveda o burn (el token propio del programa), none cuando burn_a es 0. Lo que salió es una nota calculada por la cadena por cada pago: primero pays desde la bóveda y luego mints de un token cuya autoridad de emisión es este programa. Cada palabra de cada nota está aquí bajo los nombres de campo de un token_mint; time es el del bundle, cm la hoja que la cadena añadió, y el from de la nota es el PROGRAM_FROM fijo de la cadena. Las ocho palabras de salida del programa figuran en el recibo, igual que las de una llamada.
Ninguna respuesta de transferencia incluye remitente, destinatario, nonce, cantidad ni activo: en una transferencia almacenada no existe ningún campo de ese tipo.
rand_getRawTransaction
Parámetros [hash]. Resultado: la transacción confirmada completa como hex de bincode, con los bytes de la prueba incluidos: lo que necesita un aggregator y que rand_getTransaction nunca muestra.
Programas y recibos
rand_getProgram
Parámetros [program_id]. Resultado null o { "id", "base_pc", "words_len", "code_hash", "deployed_at", "public_words_len", "public_digest" }. No hay campo deployer: un despliegue lo paga un bundle. public_words_len es la longitud de la entrada pública del programa fijada al desplegarlo (0 si no tiene); public_digest es su digest, el valor contra el que se comprueba la prueba de cada llamada, o null si no tiene.
rand_getProgramCode
Parámetros [program_id]. Resultado null o { "base_pc": 0, "words": [ … ] }.
rand_getProgramPublic
Parámetros [program_id]. Resultado: las palabras públicas del programa fijadas al desplegarlo, como una sola cadena hexadecimal, cada palabra en sus 4 bytes little-endian (8 dígitos hexadecimales por palabra): [1, 2, 0xdeadbeef] es "0100000002000000efbeadde". "" para un programa desplegado sin entrada pública, null para un id que ningún programa tiene. Una wallet que prueba una llamada pasa estas palabras al prover; el libro mayor comprueba el compromiso de la prueba contra el public_digest del programa.
rand_getProgramCell
v0.6.8, RPL-2. Parámetros [program_id, key], con la clave como un Word8 en 64 dígitos hexadecimales (con o sin 0x). Resultado { "key": "<64 hex>", "value": "<64 hex>" }. Una celda que el programa nunca escribió, o en la que escribió ceros (lo que la elimina), se lee como 64 ceros, la única codificación de «ausente»; lo mismo ocurre con cualquier clave de un programa que nadie desplegó, ya que no se comprueba la existencia del programa. { "enabled": false } en una cadena sin sección program_state. Una celda es pública por diseño: es lo que una wallet lee para construir los reads de un invoke.
rand_getProgramCells
v0.6.8. Parámetros [program_id, { "after": "<64 hex>" | null, "limit": n }], con el objeto opcional. Resultado { "cells": [{ "key", "value" }, …], "next": "<64 hex>" | null }: las celdas del programa en orden de clave (una comparación sin signo de las ocho palabras), a partir de after, como máximo limit de ellas (limitado al rango de 1 a 1000). next es la última clave servida cuando quedan más; se devuelve como after. Es null en la última página. Un programa sin celdas responde { "cells": [], "next": null }; { "enabled": false } sin la sección.
rand_getProgramVault
v0.6.8. Parámetros [program_id]. Resultado [{ "asset": 0, "amount": "123" }, …], en orden ascendente por índice de activo (0 es RAND, cualquier otro índice es el del registro de tokens), con los importes como cadenas decimales en las unidades propias del activo. Una fila en cero no existe, así que una bóveda vacía, y un programa que nadie desplegó, es []. { "enabled": false } sin la sección. El valor entra en una bóveda a través del paquete de un invoke (burn_r, y burn_a de burn_asset cuando el inflow es deposit) y sale como las notas que nombran los pays de la transición.
rand_getLimits
Parámetros []. Resultado: lo que una wallet necesita del génesis de la cadena para construir una transacción: los cinco límites de llamada, el tamaño del sobre de la nota, el interruptor v0.6, el guest de autenticación, los términos de gas y, desde v0.6.8, los campos de génesis de audit-v6 y los límites del estado de programa. En la cadena 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 génesis sin los cinco campos de límite (cadena 12) obtiene 4096, 2097152, 4194304, 18432 y 0. max_proof_bytes era 8 388 608 en las cadenas 13 a 15.
| field | meaning |
|---|---|
envelope_bytes | 1860 cuando el génesis fija cada sobre que crea notas exactamente en esa longitud, el formato que lleva memo; null en un génesis sin el campo (cadenas 14 a 17), donde una wallet sella el sobre de 1348 bytes sin memo. No existe ningún otro valor |
hardening_v6 | true cuando el génesis aplica las reglas de validez v0.6. Entonces una wallet prueba una llamada sobre la entrada pública del programa seguida del binding de llamada de la transacción, y no solo sobre la entrada pública: primero se eligen las notas del paquete de comisión, en segundo lugar se prueba la llamada y por último el paquete. Una cadena con la bandera rechaza la prueba antigua, y una cadena sin ella rechaza la nueva |
hc_auth | el guest de autenticación que fija el génesis, en hexadecimal, o null. Si está definido, hc_bundle es el guest de paquete v3 y cada paquete lleva auth_commit y una prueba de autenticación: la wallet entrega al guest de paquete nk y una sal nueva, y prueba el guest de autenticación sobre la clave de gasto |
gas_metering | "circuit" en una cadena cuyo génesis tiene una sección gas (el medidor dentro del circuito); "header" en una cadena sin ella cuando el nodo aplica su propia política de gas (--gas-price, --byte-price); null en ninguno de los dos casos |
gas_price, byte_price | unidades por gas y unidades por KiB del sobre de prueba y entrada de una llamada, como cadenas decimales. Bajo una sección gas son estado de consenso e iguales en todos los nodos: con gas.dynamic, como en la cadena 20, los precios vigentes en la punta, que se mueven por bloque según su ocupación, nunca bajan de los pisos del génesis (100 y 800) y nunca suben por encima de los techos; sin ella, los precios fijos de la sección. Sin sección son la política propia de este nodo, y dos nodos pueden responder de forma distinta |
bundle_gas_limit | el gas fijo que toda prueba de paquete debe declarar, tomado de la sección gas del génesis; null sin ella |
adjust_bps | el mayor movimiento de precio en un bloque que permite el controlador dinámico, en puntos básicos; null en una cadena sin gas.dynamic |
max_gas_price, max_byte_price | v0.6.8: los techos sobre los que el controlador nunca eleva un precio, como cadenas decimales; "10000" y "80000" en la cadena 20, null donde el génesis no fija ninguno (cadenas 18 y 19) |
byte_load | v0.6.8: "paying" cuando solo el sobre de prueba y entrada de una llamada mueve byte_price, de modo que un bloque de transferencias no mueve ninguno, como en la cadena 20; null donde cuentan los bytes de todas las transacciones (cadenas 18 y 19) |
admission_by_vote | v0.6.8: si un bond que registra una nueva clave de validador necesita antes el voto del conjunto de validadores (rand_getAdmitted); true en la cadena 20 |
testnet | v0.6.8: la marca testnet del génesis, que permite que un faucet conviva con una sección de bridge; true en la cadena 20, false en todas las anteriores |
slashing | v0.6.8: { "equivocation_bps", "jail_epochs" }, lo que cuesta que un líder incurra en equivocación, o null; null en la cadena 20 |
binding_domain | v0.6.8: 0 cuando el binding de una transacción y todo mensaje de acción firmado se ligan solo al id de la cadena (cadenas 14 a 19), 1 cuando incluyen además el hash del génesis, de modo que una prueba o firma hecha para una cadena no se verifica en ninguna otra (cadena 20). Una wallet decide qué forma probar según el id de la cadena, nunca según esta respuesta: la wallet rand v0.6.8 aplica a los ids de cadena 14 a 19 la forma con id de cadena y a cualquier otro id la forma ligada al génesis, y lee este campo solo para rechazar con antelación. Una wallet anterior a v0.6.8 no puede enviar en la cadena 20 |
proof_window_blocks | v0.6.8: la antigüedad máxima, en bloques, del ancla de un paquete y cuánto puede quedar su time por detrás de la altura, una sola ventana para ambos; 1024 en la cadena 20, null (256) en las cadenas hasta la 19. Una wallet con un prover lento o delegado lo lee para saber cuánto puede tardar una prueba |
program_state | v0.6.8, RPL-2: la sección program_state del génesis y sus límites de invoke, o null, en cuyo caso todo invoke es rechazado y no se puede registrar ningún token de programa. cell_fee son las unidades de RAND (una cadena decimal) que gana el piso de comisión de un invoke por cada celda que crea, es decir, una escritura de un valor distinto de cero en una celda que se lee como ceros; reescribir, eliminar o escribir ceros no cuesta nada. max_reads, max_writes y max_payouts (pays y mints juntos) son topes estrictos. En la práctica, la regla de segmento actúa primero: las palabras de contexto de la transición (11 + 16 por lectura o escritura + 3 por pago) deben caber junto a la entrada pública del programa y las 8 palabras de binding sin hacer crecer la tabla pública del zkVM; para un programa sin entrada pública esa tabla es de 128 filas, lo que deja 119 palabras de contexto |
Un nodo anterior a un campo responde sin él. Nada de esta respuesta está autenticado, así que una wallet no toma envelope_bytes solo por la palabra del nodo: la wallet rand sella el sobre heredado en los ids de cadena 14 a 17 sea cual sea la respuesta del nodo, y los demás clientes deberían hacer lo mismo.
rand_getReceipt
Parámetros [tx_hash]. Resultado null hasta que la llamada se confirma, y luego { "tx", "program", "tier": 14, "outputs": [1, 0, 25, 0, 0, 0, 0, 0], "height": 17, "index": 0, "h_in": "9c0e…7f", "h_pub": null }. Sin campo effect. h_pub es el digest de la entrada pública del programa fijada al desplegarlo, contra la que se comprobó la prueba de la llamada, null para un programa sin ella. Un invoke (v0.6.8) tiene el recibo de una llamada, y rand_getReceipts y el tema receipts lo transportan sin cambios.
rand_getReceipts
Parámetros [program_id, from_height, to_height, limit?]. Resultado { "receipts": [ … ], "next_height": 2051 }: los recibos de program_id con from_height <= height <= to_height, por altura y luego por índice, cada uno exactamente el objeto de rand_getReceipt. limit tiene por valor predeterminado 256, que es también su tope, y nunca parte una altura: una vez que una página contiene limit recibos, sigue sirviendo el resto de esa altura. next_height es la primera altura no servida, o null cuando to_height puso fin a la página. -32602 si to_height es menor que from_height.
rand_getCallEnvelope
Parámetros [tx_hash]. Resultado null, o { "tx", "h_in", "kem_ct", "to_sender", "to_auditor", "body" } en hexadecimal — la transcripción de entrada sellada de la llamada, servida tal cual; el nodo no posee ninguna clave que la abra. null cuando la llamada no publicó ninguna (--no-envelope), la transacción no es una llamada o no hay recibo.
Staking y suministro
rand_getValidators
Parámetros []. Resultado: una fila por cada entrada del registro, en orden de dirección, con los importes como cadenas decimales:
[{ "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) es la primera época en la que una clave penalizada puede volver a estar en un conjunto (18446744073709551615 para siempre), null cuando no está encarcelada. La cadena 20 no tiene staking.slashing, así que allí siempre es null.
rand_getAdmitted
v0.6.8. Parámetros []. Resultado { "admission_by_vote": true, "max": 256, "admitted": ["<address>", …] }: las claves que el conjunto de validadores ha admitido por votación con un AdmitValidator y que aún no se han registrado, en orden de dirección. En una cadena cuyo génesis establece staking.admission_by_vote, como el de la cadena 20, un Bond que registre una clave nueva debe estar entre ellas. max es cuántas retiene el libro mayor a la vez. En una cadena sin el indicador, admission_by_vote es false, la lista siempre está vacía y un registro no requiere voto. La cadena 20 respondió "admitted": [] el 2026-10-01.
rand_getEpoch
Parámetros []. Resultado { "epoch": 41, "epoch_blocks": 1000, "next_set": ["…", "…"] }; next_set es una proyección.
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 y slashed solo se mueven en una cadena con agregación. faucet_epoch y faucet_minted_in_epoch son el contador por época del faucet frente a staking.faucet_budget_per_epoch (estado de consenso en la cadena 20). Los cuatro campos vesting_* son los contadores del vesting del génesis, todos "0" en una cadena sin sección vesting, como es la cadena 20. program_rand_out y program_rand_held (v0.6.8, RPL-2; "0" sin una sección program_state) son el RAND que las invocaciones han pagado desde las bóvedas de programa como notas (lado del pool, dentro de pool_value) y lo que las bóvedas aún retienen (lado del registro, dentro de total_supply); entró mediante el burn_r de una invocación, por lo que está dentro de burned en el lado del pool. registration_fees_burned es Σ de las comisiones de registro de tokens quemadas según el tokens.burn_registration_fee del génesis, que la cadena 20 establece; invariant_holds la resta, junto con slashed, de lo que la cadena emitió. Supply explica la identidad.
rand_getEmission
Parámetros []. Resultado { "inflation": "0", "subsidy": null, "faucet": true }. inflation es un "0" fijo. subsidy es el calendario de agregación de bloques (current, base, halving_blocks, sealed_blocks, next_halving_at) y null en una cadena sin sección aggregation, como es la cadena 20. faucet refleja rand_status.
Bridge
Los cuatro responden en cualquier cadena; en una cadena sin sección bridge el estado es { "enabled": false } y el registro es []. El génesis de la cadena 20 tiene una: el conjunto de guardianes 1 (guardian_set_index 1) con ocho guardianes, ocho guardianes PQ, una clave de pausa, burn_sequence 13 en el génesis, un umbral de repetición (min_inbound_sequence 3 para las cadenas de origen 2, 3 y 4, y 7 para la cadena de origen 5), rules_v2 del bridge con un tope global de emisión de 4,000 zUSD por ventana de 24 horas entre todos los respaldos, y dos grupos nuevos en v0.6.8: rotation (una rotación de guardianes PQ o de la clave de pausa requiere prueba de posesión de las nuevas claves y entra en vigor 86,400 s después de confirmarse) y fees (10 bps de cada depósito y 10 bps de cada quema, retenidos en Rand como una nota zUSD a una dirección de tesorería). La cadena 19 tenía burn_sequence 8, umbrales de 1 y 4, y ninguno de los dos grupos. Su sección tokens tiene un registration_fee de 1 RAND (quemado), un mint_cap_per_day por respaldo de 10000000000000 (100,000 zUSD con ocho decimales) y lista al propio zUSD: trasladado desde la cadena 14 en el génesis, con el mismo id de activo, índice 1, siete respaldos.
rand_getBridgeState
Parámetros []. Resultado { "enabled": false }, o:
{
"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": [ … ]
}
| field | meaning |
|---|---|
emitter | la dirección del emisor saliente de esta cadena, 32 bytes en hex |
emitters | id de la cadena de origen → la dirección del emisor de confianza allí |
guardians | las direcciones de 20 bytes del conjunto actual, en hex |
pq_guardians | el conjunto PQ: claves públicas Dilithium2 (1,312 bytes), en hex, alineadas por índice con el conjunto de guardianes actual (el conjunto 1 en la cadena 20). Cada BridgeAttest lleva un quórum de cofirmas de este conjunto. Una rotación del conjunto de guardianes nunca lo mueve; solo lo hace un rotate_pq_guardians, en una cadena rules_v2 |
mint_paused | mientras sea true, toda attest de transferencia se rechaza con bridge minting is paused; las quemas y las rotaciones siguen abiertas |
pause_nonce | lo que debe llevar la siguiente pausa o reanudación; ambas lo incrementan |
list_nonce | lo que debe llevar el siguiente register_bridged_token o list_backing; ambos lo incrementan |
pause_key | la única clave Dilithium2 que puede pausar la emisión, en hex. Solo puede pausar: reanudar requiere el quórum de guardianes PQ |
registration_fee | lo que debe un RegisterBridgedToken además de la base del paquete, en unidades de RAND, como cadena decimal |
burn_sequence | mensajes salientes emitidos hasta ahora |
rotation_nonce | lo que debe llevar el siguiente rotate_pq_guardians / rotate_pause_key |
rules_v2 | el tope global de emisión y su ventana móvil, o null en una cadena sin las reglas v2 del bridge. Bajo ellas, el tope por respaldo también es una ventana móvil, y se rechaza un listado mientras la emisión está en pausa. Desde v0.6.8 también incluye global_minted_in_window y global_mint_headroom, cadenas decimales |
min_inbound_sequence | el umbral de repetición del génesis: id de la cadena de origen → la secuencia más baja que puede llevar una transferencia desde esa cadena, números simples; null en una cadena sin él (cadena 15 y anteriores). Un bridge_attest por debajo se rechaza con BelowReplayFloor, un veredicto permanente. Un relayer lo lee para descartar un bloqueo que la cadena de la que se derivó esta ya emitió |
rotation_rules | v0.6.8: { "delay_secs", "needs_possession" } del bridge.rotation del génesis, o null. Bajo ellas, una rotación es la acción _v2, que lleva las firmas de posesión de las nuevas claves, y espera delay_secs antes de entrar en vigor |
pending_rotations | v0.6.8: rotaciones confirmadas que aún no están en vigor, cada una { "kind": "pq_guardians", "new_pq_guardians", "effective_at_secs" } o { "kind": "pause_key", "new_pause_key", "effective_at_secs" }; null sin rotation_rules. Un cancel_rotation firmado por la clave de pausa actual descarta una |
fees | v0.6.8: { "mint_bps", "burn_bps", "recipient" } del bridge.fees del génesis, o null (cadenas 14 a 19). La cadena retiene esa parte de cada depósito y de cada quema, redondeada hacia abajo a una unidad de liberación completa del respaldo, como una nota zUSD para recipient. Un depósito acredita el monto bruto menos la comisión; el cuerpo firmado de una quema libera su monto menos la comisión. Una wallet lo lee para valorar su propio depósito y, cuando es recipient, para reconstruir sus notas de comisión |
assets | las filas de rand_getAssets |
Sin saldos: el valor puenteado son notas. Ya no existe next_index: un token puenteado se lista, bajo un índice que su registro ya fijó, antes de poder depositarse, así que no queda ningún índice por predecir. Lee el índice de un token listado en assets o en rand_getTokens.
rand_getAssets
Parámetros []. Resultado: el registro de activos del bridge, en orden ascendente por índice, o []:
[{ "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 v0.6.8 cada fila de respaldo, aquí y dondequiera que se sirvan respaldos (rand_getBridgeState.assets, los backings de rand_getToken, rand_getTokens y rand_getTokenSupply), incluye minted_in_window (una cadena decimal) y mint_window_secs, ambos null en una cadena con contador diario, y mint_headroom: el mayor depósito a ese respaldo que admiten los topes en el tiempo de bloque de la cabeza, el tope por respaldo menos lo que ha emitido y, bajo las reglas v2, no más de lo que le queda a la ventana de todo el registro. Lee mint_headroom, no mint_cap_per_day − minted_today, que ignora el tope global. Bajo las reglas v2, como en la cadena 20, minted_today es el conteo de la ventana móvil, la cifra contra la que se comprueba el tope por respaldo; la descripción del contador diario que sigue es la de la cadena 14.
Una fila por respaldo (moneda de origen), de modo que un token con siete respaldos son siete filas bajo un mismo index. index es la palabra asset que lleva una nota de ese activo; el índice 0 es RAND y nunca está en el registro. decimals son los decimales de origen del respaldo. locked, mint_cap_per_day y minted_today son cadenas decimales en las unidades de ocho decimales del propio token, nunca las de RAND; mint_day es un entero simple, un número de día UTC. mint_cap_per_day es el tokens.mint_cap_per_day del génesis, lo máximo que un respaldo puede emitir por día UTC del tiempo de bloque. minted_today es lo que el respaldo ha emitido en mint_day, el día UTC (timestamp_ms / 86,400,000) del bloque cabeza, de modo que un contador sobrante de un día anterior marca "0" cuando la cabeza cruza la medianoche. Un depósito que supera el tope se rechaza con MintCapExceeded y pasa a ser admisible al día siguiente. chain y token son la identidad de red sobre la que firman los guardianes; asset_id es el blake3 de ambos, lo que calcula rand_bridgeAssetId.
rand_bridgeAssetId
Parámetros [token_chain, token_address] (entero, 32 bytes en hex). Resultado: el id del activo, 64 caracteres hex. Aritmética pura.
rand_getBridgeBurn
Parámetros [sequence]. Resultado null o { "sequence": 0, "body_hex": "…", "digest": "…", "tx": "…", "height": 2, "amount": "…", "release_amount": "…", "fee": "…" }.
Los tres últimos son de v0.6.8, en toda cadena, como cadenas decimales en las unidades de ocho decimales del token. release_amount es el monto que lleva el cuerpo firmado, leído del propio body_hex: lo que libera el contrato de origen, del cual paga la comisión del relayer del cuerpo. fee es la comisión del bridge que la cadena retuvo como nota de tesorería, y amount lo que quemó el paquete, release_amount + fee. Sin bridge.fees (cadenas 14 a 19) fee es "0". La secuencia 13 en la cadena 20, una quema de 0.999 zUSD: "amount": "99900000", "fee": "99900", "release_amount": "99800100".
Tokens (RPL)
El registro de tokens RPL: todos los tokens, puenteados y nativos. Tokens explica el estándar.
rand_getTokens
Parámetros [from_index, limit], ambos opcionales (0 y 1000; limit se limita a 1,000). Resultado: el registro en orden ascendente por índice desde from_index, leído por rango desde ese í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 }
] }
En una cadena sin sección tokens: { "enabled": false, "tokens": [] }. index es la palabra asset que lleva una nota del token (0 es RAND y nunca se lista). id es el identificador de activo del token e id_text su forma de texto con suma de verificación: bech32m, HRP rpl, sobre los 32 bytes del id, 62 caracteres. authority es una de estas:
kind | otros campos |
|---|---|
none | — (suministro fijo, o renunciada) |
key | key, address |
bridge | backings: [{ "chain", "token", "decimals", "locked", "mint_cap_per_day", "minted_today", "mint_day" }], los campos de rand_getAssets, una fila por respaldo |
program | program |
Los suministros, locked, mint_cap_per_day, minted_today y registration_fee son cadenas decimales (unidades de RAND para registration_fee, unidades del token para el resto); next_index, mint_day y max_tokens son números. max_tokens es el límite de génesis del registro (4,096 en la chain 20; null si no lo hay), superado el cual se rechaza un registro con RegistryFull. burn_registration_fee indica si la comisión de un registro se quema en lugar de pagarse al proposer; bound_note_value, si una acuñación o un depósito igual o superior a 2⁶³ es una regla de validez (la admisión rechaza uno en toda cadena, en cualquier caso). Los tres están activados en la chain 20. Una página más corta que limit es la última.
Una autoridad program ({ "kind": "program", "program": "<id>" }) solo se puede registrar en una cadena con una sección program_state, como lo es la chain 20 (v0.6.8): el token comienza con suministro cero, y solo las invocaciones de ese programa lo acuñan o lo queman.
Una wallet resuelve un id de token a través de este listado, nunca mediante rand_getToken: el activo de una transferencia es privado en la cadena, y leer el registro completo cuesta lo mismo sea cual sea el token buscado.
rand_getToken
Parámetros [token]: un índice del registro (un número o una cadena decimal), el id de 64 caracteres hexadecimales (con o sin 0x, en mayúsculas o minúsculas) o la forma de texto rpl1… (toda en minúsculas o toda en mayúsculas). Resultado: la fila de rand_getTokens de ese token, o null. Un id mal formado —suma de verificación incorrecta, otro HRP, longitud errónea, mayúsculas y minúsculas mezcladas, no hexadecimal— produce -32602, de modo que un error tipográfico nunca devuelve otro token. Una consulta por token le indica al nodo qué token le interesa al llamante; está pensada para exploradores y lecturas puntuales.
rand_getTokenSupply
Parámetros [token], en las mismas formas. Resultado null, o:
{ "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 está vacío para un token nativo; en uno con puente, las cantidades locked suman total_supply. Rige la misma nota de privacidad que en rand_getToken.
Agregación de bloques (no activa en la chain 20)
Existen en el nodo para las cadenas cuyo génesis incluye una sección aggregation. En la chain 20 el registro está vacío y nunca se deja nada sin sellar.
| método | parámetros | resultado |
|---|---|---|
rand_getAggregate | [hash] | los campos covers, aggregator, subsidy, proving_share, n, height del agregado que sella; null para cualquier otra transacción |
rand_getAggregators | [] | el registro de aggregators: address, bond, payout, nonce, unbonding por fila |
rand_getUnsealed | [from, limit] | { "bundles": [{ "hash", "height", "excess" }], "next_from" }, los bundles que un aggregator aún puede cubrir |
Un Aggregate se envía mediante rand_sendTransaction, como todo lo demás.
Vesting de génesis (no activo en la chain 20)
Existen en el nodo para las cadenas cuyo génesis incluye una sección vesting. Ninguna cadena la tiene todavía: en la chain 20 cada uno responde { "enabled": false }. El endpoint público los reenvía desde el 2026-10-01.
| método | parámetros | resultado |
|---|---|---|
rand_getVesting | [id] o [id, at_ms], el id de 64 caracteres hexadecimales de la entrada | la entrada: su clase, beneficiario, calendario (amount, start_ms, cliff_ms, linear_ms, step_ms), lo reclamado, revocado y en bond, y vested_now, claimable_now, unvested_now en as_of_ms (por defecto, la hora del bloque cabeza); null si el id es desconocido. Desde v0.6.8 una entrada revocable lista revokers, el threshold de ellos que necesita una revocación y el treasury al que paga una revocación (sustituyen al único revoker), y la entrada incluye revoke_nonce y locked_now |
rand_getVestingSummary | [] | { "enabled": true, "height", "as_of_ms", "entries", "issued", "released", "locked", "classes": [ … ] }: totales por clase, sin clave ni propietario |
rand_getVestingSchedule | [from_ms, to_ms, step_ms], como máximo 1,000 puntos | { "enabled": true, "issued", "points": [{ "t_ms", "locked" }] }: el total bloqueado del registro a lo largo del tiempo |
Las cantidades son cadenas decimales. Las cuatro acciones de vesting se envían mediante rand_sendTransaction.
Suscripciones (WebSocket)
ws://127.0.0.1:8545/ o /ws. El socket solo atiende rand_subscribe y rand_unsubscribe y responde -32601 a cualquier otra cosa. Tres temas, flujos independientes sin promesa de orden entre ellos:
newHeads— con la forma derand_getHead, enviado una vez por bloque confirmado, en orden, también durante la sincronización. Aquíviewes la vista propia del bloque.receiptsoreceipts <program_id>— una notificación por cada bloque confirmado que lleve al menos un recibo de llamada coincidente:{ "height", "hash", "receipts": [ … ] }, cada recibo con la forma derand_getReceipt.transaction <hash>— una notificación, tras la cual el nodo elimina la suscripción:{ "status": "committed", "height", "index" }, o{ "status": "rejected", "reason" }para un rechazo basado en los bytes de la propia transacción (el mismo límite que tienerand_getTransactionStatus). Un rechazo que depende del estado nunca se anuncia, así que conviene combinarlo con un tiempo límite.
{ "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 } } }
Límites: 64 conexiones por nodo (la 65.ª se rechaza en el upgrade con 503), 8 suscripciones por conexión, 64 KiB por trama del cliente, un ping cada 30 s respondido en 5 s, y 256 entradas de cola atrasada por flujo: un suscriptor que se queda más atrás en un flujo que escucha se cierra con el código 1008, no se almacena en búfer; reconéctese y rellene el hueco con rand_getCompactBlocks (cabezas), rand_getReceipts (recibos) o rand_getTransactionStatus (una transacción). Un GET / simple sin cabeceras de upgrade responde 400.
Errores
| código | significado |
|---|---|
-32601 | método desconocido (incluidos los métodos de cuenta retirados) |
-32602 | parámetro inválido o ausente |
-32000 | rechazado: una transacción que el mempool rechazó, una llamada al faucet limitada por tasa, una construcción de witness que esperó más de 10 s, una lectura de más de 30 s, un método que el listener público no atiende, o una suscripción por encima del límite |
-32001 | objeto referenciado no encontrado |
-32010 | podado: una altura por debajo del umbral de retención de este nodo; data.floor lo indica (véase más abajo) |
-32603 | error interno |
-32600 | solicitud inválida: cuerpo por encima del límite de tamaño, no es JSON, un lote mal formado, o una notificación |
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32000, "message": "…" } }
Para rand_sendTransaction, solo -32000 y -32602 son un veredicto sobre la transacción; con cualquier otro código se desconoce su destino (véase rand_sendTransaction).
Nodos podados: error -32010
Un nodo iniciado con --prune-history <window> conserva todo el ledger (notas, nullifiers, anchors, el registro) pero solo los últimos <window> de bloques, transacciones y recibos; rand_status.prune_floor es la altura más baja que aún conserva. En la chain 20, 24 de los 26 validators se ejecutan con --prune-history 24h; los dos archivos se ejecutan sin la opción y conservan todos los bloques, y el endpoint público reenvía a uno de ellos.
- Por altura, por debajo del umbral (salvo el génesis):
rand_getBlockByHeight,rand_getFinalitypor altura, y un rango derand_getBlocks,rand_getCompactBlocksorand_getReceiptsque llegue por debajo de él responden-32010pruned: height h is below this node's retention floor fcondata: { "floor": f }. Consulte un nodo de archivo.[0, 0]sigue sirviendo el génesis. - Por hash:
rand_getBlockByHash,rand_getReceipt,rand_getRawTransaction,rand_getCallEnvelopeyrand_getAggregaterespondennullpara un hash podado, igual que para uno que nunca existió; solo un nodo de archivo puede distinguirlos.rand_getTransactionyrand_checkTransactiontambién respondennull, y-32010solo cuando sobrevive una fila de ubicación que nombra una altura por debajo del umbral.rand_getTransactionStatusañadefloora cada entradaunknownen un nodo podado. - El escaneo de wallets no se ve afectado:
rand_getCommitments,rand_getNullifiers,rand_getAnchory los métodos de witness leen familias que nunca se podan.
La transacción en la red
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
Configuración por defecto de bincode: enteros de ancho fijo, prefijos de longitud de 8 bytes, etiquetas de enum u32 en el orden de declaración. Las cinco variantes de agregación siguen a BridgeBurn y preceden a RegisterToken en el enum (Transacciones); la chain 20 nunca las admite, ni tampoco las cuatro variantes de vesting ni SlashEquivocation, pero un codificador que fije los números de etiqueta en el código debe contarlas igualmente.
Los dos últimos campos del bundle llegaron con v0.6.3 y la chain 17. bincode es posicional, así que un codificador escrito para la chain 16 o anterior no produce una transacción que esta cadena decodifique, y todos los ids de transacción cambiaron con ellos: el dominio del id es ahora rand-txid-3, que vincula auth_commit y el digest de la prueba de autorización. Un cliente que recalcule los ids localmente debe adaptarse. En la chain 20 todo bundle lleva una prueba de autorización, ya sea autoprobada o delegada. v0.6.8 no cambia nada en el diseño de Transaction ni de Bundle; añade las acciones 28 a 33.
Cada transacción lleva como máximo un bundle. Un Bond lleva un bundle cuyo burn_r es igual a su amount, con burn_a y burn_asset en 0. Un BridgeBurn o un TokenBurn quema a través del bundle: burn_asset debe ser el asset de la acción (nunca 0), burn_a el amount de la acción y burn_r 0, mientras que fee se paga en RAND desde las ranuras 2–3. Cualquier otra acción no quema ningún token, y RAND solo se quema a través de burn_r: un bundle con burn_asset 0 y burn_a distinto de cero es rechazado en todas partes. La r de un BridgeAttest se deriva, no se elige: la admisión exige blake3("rand-deposit-r-1" ‖ mu) sobre el digest que firmaron los guardianes y rechaza cualquier otro valor (WrongDepositBlinding, un rechazo permanente). Un token puenteado debe estar listado —en el génesis, o mediante un RegisterBridgedToken / ListBacking— antes de que se pueda admitir cualquier attestation de él; una attestation de una moneda no listada se rechaza con UnlistedToken.
Cada prueba de bundle se genera sobre la transacción en la que viaja, y se verifica contra ella: la transacción completa con sus pruebas en blanco, vinculada al identificador de cadena y, en la chain 20 (binding_domain: 1), al hash del génesis, bajo etiquetas nuevas. En las chains 14 a 19 el vínculo era solo el identificador de cadena, de modo que una prueba generada para la chain 19 no se verifica en la chain 20, y una wallet anterior a v0.6.8 no puede enviar allí. En las chains 18 a 20, un bundle sin sus dos pruebas se codifica en 7.936 bytes y una transacción de transferencia sin ellas en 7.949 (5.848 y 5.861 en las chains 14 a 16, con envoltorios de 1.348 bytes y sin campos de autenticación). Una transferencia en la red ocupa unos 2,85 MB en el perfil de producción, casi todo prueba: una prueba de bundle de unos 1,49 MB y una prueba de autenticación de unos 1,36 MB. Antes de la autorización dividida ocupaba unos 1,43 MB.