Gunakan halaman ini untuk bergabung dengan set validator pada chain yang sedang berjalan, untuk keluar darinya, dan untuk membaca kembali register. Bobot konsensus harus bersifat publik, sehingga register validator adalah satu-satunya tabel pada chain ini yang menyimpan jumlah secara terbuka; stake tetap keluar dari sebuah note terlindung dan kembali ke dalamnya.
Register
Satu baris untuk setiap validator yang pernah melakukan bonding, dengan kunci berupa alamat base58-nya:
ValidatorEntry {
public_key, // Dilithium2: signs blocks, and this validator's staking actions
stake: u64, // bonded: the weight an epoch's set gives it
pending: Vec<(u64, u64)>, // unbonding, as (release_epoch, amount), oldest first
rewards: u64, // fees earned as a block proposer, unpaid
payout: ShieldedAddress, // rand1… — where a withdraw pays
nonce: u64, // replay protection for its signed actions
activation_epoch: u64, // under a `staking` section: the first epoch this row may be in a set
}
Setiap field bersifat publik dan register di-hash ke dalam state root setiap blok. Baris tidak pernah dihapus: validator yang melakukan unbond atas seluruh stake-nya tetap memiliki satu baris dengan stake = 0.
| konstanta | nilai | arti |
|---|---|---|
MIN_STAKE | 1,000 RAND | stake yang dibutuhkan sebuah baris agar dapat masuk ke dalam set suatu epoch |
MAX_VALIDATORS | 100 | set terbesar yang dapat dimiliki sebuah epoch |
UNBONDING_EPOCHS | 2 | jumlah epoch yang harus ditunggu oleh jumlah yang di-unbond sebelum dapat ditarik |
epoch_blocks | 1,000 pada chain 20 | jumlah blok per epoch; sebuah parameter genesis |
Epoch
epoch(h) = h / epoch_blocks. Set untuk epoch e ≥ 1 diturunkan dari register pada keadaan blok terakhir epoch e − 1: setiap baris dengan stake ≥ MIN_STAKE, diambil MAX_VALIDATORS teratas menurut (stake descending, address ascending), lalu diurutkan menurut alamat. Pemimpin suatu view, pemberi suara untuk suatu blok, dan verifikasi suatu sertifikat semuanya menggunakan set dari epoch tempat blok itu berada. Dua konsekuensinya:
- Sebuah bond belum menjadi bobot hingga batas epoch berikutnya. Bond itu langsung masuk ke register, tetapi set hanya berubah pada batas epoch, yaitu batas berikutnya pada chain tanpa bagian
staking, dan lebih lambat pada chain 20 (di bawah). - Sebuah unbond mengurangi bobot pada batas epoch berikutnya, sementara jumlahnya menunggu dua epoch sebelum dapat ditarik. Validator berhenti mengusulkan blok jauh sebelum ia dapat menarik dananya.
Jika hasil penurunan kosong, set sebelumnya diteruskan. Node yang dijalankan dengan --validator dan kuncinya tidak berada dalam set mana pun hanya mengamati hingga suatu epoch menerimanya, sehingga validator yang melakukan bond setelah genesis tidak perlu memulai ulang node; rand_status melaporkan is_validator (kuncinya ada di sini) dan active_validator (kuncinya berada dalam set saat ini) secara terpisah.
Bagian staking
Sebuah genesis dapat memuat bagian staking (fullnode v0.5.4, audit v4 STAKE-2). Tanpa bagian itu, aturan di atas adalah keseluruhan ceritanya, seperti pada chain 14. Setiap chain sejak chain 15 memuatnya. Pengaturan chain 20 yang diaktifkan:
"staking": {
"faucet_budget_per_epoch": "10000000000000", "bond_activation_epochs": 2,
"max_weight_bps": 3333, "max_stake_entry_bps_per_epoch": 2500,
"admission_by_vote": true, "registration_v2": true,
"faucet_recipients": ["rand1…", "…16 wallets…"],
"faucet_minters": ["<validator address>", "…18 validators…"]
}
| field | chain 20 | aturan |
|---|---|---|
bond_activation_epochs | 2 | bond yang diterapkan pada epoch e diantrekan untuk epoch e + 1 + 2; baik registrasi maupun top-up. Jumlahnya langsung masuk ke stake tetapi belum menjadi bobot hingga saat itu, dan stake yang masih dalam antrean tidak dapat di-unbond |
max_stake_entry_bps_per_epoch | 2,500 (25 %) | stake terbanyak, registrasi dan top-up digabungkan, yang menjadi bobot pada satu batas epoch, sebagai fraksi dari bobot yang sudah aktif pada saat itu: ⌊active · bps / 10,000⌋. Baris yang jatuh tempo melampaui batas ini menunggu batas epoch berikutnya, menurut urutan bond. Pada 26,000 RAND stake aktif milik chain 20, itu berarti 6,500 RAND per batas epoch. Pangsa seorang pendatang baru setelah k batas epoch paling banyak 1 − 1.25^−k pada skala berapa pun, sekitar sepertiga setelah dua batas epoch |
admission_by_vote | true | bond yang meregistrasi kunci baru ditolak (NotAdmitted) hingga validator yang memegang lebih dari dua pertiga bobot suara telah memilih kunci tersebut masuk (di bawah); top-up tidak memerlukan pemungutan suara |
max_weight_bps | 3,333 | bobot validator mana pun tidak melebihi 33.33 % dari total set-nya; kelebihannya dipangkas dalam set, sedangkan stake pada register tidak berubah |
registration_v2 | true | registrasi menandatangani rand-register-2 atas hash genesis, chain id, alamat validator, dan payout; registrasi v1 ditolak |
faucet_budget_per_epoch | 10,000 RAND | faucet mencetak paling banyak jumlah ini per epoch (FaucetBudgetExhausted jika melampauinya; penghitung dimulai ulang pada epoch berikutnya) |
faucet_recipients | 16 wallet | Mint faucet hanya membayar wallet-wallet ini (FaucetRecipientNotAllowed); daftar inilah yang memungkinkan sebuah faucet berdampingan dengan bridge |
faucet_minters | 18 validator | Mint faucet hanya boleh ditandatangani oleh kunci validator ini (MinterNotAllowed), diperiksa saat admisi dan saat blok diterapkan, seberapa lama pun kunci lain telah di-bond. Pada chain 20 mereka adalah 18 dari 26 validator genesis. Daftar ini ada di setiap genesis sejak chain 16 |
slashing | tidak ada | tidak ada bagian slashing, sehingga tidak ada validator yang di-slash atau di-jail (Apa yang bersifat publik) |
Dengan adanya bagian ini, penghitung faucet dan antrean bond ditambahkan ke state root, di bawah domain rand-state-5, dan leaf validator adalah rand-validator-leaf-4. Chain 20 juga memiliki harga gas dinamis dan state program RPL-2, yang ditambahkan setelahnya dan memindahkan domainnya ke rand-state-8, dan admission by vote membungkus root itu sekali lagi sebagai H("rand-state-admitted-1", root ‖ admitted_root). Chain 15 tidak memiliki daftar faucet_minters: di sana, setiap node hanya mengumpulkan dan meneruskan Mint faucet jika ditandatangani oleh validator genesis (MinterNotAllowed, sebagai kebijakan node), agar validator yang di-bond setelah genesis tidak dapat menguras anggaran melalui pool. Dengan adanya daftar itu, penolakan yang sama menjadi aturan validitas.
Riwayat: chain 15 hingga 19 tidak memiliki admission_by_vote, sehingga kunci mana pun yang memegang 1,000 RAND dapat melakukan registrasi, dan anggaran masuknya ditetapkan sebagai max_stake_entry_per_epoch tetap sebesar 10,000 RAND per batas epoch. Angka tetap disesuaikan dengan satu genesis; fraksi menjaga pendatang baru pada pangsa yang sama berapa pun stake-nya. Kedua field itu tidak dapat ditetapkan bersamaan.
Admission by vote
Baru pada fullnode v0.6.8 (audit v6, STAKE-2) dan aktif untuk chain 20. Dengan 26 kunci masing-masing 1,000 RAND, sepertiga pemblokir dari set kira-kira setara 13,000 RAND stake yang dibeli, dan tidak ada yang di-slash. Di bawah aturan ini, set yang menentukan kunci baru mana yang boleh melakukan registrasi.
- Pemungutan suara adalah sebuah action,
AdmitValidator { candidate, signatures }, tanpa bundel dan tanpa biaya. Setiap tanda tangan adalah tanda tangan Dilithium2 seorang validator atasblake3("rand-admit-validator-1" ‖ genesis hash ‖ candidate address), dalam urutan menaik menurut alamat para pemberi suara. Para pemberi suara harus memegang lebih dari dua pertiga secara tegas bobot set pemberi suara, aritmetika yang sama dengan sertifikat kuorum: pada chain 20, 18 dari 26 validator. Suara terikat pada satu genesis dan tidak memerlukan nonce: sebuah admisi dihabiskan oleh registrasi yang diizinkannya. - Set pemberi suara adalah hasil penurunan register itu sendiri untuk epoch saat ini. Bond yang masih dalam antrean bukan bobot di dalamnya, dan unbond langsung mengeluarkan pemiliknya. Seorang kandidat tidak dapat memilih dirinya sendiri masuk.
- Set yang diterima adalah state konsensus, paling banyak 256 kunci yang menunggu untuk melakukan registrasi (
AdmissionSetFulljika melampauinya).rand_getAdmittedmenyajikannya;rand_getLimits.admission_by_votemenyatakan apakah suatu chain memerlukan pemungutan suara.
# each voting validator, offline
rand-node admit sign --candidate <registration hex or public key> --key node.key.json --genesis-hash <hash>
# whoever collects the lines
rand-node admit submit --candidate <…> --signature <line> --signature <line> … --rpc http://127.0.0.1:8545
Setelah itu bond dilanjutkan seperti di bawah. rand_getGenesisHash mengembalikan hash yang dibutuhkan oleh admit sign.
Empat perintah
Binary mana yang memegang action mana ditentukan oleh kunci mana yang menandatanganinya: sebuah bond membelanjakan note, sehingga ia adalah perintah wallet; sebuah unbond dan sebuah withdraw ditandatangani oleh kunci Dilithium2 milik validator, yang hanya dipegang oleh node.
| action | perintah | menumpang pada | membayar |
|---|---|---|---|
| register | rand-node register | tidak ada — mencetak sebuah blob | tidak ada |
Bond | rand bond | sebuah bundel yang burn_r-nya adalah stake | 0.001 RAND dari note milik wallet |
Unbond | rand-node unbond | tidak ada (bundle: null) | tidak ada |
Withdraw | rand-node withdraw | tidak ada (bundle: null) | 0.001 RAND dari jumlah yang ditarik |
Register
rand-node register --key node.key.json --payout "$(rand --key payout.key.json address)" --v2 [--rpc http://127.0.0.1:8545]
Mencetak alamat validator dan sebuah Registration heksadesimal: kunci publiknya, alamat payout, dan sebuah tanda tangan. Dengan --v2, yang diwajibkan chain 20, tanda tangan berada di bawah rand-register-2 atas hash genesis chain, chain id, alamat validator, dan payout; tanpa opsi itu, bentuk v1, blake3("rand-register" ‖ bincode(chain_id, payout)), yang ditolak chain 20 (pada chain dengan binding_domain: 1 seperti chain 20, pesan registrasi adalah pesan v2 bagaimanapun juga). RPC dibaca untuk mengambil chain id dan, dengan --v2, hash genesis, sehingga registrasi yang ditandatangani untuk satu chain ditolak pada chain lain. Alamat payout adalah alamat wallet, bukan kunci node, dan merupakan satu-satunya field yang tidak dapat diubah oleh top-up berikutnya. Serahkan hex tersebut kepada pihak yang memegang stake.
Bond
rand bond <validator base58> <amount in RAND> [--registration <hex>] [--fee <RAND>] [--no-wait] [--cuda]
Transaksi shielded biasa: dompet membuktikan bundel aset tersembunyi 4-in-4-out yang dibawa setiap transaksi sejak chain 14, dengan jumlah yang di-stake berada dalam burn RAND-nya, burn_r, dan ledger hanya menerima sebuah bond bila burn_r == amount. Pada chain 20, bundel membawa dua bukti, seperti setiap bundel sejak chain 17: bukti bundel tier-14 dan bukti otorisasi tier-10 atas spend key. Keduanya dibuktikan secara lokal secara bawaan, dalam sekitar dua menit pada laptop Apple Silicon (Memori pembuktian). Dengan opsi --prover pada dompet, bukti bundel dibuat oleh prover yang dipasangkan, sedangkan bukti otorisasi tetap berada di mesin dompet. --registration diwajibkan tepat ketika validator belum ada dalam register, dan ditolak ketika sudah ada; dompet menanyakan register terlebih dahulu. Pada chain 20, bond pendaftaran ditolak dengan NotAdmitted kecuali set validator telah memilih kunci tersebut terlebih dahulu (Admisi melalui pemungutan suara); top-up tidak memerlukan pemungutan suara. Pendaftaran mem-bond paling sedikit 1.000 RAND; top-up dapat berjumlah berapa pun di atas nol. Yang diketahui chain adalah bahwa stake validator ini bertambah sebesar jumlah tersebut; note mana yang membayar, dan milik siapa, tetap tersembunyi seperti pada transfer — siapa pun dapat melakukan stake ke sebuah validator tanpa mengungkapkan apa pun selain jumlahnya.
submitted bond 8c3f…e1
0 RAND out, 1000 RAND burned, 0.999 RAND change, fee 0.001 RAND, anchored at height 412
2nRdFC…: stake 1000 RAND, counting as consensus weight from epoch 69
Epoch yang dicetak dompet adalah batas berikutnya. Angka itu tidak memperhitungkan penundaan aktivasi: pada chain 20, bond yang di-commit pada epoch 68 baru berbobot paling cepat mulai epoch 71, lebih lambat bila anggaran masuk, seperempat dari bobot aktif per batas, telah habis.
Unbond
rand-node unbond <amount in RAND> --key node.key.json [--rpc …] [--no-wait]
Memindahkan amount dari stake ke pending dengan release_epoch = epoch + 2 dan menaikkan nonce. Gratis, tanpa bundel, ditandatangani atas blake3("rand-unbond" ‖ bincode(chain_id, validator, amount, nonce)) pada chain 14 hingga 19 dan atas blake3("rand-unbond-2" ‖ bincode(genesis_hash, chain_id, validator, amount, nonce)) pada chain 20 (genesis binding_domain: 1); transaksi ini di-commit dalam waktu satu blok. rand-node v0.6.8 memilih bentuk yang sesuai dengan chain yang dihubunginya. Unbond melebihi stake, atau bernilai nol, ditolak; beberapa unbond dalam satu epoch digabung menjadi satu baris pending.
Withdraw
rand-node withdraw <amount in RAND> --key node.key.json [--rpc …] [--no-wait]
Membayarkan nilai yang telah dilepas — rewards ditambah baris pending yang release_epoch-nya telah tiba, mulai dari yang tertua — ke sebuah deposit note pada alamat payout milik register. Transaksi ini ditandatangani validator (pada chain 20 di bawah rand-withdraw-2, atas genesis hash terlebih dahulu, seperti unbond) dan tanpa bundel, tetapi tidak gratis: biaya dasar 0,001 RAND diberikan kepada proposer blok yang menerapkannya, diambil dari jumlah tersebut, sehingga penarikan 1.000 RAND menghasilkan note senilai 999,999 dan jumlah yang tidak mencukupi biaya dasar ditolak. Chain menghitung note itu sendiri:
cm = H_CM(payout.pk, from = 0, amount − 0.001 RAND, asset 0, time, r)
time adalah tinggi head ketika perintah dijalankan (dicetak, dan terikat oleh tanda tangan), diterima di mana pun di dalam jendela bundel (1.024 blok pada chain 20, yang genesis-nya menetapkan proof_window_blocks; 256 pada chain sebelumnya); r dipublikasikan agar chain tidak pernah mengambil commitment dari wire. Setelahnya, dompet payout menemukan note tersebut dengan pemindaian, tanpa diberi tahu apa pun:
rand --key payout.key.json balance # balance: 999.999 RAND
Bergabung dan keluar
# on the joining validator's machine
rand-node register --key node.key.json --payout "$(rand --key payout.key.json address)" --v2
rand-node run --datadir ./data --key node.key.json --validator --bootstrap /ip4/…/p2p/…
# it syncs and observes; rand_status says is_validator true, active_validator false
# on chain 20: validators holding more than two thirds of the weight vote the key in
rand-node admit sign --candidate <hex from above> --key <their node.key.json> --genesis-hash <hash>
rand-node admit submit --candidate <hex from above> --signature <line> … --rpc http://127.0.0.1:8545
# on the machine holding the stake
rand bond <validator base58> 1000 --registration <hex>
rand validators # the new row, active false until it activates
# from its activation epoch on (on chain 20, three boundaries after the bond at the earliest)
rand-node status # active_validator: true
rand-node unbond 1000 --key node.key.json # out of the set at the next boundary
# wait two epochs
rand-node withdraw 1000 --key node.key.json # a note worth 999.999 RAND at the payout address
Periksa aritmetika kuorum sebelum melakukan unbond: sebuah set berisi n validator memerlukan lebih dari 2/3 stake-nya daring. Pada chain 20 seluruh 26 validator berada tepat pada MIN_STAKE, sehingga unbond sekecil apa pun mengeluarkan node tersebut dari set epoch berikutnya, dan 18 dari 26 harus tetap aktif. Validator yang aktif tetapi tidak memberikan suara juga dihitung melawan kuorum: sejak chain 14 sebuah validator menahan suaranya dari blok yang lebih dari 15 s di depan jam miliknya sendiri, sehingga validator yang jamnya berjalan lambat berhenti memberikan suara tanpa pesan galat. Jalankan NTP padanya (Menjalankan validator).
Genesis mengisi register secara langsung — satu entri per --validator <key or hex pubkey>,<stake>,<payout> — dan menolak stake di bawah minimum. Genesis chain 20 mengisi 26 baris masing-masing 1.000 RAND, dengan kunci yang sama seperti chain 19.
Sejak v0.5.11, build ini juga membawa genesis vesting: register publik berisi alokasi yang terkunci waktu, dan dari register itu sebuah entri yang tidak dapat dicabut dapat mem-bond RAND terkunci sebagai stake validator (rand-node vesting bond) dan menariknya kembali (rand-node vesting unbond). Fitur ini memerlukan bagian vesting dalam genesis. Tidak ada chain yang memilikinya, termasuk chain 20, dan tanpa bagian itu aksi-aksi tersebut ditolak saat admisi. (v0.6.8 juga memungkinkan entri vesting yang dapat dicabut dicabut hanya oleh ambang batas penanda tangan kepada treasury tetap, lagi-lagi hanya di bawah bagian vesting.)
Apa yang bersifat publik
| publik | tersembunyi | |
|---|---|---|
| register | setiap baris: alamat, stake, antrean unbonding, reward yang belum dibayar, alamat payout, nonce | tidak ada |
Bond | validator, jumlah, apakah pendaftaran dilampirkan, burn_r milik bundel | note mana yang membayar, siapa pemiliknya, kembaliannya |
AdmitValidator (chain 20) | kandidat dan setiap pemberi suara beserta tanda tangannya | tidak ada hal lain |
Unbond | validator, jumlah, nonce | tidak ada hal lain |
Withdraw | validator, jumlah, nonce, time dan r milik note | siapa yang dapat membuka note, dan setiap pembelanjaan berikutnya |
Reward adalah biaya dari blok yang diusulkan oleh sebuah validator. Tidak ada reward blok dan tidak ada inflasi, dan pada chain 20 tidak ada slashing maupun jailing terhadap validator: validator yang berperilaku menyimpang tidak membuat stake-nya berkurang sedikit pun, dan penanganannya ada di tangan operator. Fullnode v0.6.8 memang membawa aturan slashing untuk equivocation leader (audit v6, STAKE-1: dua header blok bertanda tangan untuk satu view oleh satu kunci menghancurkan equivocation_bps dari stake dan men-jail kunci tersebut), tetapi hanya di bawah bagian genesis staking.slashing, dan chain 20 tidak memilikinya (rand_getLimits.slashing bernilai null); fullnode merekomendasikannya hanya setelah stake dipegang oleh lebih dari satu operator. (Kode agregasi blok juga membawa aksi SlashAggregator untuk aggregator yang menandatangani dua agregat berbeda pada satu nonce, dan aksi itu tidak aktif pada chain 20, yang tidak memiliki bagian agregasi.)
Membaca kembali
rand validators # the whole register
rand status # is_validator / active_validator for the node asked
→ {"method":"rand_getValidators","params":[]}
← [{ "address": "2nRdFC…", "stake": "1000000000000",
"pending": [{ "release_epoch": 71, "amount": "1000000000000" }],
"rewards": "4000000", "payout": "rand1…", "nonce": 3, "active": true, "jailed_until": null }]
→ {"method":"rand_getAdmitted","params":[]}
← { "admission_by_vote": true, "admitted": [], "max": 256 }
→ {"method":"rand_getEpoch","params":[]}
← { "epoch": 69, "epoch_blocks": 1000, "next_set": ["2nRdFC…", "ByDkxs…"] }
Jumlah berupa string desimal dari unit. active menyatakan apakah baris tersebut berada dalam set yang menjalankan epoch saat ini; jailed_until bernilai null kecuali di bawah bagian slashing; admitted mencantumkan kunci yang telah dipilih tetapi belum mendaftar; next_set adalah proyeksi yang digeser oleh setiap bond dan unbond sebelum batas. GET /validators milik explorer menambahkan share_percent, blocks_proposed dan tinggi terakhir yang diusulkan.