استخدم هذه الصفحة لبناء معاملة أو إرسالها أو فك ترميزها: الشكل السلكي الذي تقبله rand_sendTransaction، وكيفية حساب المعرّف، والقائمة الكاملة للإجراءات مع قواعد الحزمة والرسوم الخاصة بها، وترتيب القبول الذي يحدد أول خطأ يصلك.
المعاملة
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 هو ثماني كلمات u32 بترتيب little-endian، تُعرض في 64 خانة سداسية عشرية بأحرف صغيرة. الصيغة السلكية هي bincode(Transaction) بإعدادات bincode الافتراضية (أعداد صحيحة ثابتة العرض، وبادئات أطوال من 8 بايتات، ووسوم تعداد من نوع u32)، وتقبلها rand_sendTransaction بصيغة سداسية عشرية. لا يوجد توقيع على المعاملة ولا حقل مرسل: فالحزمة تفوّض نفسها بإثباتاتها (إثبات الحزمة، ومنذ السلسلة 17 إثبات التفويض المرافق له)، أما الإجراء الموقَّع فيحمل التوقيع في داخله. وحماية الإعادة تقوم على مجموعة المُبطِلات للحزم، وعلى رقم تسلسلي لكل مدقِّق في السجل لإجراءات التخزين الموقَّعة، وعلى mint_nonce لكل رمز للإجراءين TokenMint وSetAuthority، وعلى pause_nonce وlist_nonce الخاصين بالجسر لإجراءات حوكمته.
تحمل المعاملة حزمة واحدة على الأكثر، ويحمل كل إجراء غير خالٍ من الحزم حزمة واحدة بالضبط. تحمل الخانتان 0–1 من الحزمة أصلًا خاصًا، وتحمل الخانتان 2–3 عملة RAND، فيحرّك إثبات واحد رمزًا ويدفع رسمه بعملة RAND؛ وقد زال حرق الجسر ذو الحزمتين من التصميم السابق: فالحرق حزمة واحدة (المذكرات).
تبني محفظة rand هذا كله عبر randprotocol_client::wallet::{send, submit}: تختار المدخلات، وتجلب المرساة، وتحسب الشواهد من نسخة المحفظة نفسها من الشجرة، وتبني المخرجات وتختم المغلفات الأربعة جميعًا، وتأخذ ربط المعاملة، وتُثبت الحزمة وإثبات التفويض، وتتحقق من الملخّص المنشور لإثبات الحزمة، ثم ترسل.
ربط المعاملة
ليس للمعاملة توقيع، وإثبات الحزمة يلتزم فقط بملخّص الحزمة نفسها: المرساة، والمُبطِلات، والتعهدات، والرسم، وحقول الحرق، وtime. حتى السلسلة 13 لم يكن هناك ما يربط حزمة مثبتة بالإجراء الذي سافرت معه ولا بمغلفاتها، فكان بوسع كل من رأى معاملة أن يُبقي كل بايتات الإثبات ويغيّر الباقي: وجهة BridgeBurn، أو مدقِّق Bond، أو أحد المغلفات. ومنذ السلسلة 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')) chain 20
as 8 LE u32 words
حيث تعني ' أن كل سلسلة بايتات إثبات حزمة تُستبدل بالمتجه الفارغ: bundle.proof، ومنذ السلسلة 17 bundle.auth_proof، وproof الخاص بـAggregate. وكل ما عدا ذلك داخل الربط: auth_commit، والمغلفات الأربعة جميعًا، وكل حقل حرق، والوجهة، والمدقِّق، والمستلم، والتوقيعات، وإقرار الحارس وتوقيعات Dilithium2 المشتركة معه، وإثبات Call نفسه. وتسافر الكلمات الثماني في مقطع المدخلات العامة للإثبات، الذي تربط الدائرة ملخّصه H_PUB أصلًا، فلم يحتج الإصلاح إلى تغيير في الضيف ولا في الدائرة؛ وتشغّل العقدة Machine::verify_public(hc_bundle, binding, proof) وترفض إثبات حزمة يعلن أي ارتفاع عام آخر (public height not the transaction binding's). وTransaction::binding هي الدالة الوحيدة التي تستدعيها المحفظة قبل الإثبات ويستدعيها السجل قبل التحقق. ومنذ السلسلة 17 يُنشأ إثبات التفويض على الكلمات الثماني نفسها ويُتحقق منه مقابلها، فلا يمكن نقله إلى معاملة أخرى.
تربط السلسلة 20 تجزئة التكوين الأول. حتى السلسلة 19 كان الربط، ورسائل الإجراءات الخالية من الحزم الموقَّعة، يغطيان معرّف السلسلة وحده، فلو شاركت سلسلتان معرّف السلسلة نفسه (إعادة إصدار، أو نسخة خاصة) لقبلت كل منهما إثباتات الأخرى وتوقيعاتها. وتضبط عقدة التكوين الأول للسلسلة 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)، ولإجراءات المجمِّع ورسائل حوكمة الجسر. وتسجيل المدقِّق على سلسلة كهذه هو دائمًا رسالة الإصدار الثاني (التكوين الأول، السلسلة، العنوان، جهة الدفع). ولا يصحّ على سلسلة أخرى أي شيء أُثبت أو وُقّع لسلسلة، أيًّا كان معرّف سلسلتها. وكلمات الربط مدخل عام، فلم يتغير أي مفتاح للضيف أو للمتحقق. وأي محفظة أقدم من v0.6.8 ما زالت تُثبت على صيغة معرّف السلسلة، وتُرفض على السلسلة 20. وتعرض rand_getLimits وrand_status الحقل binding_domain (القيمة 1 على السلسلة 20، و0 عند غياب الحقل).
وفي ظل hardening_v6 في التكوين الأول (السلاسل من 16 إلى 20) يُربط إثبات Call نفسه أيضًا، بملخّص ثانٍ من البناء نفسه تحت نطاقه الخاص، مع تفريغ إثبات الاستدعاء كما تُفرَّغ إثباتات الحزمة:
call_binding(tx) = blake3("rand-call-bind-1" || bincode(chain_id, bundle', action'')) as 8 LE u32 words
وعلى السلسلة 20 يكون الوسم rand-call-bind-2 وتتصدّر تجزئة التكوين الأول الصورة الأولية، كما سبق. ويُربط إثبات Invoke بالطريقة نفسها، مع بقاء الانتقال الذي أعلنه في الصورة الأولية، فيلتزم الإثبات بتغيير الحالة والمدفوعات والمستلمين الذين تحملهم المعاملة بدقة.
ويحمل إثبات الاستدعاء هذه الكلمات في مقطع مدخلاته العامة، بعد المدخل العام للبرنامج وقت النشر إن كان له مدخل، فلا يصحّ نسخة منه ملحقة بحزمة رسوم أخرى. ويتداخل الربطان: تختار المحفظة مذكرات حزمة الرسوم وتبني المعاملة بإثباتات فارغة، ثم تُثبت الاستدعاء مقابل ربط الاستدعاء، وتضع ذلك الإثبات في مكانه، ثم تأخذ ربط المعاملة وتُثبت الحزمة، وبعد ذلك فقط.
والنتيجة للعميل: ابنِ المعاملة كلها — المخرجات والمغلفات والإجراء — قبل الإثبات. أما المحفظة المبنية قبل التفرّع فتُثبت مقابل المقطع العام الفارغ وتُرفض. والإجراءات الخالية من الحزم لا إثبات فيها لربطه، وتستند إلى توقيعاتها. والربط ليس معرّف المعاملة، الذي لم يتغير.
معرّف المعاملة
txid = blake3("rand-txid-3" || bincode(view))
حيث view هي المعاملة بعد استبدال بايتات proof للحزمة بـblake3(proof) (proof_hash) وبايتات auth_proof بـblake3(auth_proof) (auth_proof_hash، بعد auth_commit الذي يدخل كما هو)، وكل حقل آخر كما هو. وكان النطاق rand-txid-2، من دون حقلي التفويض، حتى السلسلة 16؛ وتغيّر كل معرّف معاملة مع السلسلة 17. وتجزئة الإثبات بملخّصه هي ما يتيح لحزمة مقلَّمة (تجميع الكتل، غير مفعّل على السلسلة 20) أن تحتفظ بالمعرّف نفسه الذي لصورتها الخام؛ وتحتفظ الحزمة المقلَّمة بإثبات تفويضها. أما المعاملة الخالية من الحزم فتُجزَّأ بايتاتها كما هي. ويفهرس المعرّف نفسه مجمّع المعاملات المعلّقة والإيصالات وكل بحث عبر 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> | مطلوبة | على السلسلة 20: الأساس + gas_price × قيمة GAS_LIMIT المعلنة في الإثبات + byte_price لكل KiB من الإثبات والظرف المُدخَل؛ الأساس + call_fee(tier) على سلسلة بلا قسم gas |
| 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 | يجب أن تكون غائبة | 0 |
| 14 | RegisterToken | name, symbol, decimals: u8, authority: MintAuthority, initial: Option<InitialMint>, salt: [u8; 32], index: u32 | مطلوبة | الأساس + registration_fee الخاصة بالسجل (1 RAND على السلسلة 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_a الخاص بـburn_asset | الحد الأدنى لرسوم الاستدعاء + cell_fee لكل خلية منشأة |
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
على السلسلة 20 يمكن استخدام الوسوم من 0 إلى 8، ومن 14 إلى 21، و28، ومن 30 إلى 33. يضم تكوينها الأولي قسم bridge فيه rules_v2، وقسم tokens، وstaking.admission_by_vote (الوسم 28)، وbridge.rotation (الوسوم من 30 إلى 32)، وprogram_state (الوسم 33). الوسمان 22 و23 مرفوضان هناك: فمع bridge.rotation.needs_possession يجب أن يكون التدوير بصيغة …V2 التي تحمل توقيع كل مفتاح جديد بنفسه. وعلى السلسلة 19، التي لم يكن فيها أي من هذه الأقسام، كانت الوسوم من 0 إلى 8 ومن 14 إلى 23 قابلة للاستخدام (أما السلسلة 14، بلا rules_v2، فكانت ترفض 22 و23). يحتاج SlashEquivocation إلى قسم staking.slashing، وهو في السلسلة 20 فارغ (null). وتحتاج إجراءات التجميع الخمسة إلى قسم aggregation، وليس في السلسلة 20 قسم كهذا (يرفض الإصدار البرمجي الإقلاع على تكوين أولي يحمله إلى أن يُعاد قياس التجميع). تردّ العقدة هذه الإجراءات كلها عند البوابة قبل أي فحص آخر، لكنها تظل تشغل وسومها في bincode، ولذلك يجب على المرمِّز الذي يثبّت أرقام الوسوم في شيفرته أن يحتسبها. يرد التجميع في الإثباتات بوصفه ميزة قادمة. أما إجراءات الاستحقاق الأربعة في التكوين الأولي (الوسوم من 24 إلى 27، في الإصدار البرمجي منذ v0.5.11) فتحتاج إلى قسم vesting لم تضمّه أي سلسلة، ومنها السلسلة 20، وتُرفض عند القبول إن غاب. الوسوم من 28 إلى 33 جديدة في v0.6.8 وأُلحقت في الآخر، فيظل تاريخ كل سلسلة سابقة قابلًا لفك الترميز.
تسجّل إجراءات RPL الأربعة (الوسوم من 14 إلى 17) رمزًا، وتُصدر المزيد من رمز مخوَّل بـKey، وتسلّم سلطة إصداره أو تتخلى عنها، وتحرق رصيدًا؛ ويُرفض RegisterToken الذي يسمّي سلطة من نوع Bridge أو Program. ولا يوجد إجراء لتحويل الرموز: فتحويل الرمز هو None، لا يمكن تمييزه عن دفعة بـ RAND. انظر رموز RPL. أما إجراءات حوكمة الجسر الأربعة (الوسوم من 18 إلى 21) فهي إيقاف الإصدار، ورفع الإيقاف، وإدراج رمز مجسَّر أو ضمان إضافي بعد التكوين الأولي. يوقّع PauseMints مفتاحُ الإيقاف في التكوين الأولي، وهو لا يستطيع إلا الإيقاف؛ أما الثلاثة الباقية فتحتاج إلى نصاب من أوصياء Dilithium2 (PQ). ويحمل BridgeAttest نصابًا كهذا أيضًا، إلى جانب نصاب ECDSA. ويستبدل الوسمان 22 و23، في ظل rules_v2 للجسر، مجموعة أوصياء PQ أو مفتاح الإيقاف، كلٌّ منهما بنصاب PQ من المجموعة الحالية وrotation_nonce الخاص بالجسر. ويفعل الوسمان 30 و31 الشيء نفسه في ظل bridge.rotation، ويحملان كذلك توقيع Dilithium2 الخاص بكل مفتاح جديد على رسالة التدوير، دليلًا على أن المفتاح في حوزة صاحبه؛ وعلى السلسلة 20 يُسجَّل التدوير معلّقًا ويسري بعد delay_secs، أي 86,400 ثانية. ويُسقط CancelRotation (الوسم 32)، الذي يوقّعه مفتاح الإيقاف الحالي، تدويرًا معلّقًا قبل أن يسري. انظر الجسر.
AdmitValidator (الوسم 28) هو تصويت مجموعة المُصادِقين على قبول مفتاح جديد: توقيعات من مُصادِقين يملكون أكثر من ثلثي الحصة، بترتيب العناوين التصاعدي. ففي ظل staking.admission_by_vote (السلسلة 20) يُرفض Bond الذي سيسجّل مُصادِقًا جديدًا ما لم يكن عنوانه قد قُبل بهذه الطريقة (الحصص). أما Invoke (الوسم 33، RPL-2) فهو استدعاء يشهد إثباته على transition واحد معلن لحالة البرنامج: الخلايا المقروءة والمكتوبة، وما تُدخله حقول الحرق في الحزمة إلى خزنة البرنامج، والملاحظات التي تدفعها الخزنة أو يُصدرها البرنامج. ويطبّق دفتر الحسابات الانتقال إذا ظلت كل قراءة معلنة صحيحة وتحقق الإثباتان كلاهما (البرامج).
إن Deploy وCall معاملتان محمية عاديتان حزمتهما تحويل ذاتي بقيمة صفر: وجودها لدفع الحد الأدنى من الرسوم من ملاحظات المستدعي نفسه، فلا تعرف السلسلة لمن كانت. ولا يغادر RAND المجمّع إلا عبر burn_r — حصة Bond، وضمان RegisterAggregator، وإيداع Invoke في خزنة برنامج — ولا يغادره الرمز إلا عبر burn_a مع تسمية burn_asset له، في TokenBurn أو BridgeBurn أو Invoke. وكل إجراء آخر لا يحرق شيئًا، وتُرفض في كل مكان الحزمة التي فيها burn_asset = 0 وburn_a غير صفري.
ترتيب القبول
يفحص Ledger::validate_inner الأمور الرخيصة قبل المكلفة، بهذا الترتيب؛ ويجري مجمّع المعاملات المعلقة (mempool) الفحص نفسه قبل النشر، فتُرفض المعاملة الفاسدة مرة واحدة، عند الحافة.
- حدود الحجم — المعاملة كاملةً ≤
max_block_bytesالخاص بالسلسلة؛ وكل مظروف من المظاريف الأربعة في الحزمة، وأي مظروف ملاحظة يحمله الإجراء، يساوي تمامًاenvelope_bytesفي الجينيسيس (1,860 على السلسلة 20؛ وعلى سلسلة بلا هذا الحقل لا يزيد على 2,048 بايت)؛ وإثبات الحزمة وإثبات التفويض وإثبات الاستدعاء، كلٌّ منها ≤max_proof_bytes(2 MiB افتراضيًا، و4 MiB في جينيسيس السلسلة 20؛ وكان 8 MiB على السلاسل 13 إلى 16)؛ والبرنامج ≤ الحد الأقصى للبرامج في السلسلة (4,096 كلمة افتراضيًا، و65,535 في جينيسيس السلسلة 20)؛ ومظروف الاستدعاء ≤max_call_envelope_bytes(18,432 بايت افتراضيًا، و65,536 على السلسلة 20)؛ والشهادة ≤ 16 KiB. أما إثبات الحزمة بصيغة العلامة المختومة (المُقلَّمة) فيُرفض هنا خارج المزامنة بالصيغة المختومة (PrunedFormOutsideSync)، قبل أي عمل على الإثبات. - معرّف السلسلة مطابق.
- الشكل والحد الأدنى للرسوم — الإجراء الخالي من الحزمة لا يحمل حزمة، وكل ما سواه يجب أن يحمل حزمة واحدة بالضبط؛ ويحدد
check_burn_shapeأيًّا من حقول الحرق الثلاثة يجوز للإجراء ضبطه: فـTokenBurnأوBridgeBurnيحرقassetوamountالخاصين به عبرburn_assetوburn_a، وBondأوRegisterAggregatorيحرق مبلغه عبرburn_r، وكل إجراء آخر لا يحرق شيئًا؛ وfee ≥ fee_floor(action). وعلى سلسلة ذات قسمgas(السلسلة 20) يكون الحد الأدنى لـCallأوInvokeفي هذه الخطوة هو قاعدة الغاز عند حد معلن قدره 1، أيBUNDLE_BASE + gas_price + byte_price × ⌈bytes / 1024⌉على إثباته ومظروف مدخلاته، وهما معروفان قبل أي تحقق. - المرساة — أحد جذور نهاية الكتل الـ 1,024 الأخيرة على السلسلة 20 التي يضبط جينيسيسها
proof_window_blocks: 1024(v0.6.8)؛ وأحد الـ 256 الأخيرة على سلسلة بلا هذا الحقل، كما حتى السلسلة 19. - الزمن — ضمن
[height − 1024, height]على السلسلة 20؛ و[height − 256, height]بلا الحقل. وقيمة الجينيسيس الواحدة تضبط النافذتين معًا. - المُبطِلات والتعهّدات — المُبطِلات الأربعة كلها مختلفة ولم يُنفَق أي منها؛ والتعهّدات الأربعة كلها مختلفة ولا يوجد أي منها ورقةً في الشجرة.
- فحوص الإجراء — الـ faucet مفعّل، والسك تحت السقف وموقَّع من مدقّق، وعلى السلسلة 20 يسمّي مستلمًا واردًا في قائمة السماح
staking.faucet_recipientsفي الجينيسيس، ويدخل فيfaucet_budget_per_epochللحقبة، ويوقّعه مدقّق وارد في قائمةstaking.faucet_mintersفي الجينيسيس (قاعدة صلاحية منذ السلسلة 16)؛ والسك أو الإيداع عند 2⁶³ أو أكثر يُرفض على كل سلسلة؛ والبرنامج قابل للفك؛ والبرنامج موجود؛ وقواعد الـ staking (التسجيل حاضر تمامًا حين يكون المدقّق غير معروف، والـ nonce، والتوقيع، وكفاية الحصة)؛ وقواعد الجسر الخاصة بـBridgeAttestوBridgeBurnوبإجراءات الإيقاف المؤقت والإدراج؛ وقواعد RPL لإجراءاته الأربعة، ومنها رسم التسجيل؛ وعلى السلسلة 20 نصاب تصويت القبول، ولـInvokeشكل الانتقال، والقراءات المعلنة مقابل الخلايا المخزَّنة، وتغطية الخزنة لكل دفعة، ورسم الخلية. وكل ذلك يجري قبل إثبات الحزمة، فلا تكلّف المعاملة التي يتعذّر تطبيقها أي تحقق من STARK. وفي ظلhardening_v6(السلاسل 16 إلى 20) يوجد هنا رفضان آخران:Deployلبرنامج لا يستطيع أي استدعاء الإمساك به (ProgramUncallable)، وإثبات حزمة أو استدعاء يحمل ترويسته أو نصّه حقلًا لا يكتبه المُثبِت الأمين (non-canonical proof: …)، ويُرفضان قبل التحقق من أي إثبات. ومنذ v0.6.8 يُرفض أولًا، بالحكم نفسه، الإثبات الذي تعلن ترويسته درجة تتجاوز سقف أعلى جدول (تدقيق v6 ZKV-4)، قبل أن يمرّ الفحص عليه. - ملخّص الحزمة — على سلسلة التفويض المنفصل (كل سلسلة منذ 17) تُفحص حقول التفويض أولًا: تُرفض الحزمة التي بلا إثبات تفويض، ويجب أن يساوي الـ
cالذي ينشره إثبات التفويض (يُقرأ ولم يُتحقق منه بعد) قيمةauth_commit، وعلى السلسلة 20 يجب أن يعلن إثبات التفويضGAS_LIMITيساوي 1,279 تمامًا. ثم يعيد دفتر الأستاذ حساب ملخّص الحقول المنشورة للحزمة، ومنهاauth_commit، ويجب أن يساوي ما نشره الإثبات. وعلى السلسلة 20 يجب أيضًا أن يعلن إثبات الحزمةGAS_LIMITيساوي تمامًاbundle_gas_limitفي الجينيسيس، أي 20,479. - إثبات الحزمة —
Machine::verify_publicمقابلhc_bundleالمثبَّت في الجينيسيس والربط الخاص بالمعاملة. وعلى سلسلة التفويض المنفصل يُتحقق من إثبات التفويض بعده، مقابلhc_authالمثبَّت في الجينيسيس والربط نفسه. - إثبات الاستدعاء ورسم فئته — لـ
CallأوInvokeتُثبَّت ترويسة الإثبات أولًا (الفئة 14 على الأكثر، وجدول keccak حتى 2¹² على الأكثر، وجدول sha256 حتى 2¹³ على الأكثر، وارتفاع البرنامج المنشور بحدٍّ أدنى 2⁷ صفًا في ظلhardening_v6، وعلى السلسلة 20GAS_LIMITمعلن لا يزيد على سقف الترويسةgas_max)، ثم STARK الاستدعاء مقابلcode_hashالخاص بالبرنامج، وفي ظلhardening_v6مقابل ربط الاستدعاء الخاص بالمعاملة. ويُفحص الرسم أخيرًا، لأنه لا يُعرف إلا بعد فك الإثبات: فعلى السلسلة 20fee ≥ BUNDLE_BASE + gas_price × GAS_LIMIT + byte_price × ⌈bytes / 1024⌉بالأسعار السارية، يضاف إليهاcell_feeعن كل خلية منشأة فيInvoke(الرسوم)؛ وعلى سلسلة بلا قسمgasيكونfee ≥ BUNDLE_BASE + call_fee(tier).
تعود الأخطاء من rand_sendTransaction بالرمز -32000 مع السبب: nullifier already spent، anchor is not one of the last 1024 roots (256 على سلسلة بلا 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، ومنذ السلسلة 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؛ و1,380 (1,348) حتى السلسلة 17 |
Bundle دون إثباتيه | 7,936 (أربعة مُبطِلات، وأربعة تعهّدات، وأربعة مظاريف، وauth_commit) |
| معاملة تحويل دون إثباتيها | 7,949 |
| معاملة نشر دون إثباتيها، برنامج من 100 كلمة، بلا مدخل عام | 8,369 |
| معاملة استدعاء دون إثباتاتها الثلاثة، بلا مظروف مدخلات | 7,990 |
| معاملة سك (بلا حزمة) | 5,761 (مفتاح Dilithium2 بحجم 1,312 بايت وتوقيع بحجم 2,420 بايت) |
| إثبات حزمة، الفئة 14، ملف الإنتاج | 1,497,544 و1,504,260 قُرئا على السلسلة 18 (نشر عند الارتفاع 97,821 واستدعاء عند 98,335، 2026-09-30)؛ و1,422,116 و1,423,170 قيسا على السلسلة 14 (تسجيل zUSD وإدراج دعم، 2026-09-20) |
| إثبات تفويض، الفئة 10، ملف الإنتاج | 1,370,827 و1,367,303 في معاملتي السلسلة 18 نفسيهما |
الصفوف الستة الأولى هي الترميز منذ السلسلة 18: فقد أضاف حقل المذكّرة 512 بايت إلى كل مظروف، وأضاف التفويض المنفصل 40 بايت إلى الحزمة قبل بايتات إثبات التفويض نفسها. فالتحويل المحمي على الشبكة نحو 2.88 MB منذ السلسلة 18، السلسلة 20 منها، وهو في معظمه إثباتات، أيًّا كان الأصل الذي ينقله: نحو 1.5 MB إثبات حزمة و1.37 MB إثبات تفويض. وكان نحو 1.43 MB حتى السلسلة 15، بإثبات واحد. وتُحدّ الكتل بـ 2,000 معاملة (MAX_BLOCK_TXS) وبـ max_block_bytes الخاص بالسلسلة من بايتات المعاملات، وكلاهما قاعدة إجماع: 4 MiB افتراضيًا (MAX_BLOCK_BYTES)، وهو يتّسع لتحويل واحد فقط من هذا النوع، و20 MiB في جينيسيس السلسلة 20، وهو يتّسع لسبعة. ويجب على جينيسيس يحوي hc_auth أن يضبط max_block_bytes على ما لا يقل عن ثلاثة أضعاف max_proof_bytes زائد 1 MiB، لأن المعاملة قد تحمل ثلاثة إثباتات (الحزمة والتفويض والاستدعاء)، ولذلك يُرفض هناك الافتراضي 4 MiB. والتجميع على مستوى الكتلة هو العلاج المرتقب؛ انظر الإثباتات.
قراءتها لاحقًا
تعيد rand_getTransaction(hash) القيمة null إلى أن تُودَع المعاملة، ثم تعيد موضعها في الكتلة والحقول العامة فقط:
{
"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" }
}
}
لا يوجد في عملية التحويل حقل from ولا to ولا nonce ولا مبلغ ولا حقل asset، ولا شيء من ذلك في الكتلة المخزَّنة أيضًا: فليس لدى العقدة ما تحجبه بعد ذلك. أما auth_commit وauth_proof_bytes (طول إثبات التفويض) فموجودان منذ chain 17. وتضم الحزمة دائمًا أربع خانات، بما فيها الخانات الوهمية، ويحمل كلٌّ من تحويل RAND وتحويل أي رمز RPL القيمة "kind": "none". وكل مبلغ من النوع u64 هو سلسلة نصية عشرية منذ chain 14 (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، وأنواع الاستحقاق (vesting) الأربعة 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 — كما هي مدرجة في مرجع JSON-RPC.