Usa questa pagina per eseguire il tuo rand-node contro la testnet, che è anche il modo consigliato per usare un wallet in modo privato: un nodo che gestisci tu non viene a sapere da nessuno, se non da te, quale foglia stai per spendere. Un observer si sincronizza, riverifica ogni prova ed espone la JSON-RPC; un validatore fa lo stesso e partecipa al consenso una volta che la sua chiave è nell’insieme di un’epoca.
Compilazione
Requisiti: Rust 1.98.1 (fissato in rust-toolchain.toml; rustup lo installa), un compilatore C++ e cmake per RocksDB. Il crate zkVM ha dipendenze di percorso verso un checkout circuits/ affiancato del repository del sistema di prove (randprotocol/zkp-circuits), che deve trovarsi accanto a fullnode/, al commit da cui è stata importata la release: la riga circuits: di crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md (aeacf31 per v0.6.8, come per v0.6.7). La prima compilazione richiede da 10 a 20 minuti.
git clone https://github.com/randprotocol/fullnode
cargo build --release # target/release/rand-node, target/release/rand, target/release/rand-prover
Esegui v0.6.8 (git checkout v0.6.8, commit c9c9bd3c, è la release che la flotta esegue; rand_getVersion riporta lo sha di un nodo). La sua release su GitHub contiene rand-node, rand, rand-prover e SHA256SUMS, compilati su un host della flotta e non firmati. La chain 20 la richiede: il suo genesis contiene campi che nessuna build precedente legge (testnet, binding_domain, proof_window_blocks, program_state, i gruppi rotation e fees del bridge, i massimali di gas e l’ammissione allo staking tramite voto), e v0.6.8 include modifiche al consenso che un nodo più vecchio non esegue. Le prove sono ancora prodotte con il constraint set 8, come sulle chain 18 e 19, e ogni bundle porta ancora una prova di autorizzazione accanto alla prova del bundle (autorizzazione separata, dalla chain 17), perciò il genesis fissa gli stessi due guest: il bundle guest v3 (hc_bundle 60af094a…) e l’auth guest (hc_auth 1e4e347f…). Il genesis contiene anche una sezione gas, hardening_v6 e envelope_bytes. Una build v0.6.8 rifiuta il genesis delle chain 14, 15, 16 e 17 a run e a verify, in base all’hash; può ancora eseguire quello della chain 19. Ogni nodo usa la build della flotta.
Chain 20: un hard fork con arresto totale
La chain 20 è entrata in funzione il 2026-10-01 alle 06:17 UTC. È stata ricavata da uno snapshot della chain 19 e avviata con arresto totale e riavvio totale: ogni nodo della chain 19 si è fermato all’altezza 7.700, e ogni nodo è ripartito sulla chain 20 con v0.6.8. Non è stato un aggiornamento progressivo, per due ragioni. La chain 20 è un nuovo genesis, quindi nessun blocco è condiviso con la chain 19. E v0.6.8 include modifiche al consenso dell’audit v6 che non devono mai essere applicate nodo per nodo: CON-4 elimina il rilascio automatico del lock di un validatore, e CH-1 aggiunge un pacemaker con timeout certificate. Tutti i 26 validatori, le loro chiavi, i peer id e i bootstrap sono stati riportati; un quorum è ancora 18 su 26. Le chain 19 e 18 sono dismesse.
Spostare un nodo dalla chain 19 alla chain 20 richiede quindi il nuovo binario, il nuovo file di genesis e una directory dati nuova, come sotto. I wallet hanno bisogno di v0.6.8 per inviare sulla chain 20: il suo genesis lega ogni prova e ogni messaggio firmato al proprio hash (binding_domain: 1), cosa che un wallet più vecchio non fa.
Chiavi
rand-node keygen --out node.key.json # prints the address
rand-node address --key node.key.json # address, public key, libp2p peer id
Il file è { "seed", "address", "public_key" }, con modalità 0600; solo il seed è segreto. Anche un observer ha bisogno di una chiave: è l’identità p2p. Una chiave di nodo non è una chiave di wallet: per un wallet usa rand keygen.
Genera la tua chiave e tienila fuori dal checkout. Il repository del fullnode non traccia più alcuna chiave (audit v3, OPS-1): i file deploy/node-*.key.json e deploy/payout/*.key.json che erano stati committati per le chain da 8 a 13 sono seed pubblicati e non devono essere usati. Le chiavi dei validatori della chain 20 sono state generate fuori dal repository e non ne hanno mai fatto parte: i suoi 26 validatori di genesis sono le diciotto chiavi generate per la chain 14 e le otto vincolate sulla chain 15, riportate a ogni taglio successivo.
Da v0.6.8 rand-node keygen rifiuta un file --out che esiste già; v0.6.7 lo sovrascriveva senza chiedere. Il file è l’unica copia del seed. Fanne un backup prima che un bond dipenda da esso.
Inizializzazione dal genesis
Ogni nodo di una chain ha bisogno del file di genesis identico byte per byte; rand-node init lo copia nella directory dati e stampa il suo hash, che per la chain 20 deve essere 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135. Il file è deploy/genesis-chain20.json (sha256 0020247a…3a21). È stato committato su main del fullnode con il record di lancio (commit 74cfaca0), dopo il tag, quindi un checkout di v0.6.8 non lo contiene: scaricalo da main.
git -C fullnode show origin/main:deploy/genesis-chain20.json > genesis-chain20.json
rand-node init --datadir ./data-6210cf07 --genesis genesis-chain20.json
Questo crea <datadir>/db (RocksDB) con il blocco 0, le nove note di genesis come prime foglie dell’albero (sette note RAND che portano 5.184,243719258 RAND di wallet degli operatori dalla chain 19, e due note zUSD da 10 e 89 zUSD, i 99 zUSD bloccati nella custodia del bridge) e il registro dei validatori. Rieseguire con lo stesso genesis non ha effetto; un genesis diverso viene rifiutato (already initialized with a different genesis significa che la datadir appartiene a un’altra chain). Dai alla directory dati il nome composto dai primi otto caratteri dell’hash di genesis, come fa la flotta (data-<name>-6210cf07), così da non entrare mai in collisione con quella della chain 19 (-a3defc93).
La struttura del file di genesis:
{
"chain_id": 20,
"timestamp_ms": 1790835251661,
"validators": [ { "public_key": "<hex>", "stake": 1000000000000, "payout": "rand1…" } ],
"alloc": [ { "cm": "<64 hex>", "envelope": { "kem_ct": "…", "to_receiver": "…", "to_sender": "…", "body": "…" }, "amount": 1000000000000,
"opening": { "pk": "<64 hex>", "time": 0, "r": "<64 hex>" } },
{ "cm": "…", "envelope": { … }, "amount": 1000000000,
"opening": { "pk": "<64 hex>", "time": 0, "r": "<64 hex>", "asset": 1 } } ],
"faucet": true,
"confidential": true,
"fri_profile": "production",
"hc_bundle": "60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce",
"bridge": { "emitter": "<64 hex>", "guardians": [ "<40 hex>" ], "emitters": { "2": "<64 hex>", "3": "…", "4": "…", "5": "…" },
"pq_guardians": [ "<hex>" ], "pause_key": "<hex>",
"rules_v2": { "global_mint_cap_per_window": 400000000000, "cap_window_secs": 86400 },
"guardian_set_index": 1, "burn_sequence": 13,
"min_inbound_sequence": { "2": 3, "3": 3, "4": 3, "5": 7 },
"rotation": { "delay_secs": 86400, "needs_possession": true },
"fees": { "mint_bps": 10, "burn_bps": 10, "recipient": "rand1…" } },
"tokens": { "registration_fee": 1000000000, "mint_cap_per_day": 10000000000000,
"tokens": [ { "name": "Shielded USD", "symbol": "zUSD", "salt": "<64 hex>",
"backings": [ { "chain": 2, "token": "<64 hex>", "decimals": 6 }, … ] } ],
"max_tokens": 4096, "burn_registration_fee": true, "bound_note_value": true },
"consensus_domain": 1,
"staking": { "faucet_budget_per_epoch": "10000000000000", "bond_activation_epochs": 2,
"max_weight_bps": 3333, "registration_v2": true,
"faucet_recipients": [ "rand1…" ], "faucet_minters": [ "<validator address>" ],
"max_stake_entry_bps_per_epoch": 2500, "admission_by_vote": true },
"epoch_blocks": 1000,
"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": { "gas_price": "100", "byte_price": "800", "bundle_gas_limit": 20479, "metering": "circuit",
"dynamic": { "target_block_bytes": 10485760, "target_block_gas": 262144,
"adjust_bps": 1250, "min_gas_price": "100", "min_byte_price": "800",
"max_gas_price": "10000", "max_byte_price": "80000", "byte_load": "paying" } },
"testnet": true,
"binding_domain": 1,
"proof_window_blocks": 1024,
"program_state": { "cell_fee": 10000000 }
}
Ogni campo rientra nell’hash di genesis. hc_bundle fissa il bundle guest rispetto al quale è verificata ogni prova di bundle, e hc_auth l’auth guest rispetto al quale è verificata ogni prova di autorizzazione; un nodo la cui build assembla un guest diverso rifiuta di avviarsi e nomina entrambi i digest. I cinque campi max_* sono facoltativi e sono inclusi nell’hash solo se presenti; la chain 20 li imposta tutti e cinque. max_proof_bytes è 4 MiB, dove le chain da 13 a 16 avevano 8 MiB: dalla chain 17 una transazione può portare tre prove (bundle, autorizzazione, chiamata), e un genesis con hc_auth deve avere max_block_bytes pari ad almeno tre volte max_proof_bytes più 1 MiB. Ogni nota di alloc porta il proprio opening (pk, time, r e asset per una nota di token), quindi proprietario e importo di una nota di genesis sono pubblici per scelta di progetto. La chain 20 ha:
- una sezione
bridge: guardian set 1 all’indice 1 con otto guardiani, emitter per le chain di origine 2, 3, 4 e 5 (quelli della chain 19), ottopq_guardiansDilithium2, unapause_key,burn_sequence13, unmin_inbound_sequencedi 3 per le chain di origine 2, 3 e 4 e di 7 per la chain di origine 5, erules_v2(un tetto globale di mint di 4.000 zUSD per finestra di 24 h). Novità della chain 20:rotation, per cui la rotazione di un PQ-guardian o della pause-key richiede la prova di possesso da parte delle nuove chiavi e ha effetto 86.400 s dopo il commit; efees, per cui la chain trattiene 10 bps di ogni deposito e 10 bps di ogni burn come nota zUSD verso un indirizzo di tesoreria, così un deposito accredita il lordo meno la commissione e un burn rilascia il proprio importo meno la commissione; - una sezione
tokens: una commissione di registrazione di 1 RAND, bruciata anziché pagata al proposer; unmint_cap_per_daydi 100.000 token per backing con otto decimali; un tetto del registro di 4.096 token; il limite di valore di nota di 2^63; e zUSD elencato al genesis con i suoi sette backing, 99 zUSD bloccati (Ethereum USDT 22, BSC USDT 22, Tron USDT 30, Solana USDT 25) a fronte delle due note zUSD di genesis; consensus_domain: 1: ogni firma di consenso è legata a questo genesis (Consenso);- una sezione
staking: il faucet in allowlist per 16 wallet e per 18 chiavi di validatori che coniano, con un budget di 10.000 RAND per epoca, un ritardo di bond di due epoche, un tetto di peso di 3.333 bps e registrazioni v2, come sulla chain 19; novità della chain 20,admission_by_vote(una nuova chiave di validatore si registra solo dopo che l’insieme dei validatori l’ha votata) e un budget d’ingresso di 2.500 bps del peso attivo a ogni confine di epoca, dove la chain 19 aveva 10.000 RAND fissi (Staking). Non c’èslashing; - una sezione
gas: una chiamata paga il limite di gas dichiarato dalla sua prova e i propri byte, a prezzi che partono da 100 unità per gas e 800 unità per KiB e si muovono dopo ogni blocco in base al suo riempimento rispetto a un obiettivo di 10.485.760 byte e 262.144 gas, al massimo di 1.250 bps a blocco, mai sotto i prezzi iniziali e, novità della chain 20, mai sopra 10.000 e 80.000. Contribuiscono al carico del prezzo per byte solo i byte che pagano un prezzo per byte, ossia la prova e l’envelope di input di una chiamata (byte_load: "paying"). Ogni prova di bundle dichiara lo stesso limite, 20.479 (Commissioni); envelope_bytes: 1860: ogni envelope di nota è lungo esattamente 1.860 byte e contiene un campo memo cifrato;hardening_v6: true, l’interruttore di hardening v0.6, impostato da ogni chain a partire dalla chain 16;testnet: true, il marcatore che consente a un faucet di affiancare una sezione bridge;binding_domain: 1: le prove di ogni transazione e ogni messaggio di azione firmato includono l’hash di genesis, così nulla di dimostrato o firmato per una chain viene verificato su un’altra;proof_window_blocks: 1024: l’ancora di un bundle può essere una delle ultime 1.024 radici di fine blocco e il suotimepuò restare indietro fino a 1.024 blocchi rispetto all’altezza (256 sulla chain 19), il che concede a un prover lento o delegato circa venti minuti;program_state, RPL-2: celle di programma, vault di programma e l’azioneInvoke, con una commissione di cella di 0,1 RAND per ogni cella che un invoke crea (JSON-RPC riporta i limiti).
Non ha una sezione aggregation, e la build rifiuta di avviarsi su un genesis che ne contenga una.
timestamp_ms è lo zero dell’orologio della chain. Quando generi un genesis tuo, impostalo vicino all’effettivo momento del lancio e mai in anticipo. Se è troppo indietro nel tempo, il tempo dei blocchi resta indietro rispetto all’orologio reale finché il limite di 60 s per blocco non gli consente di recuperare. Se è più di 15 secondi nel futuro, il blocco 1 non viene affatto finalizzato: ogni voto, compreso quello del leader, viene trattenuto finché l’ora reale non raggiunge il timestamp del genesis. Verificalo con l’orologio della macchina che avvia la flotta, non con quello della macchina che ha generato il file.
Esecuzione
rand-node run --datadir ./data --key node.key.json \
--listen /ip4/0.0.0.0/tcp/30303 --rpc 127.0.0.1:8545 --no-mdns \
--bootstrap /ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe \
--bootstrap /ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw \
--bootstrap /ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ
| argomento | predefinito | significato |
|---|---|---|
--datadir | obbligatorio | la directory dei dati inizializzata |
--key | obbligatorio | file della chiave: identità del validatore, identità p2p, destinatario delle commissioni |
--listen | /ip4/0.0.0.0/tcp/30303 | multiaddr di ascolto libp2p, ripetibile |
--bootstrap | nessuno | peer da contattare all’avvio e ogni 30 s finché è disconnesso, ripetibile |
--rpc | 127.0.0.1:8545 | il listener JSON-RPC e WebSocket dell’operatore: ogni metodo, e considera attendibile il loopback. Tienilo sul loopback e non inoltrare mai un endpoint pubblico verso di esso |
--public-rpc <ADDR> | off | v0.6.8: un secondo listener, pubblico, a cui puntare con un reverse proxy o un inoltro SSH: un insieme fisso di metodi senza i metodi della viewing key, rand_mint o rand_getPeers, senza batch, senza WebSocket, un unico contatore per tutti i chiamanti (JSON-RPC) |
--rpc-viewing-token-file <PATH> | off | v0.6.8: richiede un bearer token (la prima riga del file, di almeno 32 caratteri) sui metodi della viewing key di --rpc |
--reserved-peer <PEER_ID> | nessuno | v0.6.8, ripetibile: un peer ammesso oltre il limite di connessioni in ingresso; vedi Peer riservati |
--strict-gossip | off | v0.6.8: accetta solo gossip con firma dell’autore, numero di sequenza e origine validi; si attiva nodo per nodo |
--validator | off | questo nodo detiene una chiave di validatore e partecipa al consenso quando la sua chiave è nell’insieme corrente |
--no-mdns | off | disattiva la scoperta in LAN; consigliato sui server |
--block-interval-ms | 1000 | distanza minima tra le proposte |
--view-timeout-ms | 3000 | timeout di base della vista, che raddoppia a ogni timeout consecutivo fino a 8× |
--verify-chain | quick | controllo di integrità all’avvio: off, quick (struttura e riesecuzione del ledger), full (anche ogni firma e QC) |
--keep-raw-proofs | off | modalità archivio per l’aggregazione dei blocchi; nessun effetto sulla chain 20 |
--prune-history | off (conserva tutto) | conserva il ledger e solo questa quantità di storia dei blocchi: <n>m, <n>h o <n>d, almeno 1h. I validatori della testnet usano 24h, tranne i due archivi; vedi Potatura della storia |
--min-free-disk-mb | 1024 | rifiuta l’avvio con meno spazio libero sul filesystem della directory dei dati; rand_getHealth risponde disk_low sotto quattro volte questo valore. 0 disattiva la protezione |
--prover <ADDR> | off | ospita un prover delegato su questo indirizzo, un listener a sé stante e mai l’RPC; vedi sotto |
--gas-price, --byte-price | 100, 800 | il prezzo minimo del pool per una chiamata su una chain senza sezione gas. Il genesis della chain 20 fissa prezzi propri, quindi il nodo ignora entrambi i flag e registra un avviso |
--prover-accept-spend-key è ritirato: un nodo v0.6.8 che lo riceve rifiuta di avviarsi, quindi eliminalo da ogni file di unit ereditato dalla v0.6.7.
I tre bootstrap indicati sopra sono i validatori C, D ed E, invariati rispetto alla chain 19. La chain 20 usa le chiavi di validatore generate per la chain 14, quindi i suoi peer id sono quelli usati dalla chain 14; un’identità p2p deriva dalla chiave del validatore. La maggior parte dei validatori conserva solo un giorno di blocchi, quindi un nodo che si sincronizza dal genesis, o che è indietro di più di un giorno, ha bisogno anche di un peer con la storia completa. Aggiungi uno dei due archivi:
--bootstrap /ip4/168.144.46.203/tcp/30303/p2p/12D3KooWS5usdMPvsbaWSaT2xtKndHvDYurwmueoNvaRRarb2wRf # obs1
--bootstrap /ip4/206.81.29.236/tcp/30303/p2p/12D3KooWPocyZGcNB9Vp68VSfgVvNXhSzBBoJa4h9R1yMkp71XHh # rand-archive-2
Ometti --validator per eseguire un osservatore. Avvio: apre lo storage, confronta le guest di questa build con hc_bundle e hc_auth del genesis, esegue il controllo di integrità (troncando una coda danneggiata e conservando lo stato di sicurezza dei voti), riprende il consenso dalla testa persistita, avvia rete e RPC, poi si sincronizza da qualsiasi peer più avanti. RUST_LOG ha come predefinito info,libp2p=warn,libp2p_mdns=off; Ctrl-C o SIGTERM, il segnale di arresto di systemd, lo arrestano in modo pulito. Riavviare dalla stessa --datadir riprende dalla testa persistita.
Regole di topologia dal fullnode: i nodi dietro NAT si collegano verso i nodi con indirizzi pubblici; apri la TCP 30303 in ingresso sui nodi pubblici; associa l’RPC a 127.0.0.1 a meno che non sia protetto da firewall: accetta transazioni da chiunque riesca a raggiungerlo e, una volta che una viewing key vi è stata importata, considera la porta come portatrice di chiavi. Mantieni --block-interval-ms a 1000 o più lento: la prova di un bundle richiede circa due minuti e il suo anchor è valido per 1.024 blocchi sulla chain 20 (256 sulla chain 19).
Un validatore ha bisogno di un orologio sincronizzato. Dalla chain 14 l’ora reale fa parte del consenso (bridge hardening B2). Un blocco il cui timestamp supera di oltre 60 s quello del suo genitore non è valido, e un validatore trattiene il voto per un blocco il cui timestamp supera di oltre 15 s il proprio orologio. Un validatore con l’orologio in ritardo smette quindi di votare senza registrare alcun errore, e sulla chain 20 per finalizzare devono votare ventisei validatori su ventisei meno otto, cioè diciotto. Esegui NTP su ogni validatore e verificalo prima di avviare il nodo:
timedatectl # want "System clock synchronized: yes" and "NTP service: active"
chronyc tracking
apt-get install -y chrony && systemctl enable --now chrony # if it is not synchronised
Peer riservati
Dalla v0.6.8 un nodo accetta al massimo 256 connessioni in ingresso stabilite e 64 semiaperte, e creare un’identità libp2p non costa nulla, quindi degli estranei potrebbero occupare ogni slot. Tre tipi di peer sono riservati, ammessi oltre il limite e serviti dalla quota di sincronizzazione dei validatori: ogni peer --bootstrap, ogni --reserved-peer e ogni identità di validatore appresa da un binding di peer firmato. Ogni nodo --validator firma la propria identità libp2p con la sua chiave di validatore e la diffonde via gossip; un nodo che conosce la chiave da un insieme di validatori riserva quel peer e conserva il record tra i riavvii. Lo store di una chain appena generata non contiene binding, quindi finché non arrivano i primi annunci sono riservati solo i primi due tipi: alla generazione, passa i peer id dei validatori della flotta con --reserved-peer oppure tienili nell’elenco dei bootstrap (rand-node address --key <file> stampa il peer id di una chiave). rand_status.reserved_peers li conta; su un nodo della flotta dovrebbe raggiungere il numero di validatori entro un minuto dall’avvio.
Verifica
rand-node status # rand_status verbatim
rand --rpc http://127.0.0.1:8545 status
rand peers
rand_status riporta height, view, syncing, sync_target, peer_count, connected_peers, reserved_peers, mempool_size, is_validator, active_validator, faucet, confidential, testnet, fri_profile, programs, notes, nullifiers, tree_root, hc_bundle, hc_auth, binding_domain, gas_prices, l’address e il peer_id del nodo, la diagnostica di sincronizzazione (sync_inflight_age_ms, sync_failures, sync_late_batches), il disco (disk_free_bytes, disk_low) e la soglia di conservazione (prune_floor, 0 su un nodo che conserva tutto; prune_history_secs, null se non impostato). Sulla chain 20 aspettati hc_bundle 60af094a…, hc_auth 1e4e347f…, faucet true, confidential true, testnet true, binding_domain 1, fri_profile "production" e gas_prices tra 100 e 10.000 per gas e tra 800 e 80.000 per KiB. rand_getGenesisHash deve rispondere 6210cf07…5135 e rand_getVersion 0.6.8.
rand_getHealth risponde disk_low (con free_bytes) prima di ok, syncing o behind quando lo spazio libero è inferiore a quattro volte --min-free-disk-mb.
Potatura della storia
Un nodo avviato con --prune-history 24h conserva per intero il ledger (note, nullifier, anchor, il registro dei validatori, i programmi) ed elimina i blocchi più vecchi, i loro certificati, le transazioni e le ricevute. Un passaggio viene eseguito a ogni sedicesimo blocco finalizzato ed elimina fino a 512 blocchi più vecchi del timestamp della testa meno la finestra; il genesis, la testa e il suo genitore non vengono mai eliminati, e la soglia può solo salire. Lo spazio su disco ritorna dopo la compattazione di RocksDB. Sulla chain 20, come sulla chain 19, 24 dei 26 validatori usano 24h e conservano circa un giorno di blocchi. Quando la potatura è stata attivata per la chain 14 (2026-09-25), le tabelle dei blocchi di ciascun validatore sono scese da 19 GB a 3,3–4,4 GB una volta smaltito l’arretrato; gli altri due, obs1 e rand-archive-2, validatori anch’essi dal 2026-09-27, funzionano senza il flag e conservano tutto. Un nodo mainnet non passa mai il flag.
Su un nodo potato, una ricerca per altezza al di sotto della soglia (rand_getBlockByHeight, rand_getFinality per altezza, un intervallo di rand_getBlocks o rand_getCompactBlocks che la raggiunge) risponde con l’errore -32010 e data.floor: rivolgiti a un archivio. Una ricerca per hash risponde null per un blocco che il nodo non conserva più, come per uno che non è mai esistito. La scansione del wallet non è interessata, perché note e nullifier non vengono mai potati.
Il controllo all’avvio di un nodo potato è strutturale (il blocco 0 e i blocchi conservati, i loro QC, i collegamenti ai genitori e i leader), non una riesecuzione dal genesis, e non si ripara da solo: se fallisce, risincronizza da un archivio. Non aprire la directory dei dati di un nodo potato con una build precedente alla v0.5.7 a meno che non sia eseguita con --verify-chain off: il suo controllo predefinito riesegue dal genesis, trova mancante il blocco 1 e tronca il ledger al genesis.
Ospitare un prover
Sulla chain 20 un wallet produce due prove per ogni bundle, e la più grande richiede circa 6 GB di memoria. Un wallet che non riesce a contenerla può affidare quella prova a un prover delegato con cui è abbinato: il binario separato rand-prover, oppure lo stesso servizio ospitato da un nodo.
rand-prover --home /root/prover keygen
rand-prover --home /root/prover pair --name laptop --url https://prover.example.net
rand-node run --datadir ./data --key node.key.json --prover 127.0.0.1:8600 --prover-home /root/prover
pair stampa un link randprover:. Il wallet lo accetta con rand prover pair <link> e poi genera le prove attraverso di esso con l’opzione globale --prover. Il listener del prover è autonomo, mai un metodo dell’RPC: un indirizzo uguale a --rpc viene rifiutato. Con --prover il nodo si rifiuta di avviarsi se <prover-home>/prover.key.json non esiste (default <datadir>/prover) e se non sono disponibili 5.74 GB per ogni slot di prova più 1 GiB di memoria; --prover-max-parallel imposta gli slot, uno per impostazione predefinita.
Sulla chain 20 il prover riceve la viewing key del wallet e un salt nuovo, non la spend key. Il wallet genera da sé la prova di autorizzazione sulla spend key, perciò un prover associato può leggere l’intera cronologia di quel wallet ma non può spendere. Tieni il listener su loopback, a meno che non sia preceduto da un proxy che termina il TLS, e non ospitarlo su una macchina che serve un RPC pubblico. Un arresto attende la prova in corso, quindi imposta TimeoutStopSec=180 in un’unità systemd.
Verifica e riparazione
rand-node verify --datadir ./data # full: hashes, QCs, signatures, proofs, ledger replay, the supply counters
rand-node verify --datadir ./data --mode quick # structure and ledger replay
rand-node verify --datadir ./data --repair # truncate a damaged tail; peers resync the rest
Arresta prima il nodo. Il codice di uscita è 0 se tutto è coerente, 2 se è stato trovato un problema e --repair non è stato indicato. Il replay riverifica la prova di ogni bundle, perciò una build il cui insieme di vincoli differisce da quello che ha prodotto la chain si ferma al primo bundle.
Diventare un validator
Un validator si unisce a una chain in esecuzione tramite bonding, non con un nuovo genesis: avvia il nodo con --validator, stampa una registrazione con rand-node register --key node.key.json --payout <rand1…> --v2 (la chain 20 rifiuta una registrazione v1), fai effettuare a un wallet il bond di almeno 1,000 RAND con rand bond <address> 1000 --registration <hex>, e il nodo propone non appena il bond si attiva: sulla chain 20, al più presto tre confini di epoca da 1,000 blocchi dopo il bond. Sulla chain 20 il bond viene in secondo luogo. Il suo genesis imposta staking.admission_by_vote, perciò un bond che registra una nuova chiave viene rifiutato finché i validator che detengono più di due terzi del peso di voto non hanno votato per ammettere la chiave: ciascuno firma con rand-node admit sign --candidate <key or registration> --key <validator key> --genesis-hash 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135, e uno di loro invia i voti con rand-node admit submit (Riga di comando). rand_getAdmitted elenca le chiavi ammesse per voto e non ancora registrate. Non più di 2,500 bps del peso attivo diventa nuovo peso a un singolo confine di epoca. Staking lo illustra passo per passo. Per una chain di test privata, rand-node genesis ne crea una:
rand-node genesis --chain-id 88 \
--validator a.key.json,1000,rand1<a's payout address> \
--validator <hex public key of b>,1000,rand1<b's payout address> \
--alloc rand1<address>=1000 \
--epoch-blocks 1000 --faucet --fri-profile production \
--out genesis.json
e scripts/local-testnet.sh avvia due validator su una macchina con RPC su 8545 e 8546. Senza ulteriori flag il genesis non ha hc_auth, né una sezione gas, né memo. La chain 20 è stata creata con --hardening-v6 --bundle-guest v3 --auth-guest --gas-price 100 --byte-price 800 --bundle-gas-limit 20479 --gas-dynamic 10485760,262144,1250 --max-gas-price 10000 --max-byte-price 80000 --gas-byte-load paying --envelope-bytes 1860 --testnet --binding-domain 1 --proof-window-blocks 1024 --program-state-cell-fee 10000000 in aggiunta (le chain 18 e 19 avevano i flag fino a --envelope-bytes), e le sue sezioni bridge e staking e il consensus_domain sono stati inseriti dallo script di creazione. Una nuova chain tutta tua dovrebbe passare --binding-domain 1: un wallet v0.6.8 genera la prova nella forma legata al genesis su ogni id di chain al di fuori dell’intervallo da 14 a 19.
Deploy su un server
La directory deploy/ del repository contiene gli script usati dalla flotta: deploy/push-to-vps.sh <ip> <letter> "<bootstraps>" [validator|observer] predispone un server Linux (rsync del sorgente, build, installazione di /usr/local/bin/{rand-node,rand}, inizializzazione di un datadir indicizzato sull’hash del genesis, installazione di un servizio systemd rand-node), e deploy/rebuild-vps.sh <ip> ricompila su un nuovo commit e riavvia mantenendo i dati. Due avvertenze. Lo script di provisioning inizializza da deploy/genesis.json, che non è il file della chain 20, perciò un nodo per la testnet si configura a mano da deploy/genesis-chain20.json (su main, vedi sopra). Inoltre entrambi gli script eseguono rsync di /root/fullnode con --delete, perciò una chiave tenuta dentro quell’albero viene eliminata dal rebuild successivo: tienila in /root/keys, come fa la flotta e come ora fa per impostazione predefinita lo script di provisioning della v0.6.8 (quello della v0.6.7 scriveva la chiave sotto /root/fullnode/deploy/). La gestione del servizio avviene con systemctl status rand-node, journalctl -u rand-node -f. Il server richiede build-essential clang cmake pkg-config libssl-dev e una toolchain Rust. Un server con 1 vCPU e 2 GB non può compilare i binari; compilali altrove e copiali. Eseguire un validator e un aggregator contiene le dimensioni e la configurazione passo per passo.
L’explorer
randscan.org funziona accanto al validator E e indicizza la chain 20; la sua API REST e il feed WebSocket sono il modo più semplice di leggere la chain senza un nodo (API dell’explorer). L’explorer è open source (randprotocol/randscan) e il suo indexer richiede soltanto l’RPC JSON rand_* di un nodo e un database PostgreSQL, perciò può essere eseguito sul tuo nodo.