使用本頁來構建、提交或解碼交易:rand_sendTransaction 所接受的線上格式、id 的計算方式、全部動作及其捆綁包與費用規則,以及決定你最先遇到哪個錯誤的准入次序。
交易
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
// (since chain 21 either the single-key auth guest's proof or the private-multisig one's)
}
Envelope { kem_ct: Vec<u8>, to_receiver: Vec<u8>, to_sender: Vec<u8>, body: Vec<u8> }
Word8 是八個小端序 u32 字,以 64 個小寫十六進位字元表示。線上格式為 bincode(Transaction),採用 bincode 的預設設定(定長整數、8 位元組長度前綴、u32 枚舉標籤),而 rand_sendTransaction 以十六進位接收。交易本身沒有簽名,也沒有發送者欄位:捆綁包由其證明自行授權(捆綁包證明,以及自 chain 17 起附於其旁的授權證明),而需要簽名的動作則把簽名放在動作內部。重放保護方面:捆綁包靠 nullifier 集合,已簽名的質押動作靠登記冊中每個驗證者的 nonce,TokenMint 與 SetAuthority 靠每個代幣的 mint_nonce,橋的治理動作則靠橋的 pause_nonce 與 list_nonce。
一筆交易至多攜帶一個捆綁包,而每個並非無捆綁包的動作恰好攜帶一個。捆綁包的槽位 0–1 承載私密資產,槽位 2–3 承載 RAND,因此一份證明即可轉移代幣並支付其 RAND 費用;早期設計中由兩個捆綁包組成的橋燒毀已不復存在:一次燒毀只用一個捆綁包(票據)。
rand 錢包透過 randprotocol_client::wallet::{send, submit} 完成上述全部工作:選取輸入、取得錨點、以錢包自身持有的樹副本計算見證、構建輸出並封存四個信封、取得交易綁定、證明捆綁包與授權證明、核對捆綁包證明所公布的摘要,然後提交。
交易綁定
交易沒有簽名,而捆綁包的證明只承諾捆綁包自身的摘要:錨點、nullifier、承諾、費用、燒毀欄位、time。直至 chain 13,沒有任何機制把已證明的捆綁包與其所附的動作或信封聯繫起來,因此任何看到交易的人都可以保留全部證明位元組而更改其餘內容:BridgeBurn 的目的地、Bond 的驗證者、某個信封。自 chain 14 起,每個捆綁包證明均基於交易綁定生成,並據此驗證:
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')) since chain 20
as 8 LE u32 words
其中 ' 表示每個捆綁包證明位元組串都被替換為空向量:bundle.proof、自 chain 17 起的 bundle.auth_proof,以及 Aggregate 的 proof。其餘一切都在其內:auth_commit、全部四個信封、每個燒毀欄位、目的地、驗證者、收款方、簽名、守護者證明及其 Dilithium2 聯署簽名,以及 Call 自身的證明。這八個字置於證明的公開輸入段中,而該段的摘要 H_PUB 已由電路綁定,因此這項修正無須更改 guest 或電路;節點執行 Machine::verify_public(hc_bundle, binding, proof),並拒絕聲明了任何其他公開高度的捆綁包證明(public height not the transaction binding's)。Transaction::binding 是錢包在證明前、賬本在驗證前所呼叫的同一個函數。自 chain 17 起,授權證明基於同樣的八個字生成並據此驗證,因此它同樣無法被挪到另一筆交易上。
自 chain 20 起,綁定涵蓋創世雜湊。 直至 chain 19,綁定以及無捆綁包動作的簽名訊息只涵蓋 chain id,因此兩條共用同一 chain id 的鏈(重新切出的鏈、私有副本)會互相接受對方的證明與簽名。chain 20 的創世設定了 binding_domain: 1(v0.6.8,審計 v6 BIND-1;crates/randprotocol-core/src/types/binding.rs)。創世雜湊隨後置於每個原像之首,並使用高一個版本的標籤:兩種綁定分別為 rand-tx-bind-2 與 rand-call-bind-2,水龍頭鑄造(rand-mint-3)、Unbond 與 Withdraw(rand-unbond-2、rand-withdraw-2)、RPL 鑄造與權限訊息(rand-rpl-mint-2、rand-rpl-authority-2)、聚合者動作以及橋的治理訊息亦然。這類鏈上的驗證者登記一律使用 v2 訊息(創世、chain、地址、payout)。無論 chain id 為何,為某一條鏈證明或簽署的內容都無法在另一條鏈上通過驗證。綁定字是公開輸入,因此 guest 與驗證者密鑰均未更改。早於 v0.6.8 的錢包仍按 chain id 形式生成證明,在 chain 20 上會被拒絕。chain 21(fullnode v0.8.0,自 2026-10-12 起上線)沿用同一綁定,基於其自身創世雜湊 ca76c276…ca9a;那裏改變的是底層的證明系統:約束集 9(rVM 第 4 階段與 MODQ 晶片)為每個 guest 提供新的驗證者密鑰與新的證明編碼,因此由早於 v0.8.0 的錢包生成的證明在 chain 21 上根本無法解碼,遑論檢查綁定。rand_getLimits 與 rand_status 會提供 binding_domain(chain 20 與 21 為 1,無此欄位時為 0)。
在創世 hardening_v6 之下(自 chain 16 起的每條鏈,包括 chain 21),Call 自身的證明同樣被綁定,方法是以相同構造、在其自身的域下生成第二個摘要,並把調用證明連同捆綁包的各項證明一併置空:
call_binding(tx) = blake3("rand-call-bind-1" || bincode(chain_id, bundle', action'')) as 8 LE u32 words
自 chain 20 起,標籤為 rand-call-bind-2,創世雜湊置於原像之首,一如上述。Invoke 的證明以同樣方式綁定,其所聲明的狀態轉換保留在原像之中,因此該證明恰好承諾交易所攜帶的狀態變更、支付與收款方。
調用證明把這些字置於其公開輸入段中,位於程式的部署時公開輸入(若有)之後,因此將其複製並附於另一個費用捆綁包時不會通過驗證。兩種綁定相互嵌套:錢包先選定費用捆綁包的票據,並在證明為空的情況下構建交易,再針對調用綁定證明該調用,填入該證明,然後才取得交易綁定並證明捆綁包。
對客戶端的意涵是:須在證明之前構建整筆交易,包括輸出、信封與動作。在分叉前構建的錢包會針對空的公開段生成證明,並會被拒絕。無捆綁包動作沒有可綁定的證明,僅依靠其自身的簽名。綁定並非交易 id,後者維持不變。
交易 id
txid = blake3("rand-txid-3" || bincode(view))
其中 view 是將捆綁包的 proof 位元組替換為 blake3(proof)(proof_hash)、將其 auth_proof 位元組替換為 blake3(auth_proof)(auth_proof_hash,位於原樣計入的 auth_commit 之後)的交易,其餘各欄位一概照原樣。直至 chain 16,域為 rand-txid-2,不含這兩個授權欄位;每個交易 id 均隨 chain 17 而改變。以摘要來雜湊證明,使得已修剪的捆綁包(區塊聚合,chain 21 上未啟用)與其原始形式保持相同的 id;已修剪的捆綁包仍保留其授權證明。無捆綁包的交易則按原樣雜湊其位元組。同一個 id 用作交易池、收據以及每一項 RPC 查詢的鍵。
全部動作
Action 是一個 bincode 枚舉,標籤按宣告次序排列:
| 標籤 | 動作 | 欄位 | 捆綁包 | 費用下限 |
|---|---|---|---|---|
| 0 | None | — | 必需 | BUNDLE_BASE = 0.001 RAND |
| 1 | Mint | cm, pk, time, r, envelope, amount, minter: PublicKey, signature | 不得附帶 | 0(由驗證者簽署;僅限水龍頭鏈,amount ≤ 100 RAND) |
| 2 | Deploy | base_pc: u32, words: Vec<u32>, public: Vec<u32> | 必需 | 基本費 + 每個程式字及公開字 100,000 單位 |
| 3 | Call | program, proof, input_envelope: Option<CallEnvelope> | 必需 | 在按燃料計量的鏈上(chain 21,chain 18 至 20 亦然):基本費 + gas_price × 證明所聲明的 GAS_LIMIT + 每 KiB 證明及輸入信封的 byte_price;在沒有 gas 區段的鏈上:基本費 + call_fee(tier) |
| 4 | Bond | validator, amount, registration: Option<Registration> | 必需,且 burn_r == amount | 基本費 |
| 5 | Unbond | validator, amount, nonce, signature | 不得附帶 | 0 |
| 6 | Withdraw | validator, amount, nonce, time, r, envelope, signature | 不得附帶 | 傳輸層面為 0;基本費自 amount 中扣除 |
| 7 | BridgeAttest | attestation, recipient: ShieldedAddress, r, time, asset, envelope, pq_signatures: Vec<PqSignature> | 必需 | 基本費 |
| 8 | BridgeBurn | asset, amount, relayer_fee, to_chain: u16, token: [u8; 32], to: [u8; 32] | 必需,且 burn_asset == asset 及 burn_a == amount | BRIDGE_BURN_FEE = 0.01 RAND |
| 9 | RegisterAggregator | registration | 必需,burn_r 即質押額 | 基本費 |
| 10 | UnbondAggregator | aggregator, nonce, signature | 不得附帶 | 0 |
| 11 | WithdrawAggregator | aggregator, nonce, time, r, envelope, signature | 不得附帶 | 0 |
| 12 | SlashAggregator | 兩個已簽署的聚合區塊頭 | 不得附帶 | 0 |
| 13 | Aggregate | covers, proof, aggregator, nonce, time, r, envelope, signature,並自 v0.8.0 起另有 payout_total 及 layout(Flat 或 Tree),故其編碼及 txid 已改變;尚無任何鏈承載過此類交易 | 不得附帶 | 0 |
| 14 | RegisterToken | name, symbol, decimals: u8, authority: MintAuthority, initial: Option<InitialMint>, salt: [u8; 32], index: u32 | 必需 | 基本費 + 登記表的 registration_fee(chain 21 為 1 RAND,與 chain 20 相同,予以銷毀) |
| 15 | TokenMint | asset, amount, recipient: ShieldedAddress, r, time, envelope, nonce, signature | 必需 | 基本費 |
| 16 | SetAuthority | asset, new: Option<PublicKey>, nonce, signature | 必需 | 基本費 |
| 17 | TokenBurn | asset, amount | 必需,且 burn_asset == asset 及 burn_a == amount | 基本費 |
| 18 | PauseMints | nonce, signature | 不得附帶 | 0 |
| 19 | UnpauseMints | nonce, pq_signatures | 不得附帶 | 0 |
| 20 | RegisterBridgedToken | name, symbol, salt, chain: u16, token: [u8; 32], decimals: u8, nonce, pq_signatures | 必需 | 基本費 + registration_fee |
| 21 | ListBacking | token_index, chain: u16, token: [u8; 32], decimals: u8, nonce, pq_signatures | 必需 | 基本費 |
| 22 | RotatePqGuardians | new_pq_guardians: Vec<PublicKey>, nonce, pq_signatures | 不得附帶 | 0 |
| 23 | RotatePauseKey | new_pause_key: PublicKey, nonce, pq_signatures | 不得附帶 | 0 |
| 24 | ClaimVested | entry: [u8; 32], amount, nonce, to: ShieldedAddress, time, r, envelope, signature | 不得附帶 | 傳輸層面為 0;基本費自 amount 中扣除 |
| 25 | RevokeVesting | entry: [u8; 32], unvested, nonce, to: ShieldedAddress, time, r, envelope, signatures(自 v0.6.8 起由該條目撤銷者的一個門檻數簽署,款項付予其創世條目所指定的庫房;此前為單一 signature) | 不得附帶 | 傳輸層面為 0;基本費自 unvested 中扣除 |
| 26 | BondVested | entry: [u8; 32], validator, amount, registration: Option<Registration>, nonce, signature | 不得附帶 | 0 |
| 27 | UnbondVested | entry: [u8; 32], amount, nonce, signature | 不得附帶 | 0 |
| 28 | AdmitValidator | candidate: PublicKey, signatures: Vec<(PublicKey, Signature)> | 不得附帶 | 0 |
| 29 | SlashEquivocation | first, second:同一領導者於同一視圖簽署的兩個區塊頭 | 不得附帶 | 0 |
| 30 | RotatePqGuardiansV2 | new_pq_guardians: Vec<PublicKey>, possession: Vec<Vec<u8>>, nonce, pq_signatures | 不得附帶 | 0 |
| 31 | RotatePauseKeyV2 | new_pause_key: PublicKey, possession: Vec<u8>, nonce, pq_signatures | 不得附帶 | 0 |
| 32 | CancelRotation | kind: u8, nonce, signature | 不得附帶 | 0 |
| 33 | Invoke | program, proof, input_envelope: Option<CallEnvelope>, transition: Transition | 必需;burn_r 及 burn_asset 的 burn_a 即進入程式的數額 | 一次調用的下限 + 每個新建單元的 cell_fee |
| 34–39 | 六個 RPL-3 永續合約動作(v0.8.0):PerpDeposit、PerpOrder、PerpCancel、PerpWithdraw、PerpOracle、PerpStateProof(tx_json 類型為 perp_deposit … perp_state_proof) | 存款的捆綁包銷毀額為交易賬戶注入資金;下單、撤單、提款及預言機更新均須簽署,不附捆綁包,亦不收費;狀態證明是引擎對一段區塊窗口的 STARK,無須簽署,故任何人均可提交證明 | 存款:必需,附抵押資產的 burn_a;其餘:不得附帶 | 存款為基本費;其餘為 0 |
| 40–43 | 四個多重簽署賬戶動作(v0.8.0):CreateMultisig、MultisigDeposit、MultisigPay、MultisigRotate(tx_json 類型為 create_multisig、multisig_deposit、multisig_pay、multisig_rotate) | 創建須指明 salt、門檻及簽署者;存款須指明賬戶;付款須指明賬戶、其 nonce、至多 max_payouts 個票據,以及已簽署者的索引;輪換須指明新集合、新門檻及已簽署者的索引 | 創建及存款:必需,burn_r 即注入的數額;付款及輪換:不得附帶 | 創建:基本費 + 創世配置的 create_fee(chain 21 為 1 RAND);存款:基本費;付款自賬戶的 RAND 行支付 0.001 RAND 基本費;輪換為 0 |
| 44 | SetRandPrice(v0.8.0) | price_micros_per_rand, nonce, votes — 驗證者集合對 RAND/USD 價格的投票,採用 AdmitValidator 的法定人數,每次更新最多變動兩倍 | 不得附帶 | 0 |
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
在 chain 21(fullnode v0.8.0,自 2026-10-12 起運行)上,標籤 0 至 8、14 至 21、28、30 至 33 及 34 至 43 可用。其創世配置具備 chain 20 的全部內容 — 帶 rules_v2 的 bridge 區段、tokens 區段、staking.admission_by_vote(標籤 28)、bridge.rotation(標籤 30 至 32)及 program_state(標籤 33)— 並新增三個隨 v0.8.0 引入的區段:perps(標籤 34 至 39:一個市場,即以 zUSD 計價的 BTC-PERP;見代幣)、multisig(標籤 40 至 43:M-of-N 的 Dilithium2 賬戶,餘額公開,並預置基金會庫房,即 2-of-3 簽署者名下的 100,000 RAND,id 為 d5fd1883…1958,create_fee 為 1 RAND,每筆付款至多 10 個簽署者及 4 筆支付)以及 fees(本身沒有對應動作:它銷毀每個捆綁包的費用下限,見費用)。標籤 44 存在於構建之中,但在 chain 21 上被拒絕(UnsupportedAction):它需要 fees.usd_subsidy,該設定以美元為聚合的補貼定價,而 chain 21 既無此設定,亦無聚合;rand_getRandPrice 在該鏈上回傳 null。標籤 22 及 23 與 chain 20 一樣被拒絕:在 bridge.rotation.needs_possession 下,輪換必須採用 …V2 形式,附帶每個新密鑰各自的簽署。在 chain 20 上,標籤 0 至 8、14 至 21、28 及 30 至 33 可用;在不具備上述任何區段的 chain 19 上,標籤 0 至 8 及 14 至 23 可用(chain 14 沒有 rules_v2,拒絕 22 及 23)。SlashEquivocation 需要 staking.slashing 區段,而 chain 21 的該區段為 null。五個聚合動作需要 aggregation 區段,chain 21 並無此區段(在重新測量聚合之前,構建版本會拒絕在載有該區段的創世配置上啟動)。節點會在所有其他檢查之前於准入關卡拒絕上述全部動作,但它們仍佔用各自的 bincode 標籤,因此硬編碼標籤編號的編碼器必須將其計算在內。聚合在證明中記載為即將推出。四個創世歸屬動作(標籤 24 至 27,自 v0.5.11 起已在構建中)需要 vesting 區段,包括 chain 21 在內,迄今沒有任何鏈具備該區段,故在沒有該區段時於准入階段即被拒絕。標籤 28 至 33 為 v0.6.8 新增,標籤 34 至 44 為 v0.8.0 新增,每批均附加於末尾,因此此前各鏈的歷史仍可解碼。
第二個驗證 guest(chain 21)。 Chain 21 的創世區塊同時固定了 hc_auth_multisig,即 9705f8e2f1bc8561848b29cb8efd57c37e3e39788fa58a5f03304d8019668247:這是一個 tier-18 guest,用以證明某個 M-of-N Dilithium2 政策已獲滿足,而無須點明該政策或簽署者。由它授權的 bundle 在鏈上傳輸時屬於普通的 v3 bundle——欄位相同、txid 相同、綁定方式相同——唯一不同的是其 auth_proof 所聲明的形態(即其標頭中的表高度)。准入時會按兩種固定形態之一解碼 auth proof,單一密鑰形態以 hc_auth 驗證,多重簽名形態以 hc_auth_multisig 驗證,其餘一律以 InvalidAuthProof 拒絕。鏈上只會得知「已獲多重簽名授權」;在沒有該欄位的鏈上,多重簽名形態的證明會被永久拒絕。錢包端的指令是 rand multisig-private(命令行);證明在本機以 tier 18 生成,需要約 96 GB 的機器。截至 chain 21 切換時,尚未有私密多重簽名的支出在 chain 21 上完成證明。
四項 RPL 操作(標籤 14 至 17)分別為登記代幣、增發由 Key 授權的代幣、移交或放棄其鑄造權限,以及銷毀持倉;若 RegisterToken 指明 Bridge 或 Program 授權,則會被拒絕。沒有代幣轉帳操作:代幣轉帳即 None,與 RAND 付款無從區分。參閱 RPL tokens。四項橋接治理操作(標籤 18 至 21)分別為暫停鑄造、解除暫停,以及在創世之後上架橋接代幣或新增後備資產。PauseMints 由創世暫停密鑰簽署,該密鑰只能暫停;其餘三項需要 Dilithium2(PQ)守護者的法定人數。BridgeAttest 除附有其 ECDSA 法定人數外,亦附有此類法定人數。標籤 22 與 23 屬於橋接 rules_v2,用於更換 PQ 守護者集合或暫停密鑰,各自須經當前集合的 PQ 法定人數及該橋接的 rotation_nonce 授權。標籤 30 與 31 在 bridge.rotation 下執行同樣的更換,並附上每個新密鑰自身對輪換訊息的 Dilithium2 簽名,以證明該密鑰確實由持有人掌握;自 chain 20 起,輪換會先記錄為待處理,並在 delay_secs(86,400 秒)後生效。CancelRotation(標籤 32)由當前暫停密鑰簽署,可在待處理輪換生效前將其撤銷。參閱 Bridge。
AdmitValidator(標籤 28)是驗證者集合就接納新密鑰所作的投票:須附上持有超過三分之二權益的驗證者的簽名,並按地址升序排列。在 staking.admission_by_vote(chain 20 與 21)之下,若某項 Bond 會登記新的驗證者,除非其地址已透過此方式獲接納,否則會被拒絕(Staking)。Invoke(標籤 33,RPL-2)是一次調用,其證明擔保程式的某一項已聲明狀態 transition:所讀取與寫入的 cell、bundle 的銷毀欄位帶入程式金庫的數額,以及金庫支付出去或程式鑄造的 note。若每項已聲明的讀取仍然成立且兩個證明均通過驗證,賬本即應用該轉換(Programs)。
Deploy 與 Call 均為普通的 shielded 交易,其 bundle 是一筆零額的自我轉帳:目的在於以調用者自己的 note 支付最低費用,使鏈上無從得知這些 note 屬於誰。RAND 只會經由 burn_r 離開資金池——Bond 的權益、RegisterAggregator 的保證金、Invoke 存入程式金庫的款項——而代幣只會經由 burn_a 離開,並以 burn_asset 指明該代幣,見於 TokenBurn、BridgeBurn 或 Invoke。其餘操作一概不銷毀任何資產;burn_asset = 0 而 burn_a 不為零的 bundle,在任何地方都會被拒絕。
准入次序
Ledger::validate_inner 先檢查成本低的項目,再檢查成本高的項目,次序如下;mempool 在廣播前會執行同樣的檢查,因此一筆有問題的交易只會在邊緣被拒絕一次。
- 大小上限——整筆交易 ≤ 鏈的
max_block_bytes;捆綁包的四個信封,以及該操作所帶的任何票據信封,均須剛好等於創世區塊的envelope_bytes(鏈 20 和 21 為 1,860;沒有該欄位的鏈則至多 2,048 位元組);捆綁包證明、授權證明和每個呼叫證明各 ≤max_proof_bytes(預設為 2 MiB;鏈 21 的創世區塊為 6 MiB,以容納第 18 層級的多重簽名授權證明;鏈 18 至 20 為 4 MiB;鏈 13 至 16 為 8 MiB),而在設有hc_auth_multisig的創世區塊上,請求主體可載有三個達到該上限的證明;程式 ≤ 鏈的程式上限(預設為 4,096 個字,鏈 21 的創世區塊為 65,535,與鏈 20 相同);呼叫信封 ≤max_call_envelope_bytes(預設為 18,432 位元組,鏈 20 和 21 為 65,536);證明聲明(attestation)≤ 16 KiB。密封(已修剪)標記形式的捆綁包證明,在密封形式同步之外一律在此被拒絕(PrunedFormOutsideSync),且在任何證明工作之前。 - 鏈 id 相符。
- 形狀與費用下限——無捆綁包的操作不帶捆綁包,其餘一切操作須剛好帶一個;
check_burn_shape規定該操作可設定三個銷毀欄位中的哪一個:TokenBurn或BridgeBurn通過burn_asset和burn_a銷毀其自身的asset和amount,Bond或RegisterAggregator通過burn_r銷毀其數額,其他所有操作均不銷毀任何東西;fee ≥ fee_floor(action)。在設有gas區段的鏈上(鏈 21,與鏈 18 至 20 相同),Call或Invoke在此步驟的下限,是宣告上限為 1 時的 gas 規則,即BUNDLE_BASE + gas_price + byte_price × ⌈bytes / 1024⌉,按其證明及輸入信封計算,而這兩者在任何驗證之前已經可知。 - 錨點——鏈 21 上為最近 1,024 個區塊末尾根之一,與鏈 20 相同,其創世區塊設有
proof_window_blocks: 1024(v0.6.8);沒有該欄位的鏈(如鏈 19 及之前)則為最近 256 個之一。 - 時間——鏈 20 和 21 上須在
[height − 1024, height]之內;沒有該欄位的鏈則為[height − 256, height]。同一個創世區塊數值同時設定兩個視窗。 - 廢止符與承諾——四個廢止符互不相同且均未被花費;四個承諾互不相同且均尚未成為葉節點。
- 操作檢查——水龍頭已啟用,鑄造數額在上限之內並已由驗證者簽署,並且自鏈 20 起須指明列於創世區塊
staking.faucet_recipients許可名單上的接收者,符合該時期的faucet_budget_per_epoch,並由創世區塊staking.faucet_minters名單上的驗證者簽署(自鏈 16 起為有效性規則);任何鏈上,數額達到或超過 2⁶³ 的鑄造或存入一律被拒絕;程式可解碼;程式存在;質押規則(驗證者未知時才附有註冊、nonce、簽名、足夠的質押);橋接自身針對BridgeAttest和BridgeBurn以及暫停和上架操作的規則;RPL 針對其四個操作的規則,包括註冊費;自鏈 20 起還有准入投票的法定人數,以及針對Invoke的狀態轉換形狀、對照已儲存單元格的已宣告讀取、金庫對每筆支付的覆蓋以及單元格費用。在鏈 21 上,永續合約規則(市場、帳戶、視窗)、多重簽名規則(簽署者集合、有效簽名的門檻、nonce、金庫的覆蓋),以及針對CreateMultisig的create_fee亦在此處檢查。所有這些均在捆綁包的證明之前執行,因此無法套用的交易不會招致任何 STARK 驗證成本。在hardening_v6之下(自鏈 16 起的每條鏈),此處另有兩項拒絕:Deploy一個沒有任何呼叫能持有的程式(ProgramUncallable),以及捆綁包或呼叫證明的標頭或轉錄帶有誠實證明者不會寫入的欄位(non-canonical proof: …),兩者均在任何一個證明被驗證之前被拒絕。自 v0.6.8 起,標頭所宣告的度數超過最高表格上限的證明,會在同一裁決之下最先被拒絕(審計 v6 ZKV-4),早於檢查遍歷該證明之前。 - 捆綁包摘要——在分離授權的鏈上(自鏈 17 起的每條鏈),先檢查授權欄位:沒有授權證明的捆綁包被拒絕,授權證明所發布的
c(只讀取,尚未驗證)須等於auth_commit,並且自鏈 20 起,單一密鑰授權證明須宣告剛好為 1,279 的GAS_LIMIT。在鏈 21 上,授權證明所宣告的形狀決定它按哪個客戶程式(guest)來檢查(上文);多重簽名形狀的證明宣告 436,159,即其自身標頭的上限。然後帳本重新計算捆綁包已發布欄位(auth_commit亦在其中)的摘要,它須等於證明所發布的內容。自鏈 20 起,捆綁包證明還須宣告剛好等於創世區塊bundle_gas_limit的GAS_LIMIT,即 20,479。 - 捆綁包證明——對照創世區塊固定的
hc_bundle及交易的綁定執行Machine::verify_public。在分離授權的鏈上,接著對照創世區塊固定的hc_auth驗證授權證明——在鏈 21 上,多重簽名形狀的證明則對照hc_auth_multisig——並使用相同的綁定。自 v0.8.0 起,節點會按其輸入的摘要保留每次驗證的Ok裁決(驗證快取,32,768 個條目),因此准入時已見過的證明在每個節點上只驗證一次,不會在套用時再驗證。 - 呼叫證明及其層級費用——對於
Call或Invoke,首先固定證明的標頭(層級至多 14,keccak 表至多 2¹²,sha256 表至多 2¹³,已部署程式的高度,在hardening_v6之下下限為 2⁷ 列,並且自鏈 18 起,所宣告的GAS_LIMIT不得大於標頭的上限gas_max),然後對照程式的code_hash檢查呼叫的 STARK,在hardening_v6之下並對照交易的呼叫綁定。費用最後才檢查,因為只有證明解碼後才能得知:在以 gas 計量的鏈上,按當前生效的價格,fee ≥ BUNDLE_BASE + gas_price × GAS_LIMIT + byte_price × ⌈bytes / 1024⌉,Invoke另加每個已建立單元格的cell_fee(費用);在沒有gas區段的鏈上,fee ≥ BUNDLE_BASE + call_fee(tier)。
錯誤會以代碼 -32000 連同原因從 rand_sendTransaction 返回:nullifier already spent、anchor is not one of the last 1024 roots(沒有 proof_window_blocks 的鏈為 256)、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,自鏈 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,自鏈 17 起有 this chain requires an auth proof on every bundle (genesis hc_auth) 和 the auth proof publishes a different commitment than the bundle's auth_commit,以及自鏈 20 起的 envelope is 1348 bytes, this chain requires exactly 1860 和 bundle proof declares gas limit …, this chain requires exactly 20479。被接受並不等於已提交:請輪詢 rand_getTransaction,直至它返回一個區塊。
包含任何無效交易的區塊即屬無效。記憶體池會為每個待處理的廢止符和承諾建立索引,並直接拒絕衝突,因此花費同一張票據的兩個捆綁包絕不會處於同一區塊之中。
大小
| 部分 | 位元組 |
|---|---|
Word8 | 32 |
一個 Envelope | 編碼後 1,892(密文 1,860),自鏈 18 起;至鏈 17 為 1,380(1,348) |
Bundle 減去其兩個證明 | 7,936(四個廢止符、四個承諾、四個信封、auth_commit) |
| 轉帳交易減去其兩個證明 | 7,949 |
| 部署交易減去其兩個證明,100 個字的程式,無公開輸入 | 8,369 |
| 呼叫交易減去其三個證明,無輸入信封 | 7,990 |
| 鑄造交易(無捆綁包) | 5,761(1,312 位元組的 Dilithium2 密鑰和 2,420 位元組的簽名) |
| 一個捆綁包證明,層級 14,生產配置 | 鏈 18 上讀得 1,497,544 和 1,504,260(高度 97,821 的一次部署和高度 98,335 的一次呼叫,2026-09-30);鏈 14 上量得 1,422,116 和 1,423,170(zUSD 註冊及一次支持資產上架,2026-09-20) |
| 一個授權證明,層級 10,生產配置 | 在鏈 18 的同樣兩筆交易中為 1,370,827 和 1,367,303 |
前六行是自 chain 18 起的編碼:備註欄位令每個信封增加 512 bytes,而拆分授權則在授權證明自身的 bytes 之前,令捆綁包增加 40 bytes。因此,由 chain 18 至 chain 20,一筆屏蔽轉賬在鏈路上約為 2.88 MB,無論轉移何種資產,幾乎全是證明:約 1.5 MB 為捆綁包證明,1.37 MB 為授權證明。至 chain 15 為止,它約為 1.43 MB,只有一個證明。Chain 21 的證明屬約束集 9,其大小此處尚未量度;私密多重簽名授權會以 tier-18 授權證明取代 tier-10 授權證明(估計超過 3.4 MB,這正是 chain 21 的證明上限為 6 MiB 的原因)。區塊上限為 2,000 筆交易(MAX_BLOCK_TXS),以及鏈的 max_block_bytes 所定的交易 bytes 數,兩者皆為共識規則:預設為 4 MiB(MAX_BLOCK_BYTES),只能容納一筆此類轉賬;chain 20 的創世區塊為 20 MiB,可容納七筆;chain 21 的為 19 MiB(19,922,944 bytes)。設有 hc_auth 的創世區塊必須把 max_block_bytes 設為至少 max_proof_bytes 的三倍加 1 MiB,因為一筆交易可攜帶三個證明(捆綁包、授權、呼叫),故此 4 MiB 的預設值在該處會被拒絕。區塊層級的聚合是已列入計劃的補救方案;參閱證明。自 v0.8.0 起,領導者會廣播緊湊區塊——區塊頭、其簽名及交易哈希——副本節點則從其內存池重建區塊,只取回所缺的交易主體(共識);上述上限針對的是區塊,而非訊框。
讀回一筆交易
在交易被提交之前,rand_getTransaction(hash) 會返回 null;提交之後,則只返回其區塊位置及公開欄位:
{
"height": 192, "index": 0, "block_hash": "63f6…08",
"tx": {
"hash": "4f2c…e7", "chain_id": 21,
"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" }
}
}
轉賬中沒有 from、沒有 to、沒有 nonce、沒有金額,也沒有 asset 欄位,已儲存的區塊中亦然:節點再無可遮蔽之物。auth_commit 與 auth_proof_bytes(授權證明的長度)自 chain 17 起出現。捆綁包永遠有四個槽位,包括虛設項在內;RAND 的轉賬與任何 RPL 代幣的轉賬,皆為 "kind": "none"。自 chain 14 起,每個 u64 金額均為十進位字串(fee、burn_a、burn_r,以及動作的 amount);索引、nonce、區塊高度與長度則仍為 JSON 數字。其他動作類型會呈現其公開欄位——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,四種歸屬類型 claim_vested、revoke_vesting、bond_vested、unbond_vested,自 v0.6.8 起的 admit_validator、slash_equivocation、rotate_pq_guardians_v2、rotate_pause_key_v2、cancel_rotation 與 invoke,以及自 v0.8.0 起的六種 perp_* 類型、create_multisig、multisig_deposit、multisig_pay、multisig_rotate 與 set_rand_price——詳見 JSON-RPC 參考。