Usa questa pagina per leggere correttamente rand_getSupply e per ragionare sull’emissione: da dove viene RAND, dove va, e l’identità che rende esatta la supply di una chain schermata anche se nessuno può sommarne le note.
Da dove viene e dove va RAND
Una chain schermata non può sommare il proprio denaro: il valore di una nota vive dentro il suo commitment. Ciò che è pubblico è ogni attraversamento del confine del pool. Ce ne sono cinque tipi, e sette su una chain con vault di programma (RPL-2, chain 20):
| direzione | attraversamento | quando |
|---|---|---|
| in ingresso | una nota di deposito del genesis (alloc nel file di genesis, aperta dalla chain 14) | blocco 0 |
| in ingresso | un mint del faucet (Mint, fino a 100 RAND, firmato dal validatore, con l’apertura della nota dalla chain 14) | chain testnet con "faucet": true; sulla chain 20 solo verso 16 wallet in allowlist, firmato da uno dei 18 minter elencati nel genesis, al massimo 10.000 RAND per epoca di 1.000 blocchi |
| in ingresso | un Withdraw di un validatore, che versa in una nota lo stake rilasciato e le ricompense | in qualsiasi momento |
| in uscita | la fee di un bundle, verso i rewards del proponente del blocco | ogni bundle |
| in uscita | il burn_r di un bundle: un Bond che brucia stake nello stake pubblico di un validatore | ogni bond |
| in uscita | il burn_r di un Invoke: RAND depositati nel vault pubblico di un programma | chain 20, dalla v0.6.8 |
| in ingresso | un pagamento del vault: RAND che un Invoke paga dal vault di un programma come nota, con importo e destinatario pubblici | chain 20, dalla v0.6.8 |
Su una chain il cui genesis imposta tokens.burn_registration_fee, come quello della chain 20, anche la registration_fee di 1 RAND di una registrazione di token esce dal pool tramite burned, ma non entra in alcuna voce del registro: viene distrutta, e il proponente trattiene soltanto la base del bundle.
Accanto al pool c’è il registro dei validatori, che tiene gli importi in chiaro perché il peso nel consenso deve essere pubblico. Lo stake nel registro è RAND reale: può essere sbloccato (unbond) e prelevato di nuovo in una nota. Sulla chain 20 i vault di programma sono un secondo saldo pubblico accanto ad esso: i RAND che un invoke deposita restano contabilizzabili lì finché un pagamento non li riporta nel pool come nota.
Sulla chain 20 non ci sono ricompense di blocco né inflazione. La prima emissione programmata della chain è il sussidio di aggregazione dei blocchi — una quantità decrescente di nuovi RAND per ogni blocco sigillato, pagata all’aggregatore la cui prova lo copre — e sulla chain 20 non è attivo (Prove). La chain 20 è una chain nuova, attiva dal 2026-10-01 alle 06:17 UTC, derivata dalla chain 19 (fullnode v0.6.8, un hard fork). Il suo genesis ha emesso 31.184,243719258 RAND: 26.000 in stake sui 26 validatori del genesis e 5.184,243719258 in sette note di deposito, i saldi dei sette wallet degli operatori riportati dalla chain 19. Ciò che gli altri wallet detenevano sulla chain 19, circa 519,9 RAND (mint del faucet verso destinatari in allowlist, pagamenti agli utenti), non è stato riportato, poiché una nota non può essere ricreata senza l’indirizzo del suo proprietario; né sono stati riportati 0,499 RAND di ricompense dei validatori non prelevate. Altre due note del genesis, nove in tutto, portano i 99 zUSD del bridge (10 e 89), che non sono RAND e restano fuori da questo audit. rand_getSupply sulla chain 20 riporta genesis_deposited 5.184.243.719.258 unità e invariant_holds: true (altezza 3.037, 2026-10-01). La chain 19, derivata lo stesso giorno da uno snapshot della chain 18 all’altezza 141.935, ha emesso 31.294,644359629 RAND: gli stessi 26.000 in stake e 5.294,644359629 in sette note, accanto a una nota da 10 zUSD. Ogni mint del faucet successivo si aggiunge alla cifra emessa, e ogni commissione di registrazione bruciata la riduce. La chain 15, derivata il 2026-09-26, ha emesso 23.000 RAND al genesis, 18.000 in stake su 18 validatori e 5.000 in cinque note; i suoi otto validatori successivi hanno fatto bond da note già esistenti, il che non ha emesso nulla.
I token sono fuori da questo audit
Gli attraversamenti qui sopra sono quelli di RAND. Un token RPL, bridged o nativo, non attraversa mai il confine di RAND: l’indice d’asset 0 è riservato a RAND e il registro dei token non lo assegna mai, quindi un BridgeAttest, un TokenMint o il mint iniziale di una registrazione depositano sempre una nota di un altro asset, e il burn_a di un BridgeBurn o di un TokenBurn ne distrugge sempre una (RAND bruciati tramite burn_a vengono rifiutati). fees_paid e burned sono conteggiati solo a partire da fee e burn_r di un bundle, e un trasferimento di token dentro il pool non sposta alcun contatore, dato che il suo asset non è nemmeno pubblico. Sulla chain 20 un Invoke può anche far entrare un token tramite burn_a: nel vault del programma (deposit), il che lascia invariata la sua supply, oppure distrutto (burn), solo per il token del programma stesso. Le note di commissione del bridge (chain 20, 10 bps di ogni deposito e burn di zUSD, verso un indirizzo di tesoreria) sono zUSD, mai RAND: emessi e garantiti, per cui il backing di un deposito e la supply si muovono dell’importo lordo e quelli di un burn calano di amount − fee. La supply di un token è il conteggio pubblico del registro: rand_getTokenSupply restituisce total_supply e, per un token bridged, l’importo locked di ciascun backing, che sommati danno il totale (Token RPL).
L’identità di audit
Sei contatori monotoni in unità (1 RAND = 10⁹), due che registrano ciò che è stato distrutto e, sulla chain 20, due per i vault di programma:
| contatore | somma |
|---|---|
genesis_deposited | le note di deposito alloc nel file di genesis |
genesis_staked | gli stake con cui il genesis ha inizializzato il registro |
faucet_minted | ogni Mint accettato |
withdraw_deposited | le note create dai Withdraw accettati (amount − 0.001 RAND ciascuno) |
fees_paid | ogni fee di bundle |
burned | ogni burn_r di bundle (lo stake di un Bond e, sulla chain 20, il deposito nel vault di un invoke), e ogni commissione di registrazione bruciata |
slashed | bond degli aggregatori sanzionati con slashing (aggregazione dei blocchi; 0 finché è disattivata) |
registration_fees_burned | le commissioni di registrazione bruciate con tokens.burn_registration_fee, contenute anche in burned |
program_rand_out | note RAND che i vault di programma hanno pagato (RPL-2; 0 senza una sezione program_state) |
program_rand_held | i RAND che i vault ancora detengono: il burn_r di ogni invoke meno program_rand_out. Vi sono arrivati tramite burned, quindi è il lato dei vault di quel contatore |
pool_value = genesis_deposited + faucet_minted + withdraw_deposited + program_rand_out − fees_paid − burned
register_total = Σ over the register of (stake + pending + rewards)
total_supply = pool_value + register_total + program_rand_held
issued = genesis_deposited + genesis_staked + faucet_minted
invariant: total_supply == issued − slashed − registration_fees_burned
pool_value è ciò che è entrato meno ciò che è uscito — lo stesso numero della somma delle note, che nessuno può calcolare. La base di 0,001 RAND di un withdraw non è un attraversamento: passa da una riga del registro a quella del proponente, e solo la nota ha attraversato il confine. Se invariant_holds è falso si tratta di un bug del consenso o di un database danneggiato, mai di uno stato legittimo. I due termini del programma sono zero su una chain senza vault di programma, quindi lì l’identità è quella della chain 19. Una sezione vesting del genesis, che nessuna chain ha mai avuto, aggiungerebbe allo stesso modo un terzo registro pubblico (JSON-RPC).
Seguiti attraverso un bond e un withdraw di 1.000 RAND su una chain che ha depositato 2.000 e messo in stake 4.000:
| dopo | burned | withdraw_deposited | fees_paid | pool_value | register_total | total_supply |
|---|---|---|---|---|---|---|
| genesis | 0 | 0 | 0 | 2.000 | 4.000 | 6.000 |
| un bond di 1.000 (fee 0,001) | 1.000 | 0 | 0,001 | 999,999 | 5.000,001 | 6.000 |
| il suo unbond | 1.000 | 0 | 0,001 | 999,999 | 5.000,001 | 6.000 |
| il suo withdraw di 1.000 | 1.000 | 999,999 | 0,001 | 1.999,998 | 4.000,002 | 6.000 |
Come leggerla
curl -s http://127.0.0.1:8545 -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"rand_getSupply","params":[]}'
{ "height": 1998,
"genesis_deposited": "2000000000000", "genesis_staked": "4000000000000",
"faucet_minted": "0", "withdraw_deposited": "999999000000",
"fees_paid": "1000000", "burned": "1000000000000",
"slashed": "0", "registration_fees_burned": "0",
"pool_value": "1999998000000", "register_total": "4000002000000",
"total_supply": "6000000000000", "invariant_holds": true }
Ogni importo è una stringa decimale di unità, perché un numero JSON non è un intero esatto oltre 2⁵³. L’oggetto completo contiene più campi di quelli mostrati qui, tra cui la coppia per epoca del faucet faucet_epoch e faucet_minted_in_epoch, che la chain 20 verifica rispetto al proprio budget, program_rand_out e program_rand_held (dalla v0.6.8) e quattro contatori vesting_* che sulla chain 20 valgono "0", il cui genesis non ha una sezione vesting (JSON-RPC). L’explorer serve lo stesso oggetto su GET /supply e le cifre principali su GET /stats.
Quanto è esatta
Per tutto ciò che la chain ha fatto da sé i contatori sono esatti: ciascuno viene incrementato nel percorso di codice che applica l’azione, a partire dai campi pubblici dell’azione stessa.
Due voci un tempo poggiavano su un’asserzione, e la chain 14 le trasforma entrambe in verifiche (audit v3, POOL-1):
- Un
Mintdel faucet porta l’apertura della nota. Oltre acmeamount, l’azione pubblicapk,timeer. L’ammissione ricalcola l’impegno di(pk, no sender, amount, asset 0, time, r)e rifiuta una discordanza conthe mint's commitment does not open to its published note and amount, e vincolatimealla finestra del bundle. Il minter firma tutti e sette i campi con il dominiorand-mint-2. Prima di questa modifica, un validator poteva pubblicare un importo e sigillare una nota di valore diverso. Il costo è che lapkdel proprietario di una nota del faucet è pubblica, come lo è il payout di un withdraw; i parametri dirand_mintrestano invariati. - Anche una nota
allocdella genesi porta la propria apertura. Su una chain con una sezionetokens, ogni riga è{ cm, envelope, amount, opening: { pk, time, r } }, e un nodo ricalcola l’impegno, sull’asset 0 a meno che l’apertura non indichi l’assetdi un token elencato, e rifiuta un file di genesi il cuicmnon corrisponda. Solo le righe dell’asset 0 contano pergenesis_deposited. Uncmopaco era l’unico modo in cui l’autore della genesi poteva inserire nel pool una nota priva di copertura, di qualunque asset, senza che nessuno potesse verificarlo. Il proprietario e l’importo di una nota di genesi sono quindi pubblici per scelta progettuale una volta pubblicato il file; resta privato solo quando, e verso che cosa, viene spesa in seguito.rand-node genesisscrive sempre l’apertura.
Su una chain avviata senza una sezione tokens vale ancora la regola precedente: genesis_deposited è la somma dei campi amount dichiarati, ritenuti attendibili in base al file di genesi. In entrambi i casi gli importi della genesi rientrano nell’hash della genesi, quindi ogni nodo concorda su di essi.
I contatori non fanno deliberatamente parte dello stato di consenso — la state root non li include nell’hash — e rand-node verify --mode quick li ricalcola tutti riesaminando la catena, segnalando una discordanza se lo snapshot salvato non coincide.