Rand Protocol
Dokumentasi
Konsep teras

Mempool

Apa yang dilakukan oleh sesebuah nod terhadap transaksi antara saat menerimanya dengan saat memasukkannya ke dalam blok - susunan kemasukan, penjejakan konflik sebagai ganti nonce, empat pekerja pengesahan, meter rakan sebaya dan cache keputusan, cara seorang pencadang memilih blok, dan sebab pembelanjaan berganda yang kalah hilang dengan sendirinya.

Gunakan halaman ini untuk memahami apa yang berlaku pada sesuatu transaksi selepas rand_sendTransaction menerimanya dan sebelum sesuatu blok membawanya: mengapa ia ditolak jika ia ditolak, mengapa ia boleh hilang daripada kolam tanpa pernah gagal, apakah susunan pengisian sesuatu blok, dan apa yang boleh dan tidak boleh dilakukan oleh banjir bukti yang buruk terhadap seorang validator. Mempool ialah crates/randprotocol-node/src/mempool.rs; pengawal di hadapannya ialah admission.rs.

Tiada penghantar, jadi tiada nonce

Pada rantaian akaun, mempool menyusun transaksi setiap penghantar mengikut nonce. Rantaian terlindung (shielded) tidak mempunyai penghantar: sesuatu bundle tidak membawa alamat dan tiada tandatangan, dan dua bundle hanya berkaitan apabila kedua-duanya menyentuh nota yang sama. Maka tiada lagi susunan bagi setiap penghantar untuk dilakukan. Yang menggantikan pengurusan nonce ialah penjejakan konflik: kolam mengindeks setiap nullifier dan commitment bagi setiap transaksi yang belum selesai, dan menolak pendatang baru yang menuntut mana-mana daripadanya. Perkara yang sama berlaku bagi beberapa pembilang yang lejar terima untuk satu transaksi sahaja bagi setiap nilai: nonce daftar seorang validator (Unbond atau Withdraw), mint_nonce bagi sesuatu token (dikongsi oleh TokenMint dan SetAuthority), indeks pendaftaran yang dipegang oleh RegisterToken, serta pause_nonce dan list_nonce bagi jambatan. Setiap satu ialah slot yang boleh dipegang oleh paling banyak satu transaksi dalam kolam. Paling banyak satu daripada dua transaksi sedemikian boleh dimasukkan, dan membawa yang satu lagi akan membebankan pencadang (proposer) dengan ruang blok dan setiap nod dengan satu pengesahan bukti bagi setiap pusingan gosip.

Kolam menyimpan paling banyak 10,000 transaksi (Mempool::new(10_000) dalam node.rs) dan, sejak v0.6.8, paling banyak bait bernilai lapan blok: MAX_POOL_BLOCKS = 8 kali max_block_bytes rantaian, iaitu 160 MiB pada chain 20 (audit v6, CH-7). Sebelum itu hanya bilangan yang dihadkan, sedangkan satu transaksi yang membawa bukti bersaiz dari kira-kira 1.3 MB hingga lebih 12 MB. Setiap satu disahkan terhadap lejar pada hujung pokok konsensus, bukan blok terakhir yang dimuktamadkan: keadaan yang sebenarnya akan dijadikan asas oleh seorang pencadang.

Kemasukan, yang murah dahulu sebelum yang mahal

Sesuatu transaksi yang tiba melalui RPC atau gosip melalui langkah-langkah ini mengikut tertib, dan penolakan pertama ialah ralat yang anda lihat:

  1. Pendua. Hash sudah ada dalam kolam: already in mempool.
  2. Konflik. Nullifier, commitment atau salah satu slot nonce dan indeks di atas sudah dituntut oleh transaksi yang belum selesai: conflicts with a pending transaction over <hex>. Bagi slot token, hex ialah kunci paparan: satu perkataan teg (tokn untuk mint_nonce, tidx untuk indeks pendaftaran), kemudian indeks dan nonce. Sesuatu pengesahan jambatan (bridge attestation) yang dipertandingkan oleh dua relayer dibezakan melalui digestnya: conflicts with a pending transaction over bridge attestation <hash>.
  3. Penuh. mempool full. Semakan kapasiti ialah yang terakhir daripada ketiga-tiganya. Pada had bait, pendatang baru boleh mengambil tempat entri dalam kolam yang berkedudukan benar-benar di bawahnya — mengikut yuran melebihi lantai semasa setiap entri bagi setiap KiB, kemudian mengikut yuran — dengan menyingkirkan yang paling murah dahulu sehingga ia muat; jika itu tidak mencukupi, atau ia hanya sama taraf, maka ialah ia yang ditolak. Tindakan tadbir urus berada di luar kedua-dua had dan tidak sekali-kali disingkirkan: empat tindakan tadbir urus jambatan PauseMints, UnpauseMints, RegisterBridgedToken, ListBacking, dan sejak v0.6.8 RotatePqGuardians, RotatePauseKey, bentuk …V2 mereka, CancelRotation, AdmitValidator dan SlashEquivocation. Bait dan entri mereka tetap dikira dalam had tersebut. PauseMints ialah brek bagi kompromi kunci penjaga (guardian): tanpa bundle, tanpa yuran, dan satu-satunya transaksi yang mesti sampai ke dalam blok semasa seorang penyerang sedang mencetak, maka kolam yang penuh tidak boleh menghalangnya. Pengecualian ini dibatasi oleh langkah konflik: pause_nonce dan list_nonce masing-masing menerima satu transaksi dalam kolam pada satu masa, maka empat tindakan jambatan itu boleh menambah paling banyak dua entri melebihi had; yang lain masing-masing membelanjakan nonce atau kuorum tersendiri.
  4. Separuh murah daripada Ledger::validate. Segala yang boleh menjadi lapuk antara kemasukan dan penyertaan dan tidak memerlukan bukti: sauh (anchor) ialah salah satu daripada 1,024 akar terakhir pada chain 20 (proof_window_blocks genesis; 256 tanpanya), time berada dalam tetingkap, nullifier belum dibelanjakan, commitment tiada, digest sesuatu pengesahan belum dituntut, nonce daftar sesuatu tindakan staking masih semasa, mint_nonce atau indeks pendaftaran sesuatu tindakan token ialah yang sedang dicapai oleh pendaftar (wrong mint nonce, wrong token index setelah rantaian melepasinya), nonce sesuatu jeda atau penyenaraian ialah nonce semasa jambatan. Commitment yang dicipta oleh sesuatu transaksi turut dikira di sini, termasuk nota yang diterbitkan oleh lejar sendiri bagi Withdraw, BridgeAttest atau bayaran aggregator, yang tidak berada pada wayar tetapi tidak boleh berlanggar juga. Had saiz disemak sebelum apa-apa dinyahkod: bukti melebihi max_proof_bytes rantaian (2 MiB secara lalai, 4 MiB pada chain 20), pengesahan melebihi 16 KiB, atau transaksi yang lebih besar daripada sebuah blok (max_block_bytes: 4 MiB secara lalai, 20 MiB pada chain 20) ditolak serta-merta, maka blob yang terlalu besar tidak membeli sebarang kerja. Bukti bundle dalam bentuk penanda termeterai (dipangkas) ditolak pada langkah yang sama di luar penyegerakan bentuk termeterai, sebagai PrunedFormOutsideSync. Kemudian, masih tanpa mengesahkan apa-apa, kolam membaca pengepala bukti. Tiga dasar didahulukan: panggilan yang jadual input, keccak atau sha256 kurang daripada 2^7 baris tidak dimasukkan ke dalam kolam (CallRevealsPrivateInputs), begitu juga penerapan (deploy) yang tiada panggilan boleh memegangnya (ProgramUncallable), dan transaksi yang bukti bundle atau panggilannya mempunyai medan pengepala yang tidak akan ditulis oleh prover yang jujur (NonCanonicalProof). Dua yang terakhir juga merupakan peraturan lejar pada chain 20, di bawah hardening_v6. Sejak v0.6.8, pengepala yang darjah diisytiharkannya melepasi siling jadual tertinggi ditolak sebagai NonCanonicalProof sebelum semakan menelusurinya (audit v6, ZKV-4), dan panik di mana-mana dalam saringan awal ini ialah penolakan transaksi itu (VerifierPanicked), bukan nod yang mati. Kemudian lantai yuran: pada chain 20 kolam menyahkod had gas yang diisytiharkan oleh bukti panggilan atau invoke dan menolak yuran di bawah BUNDLE_BASE + gas_price × limit + byte_price × ⌈bytes/1024⌉ pada harga hujung pokok, ditambah yuran sel bagi sesuatu invoke, sebagai FeeTooLow (Fees). Itulah peraturan blok sendiri, maka kolam menuntut tepat apa yang dituntut oleh sesuatu blok.
  5. Separuh mahal, di luar gelung konsensus. Transaksi dimasukkan ke dalam baris gilir, paling dalam 64, untuk salah satu daripada empat pekerja pengesahan. Seorang pekerja menjalankan baki Ledger::validate pada tugas yang menyekat: digest bundle, had gas yang diisytiharkan oleh bukti bundle (pada chain 20 tepat 20,479, jika tidak BundleGasLimit), bukti bundle dan, sejak chain 17, bukti kebenarannya terhadap pengikatan (binding) transaksi, dan bagi panggilan, buktinya sendiri dan lantai yuran. Ia mengesahkan terhadap petikan hujung pokok yang diklon secara malas, paling banyak sekali bagi setiap perubahan hujung pokok dan hanya apabila ada sesuatu yang menunggu. Transaksi yang digosipkan yang mendapati baris gilir penuh digugurkan, tidak disahkan dan tidak dimajukan, dan tidak menyekat gelung yang mengundi; pusingan gosip rakan sebaya (peer) yang seterusnya membawanya semula.
  6. Semak semula dan masukkan ke dalam kolam. insert_verified menjalankan langkah 4 sekali lagi terhadap hujung pokok yang sebenarnya menjadi tempat transaksi dimasukkan ke dalam kolam, kerana hujung pokok mungkin telah bergerak semasa bukti disahkan, kemudian menerimanya dan, bagi trafik yang digosipkan, memajukannya.

Langkah 1 hingga 4 ialah Mempool::precheck; langkah 5 ialah satu-satunya yang mengesahkan STARK. Oleh sebab kos itu dibayar pada seorang pekerja, banjir bukti yang buruk menduduki empat thread dan tidak pernah gelung konsensus. Transactions and actions menyenaraikan tertib kemasukan lejar sendiri, yang dijalankan oleh langkah 4 dan 5 bersama-sama.

Dua pengawal dan satu cache untuk gosip

Di hadapan kemasukan, dua perkara hanya terpakai pada transaksi yang tiba daripada rakan sebaya; penyerahan RPC melangkauinya, kerana port itu milik operator sendiri dan sudah dibatasi oleh had badan permintaan. Satu-satunya laluan RPC yang diukur ialah faucet, di bawah.

  • Meter bait per rakan sebaya. Sejak v0.6.8, setiap bingkai gossip dikenakan caj pada belanjawan bait penghantarnya sebelum ia sempat dinyahkod, dengan letusan lapan bingkai dan pengisian semula dua bingkai bersaiz penghantaran maksimum sesaat. Selepas had itu, bingkai digugurkan tanpa dinyahkod (audit v6, GOSSIP-1). ID transaksi, yang meng-hash keseluruhan bukti, hanya dikira dalam had yang dibenarkan kepada penghantar.
  • Meter transaksi per rakan sebaya. Satu token bucket bagi setiap rakan sebaya yang menghantar, letusan 16, diisi semula pada kadar 4 sesaat (PEER_TX_BURST, PEER_TX_PER_SEC). Ia mengawal rakan sebaya yang menghantar transaksi itu, bukan pengarangnya, yang tidak dapat dinamakan oleh rantaian terlindung.
  • Cache keputusan. Transaksi yang telah ditolak oleh nod ini atas sebab yang bergantung pada bait transaksi itu sahaja, seperti bukti yang tidak sah, tandatangan yang tidak sah atau bahagian yang terlalu besar, ditolak semula daripada cache FIFO 8,192 entri (REFUSED_CACHE_ENTRIES) tanpa disahkan kali kedua. Keputusan yang menyatakan sesuatu tentang keadaan nod ini, iaitu anchor yang tidak diketahui atau nullifier yang telah dibelanjakan, tidak pernah dicache: nod yang ketinggalan satu blok akan merosakkan dirinya sendiri terhadap transaksi yang tidak lama lagi menjadi sah. Senarai ini ialah senarai kebenaran, maka ralat baharu dianggap keadaan sehingga ada yang memutuskan sebaliknya. Entri-entri ini menunjukkan di mana garisnya:
    • BadPauseSignature (the pause signature does not verify) bukan kekal sejak v0.6.8 (audit v6, BRG-18). Ia menyemak tandatangan di bawah kunci jeda semasa rantaian, yang boleh diputar oleh bridge rules v2, jadi ia ialah keadaan: nod yang ketinggalan satu blok daripada satu pemutaran akan menolak PauseMints pemegang baharu sehingga dimulakan semula. Indeks tandatangan bersama PQ di luar julat meninggalkan cache atas sebab yang sama. Sehingga v0.6.7, pada rantaian 18 dan 19, kedua-duanya dicache sebagai kekal. Jeda tidak sah yang berulang kini menelan satu pengesahan Dilithium2 bagi setiap penghantaran, dihadkan oleh meter per rakan sebaya.
    • PrunedFormOutsideSync sengaja tidak dijadikan kekal. Bentuk penanda bagi satu bundle yang termeterai di-hash kepada id transaksi mentah itu sendiri, dan cache menggunakan id tersebut sebagai kunci, jadi mencache penolakan itu akan membolehkan mana-mana rakan sebaya gossip menapis transaksi yang jujur di seluruh rangkaian.
    • Had gas yang diisytiharkan oleh sesuatu bukti ialah baitnya sendiri berbanding pemalar genesis, maka BundleGasLimit dan AuthGasLimit adalah kekal. FeeTooLow bukan: pada rantaian 20 lantai bergerak bersama harga. Tiga dasar header pada langkah 4 juga tidak pernah dicache: setiap satunya ialah pengetahuan binaan ini, yang boleh diubah oleh binaan kemudian.
    • Pada rantaian yang mempunyai senarai kebenaran faucet (rantaian 20), FaucetRecipientNotAllowed adalah kekal: ia membandingkan penerima mint itu sendiri dengan pemalar genesis. FaucetBudgetExhausted bukan: ia ialah keadaan, dan mint yang sama diterima semula dalam epoch seterusnya.
    • BadSignature bagi tindakan token juga bukan kekal, tidak seperti tindakan staking: pihak berkuasa mint sesuatu token ialah keadaan, SetAuthority boleh menyerahkannya kepada kunci lain, dan bait yang sama boleh ditolak sebelum pemutaran itu dikomit dan diterima selepasnya. Penolakan token peringkat bait (nama atau simbol yang tidak sah, terlalu banyak perpuluhan, jumlah sifar, indeks token 0) dicache; begitu juga medan burn yang tidak boleh ditetapkan oleh tindakan itu, mint yang komitmennya tidak terbuka kepada jumlahnya, dan deposit bridge yang blinding-nya bukan yang diterbitkan.

Had faucet

rand_mint tidak mengenakan yuran dan memakan satu transaksi terkumpul bagi setiap panggilan, dan pada rantaian 20 faucet dihidupkan dengan bridge yang memegang nilai di belakangnya. Genesis menghadkan apa yang boleh dilakukannya: satu mint hanya membayar 16 dompet yang disenaraikan dan paling banyak 10,000 RAND bagi setiap epoch 1,000 blok (Staking), dan hanya satu daripada 18 kunci dalam senarai staking.faucet_minters genesis boleh menandatanganinya (MinterNotAllowed, tidak pernah dicache: peraturan lejar sejak rantaian 16, dasar nod pada rantaian 15, yang senarainya ialah validator genesis). Selain itu, setiap nod mengawal faucetnya sendiri: lapan mint berturut-turut, diisi semula pada kadar satu sesaat (FAUCET_MINT_BURST, FAUCET_MINT_PER_SEC). Selepas itu panggilan dijawab dengan faucet is rate limited on this node (8 mints back to back, refilling at 1/s); try again shortly. Had ini dikenakan bagi setiap proses nod, bukan setiap pemanggil, kerana port RPC tidak mempunyai identiti rakan sebaya untuk dikawal dan sumber yang dilindungi ialah pool nod ini. Bersama pengecualian kapasiti di atas, banjir faucet tidak dapat memenuhi pool sebelum PauseMints.

Gossipsub berjalan dengan pengesahan peringkat aplikasi, jadi sesuatu transaksi hanya dimajukan kepada rakan sebaya lain setelah ia disahkan di sini. Rakan sebaya yang membanjiri transaksi tidak sah akan dihadkan oleh meter, dijawab daripada cache, dan tidak membebankan gelung konsensus sama sekali.

Membina blok

Apabila seorang validator mengetuai sesuatu view, ia meminta calon daripada pool. candidates_within hanya mengekalkan transaksi yang masih terpakai pada lejar yang sedang dibina, dengan menjalankan semula separuh murah daripada kemasukan: anchor masih dalam tetingkap, time masih di dalamnya, nullifier belum dibelanjakan, komitmen belum wujud. Ia juga menggugurkan tindakan token yang mint_nonce atau indeks pendaftarannya telah dilepasi oleh rantaian, serta jeda atau penyenaraian pada nonce yang lapuk. Sejak v0.6.8, ia menetapkan semula harga setiap call dan invoke mengikut harga yang berkuat kuasa pada hujung rantaian yang dibinanya, daripada had gas yang diingati semasa kemasukan, dan mengecualikan yang yurannya kini di bawah lantainya; ia kekal dalam pool, dan ditawarkan semula apabila harga turun (audit v6, CH-9). Pada rantaian 20 ia kemudian menyusun selebihnya tadbir urus dahulu, kemudian mengikut yuran melebihi lantai semasa, bagi setiap KiB transaksi, kemudian mengikut yuran, tertinggi dahulu, dengan persamaan dipecahkan menggunakan hash, supaya setiap pencadang yang jujur yang membina di atas pool yang sama memilih blok yang sama, dan mengisi sehingga bajet 2,000 transaksi dan had blok rantaian (MAX_BLOCK_TXS; max_block_bytes, 4 MiB secara lalai dan 20 MiB pada rantaian 20). Bait ialah apa yang kekurangan dalam sesebuah blok, itulah sebabnya lebihan diambil bagi setiap KiB. Rantaian tanpa bahagian gas dan nod tanpa dasar gas melangkau kunci itu dan menyusun mengikut tadbir urus, yuran dan hash, seperti rantaian 15. Tadbir urus dahulu ialah separuh lagi jaminan jeda: PauseMints tidak membayar yuran mengikut reka bentuk, kerana ia mesti berfungsi daripada dompet yang tidak memegang RAND, maka susunan yuran biasa akan meletakkan brek kecemasan di belakang setiap transaksi yang membayar.

Satu lagi peraturan terpakai semasa sesuatu call atau invoke sedia (audit v6, POOL-2; dasar nod pada setiap rantaian, bukan peraturan kesahan). Hanya kedua-duanya membayar harga bait, dan pemindahan yang membayar sedikit melebihi asas ratanya mengatasi kedudukan mereka bagi setiap KiB, jadi aliran pemindahan boleh menghalang call yang sedia daripada masuk ke setiap blok. Maka transaksi yuran rata mengambil paling banyak tiga perempat daripada bait blok dalam laluan pertama; setelah call ditempatkan, ruang yang tinggal diisi dengan pemindahan yang ditahan, mengikut susunannya. Tiada ruang blok yang hilang, dan jika tiada call yang sedia, tiada apa yang berubah (Fees).

Transaksi yang terlalu besar untuk ruang yang tinggal dilangkau, bukan penghujung blok: transaksi yang lebih kecil di belakangnya masih dibawa. Satu pemindahan rantaian 18 adalah lebih kurang 2.85 MB, iaitu bukti bundle 1.49 MB dan bukti kebenaran 1.36 MB, jadi blok 20 MiBnya memuatkan kira-kira tujuh dan blok lalai 4 MiB memuatkan satu. Pada rantaian 15, pada kira-kira 1.43 MB bagi setiap pemindahan, 20 MiB yang sama memuatkan empat belas. Di bawah beban, yuranlah yang menentukan yang mana (Fees).

Pemangkasan

Selepas setiap commit, prune menggugurkan daripada pool tepat apa yang akan dilangkau oleh candidates_within: transaksi yang notanya telah dibelanjakan oleh orang lain, yang komitmennya kini wujud, yang nonce atau indeks pendaftarannya telah dilepasi oleh rantaian, atau yang anchor atau time-nya telah keluar daripada tetingkap (1,024 blok pada rantaian 20, 256 sehingga rantaian 19). Bundle yang kalah dalam perlumbaan double-spend dengan itu hilang dengan sendirinya, tanpa pernah menghasilkan ralat kepada sesiapa. Penerimaan oleh rand_sendTransaction bukan komitmen: buat poll rand_getTransaction sehingga ia mengembalikan blok, dan jika tetingkap anchor berlalu tanpa satu pun, bina semula bundle pada anchor yang baharu dan hantar semula.

Memantaunya

rand_status melaporkan mempool_size, verify_queue (transaksi yang menunggu pekerja) dan refused_cache (entri dalam cache keputusan). verify_queue yang kekal pada 64 bermakna bukti tiba lebih pantas daripada pengesahan oleh empat pekerja, kira-kira 16 ms setiap satu dengan kunci yang sudah dipanaskan; mempool_size yang terus membesar sementara blok kekal penuh bermakna yuran, bukan susunan ketibaan, yang menentukan kemasukan.

Apa yang belum ada

  • Tiada penggantian. Harga gas dan harga bait Chain 20 menggerakkan lantai (floor) sesuatu panggilan pada setiap blok, sehingga had maksimumnya; lantai bagi sesuatu pemindahan adalah tetap. Tiada penggantian transaksi dalam kolam oleh transaksi berbayaran lebih tinggi ke atas nota yang sama, kerana peraturan konflik menolaknya. Panggilan yang harganya terlalu tinggi bagi bayarannya menunggu dalam kolam, tanpa ditawarkan, sehingga harga turun atau tetingkap anchornya luput. Pada v0.6.7 (chain 18 dan 19), panggilan dalam kolam mengekalkan lantai yang berkuat kuasa semasa ia diterima masuk, masih ditawarkan selepas kenaikan harga, dan gagal dalam penerapan percubaan oleh proposer sebagai FeeTooLow. Dokumen ruang blok fullnode menyenaraikan mempool tersusun mengikut yuran sebagai langkah sebelum blok yang lebih besar, dan pengagregatan peringkat blok sebagai yang menaikkan had maksimum bagi setiap blok.
  • Tiada tamat tempoh mengikut usia. Sesuatu transaksi dalam kolam hanya keluar melalui kemasukan dalam blok, melalui penyingkiran pada had bait, atau melalui tetingkap anchor dan masa: 1,024 blok pada chain 20, kira-kira 23 minit pada 1.34 s setiap blok seperti yang dilaporkan oleh explorer di sana. Sehingga chain 19, tetingkap itu ialah 256 blok, kira-kira lima minit.
  • Tiada RPC mempool. Tiada kaedah yang menyenaraikan transaksi yang belum selesai; mempool_size dalam rand_status serta bilangan, bait dan usia tertua dalam rand_getMempoolInfo ialah satu-satunya paparan, dan explorer hanya mengindeks blok yang telah disahkan.

Disahkan kali terakhir terhadap commit fullnode c0878c3f (rantai 21) pada 2026-10-12, dan fullnode v0.6.8 `c9c9bd3c` (chain 20): `crates/randprotocol-node/src/mempool.rs` (`MAX_POOL_BLOCKS`, `make_room`, `is_governance`, the call reservation in `candidates_within`), the commits for CH-7, CH-9, POOL-2, BRG-18, GOSSIP-1 and ZKV-4, and `rand_getLimits` on chain 20, fullnode v0.6.7 `86941a1`: `crates/randprotocol-node/src/mempool.rs`, `admission.rs`, `crates/randprotocol-core/src/ledger/mod.rs` (the gas floor), fullnode `90e7716`: `docs/architecture.md` §8, `docs/rpc.md` (changelog, the 2026-09-28 gas entries), fullnode `ed88241`: `docs/confidential.md` (transaction binding). Jika kod dan halaman ini tidak selari, kodlah yang betul; sila maklumkan kepada kami.