Rand Protocol
الوثائق
المفاهيم الأساسية

المعاملات والإجراءات

المعاملة كما تُرسَل عبر الشبكة، ومعرّفها، وكل إجراء (Action) يعرفه السجل، وأيٌّ منها تقبله chain 20، والترتيب الذي تفحص به العقدة أي معاملة مُقدَّمة.

استخدم هذه الصفحة لبناء معاملة أو إرسالها أو فك ترميزها: الشكل السلكي الذي تقبله 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، ووسومه بترتيب التصريح:

الوسمالإجراءالحقولالحزمةالحد الأدنى للرسوم
0None—مطلوبةBUNDLE_BASE = 0.001 RAND
1Mintcm, pk, time, r, envelope, amount, minter: PublicKey, signatureيجب أن تكون غائبة0 (يوقّعه المُصادِق؛ سلاسل الصنبور فقط، amount ≤ 100 RAND)
2Deploybase_pc: u32, words: Vec<u32>, public: Vec<u32>مطلوبةالأساس + 100,000 وحدة لكل كلمة برنامج وكل كلمة عامة
3Callprogram, proof, input_envelope: Option<CallEnvelope>مطلوبةعلى السلسلة 20: الأساس + gas_price × قيمة GAS_LIMIT المعلنة في الإثبات + byte_price لكل KiB من الإثبات والظرف المُدخَل؛ الأساس + call_fee(tier) على سلسلة بلا قسم gas
4Bondvalidator, amount, registration: Option<Registration>مطلوبة، وburn_r == amountالأساس
5Unbondvalidator, amount, nonce, signatureيجب أن تكون غائبة0
6Withdrawvalidator, amount, nonce, time, r, envelope, signatureيجب أن تكون غائبة0 على الشبكة؛ يُقتطع الأساس من amount
7BridgeAttestattestation, recipient: ShieldedAddress, r, time, asset, envelope, pq_signatures: Vec<PqSignature>مطلوبةالأساس
8BridgeBurnasset, amount, relayer_fee, to_chain: u16, token: [u8; 32], to: [u8; 32]مطلوبة، مع burn_asset == asset وburn_a == amountBRIDGE_BURN_FEE = 0.01 RAND
9RegisterAggregatorregistrationمطلوبة، burn_r = الضمانالأساس
10UnbondAggregatoraggregator, nonce, signatureيجب أن تكون غائبة0
11WithdrawAggregatoraggregator, nonce, time, r, envelope, signatureيجب أن تكون غائبة0
12SlashAggregatorترويستان مجمَّعتان موقّعتانيجب أن تكون غائبة0
13Aggregatecovers, proof, aggregator, nonce, time, r, envelope, signatureيجب أن تكون غائبة0
14RegisterTokenname, symbol, decimals: u8, authority: MintAuthority, initial: Option<InitialMint>, salt: [u8; 32], index: u32مطلوبةالأساس + registration_fee الخاصة بالسجل (1 RAND على السلسلة 20، تُحرَق)
15TokenMintasset, amount, recipient: ShieldedAddress, r, time, envelope, nonce, signatureمطلوبةالأساس
16SetAuthorityasset, new: Option<PublicKey>, nonce, signatureمطلوبةالأساس
17TokenBurnasset, amountمطلوبة، مع burn_asset == asset وburn_a == amountالأساس
18PauseMintsnonce, signatureيجب أن تكون غائبة0
19UnpauseMintsnonce, pq_signaturesيجب أن تكون غائبة0
20RegisterBridgedTokenname, symbol, salt, chain: u16, token: [u8; 32], decimals: u8, nonce, pq_signaturesمطلوبةالأساس + registration_fee
21ListBackingtoken_index, chain: u16, token: [u8; 32], decimals: u8, nonce, pq_signaturesمطلوبةالأساس
22RotatePqGuardiansnew_pq_guardians: Vec<PublicKey>, nonce, pq_signaturesيجب أن تكون غائبة0
23RotatePauseKeynew_pause_key: PublicKey, nonce, pq_signaturesيجب أن تكون غائبة0
24ClaimVestedentry: [u8; 32], amount, nonce, to: ShieldedAddress, time, r, envelope, signatureيجب أن تكون غائبة0 على الشبكة؛ يُقتطع الأساس من amount
25RevokeVestingentry: [u8; 32], unvested, nonce, to: ShieldedAddress, time, r, envelope, signatures (منذ v0.6.8 نصاب من الجهات المخوّلة بالإلغاء في الإدخال، يدفع إلى الخزينة التي يسمّيها إدخال التكوين الأولي؛ وكان قبل ذلك signature واحدًا)يجب أن تكون غائبة0 على الشبكة؛ يُقتطع الأساس من unvested
26BondVestedentry: [u8; 32], validator, amount, registration: Option<Registration>, nonce, signatureيجب أن تكون غائبة0
27UnbondVestedentry: [u8; 32], amount, nonce, signatureيجب أن تكون غائبة0
28AdmitValidatorcandidate: PublicKey, signatures: Vec<(PublicKey, Signature)>يجب أن تكون غائبة0
29SlashEquivocationfirst, second: ترويستا كتلتين موقّعتان من قائد واحد لرؤية واحدةيجب أن تكون غائبة0
30RotatePqGuardiansV2new_pq_guardians: Vec<PublicKey>, possession: Vec<Vec<u8>>, nonce, pq_signaturesيجب أن تكون غائبة0
31RotatePauseKeyV2new_pause_key: PublicKey, possession: Vec<u8>, nonce, pq_signaturesيجب أن تكون غائبة0
32CancelRotationkind: u8, nonce, signatureيجب أن تكون غائبة0
33Invokeprogram, 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) الفحص نفسه قبل النشر، فتُرفض المعاملة الفاسدة مرة واحدة، عند الحافة.

  1. حدود الحجم — المعاملة كاملةً ≤ 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)، قبل أي عمل على الإثبات.
  2. معرّف السلسلة مطابق.
  3. الشكل والحد الأدنى للرسوم — الإجراء الخالي من الحزمة لا يحمل حزمة، وكل ما سواه يجب أن يحمل حزمة واحدة بالضبط؛ ويحدد 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⌉ على إثباته ومظروف مدخلاته، وهما معروفان قبل أي تحقق.
  4. المرساة — أحد جذور نهاية الكتل الـ 1,024 الأخيرة على السلسلة 20 التي يضبط جينيسيسها proof_window_blocks: 1024 (v0.6.8)؛ وأحد الـ 256 الأخيرة على سلسلة بلا هذا الحقل، كما حتى السلسلة 19.
  5. الزمن — ضمن [height − 1024, height] على السلسلة 20؛ و[height − 256, height] بلا الحقل. وقيمة الجينيسيس الواحدة تضبط النافذتين معًا.
  6. المُبطِلات والتعهّدات — المُبطِلات الأربعة كلها مختلفة ولم يُنفَق أي منها؛ والتعهّدات الأربعة كلها مختلفة ولا يوجد أي منها ورقةً في الشجرة.
  7. فحوص الإجراء — الـ 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)، قبل أن يمرّ الفحص عليه.
  8. ملخّص الحزمة — على سلسلة التفويض المنفصل (كل سلسلة منذ 17) تُفحص حقول التفويض أولًا: تُرفض الحزمة التي بلا إثبات تفويض، ويجب أن يساوي الـ c الذي ينشره إثبات التفويض (يُقرأ ولم يُتحقق منه بعد) قيمة auth_commit، وعلى السلسلة 20 يجب أن يعلن إثبات التفويض GAS_LIMIT يساوي 1,279 تمامًا. ثم يعيد دفتر الأستاذ حساب ملخّص الحقول المنشورة للحزمة، ومنها auth_commit، ويجب أن يساوي ما نشره الإثبات. وعلى السلسلة 20 يجب أيضًا أن يعلن إثبات الحزمة GAS_LIMIT يساوي تمامًا bundle_gas_limit في الجينيسيس، أي 20,479.
  9. إثبات الحزمة — Machine::verify_public مقابل hc_bundle المثبَّت في الجينيسيس والربط الخاص بالمعاملة. وعلى سلسلة التفويض المنفصل يُتحقق من إثبات التفويض بعده، مقابل hc_auth المثبَّت في الجينيسيس والربط نفسه.
  10. إثبات الاستدعاء ورسم فئته — لـ Call أو Invoke تُثبَّت ترويسة الإثبات أولًا (الفئة 14 على الأكثر، وجدول keccak حتى 2¹² على الأكثر، وجدول sha256 حتى 2¹³ على الأكثر، وارتفاع البرنامج المنشور بحدٍّ أدنى 2⁷ صفًا في ظل hardening_v6، وعلى السلسلة 20 GAS_LIMIT معلن لا يزيد على سقف الترويسة gas_max)، ثم STARK الاستدعاء مقابل code_hash الخاص بالبرنامج، وفي ظل hardening_v6 مقابل ربط الاستدعاء الخاص بالمعاملة. ويُفحص الرسم أخيرًا، لأنه لا يُعرف إلا بعد فك الإثبات: فعلى السلسلة 20 fee ≥ 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 إلى أن يعيد كتلة.

الكتلة التي تحتوي أي معاملة غير صالحة كتلة غير صالحة. وتفهرس ذاكرة المعاملات المعلّقة كل مُبطِل وكل تعهّد معلّق وترفض أي تعارض رفضًا قاطعًا، فلا تشترك حزمتان تنفقان الملاحظة نفسها في كتلة واحدة.

الأحجام

الجزءالبايتات
Word832
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.

آخر تحقق مقابل الإيداع c0878c3f في fullnode (السلسلة 21) بتاريخ 2026-10-12. إذا اختلف الكود عن هذه الصفحة فالكود هو الصحيح؛ أبلغونا بذلك.