Ta strona pomaga poprawnie odczytać rand_getSupply i zrozumieć emisję: skąd bierze się RAND, dokąd trafia i jaka tożsamość sprawia, że podaż łańcucha shielded jest dokładna, choć nikt nie może zsumować jego not.
Skąd RAND się bierze i dokąd trafia
Łańcuch shielded nie potrafi zsumować własnych pieniędzy: wartość noty mieści się wewnątrz jej zobowiązania (commitment). Jawne jest każde przekroczenie granicy puli. Rodzajów jest pięć, a na łańcuchu z skarbcami programów (RPL-2, chain 20) siedem:
| kierunek | przekroczenie | kiedy |
|---|---|---|
| wejście | nota depozytu genesis (alloc w pliku genesis, jawna od chain 14) | blok 0 |
| wejście | mint z faucetu (Mint, do 100 RAND, podpisany przez walidatora, od chain 14 zawiera otwarcie noty) | łańcuchy testnet z "faucet": true; na chain 20 tylko dla 16 portfeli z listy dozwolonych, podpisany przez jednego z 18 minterów wskazanych w genesis, najwyżej 10 000 RAND na epokę liczącą 1000 bloków |
| wejście | Withdraw walidatora, który wypłaca uwolniony stake i nagrody do noty | w dowolnym momencie |
| wyjście | fee paczki (bundle), do rewards proposera bloku | każda paczka |
| wyjście | burn_r paczki: Bond spalający stake do jawnego stake walidatora | każdy bond |
| wyjście | burn_r w Invoke: RAND wpłacony do jawnego skarbca programu | chain 20, od v0.6.8 |
| wejście | wypłata ze skarbca: RAND, który Invoke wypłaca ze skarbca programu jako notę, z jawną kwotą i odbiorcą | chain 20, od v0.6.8 |
Na łańcuchu, którego genesis ustawia tokens.burn_registration_fee, jak w chain 20, opłata rejestracyjna registration_fee w wysokości 1 RAND za rejestrację tokena również opuszcza pulę przez burned, lecz nie trafia do żadnego wpisu rejestru: jest niszczona, a proposer zatrzymuje tylko podstawę paczki.
Obok puli znajduje się rejestr walidatorów, który przechowuje kwoty jawnie, ponieważ waga w konsensusie musi być publiczna. Stake w rejestrze to prawdziwy RAND: można go odwiązać (unbond) i wypłacić z powrotem do noty. Na chain 20 skarbce programów to drugie jawne saldo obok niego: RAND wpłacony przez invoke pozostaje tam policzalny, dopóki wypłata nie zwróci go do puli jako nota.
Na chain 20 nie ma nagród za bloki ani inflacji. Pierwszą zaplanowaną emisją łańcucha jest subsydium za agregację bloków: malejąca ilość nowego RAND za każdy zapieczętowany blok, wypłacana agregatorowi, którego dowód go obejmuje. Na chain 20 nie jest ono aktywne (Dowody). Chain 20 to nowy łańcuch, uruchomiony 2026-10-01 o 06:17 UTC, wydzielony z chain 19 (fullnode v0.6.8, hard fork). Jego genesis wyemitował 31 184,243719258 RAND: 26 000 w stake’u 26 walidatorów genesis oraz 5184,243719258 w siedmiu notach depozytowych, czyli salda siedmiu portfeli operatorów przeniesione z chain 19. To, co inne portfele trzymały na chain 19, około 519,9 RAND (mint z faucetu dla odbiorców z listy dozwolonych, płatności dla użytkowników), nie zostało przeniesione, ponieważ nie można odtworzyć noty bez adresu jej właściciela; podobnie 0,499 RAND niewypłaconych nagród walidatorów. Dwie kolejne noty genesis, dziewięć w sumie, niosą 99 zUSD z mostu (10 i 89), które nie jest RAND i nie podlega temu audytowi. rand_getSupply na chain 20 pokazuje genesis_deposited 5 184 243 719 258 jednostek i invariant_holds: true (wysokość 3037, 2026-10-01). Chain 19, wydzielony tego samego dnia ze snapshotu chain 18 na wysokości 141 935, wyemitował 31 294,644359629 RAND: te same 26 000 w stake’u i 5294,644359629 w siedmiu notach, obok jednej noty 10 zUSD. Każdy późniejszy mint z faucetu zwiększa wyemitowaną kwotę, a każda spalona opłata rejestracyjna ją zmniejsza. Chain 15, wydzielony 2026-09-26, wyemitował w genesis 23 000 RAND, z czego 18 000 w stake’u 18 walidatorów i 5000 w pięciu notach; jego osiem późniejszych walidatorów wykonało bond z istniejących not, co niczego nie wyemitowało.
Tokeny są poza tym audytem
Powyższe przekroczenia dotyczą RAND. Token RPL, mostowany lub natywny, nigdy nie przekracza granicy RAND: indeks aktywa 0 jest zarezerwowany dla RAND i rejestr tokenów nigdy go nie wydaje, więc BridgeAttest, TokenMint lub początkowy mint przy rejestracji zawsze wpłaca notę innego aktywa, a burn_a w BridgeBurn lub TokenBurn zawsze niszczy taką notę (RAND spalany przez burn_a jest odrzucany). fees_paid i burned są liczone wyłącznie z fee i burn_r paczki, a transfer tokena wewnątrz puli nie przesuwa żadnego licznika, ponieważ jego aktywo nie jest nawet jawne. Na chain 20 Invoke może też przyjąć token przez burn_a: do skarbca programu (deposit), co nie zmienia jego podaży, albo zniszczyć go (burn), wyłącznie dla własnego tokena programu. Noty opłat mostu (chain 20, 10 bps od każdego depozytu i spalenia zUSD, na adres skarbca) to zUSD, nigdy RAND: emitowane i zabezpieczone, więc zabezpieczenie depozytu i podaż rosną o kwotę brutto, a przy spaleniu maleją o amount − fee. Własną podaż tokena podaje publiczny licznik rejestru: rand_getTokenSupply zwraca total_supply oraz, dla tokena mostowanego, kwotę locked każdego zabezpieczenia, które razem się do niej sumują (Tokeny RPL).
Tożsamość audytu
Sześć monotonicznych liczników w jednostkach (1 RAND = 10⁹), dwa rejestrujące to, co zniszczono, a na chain 20 dwa dla skarbców programów:
| licznik | sumuje |
|---|---|
genesis_deposited | noty depozytowe alloc w pliku genesis |
genesis_staked | stake’i, którymi genesis zasiał rejestr |
faucet_minted | każdy przyjęty Mint |
withdraw_deposited | noty utworzone przez przyjęte Withdraw (po amount − 0.001 RAND każda) |
fees_paid | każda opłata paczki |
burned | każdy burn_r paczki (stake z Bond oraz, na chain 20, wpłata invoke do skarbca) i każda spalona opłata rejestracyjna |
slashed | obcięte (slashed) bondy agregatorów (agregacja bloków; 0, dopóki jest wyłączona) |
registration_fees_burned | opłaty rejestracyjne spalone w ramach tokens.burn_registration_fee, wliczone także w burned |
program_rand_out | noty RAND, które skarbce programów wypłaciły (RPL-2; 0 bez sekcji program_state) |
program_rand_held | RAND, który skarbce nadal przechowują: każdy burn_r z invoke pomniejszony o program_rand_out. Trafił tam przez burned, więc to strona skarbców tego licznika |
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 to to, co weszło, minus to, co wyszło — ta sama liczba, co suma not, której nikt nie może obliczyć. Podstawa 0,001 RAND za withdraw nie jest przekroczeniem granicy: przechodzi z jednego wiersza rejestru do wiersza proposera, a granicę przekroczyła tylko nota. invariant_holds równe false to błąd konsensusu lub uszkodzona baza danych, nigdy prawidłowy stan. Oba składniki programowe są zerowe na łańcuchu bez skarbców programów, więc tam tożsamość jest tą z chain 19. Sekcja genesis vesting, której żaden łańcuch dotąd nie miał, dodałaby w ten sam sposób trzeci jawny rejestr (JSON-RPC).
Prześledzone na jednym bondzie i jednym withdrawie po 1000 RAND na łańcuchu, który zdeponował 2000 i zestakował 4000:
| po | burned | withdraw_deposited | fees_paid | pool_value | register_total | total_supply |
|---|---|---|---|---|---|---|
| genesis | 0 | 0 | 0 | 2000 | 4000 | 6000 |
| bond na 1000 (opłata 0,001) | 1000 | 0 | 0,001 | 999,999 | 5000,001 | 6000 |
| jego unbond | 1000 | 0 | 0,001 | 999,999 | 5000,001 | 6000 |
| jego withdraw na 1000 | 1000 | 999,999 | 0,001 | 1999,998 | 4000,002 | 6000 |
Jak to czytać
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 }
Każda kwota jest ciągiem dziesiętnym w jednostkach, ponieważ liczba JSON nie jest dokładną liczbą całkowitą powyżej 2⁵³. Pełny obiekt zawiera więcej pól, niż pokazano tutaj, m.in. parę faucetu na epokę faucet_epoch i faucet_minted_in_epoch, którą chain 20 sprawdza względem swojego budżetu, program_rand_out i program_rand_held (od v0.6.8) oraz cztery liczniki vesting_*, które na chain 20 mają wartość "0", ponieważ jego genesis nie ma sekcji vesting (JSON-RPC). Eksplorator udostępnia ten sam obiekt pod GET /supply, a główne wartości w GET /stats.
Jak dokładna jest ta tożsamość
Dla wszystkiego, co łańcuch zrobił sam, liczniki są dokładne: każdy jest zwiększany w ścieżce kodu, która stosuje daną akcję, na podstawie jej własnych pól jawnych.
Dwa wpisy opierały się dotąd na twierdzeniu, a chain 14 zamienia oba w sprawdzenia (audyt v3, POOL-1):
- Faucet
Mintzawiera otwarcie notatki. Obokcmiamountakcja publikujepk,timeir. Admisja ponownie oblicza zobowiązanie dla(pk, no sender, amount, asset 0, time, r)i odrzuca niezgodność z komunikatemthe mint's commitment does not open to its published note and amount, a także ograniczatimedo okna paczki. Minter podpisuje wszystkie siedem pól w domenierand-mint-2. Wcześniej validator mógł opublikować jedną kwotę, a zapieczętować notatkę o innej wartości. Koszt jest taki, że klucz właściciela notatki z faucetu,pk, jest jawny, tak jak wypłata przy withdraw; parametryrand_mintpozostają bez zmian. - Notatka genesis
allocrównież zawiera swoje otwarcie. W łańcuchu z sekcjątokenskażdy wiersz ma postać{ cm, envelope, amount, opening: { pk, time, r } }, a węzeł ponownie oblicza zobowiązanie, dla asset 0, chyba że otwarcie wskazujeassettokena z listy, i odrzuca plik genesis, któregocmsię nie zgadza. Dogenesis_depositedwliczają się tylko wiersze z asset 0. Nieprzejrzystecmbyło jedynym sposobem, w jaki autor genesis mógł wprowadzić do puli niezabezpieczoną notatkę, dowolnego aktywa, bez możliwości sprawdzenia tego przez kogokolwiek. Właściciel i kwota notatki genesis są więc jawne z założenia po opublikowaniu pliku; prywatne pozostaje tylko to, kiedy i na co zostanie ona później wydana.rand-node genesiszawsze zapisuje otwarcie.
W łańcuchu utworzonym bez sekcji tokens nadal obowiązuje starsza reguła: genesis_deposited to suma zadeklarowanych pól amount, przyjęta na zaufanie z pliku genesis. Obie kwoty genesis wchodzą do skrótu genesis, więc w obu przypadkach wszystkie węzły są co do nich zgodne.
Liczniki celowo nie są częścią stanu konsensusu — korzeń stanu ich nie haszuje — a rand-node verify --mode quick przelicza każdy z nich, odtwarzając łańcuch, i zgłasza niezgodność, jeśli zapisany snapshot się z nim rozmija.