Rand Protocol
Dokumentasi
Konsep inti

Transaksi dan Action

Transaksi pada jaringan, id-nya, setiap Action yang dikenal oleh buku besar, Action mana saja yang diterima chain 20, dan urutan pemeriksaan yang dilakukan node terhadap suatu pengajuan.

Gunakan halaman ini untuk menyusun, mengirim, atau mendekode sebuah transaksi: bentuk wire yang diterima rand_sendTransaction, cara id dihitung, daftar lengkap aksi beserta aturan bundle dan biayanya, serta urutan admisi yang menentukan galat mana yang Anda terima lebih dulu.

Transaksi

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>,     // postcard(Proof) of the hidden-asset guest
  auth_commit: Word8, auth_proof: Vec<u8>,      // since chain 17: split authorisation's c and its auth proof
}
Envelope { kem_ct: Vec<u8>, to_receiver: Vec<u8>, to_sender: Vec<u8>, body: Vec<u8> }

Word8 adalah delapan word u32 little-endian, dirender sebagai 64 karakter heksadesimal huruf kecil. Bentuk wire-nya adalah bincode(Transaction) dengan bawaan bincode (bilangan bulat berlebar tetap, prefiks panjang 8 byte, tag enum u32), dan rand_sendTransaction menerimanya dalam bentuk heksadesimal. Tidak ada tanda tangan atas transaksi dan tidak ada field pengirim: sebuah bundle mengotorisasi dirinya sendiri melalui proof-nya (proof bundle dan, sejak chain 17, auth proof di sampingnya), dan aksi yang bertanda tangan membawa tanda tangan itu di dalam dirinya sendiri. Perlindungan replay berupa nullifier set untuk bundle, nonce per validator di dalam register untuk aksi staking yang bertanda tangan, mint_nonce per token untuk TokenMint dan SetAuthority, serta pause_nonce dan list_nonce milik bridge untuk aksi tata kelolanya.

Sebuah transaksi membawa paling banyak satu bundle, dan setiap aksi yang bukan bundle-less membawa tepat satu. Slot 0–1 bundle membawa aset privat dan slot 2–3 membawa RAND, sehingga satu proof memindahkan sebuah token sekaligus membayar biaya RAND-nya; burn bridge dua-bundle dari rancangan sebelumnya sudah tidak ada: satu burn adalah satu bundle (Note).

Dompet rand membangun semua ini melalui randprotocol_client::wallet::{send, submit}: memilih input, mengambil anchor, menghitung witness dari salinan tree milik dompet itu sendiri, membangun output dan menyegel keempat envelope, mengambil binding transaksi, membuktikan bundle dan auth proof, memeriksa digest yang dipublikasikan oleh proof bundle, lalu mengirim.

Binding transaksi

Sebuah transaksi tidak memiliki tanda tangan, dan proof sebuah bundle hanya berkomitmen pada digest bundle itu sendiri: anchor, nullifier, komitmen, biaya, field burn, time. Hingga chain 13, tidak ada yang mengikat bundle yang telah dibuktikan dengan aksi yang menyertainya atau dengan envelope-nya, sehingga siapa pun yang melihat sebuah transaksi dapat mempertahankan setiap byte proof dan mengubah sisanya: tujuan sebuah BridgeBurn, validator sebuah Bond, sebuah envelope. Sejak chain 14, setiap proof bundle dibuat atas, dan diverifikasi terhadap, binding transaksi:

binding(tx) = blake3("rand-tx-bind-1" || bincode(chain_id, bundle', action'))            chains 14 to 19
binding(tx) = blake3("rand-tx-bind-2" || bincode(genesis_hash, chain_id, bundle', action'))  chain 20
                                                                                  as 8 LE u32 words

di mana ' berarti setiap byte string proof bundle diganti dengan vektor kosong: bundle.proof, sejak chain 17 bundle.auth_proof, dan proof milik sebuah Aggregate. Segala yang lain berada di dalamnya: auth_commit, keempat envelope, setiap field burn, tujuan, validator, penerima, tanda tangan, atestasi guardian beserta ko-tanda tangan Dilithium2-nya, dan proof milik sebuah Call. Kedelapan word itu dibawa dalam segmen public input milik proof, yang digest H_PUB-nya sudah diikat oleh circuit, sehingga perbaikan ini tidak memerlukan perubahan guest maupun circuit; node menjalankan Machine::verify_public(hc_bundle, binding, proof) dan menolak proof bundle yang mendeklarasikan public height lain (public height not the transaction binding's). Transaction::binding adalah satu-satunya fungsi yang dipanggil dompet sebelum membuktikan dan oleh ledger sebelum memverifikasi. Sejak chain 17, auth proof dibuat atas dan diverifikasi terhadap delapan word yang sama, sehingga ia juga tidak dapat dipindahkan ke transaksi lain.

Chain 20 mengikat genesis hash. Hingga chain 19, binding, serta pesan bertanda tangan dari aksi bundle-less, hanya mencakup chain id, sehingga dua chain yang berbagi chain id (re-cut, salinan privat) akan saling menerima proof dan tanda tangan. Genesis chain 20 menetapkan binding_domain: 1 (v0.6.8, audit v6 BIND-1; crates/randprotocol-core/src/types/binding.rs). Genesis hash kemudian memimpin setiap preimage di bawah tag yang naik satu versi: rand-tx-bind-2 dan rand-call-bind-2 untuk kedua binding, demikian pula untuk mint faucet (rand-mint-3), Unbond dan Withdraw (rand-unbond-2, rand-withdraw-2), pesan mint dan otoritas RPL (rand-rpl-mint-2, rand-rpl-authority-2), aksi aggregator, dan pesan tata kelola bridge. Registrasi validator pada chain semacam itu selalu berupa pesan v2 (genesis, chain, address, payout). Tidak ada yang dibuktikan atau ditandatangani untuk satu chain yang dapat diverifikasi di chain lain, apa pun chain id-nya. Word binding adalah public input, sehingga tidak ada guest atau kunci verifier yang berubah. Dompet yang lebih lama dari v0.6.8 masih membuktikan terhadap bentuk chain-id dan ditolak di chain 20. rand_getLimits dan rand_status menyajikan binding_domain (1 di chain 20, 0 bila field tidak ada).

Di bawah genesis hardening_v6 (chain 16 hingga 20), proof milik sebuah Call juga diikat, melalui digest kedua dengan konstruksi yang sama di bawah domainnya sendiri, dengan proof call dikosongkan selain proof bundle:

call_binding(tx) = blake3("rand-call-bind-1" || bincode(chain_id, bundle', action''))   as 8 LE u32 words

Di chain 20, tag-nya adalah rand-call-bind-2 dan genesis hash memimpin preimage, seperti di atas. Proof sebuah Invoke diikat dengan cara yang sama, dengan transisi yang dideklarasikannya tetap berada di dalam preimage, sehingga proof berkomitmen tepat pada perubahan state, pembayaran, dan penerima yang dibawa transaksi.

Proof call membawa word-word ini dalam segmen public input-nya, setelah public input waktu-deploy milik program bila ada, sehingga salinannya yang dilekatkan pada bundle biaya lain tidak lolos verifikasi. Kedua binding itu bersarang: dompet memilih note milik bundle biaya dan membangun transaksi dengan proof kosong, membuktikan call terhadap binding call, memasukkan proof itu, dan baru kemudian mengambil binding transaksi dan membuktikan bundle.

Konsekuensinya bagi klien: bangun seluruh transaksi — output, envelope, aksi — sebelum membuktikan. Dompet yang dibuat sebelum fork membuktikan terhadap segmen publik yang kosong dan ditolak. Aksi bundle-less tidak memiliki proof untuk diikat dan bertumpu pada tanda tangannya sendiri. Binding bukanlah id transaksi, yang tidak berubah.

Id transaksi

txid = blake3("rand-txid-3" || bincode(view))

di mana view adalah transaksi dengan byte proof milik bundle diganti dengan blake3(proof) (proof_hash) dan byte auth_proof-nya dengan blake3(auth_proof) (auth_proof_hash, setelah auth_commit, yang masuk apa adanya), dengan setiap field lain apa adanya. Domainnya adalah rand-txid-2, tanpa kedua field auth, hingga chain 16; setiap id transaksi berubah bersama chain 17. Melakukan hash atas proof berdasarkan digest-nya memungkinkan bundle yang dipangkas (agregasi blok, tidak aktif di chain 20) mempertahankan id yang sama dengan bentuk mentahnya; bundle yang dipangkas tetap mempertahankan auth proof-nya. Transaksi bundle-less melakukan hash atas byte-nya apa adanya. Id yang sama menjadi kunci mempool, receipt, dan setiap pencarian RPC.

Setiap aksi

Action adalah enum bincode, dengan tag menurut urutan deklarasi:

tagaksibidangbundlebatas bawah biaya
0None—wajibBUNDLE_BASE = 0,001 RAND
1Mintcm, pk, time, r, envelope, amount, minter: PublicKey, signatureharus tidak ada0 (ditandatangani validator; hanya pada chain faucet, amount ≤ 100 RAND)
2Deploybase_pc: u32, words: Vec<u32>, public: Vec<u32>wajibbase + 100.000 unit per word program dan word publik
3Callprogram, proof, input_envelope: Option<CallEnvelope>wajibpada chain 20, base + gas_price × GAS_LIMIT yang dinyatakan proof + byte_price per KiB proof dan input envelope; base + call_fee(tier) pada chain tanpa bagian gas
4Bondvalidator, amount, registration: Option<Registration>wajib, dan burn_r == amountbase
5Unbondvalidator, amount, nonce, signatureharus tidak ada0
6Withdrawvalidator, amount, nonce, time, r, envelope, signatureharus tidak ada0 pada wire; base diambil dari amount
7BridgeAttestattestation, recipient: ShieldedAddress, r, time, asset, envelope, pq_signatures: Vec<PqSignature>wajibbase
8BridgeBurnasset, amount, relayer_fee, to_chain: u16, token: [u8; 32], to: [u8; 32]wajib, dengan burn_asset == asset dan burn_a == amountBRIDGE_BURN_FEE = 0,01 RAND
9RegisterAggregatorregistrationwajib, burn_r = bondbase
10UnbondAggregatoraggregator, nonce, signatureharus tidak ada0
11WithdrawAggregatoraggregator, nonce, time, r, envelope, signatureharus tidak ada0
12SlashAggregatordua header agregat yang ditandatanganiharus tidak ada0
13Aggregatecovers, proof, aggregator, nonce, time, r, envelope, signatureharus tidak ada0
14RegisterTokenname, symbol, decimals: u8, authority: MintAuthority, initial: Option<InitialMint>, salt: [u8; 32], index: u32wajibbase + registration_fee milik registri (1 RAND pada chain 20, dibakar)
15TokenMintasset, amount, recipient: ShieldedAddress, r, time, envelope, nonce, signaturewajibbase
16SetAuthorityasset, new: Option<PublicKey>, nonce, signaturewajibbase
17TokenBurnasset, amountwajib, dengan burn_asset == asset dan burn_a == amountbase
18PauseMintsnonce, signatureharus tidak ada0
19UnpauseMintsnonce, pq_signaturesharus tidak ada0
20RegisterBridgedTokenname, symbol, salt, chain: u16, token: [u8; 32], decimals: u8, nonce, pq_signatureswajibbase + registration_fee
21ListBackingtoken_index, chain: u16, token: [u8; 32], decimals: u8, nonce, pq_signatureswajibbase
22RotatePqGuardiansnew_pq_guardians: Vec<PublicKey>, nonce, pq_signaturesharus tidak ada0
23RotatePauseKeynew_pause_key: PublicKey, nonce, pq_signaturesharus tidak ada0
24ClaimVestedentry: [u8; 32], amount, nonce, to: ShieldedAddress, time, r, envelope, signatureharus tidak ada0 pada wire; base diambil dari amount
25RevokeVestingentry: [u8; 32], unvested, nonce, to: ShieldedAddress, time, r, envelope, signatures (sejak v0.6.8 berupa ambang batas dari para revoker entri tersebut, yang membayar treasury yang disebut oleh entri genesisnya; sebelumnya satu signature)harus tidak ada0 pada wire; base diambil dari unvested
26BondVestedentry: [u8; 32], validator, amount, registration: Option<Registration>, nonce, signatureharus tidak ada0
27UnbondVestedentry: [u8; 32], amount, nonce, signatureharus tidak ada0
28AdmitValidatorcandidate: PublicKey, signatures: Vec<(PublicKey, Signature)>harus tidak ada0
29SlashEquivocationfirst, second: dua header blok bertanda tangan dari satu leader untuk satu viewharus tidak ada0
30RotatePqGuardiansV2new_pq_guardians: Vec<PublicKey>, possession: Vec<Vec<u8>>, nonce, pq_signaturesharus tidak ada0
31RotatePauseKeyV2new_pause_key: PublicKey, possession: Vec<u8>, nonce, pq_signaturesharus tidak ada0
32CancelRotationkind: u8, nonce, signatureharus tidak ada0
33Invokeprogram, proof, input_envelope: Option<CallEnvelope>, transition: Transitionwajib; burn_r, dan burn_a dari burn_asset, adalah yang masuk ke dalam programbatas bawah sebuah call + cell_fee per cell yang dibuat
MintAuthority = None | Key(PublicKey) | Bridge { backings: Vec<Backing> } | Program(Hash)
InitialMint   { amount: u64, recipient: ShieldedAddress, r: Word8, time: u32, envelope: Envelope }
PqSignature   { index: u8, signature: Vec<u8> }   // one guardian's Dilithium2 co-signature, by set index

Pada chain 20, tag 0 sampai 8, 14 sampai 21, 28, dan 30 sampai 33 dapat digunakan. Genesis-nya memiliki bagian bridge dengan rules_v2, bagian tokens, staking.admission_by_vote (tag 28), bridge.rotation (tag 30 sampai 32), dan program_state (tag 33). Tag 22 dan 23 ditolak di sana: di bawah bridge.rotation.needs_possession, sebuah rotasi harus berbentuk …V2 yang membawa tanda tangan milik masing-masing kunci baru. Pada chain 19, yang tidak memiliki satu pun bagian tersebut, tag 0 sampai 8 dan 14 sampai 23 dapat digunakan (chain 14, tanpa rules_v2, menolak 22 dan 23). SlashEquivocation memerlukan bagian staking.slashing, dan milik chain 20 bernilai null. Kelima aksi agregasi memerlukan bagian aggregation, yang tidak dimiliki chain 20 (sebuah build menolak untuk dijalankan pada genesis yang memuatnya sampai agregasi diukur ulang). Node menolak semua aksi ini pada gerbang sebelum pemeriksaan lainnya, tetapi aksi-aksi itu tetap menempati tag bincode-nya, sehingga encoder yang menanamkan nomor tag secara permanen harus menghitungnya. Agregasi didokumentasikan sebagai fitur mendatang di Proofs. Keempat aksi vesting genesis (tag 24 sampai 27, ada di build sejak v0.5.11) memerlukan bagian vesting, yang belum pernah dimiliki chain mana pun, termasuk chain 20, dan ditolak saat admisi tanpa bagian tersebut. Tag 28 sampai 33 baru di v0.6.8 dan ditambahkan paling akhir, sehingga riwayat setiap chain sebelumnya tetap dapat didekode.

Keempat aksi RPL (tag 14 sampai 17) mendaftarkan sebuah token, mencetak lebih banyak token yang otoritasnya Key, menyerahkan atau melepaskan otoritas cetaknya, dan membakar kepemilikan; sebuah RegisterToken yang menyebut otoritas Bridge atau Program ditolak. Tidak ada aksi transfer token: transfer token adalah None, tidak dapat dibedakan dari pembayaran RAND. Lihat RPL tokens. Keempat aksi tata kelola bridge (tag 18 sampai 21) adalah penghentian sementara pencetakan, pencabutannya, serta pencatatan token bridged atau backing tambahan setelah genesis. PauseMints ditandatangani oleh kunci jeda genesis, yang hanya dapat menghentikan sementara; ketiga aksi lainnya memerlukan kuorum guardian Dilithium2 (PQ). Sebuah BridgeAttest juga membawa kuorum semacam itu, di samping kuorum ECDSA-nya. Tag 22 dan 23, di bawah bridge rules_v2, mengganti himpunan guardian PQ atau kunci jeda, masing-masing di bawah kuorum PQ dari himpunan saat ini dan rotation_nonce milik bridge. Tag 30 dan 31 melakukan hal yang sama di bawah bridge.rotation dan juga membawa tanda tangan Dilithium2 milik masing-masing kunci baru atas pesan rotasi, bukti bahwa kunci tersebut dipegang; pada chain 20 sebuah rotasi dicatat sebagai tertunda dan berlaku setelah delay_secs, yaitu 86.400 detik. CancelRotation (tag 32), yang ditandatangani oleh kunci jeda saat ini, membatalkan rotasi yang tertunda sebelum berlaku. Lihat Bridge.

AdmitValidator (tag 28) adalah suara himpunan validator untuk menerima sebuah kunci baru: tanda tangan dari validator yang memegang lebih dari dua pertiga stake, dalam urutan alamat menaik. Di bawah staking.admission_by_vote (chain 20), sebuah Bond yang akan mendaftarkan validator baru ditolak kecuali alamatnya telah diterima dengan cara ini (Staking). Invoke (tag 33, RPL-2) adalah sebuah call yang proof-nya menjamin satu transition status program yang dinyatakan: cell yang dibaca dan ditulis, apa yang dibawa field burn bundle ke dalam vault program, serta note yang dibayarkan vault atau dicetak program. Ledger menerapkan transisi tersebut jika setiap pembacaan yang dinyatakan masih berlaku dan kedua proof terverifikasi (Programs).

Sebuah Deploy dan sebuah Call adalah transaksi terlindung biasa yang bundle-nya merupakan transfer ke diri sendiri senilai nol: bundle itu ada untuk membayar batas bawah biaya dari note milik pemanggil sendiri, sehingga chain tidak pernah mengetahui milik siapa note tersebut. RAND keluar dari kolam terlindung hanya melalui burn_r — stake sebuah Bond, bond sebuah RegisterAggregator, setoran sebuah Invoke ke vault program — dan sebuah token hanya melalui burn_a dengan burn_asset yang menyebutnya, pada sebuah TokenBurn, BridgeBurn, atau Invoke. Setiap aksi lainnya tidak membakar apa pun, dan bundle dengan burn_asset = 0 serta burn_a bukan nol ditolak di mana pun.

Urutan admisi

Ledger::validate_inner memeriksa hal-hal yang murah sebelum yang mahal, dalam urutan ini; mempool menjalankan pemeriksaan yang sama sebelum melakukan gossip, sehingga transaksi yang buruk ditolak satu kali, di tepi jaringan.

  1. Batas ukuran: seluruh transaksi ≤ max_block_bytes milik chain; masing-masing dari empat envelope bundle, dan setiap envelope note yang dibawa aksi, tepat sebesar envelope_bytes pada genesis (1.860 pada chain 20; paling banyak 2.048 byte pada chain tanpa field tersebut); bundle proof, auth proof, dan call proof masing-masing ≤ max_proof_bytes (2 MiB secara bawaan, 4 MiB pada genesis chain 20; 8 MiB pada chain 13 hingga 16); sebuah program ≤ batas program chain (4.096 word secara bawaan, 65.535 pada genesis chain 20); sebuah call envelope ≤ max_call_envelope_bytes (18.432 byte secara bawaan, 65.536 pada chain 20); sebuah attestation ≤ 16 KiB. Bundle proof dalam bentuk penanda tersegel (pruned) ditolak di sini di luar sinkronisasi bentuk tersegel (PrunedFormOutsideSync), sebelum pekerjaan proof apa pun.
  2. Chain id sesuai.
  3. Bentuk dan batas bawah fee: aksi tanpa bundle tidak membawa bundle, dan semua aksi lainnya harus membawa tepat satu; check_burn_shape menetapkan field burn mana dari ketiganya yang boleh diisi aksi: TokenBurn atau BridgeBurn membakar asset dan amount miliknya sendiri melalui burn_asset dan burn_a, Bond atau RegisterAggregator membakar jumlahnya melalui burn_r, dan setiap aksi lainnya tidak membakar apa pun; fee ≥ fee_floor(action). Pada chain dengan bagian gas (chain 20), batas bawah Call atau Invoke pada langkah ini adalah aturan gas pada batas yang dideklarasikan sebesar 1, yaitu BUNDLE_BASE + gas_price + byte_price × ⌈bytes / 1024⌉ atas proof dan input envelope-nya, yang sudah diketahui sebelum verifikasi apa pun.
  4. Anchor: salah satu dari 1.024 root akhir blok terakhir pada chain 20, yang genesis-nya menetapkan proof_window_blocks: 1024 (v0.6.8); salah satu dari 256 terakhir pada chain tanpa field tersebut, seperti hingga chain 19.
  5. Waktu: dalam [height − 1024, height] pada chain 20; [height − 256, height] tanpa field tersebut. Satu nilai genesis menetapkan kedua jendela.
  6. Nullifier dan commitment: keempat nullifier berbeda dan tidak ada yang sudah terpakai; keempat commitment berbeda dan tidak ada yang sudah menjadi leaf.
  7. Pemeriksaan aksi: faucet diaktifkan, mint berada di bawah batas dan ditandatangani validator, dan pada chain 20 menyebut penerima yang ada dalam daftar izin staking.faucet_recipients pada genesis, muat dalam faucet_budget_per_epoch epoch tersebut, dan ditandatangani validator yang ada dalam daftar staking.faucet_minters pada genesis (aturan validitas sejak chain 16); mint atau deposit sebesar 2⁶³ atau lebih ditolak di setiap chain; program dapat didekode; program ada; aturan staking (registrasi hadir tepat ketika validator belum dikenal, nonce, tanda tangan, stake yang cukup); aturan bridge sendiri untuk BridgeAttest dan BridgeBurn serta untuk aksi jeda dan pencatatan; aturan RPL untuk keempat aksinya, termasuk biaya registrasi; pada chain 20, kuorum suara admisi, dan untuk sebuah Invoke, bentuk transisi, pembacaan yang dideklarasikan terhadap cell yang tersimpan, jaminan vault untuk setiap pembayaran, dan cell fee. Semuanya berjalan sebelum proof bundle, sehingga transaksi yang tidak dapat diterapkan tidak menimbulkan biaya verifikasi STARK. Di bawah hardening_v6 (chain 16 hingga 20), dua penolakan lagi berada di sini: sebuah Deploy program yang tidak dapat dipegang oleh call mana pun (ProgramUncallable), dan proof bundle atau call yang header atau transkripnya memuat field yang tidak akan ditulis oleh prover yang jujur (non-canonical proof: …), ditolak sebelum salah satu proof diverifikasi. Sejak v0.6.8, proof yang headernya mendeklarasikan derajat melampaui batas tabel tertinggi ditolak lebih dahulu dengan vonis yang sama (audit v6 ZKV-4), sebelum pemeriksaan menelusurinya.
  8. Digest bundle: pada chain dengan otorisasi terpisah (setiap chain sejak 17), field auth diperiksa lebih dahulu: bundle tanpa auth proof ditolak, c yang dipublikasikan auth proof (dibaca, belum diverifikasi) harus sama dengan auth_commit, dan pada chain 20 auth proof harus mendeklarasikan GAS_LIMIT tepat 1.279. Kemudian ledger menghitung ulang digest dari field bundle yang dipublikasikan, termasuk auth_commit, dan digest itu harus sama dengan yang dipublikasikan proof. Pada chain 20, proof bundle juga harus mendeklarasikan GAS_LIMIT tepat sebesar bundle_gas_limit pada genesis, yaitu 20.479.
  9. Proof bundle: Machine::verify_public terhadap hc_bundle yang dipatok pada genesis dan binding transaksi. Pada chain dengan otorisasi terpisah, auth proof diverifikasi berikutnya, terhadap hc_auth yang dipatok pada genesis dan binding yang sama.
  10. Call proof dan fee tier-nya: untuk sebuah Call atau Invoke, header proof dipatok lebih dahulu (tier paling tinggi 14, tabel keccak paling besar 2¹², tabel sha256 paling besar 2¹³, tinggi program yang dideploy, dengan batas bawah 2⁷ baris di bawah hardening_v6, dan pada chain 20 GAS_LIMIT yang dideklarasikan tidak melebihi batas atas header, gas_max), kemudian STARK call terhadap code_hash program dan, di bawah hardening_v6, binding call milik transaksi. Fee diperiksa paling akhir, karena baru dapat diketahui setelah proof didekode: pada chain 20 fee ≥ BUNDLE_BASE + gas_price × GAS_LIMIT + byte_price × ⌈bytes / 1024⌉ pada harga yang berlaku, ditambah cell_fee untuk setiap cell yang dibuat oleh sebuah Invoke (Fee); pada chain tanpa bagian gas, fee ≥ BUNDLE_BASE + call_fee(tier).

Galat dikembalikan oleh rand_sendTransaction dengan kode -32000 beserta alasannya: nullifier already spent, anchor is not one of the last 1024 roots (256 pada chain tanpa proof_window_blocks), time 12 is outside [476, 1500], 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, dan sejak chain 14 the bundle burns asset 2 on an action that burns no token, a burn of 5 is not allowed on this action, the bundle burns 399, not the 400 the action declares, wrong mint nonce: expected 1, got 0, wrong token index: expected 3, got 2, sejak chain 17 this chain requires an auth proof on every bundle (genesis hc_auth) dan the auth proof publishes a different commitment than the bundle's auth_commit, serta pada chain 20 envelope is 1348 bytes, this chain requires exactly 1860 dan bundle proof declares gas limit …, this chain requires exactly 20479. Diterima bukan berarti terkomit: lakukan polling rand_getTransaction sampai ia mengembalikan sebuah blok.

Blok yang memuat satu transaksi tidak valid adalah blok yang tidak valid. Mempool mengindeks setiap nullifier dan commitment yang tertunda dan langsung menolak konflik, sehingga dua bundle yang membelanjakan note yang sama tidak pernah berada dalam satu blok.

Ukuran

bagianbyte
Word832
satu Envelope1.892 terenkode (1.860 ciphertext) sejak chain 18; 1.380 (1.348) hingga chain 17
Bundle tanpa kedua proof-nya7.936 (empat nullifier, empat commitment, empat envelope, auth_commit)
transaksi transfer tanpa kedua proof-nya7.949
transaksi deploy tanpa kedua proof-nya, program 100 word, tanpa input publik8.369
transaksi call tanpa ketiga proof-nya, tanpa input envelope7.990
transaksi mint (tanpa bundle)5.761 (kunci Dilithium2 sebesar 1.312 byte dan tanda tangan sebesar 2.420 byte)
sebuah proof bundle, tier 14, profil produksi1.497.544 dan 1.504.260 terbaca pada chain 18 (sebuah deploy pada tinggi 97.821 dan sebuah call pada 98.335, 2026-09-30); 1.422.116 dan 1.423.170 terukur pada chain 14 (registrasi zUSD dan pencatatan sebuah backing, 2026-09-20)
sebuah auth proof, tier 10, profil produksi1.370.827 dan 1.367.303 pada kedua transaksi chain 18 yang sama

Enam baris pertama adalah pengodean sejak chain 18: field memo menambah 512 byte pada setiap envelope, dan otorisasi terpisah menambah 40 byte pada bundle sebelum byte auth proof itu sendiri. Maka sebuah transfer terlindungi (shielded) di jaringan berukuran sekitar 2,88 MB sejak chain 18, termasuk chain 20, hampir seluruhnya proof, aset apa pun yang dipindahkan: sekitar 1,5 MB proof bundle dan 1,37 MB auth proof. Ukurannya sekitar 1,43 MB hingga chain 15, dengan satu proof. Blok dibatasi 2.000 transaksi (MAX_BLOCK_TXS) dan max_block_bytes milik chain untuk byte transaksi, keduanya aturan konsensus: 4 MiB secara bawaan (MAX_BLOCK_BYTES), yang hanya memuat satu transfer seperti itu, dan 20 MiB pada genesis chain 20, yang memuat tujuh. Genesis dengan hc_auth harus menetapkan max_block_bytes sekurang-kurangnya tiga kali max_proof_bytes ditambah 1 MiB, karena sebuah transaksi dapat membawa tiga proof (bundle, auth, call), sehingga bawaan 4 MiB ditolak di sana. Agregasi tingkat blok adalah solusi yang telah dijadwalkan; lihat Proof.

Membacanya kembali

rand_getTransaction(hash) mengembalikan null sampai transaksi terkomit, lalu posisi bloknya dan hanya field publiknya:

{
  "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": 1497544, "envelope_len": [1860, 1860, 1860, 1860],
      "auth_commit": "0bab…e8a1", "auth_proof_bytes": 1370827
    },
    "action": { "kind": "none" }
  }
}

Tidak ada bidang from, to, nonce, jumlah, maupun asset dalam sebuah transfer, dan tidak ada pula di blok yang tersimpan: node tidak memiliki apa pun lagi untuk disamarkan. auth_commit dan auth_proof_bytes (panjang bukti autentikasi) ada sejak chain 17. Bundel selalu memiliki empat slot, termasuk slot dummy, dan transfer RAND maupun transfer token RPL apa pun sama-sama bernilai "kind": "none". Setiap jumlah u64 berupa string desimal sejak chain 14 (fee, burn_a, burn_r, serta amount milik sebuah aksi); indeks, nonce, tinggi blok, dan panjang tetap berupa angka JSON. Jenis aksi lainnya menampilkan bidang publiknya — mint, deploy, call, bond, unbond, withdraw, bridge_attest, bridge_burn, register_token, token_mint, set_authority, token_burn, pause_mints, unpause_mints, register_bridged_token, list_backing, rotate_pq_guardians, rotate_pause_key, keempat jenis vesting claim_vested, revoke_vesting, bond_vested, unbond_vested, dan sejak v0.6.8 admit_validator, slash_equivocation, rotate_pq_guardians_v2, rotate_pause_key_v2, cancel_rotation, dan invoke — sebagaimana tercantum dalam referensi JSON-RPC.

Terakhir diverifikasi terhadap commit fullnode c0878c3f (chain 21) pada 2026-10-12. Jika kode dan halaman ini tidak sesuai, kodelah yang benar; beri tahu kami.