The node udostępnia JSON-RPC 2.0 przez HTTP na --rpc (domyślnie 127.0.0.1:8545) oraz WebSocket na tym samym porcie dla subskrypcji. Od v0.6.8 może też otworzyć drugi, publiczny nasłuch (--public-rpc, poniżej). randprotocol_client::RpcClient (Rust) opakowuje każdą z poniższych metod. Ta strona jest listą metod w wersji v0.6.8 (c9c9bd3c), czyli w buildzie, na którym działa chain 20; tam, gdzie metoda istnieje w kodzie, ale w chain 20 jest nieaktywna, strona o tym mówi.
curl -s http://127.0.0.1:8545 -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"rand_getHead","params":[]}'
Publiczny endpoint
https://rpc.randprotocol.org (ten sam proxy jest też pod https://randprotocol.org/api/rpc) przekazuje żądania do węzła archiwalnego chain 20, który przechowuje każdy blok, dla portfeli i stron bez własnego węzła (rand --rpc https://rpc.randprotocol.org …). Obsługuje wyłącznie HTTP POST, z otwartym CORS i bez WebSocket, i jest węższy niż węzeł:
- Jedno żądanie na wywołanie. Batch jest odrzucany z kodem
-32600. - Lista dozwolonych metod: od 2026-10-01 jest to ten sam zestaw, co na własnym publicznym nasłuchu węzła (
rpc::PUBLIC_METHODSw v0.6.8), więc znajdują się na niej odczyty stanu programów potrzebnerand program invoke,rand_getAdmitted, odczyty agregacji i odczyty vestingu, a takżerand_checkTransactionirand_sendTransaction.rand_mint,rand_importViewingKey,rand_getViewingNotes,rand_removeViewingKeyirand_getPeersna niej nie ma; odpowiadają-32601method not allowed here, nie docierając do węzła: publiczny faucet jest powierzchnią nadużyć, a klucz podglądu (viewing key) powinien trafiać wyłącznie do węzła, który sami prowadzicie. - Treść żądania do 12 MiB, co mieści dowolny transfer, akcję na tokenie lub deploy oraz wywołanie, którego dowód ma do około 3,4 MB (transakcja jest zakodowana szesnastkowo, a dowody bundle i auth zajmują około 2,85 MB, zanim doliczy się dowód wywołania). Większe wywołanie trafia do własnego węzła. Po przekroczeniu limitu: HTTP 413 i
-32600. - Na adres: 1 200 żądań na minutę oraz 6 na minutę dla
rand_sendTransaction. Po przekroczeniu: HTTP 429 i-32005. Budżet odczytów jest dobrany do pierwszej synchronizacji portfela, czyli kilkuset żądań w jednej serii (645 przy wysokości 99 000 w chain 18). -32000upstream unavailable, gdy węzeł za proxy nie odpowiada.
Wszystko inne na tej stronie opisuje sam węzeł.
Dwa nasłuchy węzła
Od v0.6.8 (audyt v6) węzeł ma dwa nasłuchy JSON-RPC.
--rpc <ADDR>, nasłuch operatora. Każda metoda, batche i WebSocket. Identyfikuje wywołującego po adresie gniazda i ufa pętli zwrotnej (loopback): metody klucza podglądu odpowiadają wyłącznie na loopback, a loopback nie jest limitowany. Trzymajcie go na127.0.0.1. Reverse proxy lub przekierowanie SSH docierają przez loopback, więc za którymś z nich każdy odwiedzający jest operatorem: nigdy nie kierujcie publicznego endpointu na ten port.--public-rpc <ADDR>, nasłuch publiczny, przeznaczony właśnie na ten przeskok. Obsługuje stały zestaw metod: odczyty potrzebne portfelowi, eksploratorowi lub stronie orazrand_sendTransaction(rpc::PUBLIC_METHODS).rand_importViewingKey,rand_getViewingNotes,rand_removeViewingKey,rand_mintirand_getPeersnigdy tu nie są obsługiwane, podobnie jak żadna metoda dodana później, dopóki nie trafi na listę; takie wywołanie odpowiada-32000<method> is not served on this node's public listener. Batch to-32600, a ścieżki WebSocket nie ma. Jeden licznik obejmuje łącznie wszystkich wywołujących: 600 żądań w serii i 150 na sekundę; powyżej tego HTTP 429 z treścią-32000. Limity per odwiedzający należą do proxy, które widzi odwiedzających. Jego wywołujący zajmują co najwyżej połowę blokujących slotów odczytu węzła, dzięki czemu nasłuch operatora nigdy nie jest głodzony.
Oba nasłuchy dzielą dwa limity odczytu. Odczyt blokujący, który nie zakończył się w ciągu 30 s, jest odrzucany z -32000 this read took longer than 30 s on this node; retry with a smaller range. rand_getBlocks kończy stronę, gdy przeczyta 64 MiB bloków.
--rpc-viewing-token-file <PATH> nakłada token bearer na metody klucza podglądu w --rpc: pierwszy wiersz pliku, co najmniej 32 znaki, wysyłany jako Authorization: Bearer <token>. Z nim sam loopback nie wystarcza, a wywołujący z dowolnego miejsca, który go przedstawi, zostanie obsłużony.
Konwencje
- Adresy walidatorów to ciągi base58 (32 bajty). Hasze mają 64 znaki szesnastkowe, z
0xlub bez. Wartości chronione (shielded) — zobowiązania (commitments), nullifiery, kotwice (anchors), korzenie drzew, poziomy świadków — toWord8: osiem słówu32w kolejności little-endian jako 64 małe znaki szesnastkowe. - Adresy chronione (shielded) mają postać
rand1+ base58, 1 667 znaków. Parametr dłuższy niż 2 000 znaków jest odrzucany ze względu na długość, zanim zostanie sparsowany. - Każda kwota
u64jest ciągiem dziesiętnym ("1500000000"= 1,5 RAND; 1 RAND = 10⁹ jednostek): jednostki RAND lub jednostki tokena, stan łańcucha lub własne pole zdekodowanej transakcji. Liczba JSON nie jest dokładną liczbą całkowitą powyżej 2⁵³, a podaż tokena z 9 miejscami dziesiętnymi przekracza ten próg przy kilkudziesięciu milionach jednostek. Co to zmieniło, opisuje datowana uwaga poniżej. - Indeksy, nonce, wysokości, indeksy liści, widoki (views), długości, liczby miejsc dziesiętnych i liczniki dni (
mint_day) nigdy nie są kwotami i wszędzie są liczbami całkowitymi JSON. - Każde żądanie musi zawierać składową
id. Obiekt bez niej jest powiadomieniem (notification) i jest odrzucany z-32600; jawne"id": nulljest zwykłym żądaniem. - Nie ma metody salda ani metody konta. Portfel oblicza saldo, skanując
rand_getCommitmentsirand_getNullifiersswoim kluczem podglądu.rand_getBalance,rand_getAccountirand_getAssetBalanceodpowiadają-32601.
Zmiana łamiąca zgodność, 2026-09-20 (chain 14): każda kwota jest ciągiem dziesiętnym
Przed chain 14 kwoty wewnątrz zdekodowanej transakcji były liczbami całkowitymi JSON. Ten wyjątek zniknął. Poniższe pola zmieniły się z liczb JSON na ciągi dziesiętne, bez innych zmian znaczenia ani położenia:
bundle.fee, wtxzrand_getTransactionoraz wtransactions[]zrand_getBlockByHeight/rand_getBlockByHash;action.amountdlakind=mint,bond,unbond,withdraw,bridge_attest(te same trzy metody);action.amountiaction.relayer_feedlakind=bridge_burn(te same trzy metody);lockedw wierszachrand_getAssetsirand_getBridgeState.assets[].
Klient, który czyta którekolwiek z nich jako liczbę, musi zamiast tego sparsować ciąg. aggregation.subsidy_base w rand_status (tylko łańcuchy z agregacją) stało się ciągiem w tej samej zmianie. Każda inna kwota już była ciągiem: rand_getSupply, rand_getEmission, rand_getValidators, notki podglądu oraz każde pole wprowadzone w chain 14 — burn_a i burn_r bundla, podaże tokenów, locked każdego zabezpieczenia, mint_cap_per_day i minted_today, registration_fee oraz amount w token_mint, token_burn i register_token (initial_amount, initial.amount).
Batche
Treścią POST może być tablica złożona z co najwyżej 20 obiektów żądań, a odpowiedzią tablica tej samej długości w kolejności żądań, łącznie z błędami. Żądania są wykonywane jedno po drugim. Pusta tablica, tablica powyżej 20 elementów albo treść będąca ani obiektem, ani tablicą to pojedyncze -32600 z id równym null. Całość treści nadal podlega limitowi rozmiaru żądania w węźle, dobranemu do jednej transakcji z dowodem: batch dwóch wywołań rand_sendTransaction z dowodami jest odrzucany z 413. Batchujcie odczyty, nie zgłoszenia z dowodami.
Łańcuch i węzeł
rand_chainId
Parametry []. Wynik: identyfikator łańcucha (liczba całkowita); 20 w testnet.
rand_tokenInfo
Parametry []. Wynik { "symbol": "RAND", "decimals": 9 }.
rand_getHead
Parametry []. Wynik { "height": 1998, "hash": "…", "view": 2251 }. view to bieżący widok konsensusu węzła, który wyprzedza wysokość, gdy widoki przekraczają limit czasu.
rand_status (alias rand_syncStatus)
Parametry []. Wynik:
{
"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: ten węzeł posiada klucz walidatora; active_validator: ten klucz należy do zbioru obsługującego bieżącą epokę. reserved_peers (v0.6.8) zlicza peery dopuszczone ponad limit połączeń przychodzących: bootstrapy, każdy --reserved-peer oraz każdą tożsamość walidatora poznaną z podpisanego powiązania peera, każdą raz; na węźle floty powinno to osiągnąć liczbę walidatorów w ciągu minuty od startu. viewing_keys to liczba kluczy podglądu, które węzeł trzyma w pamięci do skanowania po stronie węzła. verify_queue to liczba transakcji oczekujących na jednego z czterech workerów weryfikacji dowodów (co najwyżej 64 w kolejce). hc_bundle to guest bundle, względem którego są dowody tego łańcucha, a hc_auth to guest auth przypięty w jego genesis (podzielona autoryzacja, od chain 17), albo null w łańcuchu bez niego; węzeł, którego build nie zgadza się z którymkolwiek z nich, odmawia startu. testnet i binding_domain to pola genesis o tych samych nazwach, tak jak serwuje je rand_getLimits. gas_prices to bieżące ceny gazu z rejestru napiwków (tip ledger), odświeżane przy każdym commicie, jako ciągi dziesiętne; null w łańcuchu bez sekcji gas. Ceny w chain 20 są dynamiczne i zmieniają się z blokiem w zależności od wypełnienia, nigdy poniżej dolnych limitów 100 i 800 i nigdy powyżej górnych limitów 10 000 i 80 000, więc czytajcie je tutaj lub w rand_getLimits i nie zapisujcie ich na stałe w kodzie. Obiekt zawiera też obiekt aggregation (jego subsidy_base jest ciągiem dziesiętnym, reszta to liczby całkowite), który w łańcuchu bez sekcji aggregation, jak chain 20, ma same zera.
Obiekt zawiera także disk_free_bytes (liczba) i disk_low, oraz parę dotyczącą retencji: prune_floor, najniższą wysokość, jaką węzeł jeszcze przechowuje (0 na archiwalnym), i prune_history_secs, okno, które utrzymuje węzeł uruchomiony z --prune-history (null, gdy trzyma wszystko). W chain 20, tak jak w chain 19, 24 z 26 walidatorów trzyma 24 godziny bloków; dwa archiwalne trzymają wszystkie. Zob. Węzły z przycinaniem.
rand_getPeers
Parametry []. Wynik: tablica { "peer_id": "12D3KooW…", "addrs": ["/ip4/…/tcp/30303"], "connected_secs": 1241 }.
rand_getBlockByHeight / rand_getBlockByHash
Parametry [height] lub [hash]. Wynik null, jeśli nieznany, w przeciwnym razie:
{
"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": [ ]
}
Wyłącznie zatwierdzone bloki są udostępniane. transactions ma ten sam kształt co tx w rand_getTransaction. Blok zawiera także sealed, a każda jego transakcja sealed_by; w łańcuchu bez agregacji mają one wartości false i null.
rand_getBlocks
Parametry [from_height, to_height]. Wynik: nagłówki bloków, od najstarszego, najwyżej 1 024 począwszy od from_height (128 w węźle sprzed 2026-09-24): pola rand_getBlockByHeight bez transactions. Zakres szerszy niż limit lub wykraczający poza głowę łańcucha jest obcinany, a nie odrzucany, a od v0.6.8 strona kończy się także wtedy, gdy odczytano już 64 MiB bloków; kolejne zapytanie zacznij od ostatniej zwróconej wysokości. -32602, gdy to_height jest mniejsze niż from_height.
Od v0.6.8 każdy nagłówek zawiera też public_notes: transakcje bloku bridge_attest, token_mint i register_token, a w łańcuchu z opłatami mostu także jego transakcje bridge_burn, jako [{ "hash", "raw" }] (w kodowaniu, które zwraca rand_getRawTransaction); dla każdego innego bloku pole jest puste. Transakcja spalenia jest udostępniana z opróżnionymi dowodami i z "proofs_stripped": true; jej hash to prawdziwy identyfikator transakcji. Pierwsza synchronizacja portfela czyta te strony i nie potrzebuje niczego więcej, aby odbudować jawne notatki.
rand_getFinality
Parametry [height] lub [hash]. Wynik, jeden z { "status": "committed", "height", "hash" }, { "status": "certified", "height", "hash", "qc_view" }, { "status": "proposed", "height", "hash" }, { "status": "unknown" }. Wysokość jest zawsze sprawdzana wyłącznie w zatwierdzonym łańcuchu, więc odpowiedzią jest committed albo unknown; hash może dać także certified (w niezatwierdzonym drzewie repliki, z certyfikatem kworum) lub proposed (w drzewie, bez certyfikatu).
rand_getProposer
Parametry [view] lub [from_view, to_view], najwyżej 64 widoki. Wynik { "epoch": 3, "proposers": [ { "view": 2251, "proposer": "2nRdFC…" } ] }: lider każdego widoku według bieżącego zbioru walidatorów, a nie zbioru, który działał w danym widoku w przeszłości. -32602 dla zakresu odwróconego lub obejmującego więcej niż 64 widoki.
rand_getVersion
Parametry []. Wynik { "version", "git_sha", "chain_id", "hc_bundle", "hc_auth", "fri_profile" }. version to wersja skrzynki (crate) workspace; git_sha to hash commitu zarejestrowany podczas budowania, z dopiskiem -dirty, gdy śledzone pliki się różniły, albo "unknown". hc_auth to genesisowy guest uwierzytelniania, jak w rand_status, lub null. Publiczny punkt końcowy w dniu 2026-10-01, w łańcuchu 20:
{ "version": "0.6.8", "git_sha": "c9c9bd3c1903aa4cc5833b7ab8c62fc3e6942017", "chain_id": 20,
"hc_bundle": "60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce",
"hc_auth": "1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1",
"fri_profile": "production" }
rand_getGenesisHash
Parametry []. Wynik: hash genesis w postaci szesnastkowej; "6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135" w łańcuchu 20 (w łańcuchu 19 był to a3defc93…228a). Sam identyfikator łańcucha nie pozwala odróżnić dwóch wydań łańcucha; hash genesis na to pozwala. W łańcuchu 20 wchodzi on także w skład powiązania każdej transakcji i każdego podpisanego komunikatu akcji (binding_domain: 1, zob. rand_getLimits).
rand_getHealth
Parametry []. Wynik, jeden z { "status": "disk_low", "free_bytes": "3221225472" }, { "status": "ok" }, { "status": "syncing", "behind": 412 }, { "status": "behind", "behind": 30 }. disk_low ma pierwszeństwo przed wszystkim innym, gdy wolne miejsce w systemie plików katalogu danych jest mniejsze niż czterokrotność --min-free-disk-mb węzła (domyślnie 1024, czyli poniżej 4 GB); free_bytes jest ciągiem dziesiętnym. ok, gdy sync_target - height wynosi co najwyżej 2 i nie ma oczekującego żądania partii synchronizacji; syncing, dopóki takie żądanie oczekuje; behind, gdy węzeł się nie synchronizuje, a opóźnienie nadal przekracza 2.
rand_getMempoolInfo
Parametry []. Wynik { "count": 2, "bytes": 2611200, "oldest_ms": 1450, "max_count": 10000 }. bytes sumuje zakodowaną długość każdej transakcji w puli; oldest_ms ma wartość null, gdy pula jest pusta. Od v0.6.8 pula ma też limit w bajtach, równy ośmiokrotności genesisowego max_block_bytes (160 MiB w łańcuchu 20): po jego przekroczeniu transakcja płacąca więcej ponad swój próg na KiB wypiera najtańszą, a transakcja płacąca mniej lub tyle samo jest odrzucana z komunikatem mempool full. Akcje zarządcze mieszczą się w obu limitach.
Wysyłanie
rand_sendTransaction
Parametry [hex], gdzie hex to bincode(Transaction). Wynik: hash transakcji. Węzeł waliduje ją w kolejności przyjmowania (Transactions), umieszcza w puli i rozsyła plotkarsko (gossip). Błędy mają kod -32000 wraz z przyczyną: nullifier already spent, anchor is not one of the last 1024 roots, time 12 is outside [1500, 2524] (oba okna to genesisowe proof_window_blocks, 1 024 w łańcuchu 20; 256 w łańcuchach do 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; dla invoke: cell <key> is no longer what this transition read (werdykt dotyczący stanu: odczytaj komórkę ponownie i wygeneruj dowód od nowa) lub the vault holds … of asset … and the transition pays …; dla rejestrującego Bond w trybie przyjmowania przez głosowanie: validator … has not been admitted by the validator set's vote (staking.admission_by_vote); ask the validators for an AdmitValidator first; dla pakietu niepasującego do genesis łańcucha 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; dla akcji mostu: 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; dla pakietu spalającego to, czego jego akcja nie może spalać: the bundle burns asset 2 on an action that burns no token, a burn of 5 is not allowed on this action lub RAND burned through burn_a (5); a RAND burn goes through burn_r; dla stanu mostu: 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; dla rejestru tokenów: wrong mint nonce i wrong token index. Przyjęcie nie oznacza zatwierdzenia: odpytuj rand_getTransaction lub rand_getTransactionStatus.
Transakcja większa niż limit bloku w danym łańcuchu (max_block_bytes z rand_getLimits) jest odrzucana z kodem -32000, z podaniem obu rozmiarów, zanim trafi do mempoola. Treść żądania ma limit 2 × (2 × max_proof_bytes + 4 × 2048 + max_call_envelope_bytes + 16,384 + 64 KiB) + 256 KiB, obliczany z genesis przy uruchomieniu: 8 867 840 bajtów w łańcuchu domyślnym i 17 350 656 przy limitach łańcucha 20, tyle samo co w łańcuchach od 17 do 19 (34 127 872 w łańcuchach od 13 do 15, których limit dowodu wynosił 8 MiB). 4 × 2048 to cztery koperty pakietu przy limicie koperty. Treść powyżej limitu skutkuje kodem -32600 z podaniem limitu.
Tylko -32000 (przyjęcie odmówiło) i -32602 (nie dało się zdekodować) są werdyktem w sprawie transakcji. Każda inna awaria, łącznie z -32603, pozostawia jej los nieznanym: węzeł umieszcza transakcję w puli i rozsyła ją, zanim odpowie, więc węzeł, który zatrzyma się w tym oknie, mógł przyjąć coś, na co nigdy nie odpowiedział. randprotocol_client traktuje wysłanie jako odrzucone wyłącznie przy tych dwóch kodach.
rand_getTransactionStatus
Parametry [[hash, …]], od 1 do 64 hashów. Wynik: jeden wpis na hash, w tej samej kolejności:
[ { "hash": "…", "status": "committed", "height": 1998, "index": 0 },
{ "hash": "…", "status": "pending" },
{ "hash": "…", "status": "rejected", "reason": "bad mint signature" },
{ "hash": "…", "status": "unknown" } ]
Kolejność wyszukiwania dla każdego hasha: zatwierdzone (storage), oczekujące (mempool), odrzucone (pamięć podręczna odrzuceń, którą zlicza refused_cache w rand_status), w przeciwnym razie unknown. rejected obejmuje wyłącznie odmowy dotyczące własnych bajtów transakcji, których żaden późniejszy blok nie może zmienić: nieprawidłowy dowód, digest pakietu inny niż ten, który opublikował jego dowód, zły podpis mintu, zły identyfikator łańcucha, zbyt duża część, powtórzony nullifier lub zobowiązanie wewnątrz transakcji, koperta niewłaściwego rozmiaru, brakujący lub niezgodny dowód uwierzytelniania, pakiet lub dowód uwierzytelniania deklarujący zły limit gazu. Odmowa zależna od stanu węzła w danej chwili — wydany nullifier, kotwica lub time poza oknem, opłata poniżej progu (który w łańcuchu 20 zmienia się wraz z cenami gazu), nieznany program, nonce rejestru, nieaktualny odczyt invoke — nie jest zapamiętywana i daje unknown. -32602 dla pustej listy lub więcej niż 64 hashów.
rand_mint (faucet testnetu)
Parametry [address] lub [address, amount]; address to adres rand1…, amount to ciąg jednostek, co najwyżej 100000000000 (100 RAND, wartość domyślna). Wynik: hash transakcji mintu. Tylko w łańcuchu, którego genesis ma "faucet": true; w przeciwnym razie -32000 faucet is disabled on this chain. Obserwator odpowiada faucet mints are signed by validators; ask a validator node.
W łańcuchu, którego genesis ustawia staking.faucet_recipients, jak w łańcuchu 20 (16 portfeli), płatność może trafić tylko do wymienionych portfeli: mint na jakikolwiek inny adres jest odrzucany z komunikatem the faucet may not mint to this recipient (not in staking.faucet_recipients). Genesis łańcucha 20 ustawia także staking.faucet_minters (18 kluczy walidatorów): mint może podpisać tylko wymieniony klucz. Faucet ma również budżet na epokę, staking.faucet_budget_per_epoch (10 000 RAND na epokę 1 000 bloków w łańcuchu 20); mint ponad budżet jest odrzucany z komunikatem FaucetBudgetExhausted, werdyktem dotyczącym stanu, który po opuszczeniu puli daje unknown.
Pula faucet jest ograniczana szybkością osobno dla każdego procesu węzła: osiem wywołań mint jedno po drugim, z odnawianiem co sekundę. Po przekroczeniu limitu wywołanie odpowiada faucet is rate limited on this node (8 mints back to back, refilling at 1/s); try again shortly. Zalew żądań do faucetu nie może więc zapełnić puli przed bridge’owym PauseMints, który, tak jak pozostałe trzy akcje governance mostu, jest również zwolniony z odmowy mempool full i ustawiany w bloku na pierwszym miejscu.
Od chain 14 mint jest otwarty: akcja Mint niesie pk, time i r noty obok cm i amount, admisja przelicza zobowiązanie i odrzuca cm, które nie otwiera się do tych wartości (the mint's commitment does not open to its published note and amount), a minter podpisuje wszystkie siedem pól w domenie rand-mint-2; na chain 20 (binding_domain: 1) w domenie rand-mint-3, z hashem genesis na początku. Właściciel i kwota noty z faucetu są zatem jawne, tak jak wypłata przy withdraw. Parametry rand_mint pozostają bez zmian.
rand_estimateFee
Parametry [spec], jedna z postaci {"kind":"bundle"}, {"kind":"deploy","words":n,"public_words":m}, {"kind":"call","tier":t,"bytes":b,"gas":g}, gdzie t należy do 10, 12, 14, 16, 18, 20. Wynik: minimalna opłata w jednostkach, jako string. {"kind":"bundle"} daje "1000000". public_words (opcjonalne, domyślnie 0) jest płatne za słowo tak jak kod, więc opłata jest opłatą za deploy n + m słów. bytes (opcjonalne, domyślnie 0) to długość dowodu wywołania plus długość jego koperty wejściowej.
Sposób wyceny wywołania zależy od gas_metering z rand_getLimits:
"circuit", czyli chain z własną sekcjągas, jak chain 20.gasto limit gazu, który deklaruje dowód wywołania, i jest wymagany: bez niego wywołanie odpowiada-32602under the gas section a call estimate needs its gas. Wynik to1,000,000 + gas_price × gas + byte_price × ⌈bytes / 1024⌉według bieżących cen na końcu łańcucha, tych, które podajerand_getLimits. Przy minimalnych cenach chain 20, wynoszących 100 i 800, wywołanie deklarujące 20 479 gazu z 1 300 000 bajtów dowodu i koperty kosztuje"4063900". Ceny zmieniają się z blokiem, więc szacuj tuż przed wysłaniem."header", polityka gazu na poziomie węzła w chainie bez tej sekcji. Specyfikacja wywołania przyjmujekeccak_log_heightisha256_log_height(opcjonalne, domyślnie 0, każde od 0 do 40, w przeciwnym razie-32602), czyli wysokości tablic hashy deklarowane w nagłówku dowodu, a odpowiedzią jest większa z dwóch wartości: dolna granica opłaty z poziomu rejestru i dolna granica gazu z tego nagłówka. Przy sekcjigasobie wysokości są przyjmowane i nieużywane.null, żadne z powyższych. Sam harmonogram poziomów rejestru: do wysokości darmowego limitu (2 097 152 + 18 432 bajtów) wywołanie kosztuje opłatę swojego poziomu; każdy KiB ponad limit, przy czym niepełny KiB liczy się jako pełny, dodaje 1 000 jednostek.
Od v0.6.8 {"kind":"invoke", …, "created_cells": c} wycenia invoke RPL-2: wszystkie pola specyfikacji wywołania plus created_cells (opcjonalne, domyślnie 0, najwyżej max_writes, w przeciwnym razie -32602), czyli komórki, które przejście by utworzyło. Każda z nich dodaje cell_fee chaina (rand_getLimits.program_state). Liczy je wywołujący: to zapis niezerowej wartości do komórki, którą rand_getProgramCell odczytuje jako zera. Na chain 20 powyższe wywołanie z dwiema utworzonymi komórkami kosztuje "24063900". W chainie bez sekcji program_state ten rodzaj daje -32602.
Opłaty zawierają pełny harmonogram.
Pula
rand_getTreeInfo
Parametry []. Wynik { "next_index": 41, "root": "6b1d…c4", "nullifiers": 12 }: liczba liści, bieżący korzeń, liczba wydanych not.
rand_getCommitments
Parametry [from_index] lub [from_index, limit]. Wynik: strona liści od from_index, od najstarszego, co najwyżej 1 000 wierszy bez względu na wielkość limit.
[ { "index": 40, "cm": "2a9f…07", "height": 37,
"envelope": { "kem_ct": "b41c…", "to_receiver": "77e0…", "to_sender": "0c31…", "body": "9dd2…" } } ]
rand_getNullifiers
Parametry [from_height] lub [from_height, limit]. Wynik: każdy nullifier opublikowany od tej wysokości wzwyż, z tym samym limitem 1 000 wierszy. Strona może urwać się wewnątrz wysokości; cofnij się do najwyższej widzianej wysokości.
[ { "height": 37, "nullifier": "8c04…d1" }, { "height": 41, "nullifier": "12be…9a" } ]
rand_getCompactBlocks
Parametry [from_height, to_height], oba wymagane. Wynik: jeden wiersz na blok, od najstarszego, z tym, czego potrzebuje lekki portfel, i niczym więcej:
[ { "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"] } ] } ]
Każda transakcja niosąca bundle ma tu cztery noty i cztery nullifiery, czyli swoje cztery sloty, razem ze slotami pustymi, których żaden czytelnik nie odróżni od prawdziwych (pokazano tylko pierwszy wiersz zobowiązania z przykładu). Od v0.6.8 niektóre mają więcej not, po tych czterech: invoke ma jedną notę na wypłatę, najpierw pays, potem mints, każdą z własną kopertą wypłaty, więc odbiorca znajduje ją próbnym odszyfrowaniem; w chainie z opłatami mostu, jak chain 20, bridge_burn ma notę swojej opłaty skarbca, a bridge_attest ma notę opłaty po swoim depozycie. Koperta noty opłaty jest pusta, zapieczętowana dla nikogo: portfel skarbca odtwarza notę z publicznych pól transakcji.
Najwyżej 128 bloków na wywołanie (szerszy zakres jest przycinany) i, poza pierwszym blokiem, który jest zawsze zwracany w całości, 1 000 not; wznów od ostatniego zwróconego height plus jeden. Tablica commitments na poziomie bloku zawiera depozyty genesis na wysokości 0 i jest pusta w pozostałych; noty pochodne Withdraw i BridgeAttest pojawiają się pod ich transakcją. -32602 dla zakresu w tył lub brakującej granicy.
rand_getAnchor
Parametry [] dla głowy lub [height]. Wynik { "height": 192, "root": "6b1d…c4" } albo -32001 dla wysokości bez zapisanej kotwicy. Kotwicami są tylko korzenie z końca bloków. Węzeł może odpowiedzieć dla starej wysokości, ale kotwica bundle’a jest dopuszczalna tylko wtedy, gdy jest jednym z ostatnich proof_window_blocks korzeni: 1 024 na chain 20, 256 na chainach do 19. Buduj względem głowy.
rand_getWitness
Parametry [index]. Wynik null poza końcem drzewa, w przeciwnym razie ścieżka Merkle’a tego liścia, od liścia, dokładnie 32 poziomy, z bieżącym korzeniem drzewa:
{ "index": 40, "root": "6b1d…c4", "path": ["0000…00", "f2a1…3b", "…"] }
Najdroższy odczyt, jaki obsługuje węzeł (odbudowuje pełne drzewo o głębokości 32) i jedyne żądanie, które ujawnia coś o wywołującym. Węzeł wykonuje najwyżej dwie odbudowy drzewa naraz, łącznie dla rand_getWitness i rand_getWitnesses; żądanie, które czeka na wolne miejsce dłużej niż 10 s, jest odrzucane z -32000 witness builds are busy on this node; retry shortly.
rand_getWitnesses
Parametry [[index, …]], od 1 do 32 indeksów liści. Wynik { "root": "…", "witnesses": [ { "index": 7, "path": ["…"] }, { "index": 9, "path": null } ] }: rand_getWitness zwinięte na wiele liści w jednej budowie drzewa, tak że portfel dowodzący kilka not płaci za odbudowę raz. Indeks poza końcem drzewa daje dla tego wpisu path: null. -32602 dla pustej listy lub więcej niż 32 indeksów.
Klucze podglądu i ujawnianie
rand_importViewingKey
Parametry [viewing_key] lub [viewing_key, rescan_from_height], klucz jako 64 znaki szesnastkowe. Wynik { "imported": true, "rescan_from_height": 0, "viewing_keys": 3 }. Węzeł przechowuje klucz wyłącznie w pamięci: najwyżej 64 na węzeł, czyszczone przy restarcie; klucz już przechowywany nie zmienia niczego ("imported": false). Import nigdy nie skanuje; skan napędza następna metoda. -32602 dla źle sformowanego klucza; -32000 przy 65. kluczu.
Trzy metody kluczy podglądu odpowiadają wyłącznie wywołującemu z loopbacku i odmawiają każdemu innemu z -32000, chyba że węzeł działa z --rpc-viewing-open za czymś, co uwierzytelnia. rand_removeViewingKey ([viewing_key] → { "removed": bool, "viewing_keys": n }) zwalnia slot i zeruje klucz w pamięci. Rejestr jest indeksowany jednokierunkowym identyfikatorem klucza, blake3("rand-viewing-registry-id-1" ‖ nk), a nigdy samym kluczem, więc import jest jedyną długotrwałą kopią, a usunięcie ją wymazuje. Tekst JSON samego żądania i przejściowe kopie tworzone przez próbne odszyfrowanie nie są wymazywane.
rand_getViewingNotes
Parametry [viewing_key] lub [viewing_key, from_index, limit] (domyślny i maksymalny limit to 1 000). Każde wywołanie przesuwa skan klucza o co najwyżej 10 000 liści, a potem zwraca stronę:
{ "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 to received (koperta otworzyła się jako odbiorcza, a nota wskazuje pk klucza) albo sent (otwarta przez wychodzący klucz podglądu). memo noty to zaszyfrowane memo nadawcy, tekst UTF-8 o długości najwyżej 510 bajtów, albo null, gdy go nie ma lub jego pole otworzyło się niepoprawnie; źle sformowane memo nigdy nie kosztuje odbiorcy noty. Memo to dowolny tekst: pokazuj je jako niezaufane. -32001 dla klucza, którego ten węzeł nie zaimportował.
rand_checkTransaction
Parametry [hash, key], gdzie key to klucz TxKey pojedynczej transakcji jako 64 znaki szesnastkowe. Wynik null dla nieznanego hasha, w przeciwnym razie to, co klucz ujawnia:
{ "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" } } ] }
Bezstanowe: klucz jest odrzucany razem z wywołaniem. output to bundle:0 … bundle:3 dla czterech slotów wyjściowych pakietu (sloty 0–1 to wyjścia aktywa prywatnego, sloty 2–3 to wyjścia RAND, wraz z wyjściami pozornymi), deposit dla koperty depozytu w attestacji mostu, token_mint dla notatki TokenMint, initial_mint dla początkowej emisji RegisterToken, mint:0 dla jedynej koperty emisji z faucetu, albo (v0.6.8) payout:0 … payout:3 dla notatek wypłaconych przez invoke, numerowanych według miejsca w przejściu, najpierw pays, potem mints; asset_bundle:* zniknęło wraz z drugim pakietem. W łańcuchu z opłatami mostu deposit otwiera depozyt netto, czyli kwotę brutto pomniejszoną o opłatę. Ujawniona note zawiera swoje asset: to wywołanie, z kluczem, którym nadawca zapieczętował notatkę, jest jedynym miejscem, w którym RPC ujawnia, jakie aktywo przeniósł transfer. Zawiera też memo, tak jak rand_getViewingNotes: klucz, który otwiera notatkę, otwiera memo, z tego samego zapieczętowanego ciała. Błędny klucz zwraca { "disclosed": [] }, nie do odróżnienia od transakcji, która niczego nie ujawnia. Koperty wypłaty (withdraw) i alokacji genesis nie są próbowane: są zapieczętowane wewnątrz węzła kluczami odrzucanymi od razu, więc nie istnieje dla nich żaden TxKey. Koperta emisji z faucetu jest próbowana: jej odbiorca odzyskuje klucz przez połowę KEM koperty (rand tx-key).
Transakcje
rand_getTransaction
Parametry [hash]. Wynik: null do czasu zatwierdzenia, potem:
{
"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 ma wartość null przy akcjach bez pakietu. Dowody i koperty są podawane tylko jako długości. envelope_len wynosi 1860 dla każdego slotu w chain 20, którego genesis ustala rozmiar koperty notatki na tę wartość (envelope_bytes w rand_getLimits); w chain 14 do 17 było to 1348. auth_commit i auth_proof_bytes dotyczą podzielonej autoryzacji (od chain 17): to publiczne zobowiązanie c = H(AUTH, nk, salt), które publikują zarówno dowód pakietu, jak i dowód autoryzacji, oraz długość dowodu autoryzacji. W łańcuchu bez hc_auth są to zera i 0.
bundle to pakiet ukrytego aktywa (od chain 14): cztery sloty wejściowe i cztery wyjściowe, więc zawsze cztery nullifiers, cztery commitments i cztery envelope_len, wraz z pozornymi. Każda transakcja zawiera co najwyżej jeden; drugiego pakietu nie ma. Nie ma w nim pola asset: sloty 0–1 niosą aktywo prywatne, a sloty 2–3 RAND, i nic publicznego nie mówi, które aktywo przeniosły sloty 0–1. Transfer RAND i transfer dowolnego tokena RPL mają oba "kind": "none", przy czym burn_a, burn_r i burn_asset wynoszą 0 — ten sam kształt, pole w pole. Rodzaj token_transfer nie istnieje. Trzy pola spalenia to jedyne publiczne oświadczenie pakietu o wartości opuszczającej pulę:
burn_a/burn_asset— ilość spalonego aktywa prywatnego i informacja, które to aktywo. Niezerowe przytoken_burnlubbridge_burn, gdzie są równeamountiassetakcji, oraz przyinvoke, któregoinflowtodepositlubburn.burn_r— spalone RAND. Niezerowe przybond(równe jegoamount),register_aggregatororazinvoke, który wpłaca RAND do skarbca programu.fee— opłata w RAND, zawsze ze slotów 2–3.
Postacie akcji (każde amount, relayer_fee i initial_amount jest ciągiem dziesiętnym; kwoty tokena są w jego własnych jednostkach, nie w jednostkach RAND):
| rodzaj | pola |
|---|---|
none | — |
mint | cm, amount, minter (validator w base58) |
deploy | program, words, public_words_len |
call | program, proof_len, input_envelope_len (null, gdy wywołanie jej nie zawiera) |
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 (indeksy współpodpisujących strażników w pq_guardians; 2420-bajtowe podpisy nie są renderowane). asset_index, amount i commitment mają wartość null przy rotacji zbioru strażników. r jest wyprowadzane, blake3("rand-deposit-r-1" ‖ mu) z skrótu podpisanego przez strażników. Od v0.6.8 także deposit_amount (notatka deponenta: amount, kwota brutto podpisana przez strażników, pomniejszona o opłatę mostu) i fee_note ({ amount, asset, time, r, commitment }, notatka skarbca bez właściciela, lub null bez opłat mostu); commitment to liść depozytu netto |
bridge_burn | asset, amount, relayer_fee, to_chain, token (wykup zabezpieczenia), to. Jeden pakiet niesie całe spalenie: jego burn_asset i burn_a to asset i amount akcji. Od v0.6.8 także release_amount (to, co uwalnia podpisane ciało, czyli amount pomniejszone o opłatę mostu) i fee_note, jak przy attestacji |
register_token | name, symbol, decimals, authority ("none", "key", "bridge" lub "program"), index, initial_amount, initial ({ amount, recipient, time, r } lub null) |
token_mint | asset, amount, recipient, time, r, nonce |
set_authority | asset, nonce, new_authority (base58, lub null przy zrzeczeniu się) |
token_burn | asset, amount; burn_asset / burn_a pakietu je powtarzają |
pause_mints | nonce; bez pakietu i bez opłaty, podpisane przez klucz wstrzymania z genesis |
unpause_mints | nonce, pq_signers; bez pakietu i bez opłaty |
register_bridged_token | name, symbol, salt, chain, token, decimals (dziesiętne miejsca źródłowe pierwszego zabezpieczenia), nonce, asset_id, pq_signers |
list_backing | token_index, chain, token, decimals, nonce, pq_signers |
rotate_pq_guardians | new_pq_guardians, nonce (wykorzystane rotation_nonce), pq_signers (indeksy w zbiorze PQ sprzed rotacji); bez pakietu i bez opłaty, tylko w łańcuchach z mostem rules_v2 |
rotate_pause_key | new_pause_key, nonce, pq_signers; tak samo |
rotate_pq_guardians_v2, rotate_pause_key_v2 | v0.6.8: pola v1, a w formie PQ dodatkowo possession_signatures (liczba). Bez pakietu i bez opłaty; wymagane w łańcuchu, w którego genesis bridge.rotation ustawia needs_possession, jak w chain 20. Rotacja wchodzi w życie po delay_secs (86 400 s w chain 20) |
cancel_rotation | v0.6.8: rotation_kind ("pq_guardians" lub "pause_key"), nonce; podpisane przez bieżący klucz wstrzymania, odrzuca oczekującą rotację |
admit_validator | v0.6.8: candidate (adres), candidate_key (hex), voters (adresy). Bez pakietu i bez opłaty: głosowanie zbioru validatorów za dopuszczeniem rejestracji nowego klucza, w łańcuchu z staking.admission_by_vote, jak chain 20 |
slash_equivocation | v0.6.8: offender, view, first i second ({ hash, height }); tylko łańcuchy z staking.slashing, czym chain 20 nie jest |
invoke | v0.6.8, RPL-2: pola wywołania (program, proof_len, input_envelope_len) i jego transition (poniżej). Tylko łańcuchy z sekcją program_state, jak chain 20 |
register_aggregator, unbond_aggregator, withdraw_aggregator, slash_aggregator, aggregate | ich pola publiczne; tylko łańcuchy z agregacją |
claim_vested, revoke_vesting, bond_vested, unbond_vested | entry (hex), amount (unvested przy odwołaniu), nonce; time przy odebraniu lub odwołaniu; validator i registers przy bond; od v0.6.8 signers przy odwołaniu (pozycje jego podpisujących w revokers wpisu). Bez pakietu; tylko łańcuchy z sekcją genesis vesting, czym chain 20 nie jest |
Rejestracja tokena i jego emisje są publiczne, tak jak depozyt mostu: każde słowo wyemitowanej notatki znajduje się w akcji (jej from to stałe MINT_FROM łańcucha), więc odbiorca odtwarza notatkę z tych pól bez deszyfrowania czegokolwiek. Ciągi rodzajów bridge_attest, token_mint, register_token i invoke to te, według których skanuje portfel, i są przypięte testem.
invoke na wysokości 3079 w chain 20, który odczytał jedną komórkę, usunął ją i wypłacił dwie notatki ze skarbca:
{ "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": [] } }
Wszystko to jest publiczne z założenia. reads to komórki odczytane przez program, wraz z odczytanymi wartościami: dowód powstał względem nich, a księga odrzuca transakcję, jeśli nie obowiązują już nadal. writes to komórki, które zapisał; zapisana wartość złożona z 64 zer usuwa komórkę. Klucz i wartość komórki to Word8. To, co wpłynęło, pochodzi z pakietu: burn_r to RAND wpłacone do skarbca programu, a burn_a z burn_asset to token, który nazywa inflow: deposit do skarbca lub burn (własny token programu), none, gdy burn_a wynosi 0. To, co wypłynęło, to jedna obliczona przez łańcuch notatka na każdą wypłatę, najpierw pays ze skarbca, potem mints tokena, którego uprawnienie do emisji należy do tego programu. Każde słowo każdej notatki jest tu podane pod nazwami pól token_mint; time pochodzi z pakietu, cm to liść dołączony przez łańcuch, a from notatki to stałe PROGRAM_FROM łańcucha. Osiem słów wyjściowych programu znajduje się na pokwitowaniu, tak jak przy wywołaniu.
Żadna odpowiedź transferu nie zawiera nadawcy, odbiorcy, nonce, kwoty ani aktywa: w zapisanym transferze nie istnieje żadne takie pole.
rand_getRawTransaction
Parametry [hash]. Wynik: pełna zatwierdzona transakcja jako hex bincode, wraz z bajtami dowodu — to, czego potrzebuje aggregator, a czego rand_getTransaction nigdy nie renderuje.
Programy i pokwitowania
rand_getProgram
Parametry [program_id]. Wynik: null lub { "id", "base_pc", "words_len", "code_hash", "deployed_at", "public_words_len", "public_digest" }. Brak pola deployer: wdrożenie opłaca pakiet. public_words_len to długość publicznego wejścia programu z czasu wdrożenia (0, gdy go nie ma); public_digest to jego skrót, wartość, względem której sprawdzany jest dowód każdego wywołania, lub null, gdy go nie ma.
rand_getProgramCode
Parametry [program_id]. Wynik: null lub { "base_pc": 0, "words": [ … ] }.
rand_getProgramPublic
Parametry [program_id]. Wynik: publiczne słowa programu z czasu wdrożenia jako jeden ciąg szesnastkowy, każde słowo zapisane jako 4 bajty w porządku little-endian (8 cyfr szesnastkowych na słowo): [1, 2, 0xdeadbeef] to "0100000002000000efbeadde". "" dla programu wdrożonego bez publicznego wejścia, null dla identyfikatora, którego nie ma żaden program. Portfel dowodzący wywołanie przekazuje te słowa proverowi; księga sprawdza zobowiązanie dowodu względem public_digest programu.
rand_getProgramCell
v0.6.8, RPL-2. Parametry [program_id, key], klucz jako Word8 zapisany jako 64 cyfry szesnastkowe (z 0x lub bez). Wynik { "key": "<64 hex>", "value": "<64 hex>" }. Komórka, której program nigdy nie zapisał albo w której zapisał zera (co ją usuwa), odczytuje się jako 64 zera, jedyne kodowanie stanu „brak”; tak samo każdy klucz programu, którego nikt nie wdrożył, ponieważ istnienie programu nie jest sprawdzane. { "enabled": false } w łańcuchu bez sekcji program_state. Komórka jest z założenia publiczna: to właśnie ją portfel odczytuje, aby zbudować reads dla invoke.
rand_getProgramCells
v0.6.8. Parametry [program_id, { "after": "<64 hex>" | null, "limit": n }], obiekt opcjonalny. Wynik { "cells": [{ "key", "value" }, …], "next": "<64 hex>" | null }: komórki programu w kolejności kluczy (porównanie bez znaku ośmiu słów), zaczynając po after, nie więcej niż limit (ograniczone do zakresu od 1 do 1 000). next to ostatni zwrócony klucz, gdy są dalsze komórki; przekaż go z powrotem jako after. Na ostatniej stronie ma wartość null. Program bez komórek odpowiada { "cells": [], "next": null }; { "enabled": false }, gdy brak sekcji.
rand_getProgramVault
v0.6.8. Parametry [program_id]. Wynik [{ "asset": 0, "amount": "123" }, …], rosnąco według indeksu aktywa (0 to RAND, każdy inny indeks pochodzi z rejestru tokenów), kwoty jako ciągi dziesiętne w jednostkach danego aktywa. Wiersz z zerem nie istnieje, więc pusty skarbiec, podobnie jak program, którego nikt nie wdrożył, to []. { "enabled": false }, gdy brak sekcji. Wartość trafia do skarbca przez pakiet invoke (burn_r oraz burn_a dla burn_asset, gdy inflow ma wartość deposit), a opuszcza go jako notatki, które wskazuje pays przejścia.
rand_getLimits
Parametry []. Wynik: to, czego portfel potrzebuje z genesis łańcucha, aby zbudować transakcję: pięć limitów wywołania, rozmiar koperty notatki, przełącznik v0.6, guest uwierzytelniający, warunki gazu oraz, od v0.6.8, pola genesis audit-v6 i limity stanu programu. W łańcuchu 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 } }
Genesis bez pięciu pól limitów (łańcuch 12) otrzymuje 4096, 2097152, 4194304, 18432 i 0. max_proof_bytes wynosiło 8 388 608 w łańcuchach od 13 do 15.
| field | meaning |
|---|---|
envelope_bytes | 1860, gdy genesis ustala każdą kopertę tworzącą notatkę dokładnie na tę długość, w formacie z memo; null w genesis bez tego pola (łańcuchy 14 do 17), gdzie portfel zapieczętowuje kopertę 1 348 bajtów bez memo. Żadna inna wartość nie występuje |
hardening_v6 | true, gdy genesis stosuje reguły poprawności v0.6. Portfel dowodzi wtedy wywołania względem publicznego wejścia programu, po którym następuje powiązanie wywołania transakcji, a nie samego publicznego wejścia: najpierw wybiera się notatki pakietu opłat, potem dowodzi wywołania, na końcu pakietu. Łańcuch z tą flagą odrzuca stary dowód, a łańcuch bez niej nowy |
hc_auth | guest uwierzytelniający przypięty w genesis, w zapisie szesnastkowym, lub null. Gdy ustawiony, hc_bundle to guest pakietu v3, a każdy pakiet zawiera auth_commit i dowód uwierzytelnienia: portfel przekazuje guestowi pakietu nk i świeży salt oraz dowodzi guesta uwierzytelniającego względem klucza wydawania |
gas_metering | "circuit" w łańcuchu, którego genesis ma sekcję gas (licznik w obwodzie); "header" w łańcuchu bez niej, gdy węzeł stosuje własną politykę gazu (--gas-price, --byte-price); null w żadnym z tych przypadków |
gas_price, byte_price | jednostki za gaz oraz jednostki za KiB dowodu wywołania i koperty wejściowej, jako ciągi dziesiętne. Przy sekcji gas są stanem konsensusu i jednakowe na każdym węźle: z gas.dynamic, jak w łańcuchu 20, to bieżące ceny czoła łańcucha, które zmieniają się co blok zależnie od zapełnienia, nigdy nie spadają poniżej dolnych granic genesis (100 i 800) i nigdy nie rosną ponad pułapy; bez niej to stałe ceny z sekcji. Bez sekcji są własną polityką danego węzła i dwa węzły mogą odpowiadać różnie |
bundle_gas_limit | stały gaz, który musi zadeklarować dowód każdego pakietu, z sekcji gas genesis; null bez niej |
adjust_bps | największa zmiana ceny w jednym bloku dokonywana przez kontroler dynamiczny, w punktach bazowych; null w łańcuchu bez gas.dynamic |
max_gas_price, max_byte_price | v0.6.8: pułapy, ponad które kontroler nigdy nie podnosi ceny, ciągi dziesiętne; "10000" i "80000" w łańcuchu 20, null tam, gdzie genesis ich nie ustala (łańcuchy 18 i 19) |
byte_load | v0.6.8: "paying", gdy byte_price zmieniają tylko dowód wywołania i koperta wejściowa, więc blok transferów nie zmienia żadnej, jak w łańcuchu 20; null tam, gdzie liczą się bajty każdej transakcji (łańcuchy 18 i 19) |
admission_by_vote | v0.6.8: czy bond rejestrujący nowy klucz walidatora wymaga wcześniejszego głosu zbioru walidatorów (rand_getAdmitted); true w łańcuchu 20 |
testnet | v0.6.8: znacznik testnet w genesis, który pozwala faucetowi działać obok sekcji mostu; true w łańcuchu 20, false w każdym wcześniejszym |
slashing | v0.6.8: { "equivocation_bps", "jail_epochs" }, czyli koszt ekwiwokacji lidera, lub null; null w łańcuchu 20 |
binding_domain | v0.6.8: 0, gdy powiązanie transakcji i każdy podpisany komunikat akcji wiążą sam identyfikator łańcucha (łańcuchy 14 do 19), 1, gdy zawierają także hash genesis, więc dowód lub podpis wykonany dla jednego łańcucha nie weryfikuje się w żadnym innym (łańcuch 20). Portfel decyduje, którą postać dowodzić, według identyfikatora łańcucha, nigdy według tej odpowiedzi: portfel rand w wersji v0.6.8 stosuje dla identyfikatorów łańcucha od 14 do 19 postać z samym identyfikatorem łańcucha, a dla każdego innego postać związaną z genesis, i odczytuje to pole tylko po to, by odmówić wcześnie. Portfel starszy niż v0.6.8 nie może wysyłać w łańcuchu 20 |
proof_window_blocks | v0.6.8: jak stara, w blokach, może być kotwica pakietu i o ile bloków za wysokością może pozostawać jego time, jedno okno dla obu; 1024 w łańcuchu 20, null (256) w łańcuchach do 19. Portfel z wolnym lub zdelegowanym proverem odczytuje je, by wiedzieć, jak długo może trwać dowód |
program_state | v0.6.8, RPL-2: sekcja program_state genesis i jej limity dla invoke, lub null, a wtedy każdy invoke jest odrzucany i nie można zarejestrować żadnego tokenu programu. cell_fee to jednostki RAND (ciąg dziesiętny), o które rośnie dolna granica opłaty invoke za każdą tworzoną komórkę, czyli zapis niezerowej wartości do komórki odczytywanej jako zera; nadpisanie, usunięcie lub zapis zer nie kosztuje nic. max_reads, max_writes i max_payouts (pays i mints łącznie) to twarde limity. W praktyce najpierw wiąże reguła segmentu: słowa kontekstu przejścia (11 + 16 na odczyt lub zapis + 3 na wypłatę) muszą zmieścić się obok publicznego wejścia programu i 8 słów powiązania bez powiększania tabeli publicznej zkVM; dla programu bez publicznego wejścia ta tabela ma 128 wierszy, co zostawia 119 słów kontekstu |
Węzeł, który nie zna jakiegoś pola, odpowiada bez niego. Nic w tej odpowiedzi nie jest uwierzytelnione, więc portfel nie przyjmuje envelope_bytes wyłącznie na słowo węzła: portfel rand zapieczętowuje starszą kopertę dla identyfikatorów łańcucha od 14 do 17, cokolwiek odpowie węzeł, i inni klienci powinni postępować tak samo.
rand_getReceipt
Parametry [tx_hash]. Wynik null, dopóki wywołanie nie zostanie zatwierdzone, potem { "tx", "program", "tier": 14, "outputs": [1, 0, 25, 0, 0, 0, 0, 0], "height": 17, "index": 0, "h_in": "9c0e…7f", "h_pub": null }. Bez pola effect. h_pub to skrót publicznego wejścia programu z czasu wdrożenia, względem którego sprawdzono dowód wywołania, null dla programu bez takiego wejścia. invoke (v0.6.8) ma pokwitowanie wywołania, a rand_getReceipts i temat receipts przekazują je bez zmian.
rand_getReceipts
Parametry [program_id, from_height, to_height, limit?]. Wynik { "receipts": [ … ], "next_height": 2051 }: pokwitowania program_id dla from_height <= height <= to_height, według wysokości, a potem indeksu, każde dokładnie jako obiekt rand_getReceipt. limit domyślnie wynosi 256, jest do tej wartości ograniczony i nigdy nie dzieli wysokości: gdy strona zawiera już limit pokwitowań, nadal zwraca resztę tej wysokości. next_height to pierwsza wysokość, której nie zwrócono, lub null, gdy stronę zakończyło to_height. -32602, gdy to_height jest mniejsze niż from_height.
rand_getCallEnvelope
Parametry [tx_hash]. Wynik null lub { "tx", "h_in", "kem_ct", "to_sender", "to_auditor", "body" } w zapisie szesnastkowym — zapieczętowany zapis wejścia wywołania, zwracany bez zmian; węzeł nie posiada klucza, który by go otwierał. null, gdy wywołanie nie opublikowało żadnego (--no-envelope), transakcja nie jest wywołaniem albo nie ma pokwitowania.
Staking i podaż
rand_getValidators
Parametry []. Wynik: jeden wiersz na wpis rejestru, w kolejności adresów, kwoty jako ciągi dziesiętne:
[{ "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) to pierwsza epoka, w której ukarany klucz może znów znaleźć się w zbiorze (18446744073709551615 na stałe), null, gdy nie jest uwięziony. Łańcuch 20 nie ma staking.slashing, więc tam zawsze jest null.
rand_getAdmitted
v0.6.8. Parametry []. Wynik { "admission_by_vote": true, "max": 256, "admitted": ["<address>", …] }: klucze, które zbiór walidatorów przyjął głosowaniem przez AdmitValidator i które jeszcze się nie zarejestrowały, w kolejności adresów. W łańcuchu, którego genesis ustawia staking.admission_by_vote, jak w łańcuchu 20, Bond rejestrujący nowy klucz musi znajdować się wśród nich. max to liczba kluczy, które rejestr przechowuje jednocześnie. W łańcuchu bez tej flagi admission_by_vote ma wartość false, lista jest zawsze pusta, a rejestracja nie wymaga głosowania. Łańcuch 20 odpowiedział "admitted": [] dnia 2026-10-01.
rand_getEpoch
Parametry []. Wynik { "epoch": 41, "epoch_blocks": 1000, "next_set": ["…", "…"] }; next_set jest projekcją.
rand_getSupply
Parametry []. Wynik:
{ "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 i slashed zmieniają się tylko w łańcuchu z agregacją. faucet_epoch i faucet_minted_in_epoch to licznik faucetu w danej epoce, porównywany z staking.faucet_budget_per_epoch (stan konsensusu w łańcuchu 20). Cztery pola vesting_* to liczniki westingu z genesis, wszystkie mają wartość "0" w łańcuchu bez sekcji vesting, a tak jest w łańcuchu 20. program_rand_out i program_rand_held (v0.6.8, RPL-2; "0" bez sekcji program_state) to RAND, który wywołania wypłaciły ze skarbców programów jako noty (strona puli, wewnątrz pool_value), oraz to, co skarbce nadal przechowują (strona rejestru, wewnątrz total_supply); trafił on tam przez burn_r wywołania, więc po stronie puli mieści się w burned. registration_fees_burned to Σ opłat rejestracyjnych tokenów spalonych na podstawie genesis tokens.burn_registration_fee, które łańcuch 20 ustawia; invariant_holds odejmuje tę sumę, wraz z slashed, od tego, co łańcuch wyemitował. Podaż wyjaśnia tę tożsamość.
rand_getEmission
Parametry []. Wynik { "inflation": "0", "subsidy": null, "faucet": true }. inflation to stałe "0". subsidy to harmonogram agregacji bloków (current, base, halving_blocks, sealed_blocks, next_halving_at) i ma wartość null w łańcuchu bez sekcji aggregation, a tak jest w łańcuchu 20. faucet odzwierciedla rand_status.
Bridge
Wszystkie cztery odpowiadają w każdym łańcuchu; w łańcuchu bez sekcji bridge stan to { "enabled": false }, a rejestr to []. Genesis łańcucha 20 ją zawiera: zbiór strażników 1 (guardian_set_index 1) z ośmioma strażnikami, ośmioma strażnikami PQ, kluczem wstrzymania, burn_sequence 13 w genesis, progiem ochrony przed powtórzeniem (min_inbound_sequence 3 dla łańcuchów źródłowych 2, 3 i 4 oraz 7 dla łańcucha źródłowego 5), bridge rules_v2 z globalnym limitem emisji 4 000 zUSD na 24-godzinne okno dla wszystkich zabezpieczeń oraz dwiema grupami nowymi w v0.6.8: rotation (rotacja strażników PQ lub klucza wstrzymania wymaga dowodu posiadania nowych kluczy i wchodzi w życie 86 400 s po zatwierdzeniu) oraz fees (10 bps od każdego depozytu i 10 bps od każdego spalenia, zatrzymywane w Rand jako nota zUSD na adres skarbca). Łańcuch 19 miał burn_sequence 8, progi 1 i 4 oraz żadnej z tych grup. Jego sekcja tokens zawiera registration_fee w wysokości 1 RAND (spalane), mint_cap_per_day dla każdego zabezpieczenia równy 10000000000000 (100 000 zUSD przy ośmiu miejscach dziesiętnych) i wymienia sam zUSD: przeniesiony z łańcucha 14 w genesis, ten sam identyfikator aktywa, indeks 1, siedem zabezpieczeń.
rand_getBridgeState
Parametry []. Wynik { "enabled": false } lub:
{
"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": [ … ]
}
| pole | znaczenie |
|---|---|
emitter | adres wychodzącego emitera tego łańcucha, 32 bajty w hex |
emitters | identyfikator łańcucha źródłowego → adres emitera, któremu ufa się tam |
guardians | 20-bajtowe adresy bieżącego zbioru, w hex |
pq_guardians | zbiór PQ: klucze publiczne Dilithium2 (1312 bajtów), w hex, ułożone zgodnie z indeksami bieżącego zbioru strażników (zbiór 1 w łańcuchu 20). Każdy BridgeAttest zawiera kworum współpodpisów tego zbioru. Rotacja zbioru strażników nigdy go nie zmienia; robi to tylko rotate_pq_guardians, w łańcuchu z rules_v2 |
mint_paused | dopóki ma wartość true, każde poświadczenie transferu jest odrzucane z komunikatem bridge minting is paused; spalenia i rotacje pozostają otwarte |
pause_nonce | wartość, którą musi nieść następne wstrzymanie lub wznowienie; oba ją zwiększają |
list_nonce | wartość, którą musi nieść następny register_bridged_token lub list_backing; oba ją zwiększają |
pause_key | jedyny klucz Dilithium2, który może wstrzymać emisję, w hex. Może tylko wstrzymywać: wznowienie wymaga kworum strażników PQ |
registration_fee | ile RegisterBridgedToken jest winien ponad podstawę pakietu, w jednostkach RAND, jako łańcuch dziesiętny |
burn_sequence | liczba dotąd wyemitowanych wiadomości wychodzących |
rotation_nonce | wartość, którą musi nieść następny rotate_pq_guardians / rotate_pause_key |
rules_v2 | globalny limit emisji i jego okno kroczące albo null w łańcuchu bez reguł mostu v2. Według nich limit dla zabezpieczenia również jest oknem kroczącym, a wpis na listę jest odrzucany, gdy emisja jest wstrzymana. Od v0.6.8 zawiera także global_minted_in_window i global_mint_headroom, łańcuchy dziesiętne |
min_inbound_sequence | próg ochrony przed powtórzeniem z genesis: identyfikator łańcucha źródłowego → najniższy numer sekwencyjny, jaki może nieść transfer z tego łańcucha, zwykłe liczby; null w łańcuchu bez progu (łańcuch 15 i wcześniejsze). bridge_attest poniżej progu jest odrzucany z BelowReplayFloor, werdyktem trwałym. Relayer odczytuje go, by pominąć blokadę, którą łańcuch, z którego ten został wydzielony, już wyemitował |
rotation_rules | v0.6.8: { "delay_secs", "needs_possession" } z genesis bridge.rotation albo null. Według nich rotacja jest akcją _v2, niesie podpisy dowodzące posiadania nowych kluczy i czeka delay_secs, zanim wejdzie w życie |
pending_rotations | v0.6.8: rotacje zatwierdzone, lecz jeszcze nieobowiązujące, każda jako { "kind": "pq_guardians", "new_pq_guardians", "effective_at_secs" } albo { "kind": "pause_key", "new_pause_key", "effective_at_secs" }; null bez rotation_rules. cancel_rotation podpisany bieżącym kluczem wstrzymania usuwa jedną z nich |
fees | v0.6.8: { "mint_bps", "burn_bps", "recipient" } z genesis bridge.fees albo null (łańcuchy 14 do 19). Łańcuch zatrzymuje ten udział w każdym depozycie i każdym spaleniu, zaokrąglony w dół do pełnej jednostki wypłaty zabezpieczenia, jako notę zUSD dla recipient. Depozyt uznaje kwotę brutto pomniejszoną o opłatę; podpisana treść spalenia wypłaca jego kwotę pomniejszoną o opłatę. Portfel odczytuje to, by wycenić własny depozyt, a gdy jest recipient, by odtworzyć swoje noty z opłatami |
assets | wiersze rand_getAssets |
Bez sald: wartość przeniesiona mostem to noty. Nie ma już next_index: token przeniesiony mostem jest wpisywany na listę, pod indeksem ustalonym już przy jego rejestracji, zanim będzie można go wpłacić, więc nie ma indeksu do przewidywania. Indeks wpisanego tokenu odczytaj z assets lub rand_getTokens.
rand_getAssets
Parametry []. Wynik: rejestr aktywów mostu, rosnąco według indeksu, lub []:
[{ "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" }]
Od v0.6.8 każdy wiersz zabezpieczenia, tu i wszędzie tam, gdzie zabezpieczenia są zwracane (rand_getBridgeState.assets, backings w rand_getToken, rand_getTokens i rand_getTokenSupply), zawiera minted_in_window (łańcuch dziesiętny) i mint_window_secs, oba null w łańcuchu z licznikiem dziennym, oraz mint_headroom: największy depozyt w to zabezpieczenie, jaki limity dopuszczają w czasie bloku głowy, czyli limit zabezpieczenia pomniejszony o to, co wyemitowało, i, według reguł v2, nie więcej, niż zostało w oknie obejmującym cały rejestr. Czytaj mint_headroom, a nie mint_cap_per_day − minted_today, które pomija limit globalny. Według reguł v2, jak w łańcuchu 20, minted_today jest licznikiem okna kroczącego, wielkością, z którą sprawdzany jest limit zabezpieczenia; opis licznika dziennego poniżej dotyczy łańcucha 14.
Jeden wiersz na zabezpieczenie (monetę źródłową), więc token z siedmioma zabezpieczeniami to siedem wierszy pod jednym index. index to słowo asset, które niesie nota tego aktywa; indeks 0 to RAND i nigdy nie występuje w rejestrze. decimals to liczba miejsc dziesiętnych zabezpieczenia w źródle. locked, mint_cap_per_day i minted_today to łańcuchy dziesiętne w ośmiodziesiętnych jednostkach samego tokenu, nigdy RAND; mint_day to zwykła liczba całkowita, numer dnia UTC. mint_cap_per_day to tokens.mint_cap_per_day z genesis, czyli najwięcej, ile jedno zabezpieczenie może wyemitować na dzień UTC czasu bloku. minted_today to ilość, którą zabezpieczenie wyemitowało w mint_day, dniu UTC (timestamp_ms / 86,400,000) bloku głowy, więc licznik pozostały z wcześniejszego dnia odczytuje się jako "0", gdy głowa przekroczy północ. Depozyt ponad limit jest odrzucany z MintCapExceeded i staje się dopuszczalny następnego dnia. chain i token to tożsamość w protokole przesyłowym, którą strażnicy podpisują; asset_id to blake3 z obu, czyli to, co oblicza rand_bridgeAssetId.
rand_bridgeAssetId
Parametry [token_chain, token_address] (liczba całkowita, 32 bajty w hex). Wynik: identyfikator aktywa, 64 znaki hex. Czysta arytmetyka.
rand_getBridgeBurn
Parametry [sequence]. Wynik null lub { "sequence": 0, "body_hex": "…", "digest": "…", "tx": "…", "height": 2, "amount": "…", "release_amount": "…", "fee": "…" }.
Ostatnie trzy pola są od v0.6.8, w każdym łańcuchu, jako łańcuchy dziesiętne w ośmiodziesiętnych jednostkach tokenu. release_amount to kwota, którą niesie podpisana treść, odczytana z samego body_hex: to, co wypłaca kontrakt źródłowy, z czego opłaca opłatę relayera zawartą w treści. fee to opłata mostu, którą łańcuch zatrzymał jako notę skarbca, a amount to to, co spalił pakiet, release_amount + fee. Bez bridge.fees (łańcuchy 14 do 19) fee wynosi "0". Sekwencja 13 w łańcuchu 20, spalenie 0,999 zUSD: "amount": "99900000", "fee": "99900", "release_amount": "99800100".
Tokeny (RPL)
Rejestr tokenów RPL: każdy token, przeniesiony mostem i natywny. Tokeny wyjaśniają standard.
rand_getTokens
Parametry [from_index, limit], oba opcjonalne (0 i 1000; limit jest przycinany do 1000). Wynik: rejestr rosnąco według indeksu od from_index, odczytywany zakresem od tego indeksu:
{ "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 to słowo asset, które niesie nota tokenu (0 to RAND i nigdy nie jest wymieniane). id to identyfikator aktywa tokenu, a id_text to jego tekstowa postać z sumą kontrolną: bech32m, HRP rpl, nad 32 bajtami identyfikatora, 62 znaki. authority przyjmuje jedną z postaci:
kind | pozostałe pola |
|---|---|
none | — (stała podaż lub zrzeczenie się uprawnień) |
key | key, address |
bridge | backings: [{ "chain", "token", "decimals", "locked", "mint_cap_per_day", "minted_today", "mint_day" }], pola rand_getAssets, po jednym wierszu na każde zabezpieczenie |
program | program |
Podaże, locked, mint_cap_per_day, minted_today i registration_fee są ciągami dziesiętnymi (jednostki RAND dla registration_fee, jednostki tokenu dla pozostałych); next_index, mint_day i max_tokens są liczbami. max_tokens to limit rejestru ustalony w genesis (4 096 w chain 20; null, gdy go nie ma), po którego przekroczeniu rejestracja jest odrzucana z błędem RegistryFull. burn_registration_fee mówi, czy opłata za rejestrację jest spalana, a nie wypłacana proposerowi; bound_note_value mówi, czy mint lub depozyt równy 2⁶³ lub większy jest regułą ważności (przyjęcie do mempoola odrzuca taki na każdym chainie niezależnie od niej). Wszystkie trzy są ustawione w chain 20. Strona krótsza niż limit jest ostatnia.
Uprawnienie program ({ "kind": "program", "program": "<id>" }) można zarejestrować tylko na chainie z sekcją program_state, jak chain 20 (v0.6.8): token startuje z zerową podażą, a mintować lub spalać go mogą wyłącznie wywołania tego programu.
Portfel rozpoznaje identyfikator tokenu przez tę listę, nigdy przez rand_getToken: aktywo transferu jest prywatne w łańcuchu, a odczyt całego rejestru kosztuje tyle samo, niezależnie od tego, o który token chodzi.
rand_getToken
Parametry [token]: indeks rejestru (liczba lub ciąg dziesiętny), 64-znakowy identyfikator hex (z 0x lub bez, w dowolnej wielkości liter) albo postać tekstowa rpl1… (wszystkie małe lub wszystkie wielkie litery). Wynik: wiersz tego tokenu z rand_getTokens albo null. Błędny identyfikator — zła suma kontrolna, inny HRP, zła długość, mieszana wielkość liter, nie hex — to -32602, więc literówka nigdy nie wskaże innego tokenu. Wyszukiwanie pojedynczego tokenu zdradza węzłowi, który token interesuje wywołującego; służy eksploratorom i jednorazowym odczytom.
rand_getTokenSupply
Parametry [token], w tych samych postaciach. Wynik null albo:
{ "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 jest puste dla tokenu natywnego; dla tokenu z mostu kwoty locked sumują się do total_supply. Obowiązuje ta sama uwaga o prywatności co przy rand_getToken.
Agregacja bloków (nieaktywna w chain 20)
Te metody istnieją w węźle dla chainów, których genesis zawiera sekcję aggregation. W chain 20 rejestr jest pusty i nic nigdy nie zostaje odpieczętowane.
| metoda | parametry | wynik |
|---|---|---|
rand_getAggregate | [hash] | pola covers, aggregator, subsidy, proving_share, n, height agregatu pieczętującego; null dla każdej innej transakcji |
rand_getAggregators | [] | rejestr agregatorów: address, bond, payout, nonce, unbonding w każdym wierszu |
rand_getUnsealed | [from, limit] | { "bundles": [{ "hash", "height", "excess" }], "next_from" }, paczki, które agregator może jeszcze objąć |
Aggregate jest wysyłany przez rand_sendTransaction jak wszystko inne.
Vesting w genesis (nieaktywny w chain 20)
Te metody istnieją w węźle dla chainów, których genesis zawiera sekcję vesting. Żaden chain jej jeszcze nie ma: w chain 20 każda odpowiada { "enabled": false }. Publiczny endpoint przekazuje je od 2026-10-01.
| metoda | parametry | wynik |
|---|---|---|
rand_getVesting | [id] lub [id, at_ms], 64-znakowy identyfikator hex wpisu | wpis: jego klasa, beneficjent, harmonogram (amount, start_ms, cliff_ms, linear_ms, step_ms), to, co zostało odebrane, odwołane i zablokowane w bondzie, oraz vested_now, claimable_now, unvested_now w chwili as_of_ms (domyślnie czas bloku głowy); null dla nieznanego identyfikatora. Od v0.6.8 wpis podlegający odwołaniu zawiera listę revokers, ich threshold wymagany do odwołania oraz treasury, do którego odwołanie wypłaca (zastępują one pojedynczy revoker), a sam wpis zawiera revoke_nonce i locked_now |
rand_getVestingSummary | [] | { "enabled": true, "height", "as_of_ms", "entries", "issued", "released", "locked", "classes": [ … ] }: sumy dla poszczególnych klas, bez klucza i właściciela |
rand_getVestingSchedule | [from_ms, to_ms, step_ms], najwyżej 1000 punktów | { "enabled": true, "issued", "points": [{ "t_ms", "locked" }] }: zablokowana suma rejestru w czasie |
Kwoty są ciągami dziesiętnymi. Cztery akcje vestingu są wysyłane przez rand_sendTransaction.
Subskrypcje (WebSocket)
ws://127.0.0.1:8545/ lub /ws. Gniazdo obsługuje wyłącznie rand_subscribe i rand_unsubscribe, a na wszystko inne odpowiada -32601. Trzy tematy, niezależne strumienie bez gwarancji kolejności między nimi:
newHeads— w postacirand_getHead, wysyłany raz na każdy zatwierdzony blok, po kolei, także podczas synchronizacji.viewoznacza tu własny widok bloku.receiptslubreceipts <program_id>— jedno powiadomienie na każdy zatwierdzony blok, który zawiera co najmniej jedno pasujące potwierdzenie wywołania:{ "height", "hash", "receipts": [ … ] }, każde potwierdzenie w postacirand_getReceipt.transaction <hash>— jedno powiadomienie, po czym węzeł usuwa subskrypcję:{ "status": "committed", "height", "index" }albo{ "status": "rejected", "reason" }dla odmowy dotyczącej samych bajtów transakcji (z tym samym ograniczeniem, co wrand_getTransactionStatus). Odmowa zależna od stanu nigdy nie jest ogłaszana, więc połącz ją z limitem czasu.
{ "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 } } }
Limity: 64 połączenia na węzeł (65. jest odrzucane przy upgrade z 503), 8 subskrypcji na połączenie, 64 KiB na ramkę klienta, ping co 30 s z odpowiedzią w ciągu 5 s oraz 256 wpisów zaległości na strumień — subskrybent opóźniony bardziej na strumieniu, którego słucha, jest zamykany kodem 1008, a nie buforowany; połącz się ponownie i uzupełnij lukę przez rand_getCompactBlocks (głowy), rand_getReceipts (potwierdzenia) lub rand_getTransactionStatus (transakcja). Zwykłe GET / bez nagłówków upgrade odpowiada 400.
Błędy
| kod | znaczenie |
|---|---|
-32601 | nieznana metoda (w tym wycofane metody kont) |
-32602 | nieprawidłowy lub brakujący parametr |
-32000 | odrzucenie: transakcja odrzucona przez mempool, wywołanie faucetu ograniczone limitem, budowa witness, która czekała ponad 10 s, odczyt trwający ponad 30 s, metoda, której nie obsługuje publiczny listener, lub subskrypcja ponad limit |
-32001 | nie znaleziono wskazanego obiektu |
-32010 | przycięte: wysokość poniżej progu retencji tego węzła; data.floor go podaje (patrz niżej) |
-32603 | błąd wewnętrzny |
-32600 | nieprawidłowe żądanie: treść ponad limit rozmiaru, nie JSON, źle sformowana paczka lub powiadomienie |
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32000, "message": "…" } }
W przypadku rand_sendTransaction werdyktem o transakcji są tylko -32000 i -32602; po każdym innym kodzie jej los jest nieznany (patrz rand_sendTransaction).
Węzły przycinające: błąd -32010
Węzeł uruchomiony z --prune-history <window> przechowuje cały ledger (noty, nullifiery, kotwice, rejestr), ale tylko ostatnie <window> bloków, transakcji i potwierdzeń; rand_status.prune_floor to najniższa wysokość, jaką jeszcze posiada. W chain 20 24 z 26 walidatorów działa z --prune-history 24h; dwa archiwa działają bez tej flagi i przechowują każdy blok, a publiczny endpoint przekazuje żądania do jednego z nich.
- Według wysokości, poniżej progu (z wyjątkiem genesis):
rand_getBlockByHeight,rand_getFinalitywedług wysokości oraz zakresrand_getBlocks,rand_getCompactBlockslubrand_getReceiptssięgający poniżej niego odpowiadają-32010pruned: height h is below this node's retention floor fzdata: { "floor": f }. Zapytaj archiwum.[0, 0]nadal zwraca genesis. - Według hasha:
rand_getBlockByHash,rand_getReceipt,rand_getRawTransaction,rand_getCallEnvelopeirand_getAggregateodpowiadająnulldla przyciętego hasha, tak jak dla takiego, który nigdy nie istniał; odróżnić je może tylko archiwum.rand_getTransactionirand_checkTransactionteż odpowiadająnull, a-32010tylko wtedy, gdy ocalał wiersz lokalizacji wskazujący wysokość poniżej progu.rand_getTransactionStatusdodajefloordo każdego wpisuunknownna węźle przycinającym. - Skanowanie portfela pozostaje nienaruszone:
rand_getCommitments,rand_getNullifiers,rand_getAnchori metody witness odczytują rodziny danych, które nigdy nie są przycinane.
Transakcja w formacie przesyłowym
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
Domyślna konfiguracja bincode: liczby całkowite o stałej szerokości, 8-bajtowe prefiksy długości, tagi enum u32 w kolejności deklaracji. Pięć wariantów agregacji następuje po BridgeBurn i poprzedza RegisterToken w enum (Transakcje); chain 20 nigdy ich nie przyjmuje, podobnie jak czterech wariantów vestingu ani SlashEquivocation, ale enkoder, który na stałe wpisuje numery tagów, nadal musi je zliczyć.
Dwa ostatnie pola paczki pojawiły się w v0.6.3 i chain 17. bincode jest pozycyjny, więc enkoder napisany dla chain 16 lub wcześniejszego nie tworzy transakcji, którą ten chain zdekoduje, a razem z nimi zmienił się każdy identyfikator transakcji: domeną identyfikatora jest teraz rand-txid-3, która wiąże auth_commit i skrót dowodu uwierzytelnienia. Klient, który przelicza identyfikatory lokalnie, musi się do tego dostosować. W chain 20 każda paczka niesie dowód uwierzytelnienia, zarówno samodzielnie wygenerowany, jak i delegowany. v0.6.8 nie zmienia układu Transaction ani Bundle; dopisuje akcje od 28 do 33.
Każda transakcja zawiera co najwyżej jeden pakiet (bundle). Bond zawiera pakiet, w którym burn_r jest równe jego amount, a burn_a i burn_asset wynoszą 0. BridgeBurn lub TokenBurn spala przez pakiet: burn_asset musi być równe polu asset akcji (nigdy 0), burn_a jej polu amount, a burn_r wynosi 0, natomiast fee jest płatna w RAND z pozycji 2–3. Żadna inna akcja nie spala tokenu, a RAND jest spalany wyłącznie przez burn_r: pakiet z burn_asset równym 0 i niezerowym burn_a jest odrzucany wszędzie. Pole r w BridgeAttest jest wyprowadzane, a nie wybierane: dopuszczenie wymaga blake3("rand-deposit-r-1" ‖ mu) obliczonego dla skrótu podpisanego przez strażników (guardians) i odrzuca każdą inną wartość (WrongDepositBlinding, odmowa trwała). Token z mostu musi zostać wpisany na listę — w genesis albo przez RegisterBridgedToken / ListBacking — zanim jakiekolwiek jego poświadczenie (attestation) zostanie dopuszczone; poświadczenie monety spoza listy jest odrzucane z błędem UnlistedToken.
Każdy dowód pakietu jest tworzony dla transakcji, w której się znajduje, i względem niej weryfikowany: dla całej transakcji z wyzerowanymi dowodami, powiązanej z identyfikatorem łańcucha oraz, w łańcuchu 20 (binding_domain: 1), ze skrótem genesis, pod świeżymi tagami. W łańcuchach od 14 do 19 powiązanie obejmowało wyłącznie identyfikator łańcucha, więc dowód wykonany dla łańcucha 19 nie przechodzi weryfikacji w łańcuchu 20, a portfel starszy niż v0.6.8 nie może tam wysyłać. W łańcuchach od 18 do 20 pakiet bez dwóch dowodów koduje się w 7 936 bajtach, a transakcja transferu bez nich w 7 949 (5 848 i 5 861 w łańcuchach od 14 do 16, z kopertami po 1 348 bajtów i bez pól uwierzytelniania). Transfer przesyłany w sieci ma około 2,85 MB w profilu produkcyjnym, w przeważającej części to dowód: dowód pakietu o rozmiarze około 1,49 MB i dowód uwierzytelniania o rozmiarze około 1,36 MB. Przed podzieloną autoryzacją było to około 1,43 MB.