Rand Protocol
الوثائق
الأدلة

تشغيل عقدة

ابنِ الملفات التنفيذية، وأنشئ مفتاحًا، وهيّئ دليل البيانات انطلاقًا من genesis السلسلة 20، واتصل بعقد الإقلاع (bootstraps)، واربط واجهة RPC، وقلّص السجل التاريخي، وتحقّق من السلسلة - بصفتك مراقبًا أو مدقِّقًا (validator).

استخدم هذه الصفحة لتشغيل rand-node الخاص بك على testnet، وهذه أيضًا الطريقة الموصى بها لاستخدام المحفظة بخصوصية: العقدة التي تشغّلها بنفسك لا تُعلِم أحدًا غيرك بالورقة التي توشك على إنفاقها. يزامن المراقِب السلسلة ويعيد التحقق من كل إثبات ويخدم JSON-RPC؛ ويفعل المدقِّق (validator) الأمر نفسه ويشارك في الإجماع متى دخل مفتاحه في مجموعة حقبة ما.

البناء

المتطلبات: Rust 1.98.1 (مثبّت في rust-toolchain.toml؛ ويثبّته rustup)، ومترجم C++ وcmake من أجل RocksDB. تعتمد حزمة zkVM على حزم بمسارات محلية داخل نسخة circuits/ شقيقة من مستودع نظام الإثبات (randprotocol/zkp-circuits)، ويجب أن تكون بجوار fullnode/ وعلى الإيداع الذي استُمدّ منه الإصدار: السطر circuits: في crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md (aeacf31 للإصدار v0.6.8، كما في v0.6.7). يستغرق البناء الأول من 10 إلى 20 دقيقة.

git clone https://github.com/randprotocol/fullnode
cargo build --release          # target/release/rand-node, target/release/rand, target/release/rand-prover

شغّل الإصدار v0.6.8 (git checkout v0.6.8، الإيداع c9c9bd3c، وهو الإصدار الذي يشغّله الأسطول؛ ويُبلغ rand_getVersion عن بصمة sha للعقدة). يضم إصداره على GitHub الملفات rand-node وrand وrand-prover وSHA256SUMS، وقد بُنيت على مضيف واحد من الأسطول وهي غير موقّعة. تتطلبه السلسلة 20: فجينيسيسها يحمل حقولًا لا تقرؤها أي نسخة أقدم (testnet وbinding_domain وproof_window_blocks وprogram_state ومجموعتا rotation وfees في الجسر وسقوف الغاز والقبول في staking بالتصويت)، كما يتضمن v0.6.8 تغييرات في الإجماع لا تشغّلها العقدة الأقدم. ما زالت الإثباتات تُنتَج وفق مجموعة القيود 8، كما في السلسلتين 18 و19، وما زالت كل حزمة تحمل إثبات تفويض إلى جانب إثبات الحزمة (تفويض مجزّأ، منذ السلسلة 17)، ولذا يثبّت الجينيسيس الـ guest نفسيهما: guest الحزمة v3 (hc_bundle 60af094a…) وguest التفويض (hc_auth 1e4e347f…). ويحمل الجينيسيس كذلك قسم gas وhardening_v6 وenvelope_bytes. ترفض نسخة v0.6.8 جينيسيس السلاسل 14 و15 و16 و17 عند run وعند verify، بالاعتماد على البصمة؛ ويمكنها مع ذلك تشغيل جينيسيس السلسلة 19. على كل عقدة أن تستخدم بناء الأسطول.

السلسلة 20: فورك صلب بإيقاف شامل

بدأت السلسلة 20 العمل في 2026-10-01 عند 06:17 UTC. قُطعت من لقطة للسلسلة 19 وأُطلقت بإيقاف شامل وتشغيل شامل: توقفت كل عقدة من السلسلة 19 عند الارتفاع 7,700، وبدأت كل العقد على السلسلة 20 بالإصدار v0.6.8. لم يكن تحديثًا متدرجًا، لسببين. السلسلة 20 جينيسيس جديد، فلا توجد كتلة مشتركة مع السلسلة 19. ويتضمن v0.6.8 تغييرات في الإجماع من التدقيق v6 لا يجوز أن تُطبَّق عقدةً عقدة أبدًا: CON-4 يزيل الإفراج التلقائي عن قفل المدقِّق، وCH-1 يضيف منظّم إيقاع بشهادات انتهاء المهلة. انتقل المدقّقون الستة والعشرون جميعًا، بمفاتيحهم ومعرّفات أقرانهم ونقاط الإقلاع؛ والنصاب ما زال 18 من 26. السلسلتان 19 و18 متقاعدتان.

لذلك يتطلب نقل عقدة من السلسلة 19 إلى السلسلة 20 الملف التنفيذي الجديد وملف الجينيسيس الجديد ودليل بيانات جديدًا، كما يلي. تحتاج المحافظ إلى v0.6.8 للإرسال على السلسلة 20: فجينيسيسها يربط كل إثبات وكل رسالة موقّعة ببصمته (binding_domain: 1)، وهو ما لا تفعله المحفظة الأقدم.

المفاتيح

rand-node keygen --out node.key.json      # prints the address
rand-node address --key node.key.json     # address, public key, libp2p peer id

الملف هو { "seed", "address", "public_key" }، بصلاحيات 0600؛ والبذرة وحدها هي السرية. يحتاج المراقِب إلى مفتاح أيضًا، فهو هوية p2p. مفتاح العقدة ليس مفتاح محفظة: استخدم rand keygen للمحفظة.

ولّد مفتاحك الخاص واحفظه خارج نسخة المستودع. لم يعد مستودع fullnode يتتبع أي مفتاح (التدقيق v3، OPS-1): فملفات deploy/node-*.key.json وdeploy/payout/*.key.json التي أُودعت للسلاسل من 8 إلى 13 بذورها منشورة ولا يجوز استخدامها. أما مفاتيح مدقّقي السلسلة 20 فقد وُلّدت خارج المستودع ولم تكن فيه قط: مدقّقوها الستة والعشرون في الجينيسيس هم المفاتيح الثمانية عشر المولّدة للسلسلة 14 والثمانية التي ارتبطت على السلسلة 15، وقد انتقلت عبر كل قطع منذ ذلك الحين.

منذ v0.6.8 يرفض rand-node keygen ملف --out موجودًا مسبقًا؛ أما v0.6.7 فكان يستبدله دون سؤال. الملف هو النسخة الوحيدة من البذرة. خذ منه نسخة احتياطية قبل أن يعتمد أي ربط (bond) عليه.

التهيئة من الجينيسيس

تحتاج كل عقدة على سلسلة ما إلى ملف جينيسيس مطابق بايتًا ببايت؛ ينسخه rand-node init إلى دليل البيانات ويطبع بصمته، التي يجب أن تكون 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135 للسلسلة 20. الملف هو deploy/genesis-chain20.json (sha256 0020247a…3a21). أُودع في فرع main من fullnode مع سجل الإطلاق (الإيداع 74cfaca0)، بعد الوسم، فلا تحتويه نسخة v0.6.8: اجلبه من main.

git -C fullnode show origin/main:deploy/genesis-chain20.json > genesis-chain20.json
rand-node init --datadir ./data-6210cf07 --genesis genesis-chain20.json

ينشئ هذا <datadir>/db (RocksDB) مع الكتلة 0، وملاحظات الجينيسيس التسع بوصفها أوراق الشجرة الأولى (سبع ملاحظات RAND تحمل 5,184.243719258 RAND من محافظ المشغّلين على السلسلة 19، وملاحظتا zUSD بقيمة 10 و89 zUSD، أي 99 zUSD المقفلة في عهدة الجسر)، وسجل المدقّقين. إعادة التشغيل بالجينيسيس نفسه لا أثر لها؛ أما الجينيسيس المختلف فيُرفض (already initialized with a different genesis تعني أن دليل البيانات يعود إلى سلسلة أخرى). سمِّ دليل البيانات بأول ثمانية أحرف من بصمة الجينيسيس، كما يفعل الأسطول (data-<name>-6210cf07)، كي لا يتعارض أبدًا مع دليل السلسلة 19 (-a3defc93).

شكل ملف الجينيسيس:

{
  "chain_id": 20,
  "timestamp_ms": 1790835251661,
  "validators": [ { "public_key": "<hex>", "stake": 1000000000000, "payout": "rand1…" } ],
  "alloc": [ { "cm": "<64 hex>", "envelope": { "kem_ct": "…", "to_receiver": "…", "to_sender": "…", "body": "…" }, "amount": 1000000000000,
               "opening": { "pk": "<64 hex>", "time": 0, "r": "<64 hex>" } },
             { "cm": "…", "envelope": { … }, "amount": 1000000000,
               "opening": { "pk": "<64 hex>", "time": 0, "r": "<64 hex>", "asset": 1 } } ],
  "faucet": true,
  "confidential": true,
  "fri_profile": "production",
  "hc_bundle": "60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce",
  "bridge": { "emitter": "<64 hex>", "guardians": [ "<40 hex>" ], "emitters": { "2": "<64 hex>", "3": "…", "4": "…", "5": "…" },
              "pq_guardians": [ "<hex>" ], "pause_key": "<hex>",
              "rules_v2": { "global_mint_cap_per_window": 400000000000, "cap_window_secs": 86400 },
              "guardian_set_index": 1, "burn_sequence": 13,
              "min_inbound_sequence": { "2": 3, "3": 3, "4": 3, "5": 7 },
              "rotation": { "delay_secs": 86400, "needs_possession": true },
              "fees": { "mint_bps": 10, "burn_bps": 10, "recipient": "rand1…" } },
  "tokens": { "registration_fee": 1000000000, "mint_cap_per_day": 10000000000000,
              "tokens": [ { "name": "Shielded USD", "symbol": "zUSD", "salt": "<64 hex>",
                            "backings": [ { "chain": 2, "token": "<64 hex>", "decimals": 6 }, … ] } ],
              "max_tokens": 4096, "burn_registration_fee": true, "bound_note_value": true },
  "consensus_domain": 1,
  "staking": { "faucet_budget_per_epoch": "10000000000000", "bond_activation_epochs": 2,
               "max_weight_bps": 3333, "registration_v2": true,
               "faucet_recipients": [ "rand1…" ], "faucet_minters": [ "<validator address>" ],
               "max_stake_entry_bps_per_epoch": 2500, "admission_by_vote": true },
  "epoch_blocks": 1000,
  "max_program_words": 65535,
  "max_proof_bytes": 4194304,
  "max_block_bytes": 20971520,
  "max_call_envelope_bytes": 65536,
  "max_program_public_words": 32768,
  "envelope_bytes": 1860,
  "hardening_v6": true,
  "hc_auth": "1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1",
  "gas": { "gas_price": "100", "byte_price": "800", "bundle_gas_limit": 20479, "metering": "circuit",
           "dynamic": { "target_block_bytes": 10485760, "target_block_gas": 262144,
                        "adjust_bps": 1250, "min_gas_price": "100", "min_byte_price": "800",
                        "max_gas_price": "10000", "max_byte_price": "80000", "byte_load": "paying" } },
  "testnet": true,
  "binding_domain": 1,
  "proof_window_blocks": 1024,
  "program_state": { "cell_fee": 10000000 }
}

كل حقل داخل بصمة الجينيسيس. يثبّت hc_bundle الـ guest الذي يُفحص به كل إثبات حزمة، ويثبّت hc_auth الـ guest الذي يُفحص به كل إثبات تفويض؛ والعقدة التي يجمّع بناؤها guest مختلفًا ترفض البدء وتذكر البصمتين. الحقول الخمسة max_* اختيارية ولا تدخل في البصمة إلا إذا وُجدت؛ والسلسلة 20 تضبطها كلها. قيمة max_proof_bytes هي 4 MiB، بينما كانت 8 MiB في السلاسل من 13 إلى 16: فمنذ السلسلة 17 يمكن أن تحمل المعاملة ثلاثة إثباتات (الحزمة والتفويض والاستدعاء)، ويجب أن يكون max_block_bytes في جينيسيس يحمل hc_auth ثلاثة أمثال max_proof_bytes زائد 1 MiB على الأقل. تحمل كل ملاحظة في alloc قيمة opening الخاصة بها (pk وtime وr، وasset لملاحظة الرمز)، فمالك ملاحظة الجينيسيس ومبلغها علنيان بالتصميم. تتضمن السلسلة 20:

  • قسم bridge: مجموعة الحراس 1 عند الفهرس 1 بثمانية حراس، وجهات إصدار لسلاسل المصدر 2 و3 و4 و5 (كما في السلسلة 19)، وثمانية pq_guardians من نوع Dilithium2، وpause_key، وburn_sequence بقيمة 13، وmin_inbound_sequence بقيمة 3 لسلاسل المصدر 2 و3 و4 و7 لسلسلة المصدر 5، وrules_v2 (سقف سك شامل قدره 4,000 zUSD لكل نافذة 24 ساعة). الجديد في السلسلة 20: rotation، وبموجبه يحتاج تدوير مفتاح PQ-guardian أو مفتاح الإيقاف المؤقت إلى إثبات حيازة من المفاتيح الجديدة ويسري بعد 86,400 ثانية من تثبيته؛ وfees، وبموجبه تحتفظ السلسلة بـ 10 bps من كل إيداع و10 bps من كل حرق في صورة ملاحظة zUSD إلى عنوان خزينة، فيُقيَّد للإيداع إجماليه ناقص الرسم، ويُفرَج بالحرق عن مبلغه ناقص الرسم؛
  • قسم tokens: رسم تسجيل قدره 1 RAND يُحرَق ولا يُدفع إلى المقترِح؛ وmint_cap_per_day قدره 100,000 رمز لكل تغطية بثماني خانات عشرية؛ وسقف للسجل قدره 4,096 رمزًا؛ وحدّ قيمة الملاحظة 2^63؛ وإدراج zUSD في الجينيسيس بتغطياته السبع، مع 99 zUSD مقفلة (Ethereum USDT 22 وBSC USDT 22 وTron USDT 30 وSolana USDT 25) مقابل ملاحظتَي zUSD في الجينيسيس؛
  • consensus_domain: 1: كل توقيع إجماع مرتبط بهذا الجينيسيس (الإجماع)؛
  • قسم staking: الـ faucet مدرج في قائمة سماح تضم 16 محفظة و18 مفتاح مدقّق سكّ، بميزانية 10,000 RAND لكل حقبة، وتأخير ربط قدره حقبتان، وسقف وزن 3,333 bps، وتسجيلات v2، كما في السلسلة 19؛ والجديد في السلسلة 20 هو admission_by_vote (لا يُسجَّل مفتاح مدقّق جديد إلا بعد أن تصوّت مجموعة المدقّقين على قبوله) وميزانية دخول قدرها 2,500 bps من الوزن الفعّال عند كل حد حقبة، بينما كانت في السلسلة 19 ثابتة عند 10,000 RAND (Staking). ولا يوجد slashing؛
  • قسم gas: تدفع المكالمة ثمن حد الغاز الذي يعلنه إثباتها وثمن بايتاتها، بأسعار تبدأ عند 100 وحدة لكل غاز و800 وحدة لكل KiB وتتحرك بعد كل كتلة بحسب امتلائها قياسًا إلى هدف قدره 10,485,760 بايتًا و262,144 غازًا، بما لا يزيد على 1,250 bps في الكتلة، ولا تنزل أبدًا دون الأسعار الابتدائية، والجديد في السلسلة 20 أنها لا تعلو أبدًا فوق 10,000 و80,000. لا يُحتسب في حمل سعر البايت إلا البايتات التي تدفع سعر بايت، أي إثبات المكالمة ومغلّف مدخلاتها (byte_load: "paying"). يعلن كل إثبات حزمة الحد نفسه، 20,479 (الرسوم)؛
  • envelope_bytes: 1860: كل مغلّف ملاحظة حجمه 1,860 بايتًا بالضبط ويحمل حقل مذكرة مشفّرًا؛
  • hardening_v6: true، مفتاح التحصين في v0.6، وقد ضبطته كل سلسلة منذ السلسلة 16؛
  • testnet: true، العلامة التي تسمح بوجود faucet بجوار قسم جسر؛
  • binding_domain: 1: تتضمن إثباتات كل معاملة وكل رسالة إجراء موقّعة بصمة الجينيسيس، فلا يصح على سلسلة أخرى ما أُثبت أو وُقّع لسلسلة؛
  • proof_window_blocks: 1024: يجوز أن يكون مرساة الحزمة أحد آخر 1,024 جذر نهاية كتلة، وأن يتأخر time فيها حتى 1,024 كتلة عن الارتفاع (256 في السلسلة 19)، وهو ما يمنح المُثبِت البطيء أو المفوَّض نحو عشرين دقيقة؛
  • program_state، RPL-2: خلايا البرامج وخزائن البرامج وإجراء Invoke، برسم خلية قدره 0.1 RAND عن كل خلية ينشئها استدعاء (JSON-RPC فيه الحدود).

وليس فيه قسم aggregation، ويرفض البناء البدء على جينيسيس يحمله.

timestamp_ms هو نقطة الصفر لساعة السلسلة. عندما تُنشئ genesis خاصًا بك، اضبطه قريبًا من وقت الإطلاق الفعلي، ولا تضبطه قبله أبدًا. إن كان بعيدًا في الماضي، يتأخر زمن الكتل عن الساعة الفعلية إلى أن يتيح لها حدّ الخطوة البالغ 60 s لكل كتلة اللحاق به. وإن زاد على 15 ثانية في المستقبل، فلن تُثبَّت الكتلة 1 إطلاقًا: يُحجب كل تصويت، بما فيه تصويت القائد، إلى أن يبلغ الوقت الفعلي طابع genesis الزمني. تحقق منه على ساعة الجهاز الذي يطلق الأسطول، لا الجهاز الذي أنشأ الملف.

التشغيل

rand-node run --datadir ./data --key node.key.json \
    --listen /ip4/0.0.0.0/tcp/30303 --rpc 127.0.0.1:8545 --no-mdns \
    --bootstrap /ip4/164.90.239.200/tcp/30303/p2p/12D3KooWEQEbUwZRgqhDPXhW7vNBmcRcnhUDGUADe81VFdv3ALYe \
    --bootstrap /ip4/165.245.173.74/tcp/30303/p2p/12D3KooWJyc5oDHggAr89e9QrRFBy9Tg8TxXh18yzrb1SM6KKLYw \
    --bootstrap /ip4/188.166.235.187/tcp/30303/p2p/12D3KooWSyX84P1DAbWByLHpRBMLRWD53r3Jj4aqVt6tHoF8B2ZQ
المعاملالقيمة الافتراضيةالمعنى
--datadirمطلوبدليل البيانات الذي جرت تهيئته
--keyمطلوبملف المفتاح: هوية المدقِّق (validator)، وهوية p2p، ومستلم الرسوم
--listen/ip4/0.0.0.0/tcp/30303عنوان libp2p المتعدد (multiaddr) للاستماع، ويمكن تكراره
--bootstrapلا شيءنظير يُتصل به عند البدء وكل 30 s ما دام الاتصال مقطوعًا، ويمكن تكراره
--rpc127.0.0.1:8545مستمع JSON-RPC وWebSocket الخاص بالمشغّل: يتيح كل الطرق ويثق بحلقة loopback. أبقِه على loopback، ولا توجّه إليه نقطة وصول عامة أبدًا
--public-rpc <ADDR>معطّلv0.6.8: مستمع ثانٍ عام ليشير إليه وكيل عكسي أو توجيه SSH: مجموعة طرق ثابتة بلا طرق مفتاح العرض ولا rand_mint ولا rand_getPeers، ولا دفعات، ولا WebSocket، وعدّاد واحد لجميع المستدعين (JSON-RPC)
--rpc-viewing-token-file <PATH>معطّلv0.6.8: يشترط رمز حامل (bearer token) (السطر الأول من الملف، 32 حرفًا أو أكثر) على طرق مفتاح العرض في --rpc
--reserved-peer <PEER_ID>لا شيءv0.6.8، ويمكن تكراره: نظير يُقبل متجاوزًا سقف الاتصالات الواردة؛ انظر النظراء المحجوزون
--strict-gossipمعطّلv0.6.8: لا يقبل إلا الـ gossip ذا توقيع مؤلف ورقم تسلسلي ومصدر صالحة؛ ويُطبَّق عقدة بعد عقدة
--validatorمعطّلتحمل هذه العقدة مفتاح مدقِّق وتشارك في الإجماع حين يكون مفتاحها في المجموعة الحالية
--no-mdnsمعطّليعطّل الاكتشاف في الشبكة المحلية؛ يُوصى به على الخوادم
--block-interval-ms1000الحد الأدنى للفاصل بين المقترحات
--view-timeout-ms3000مهلة العرض (view) الأساسية، وتتضاعف مع كل مهلة متتالية حتى 8×
--verify-chainquickفحص السلامة عند البدء: off، وquick (البنية وإعادة تشغيل دفتر الأستاذ)، وfull (ويشمل كل توقيع وكل QC)
--keep-raw-proofsمعطّلوضع الأرشيف لتجميع الكتل؛ لا أثر له على السلسلة 20
--prune-historyمعطّل (يُحتفظ بكل شيء)يُبقي دفتر الأستاذ وهذا القدر فقط من تاريخ الكتل: <n>m أو <n>h أو <n>d، على ألا يقل عن 1h. يشغّل مدقِّقو testnet القيمة 24h، عدا الأرشيفين؛ انظر تقليم التاريخ
--min-free-disk-mb1024يرفض البدء إن قلّت المساحة الحرة في نظام ملفات دليل البيانات عن هذا القدر؛ ويجيب rand_getHealth بـ disk_low دون أربعة أمثاله. القيمة 0 تعطّل هذا الحارس
--prover <ADDR>معطّليستضيف مُثبِتًا (prover) مفوَّضًا على هذا العنوان، وهو مستمع مستقل وليس RPC أبدًا؛ انظر أدناه
--gas-price, --byte-price100, 800الحد الأدنى للسعر في المجمّع (pool) لاستدعاء على سلسلة بلا قسم gas. يحدّد genesis السلسلة 20 أسعارها بنفسه، فتتجاهل العقدة العلَمين هناك وتسجّل تحذيرًا

--prover-accept-spend-key أُلغي: العقدة v0.6.8 التي يُمرَّر إليها ترفض البدء، فأزِله من أي ملف وحدة منقول من v0.6.7.

نقاط الإقلاع الثلاث أعلاه هي المدقِّقون C وD وE، دون تغيير عن السلسلة 19. تعمل السلسلة 20 على مفاتيح المدقِّقين المولَّدة للسلسلة 14، فمعرّفات نظرائها هي نفسها التي استخدمتها السلسلة 14؛ فهوية p2p مشتقة من مفتاح المدقِّق. يحتفظ أغلب المدقِّقين بيوم واحد فقط من الكتل، فالعقدة التي تتزامن من genesis، أو التي تأخرت أكثر من يوم، تحتاج أيضًا إلى نظير يحتفظ بالتاريخ كاملًا. أضف أحد الأرشيفين:

    --bootstrap /ip4/168.144.46.203/tcp/30303/p2p/12D3KooWS5usdMPvsbaWSaT2xtKndHvDYurwmueoNvaRRarb2wRf    # obs1
    --bootstrap /ip4/206.81.29.236/tcp/30303/p2p/12D3KooWPocyZGcNB9Vp68VSfgVvNXhSzBBoJa4h9R1yMkp71XHh    # rand-archive-2

احذف --validator لتشغيل مراقِب (observer). مراحل البدء: فتح التخزين، والتحقق من حواسيس (guests) هذا البناء مقابل hc_bundle وhc_auth في genesis، وتشغيل فحص السلامة (مع بتر الذيل التالف والإبقاء على حالة سلامة التصويت)، واستئناف الإجماع من الرأس المحفوظ، وبدء الشبكة وRPC، ثم التزامن مع أي نظير متقدم. القيمة الافتراضية لـ RUST_LOG هي info,libp2p=warn,libp2p_mdns=off؛ ويؤدي Ctrl-C أو SIGTERM، إشارة الإيقاف في systemd، إلى إيقاف نظيف. وإعادة التشغيل من --datadir نفسه تستأنف من الرأس المحفوظ.

قواعد الطوبولوجيا من العقدة الكاملة: تتصل العقد الواقعة خلف NAT بالعقد ذات العناوين العامة؛ افتح TCP 30303 للوارد على العقد العامة؛ اربط RPC بـ 127.0.0.1 ما لم يكن محميًا بجدار ناري — فهو يقبل المعاملات من كل من يصل إليه، وبمجرد استيراد مفتاح عرض إليه، عامِل المنفذ على أنه حامل لمفاتيح. أبقِ --block-interval-ms عند 1000 أو أبطأ: إثبات الحزمة يستغرق نحو دقيقتين، ومرساته صالحة لمدة 1,024 كتلة على السلسلة 20 (و256 على السلسلة 19).

يحتاج المدقِّق إلى ساعة متزامنة. منذ السلسلة 14 صار وقت الساعة الفعلي جزءًا من الإجماع (تحصين الجسر B2). الكتلة التي يزيد طابعها الزمني على طابع أبيها بأكثر من 60 s غير صالحة، ويحجب المدقِّق تصويته عن كتلة يتقدم طابعها الزمني على ساعته بأكثر من 15 s. لذا فالمدقِّق الذي تبطئ ساعته يتوقف عن التصويت دون تسجيل أي خطأ، ويجب أن يصوّت ستة وعشرون مدقِّقًا من ثمانية عشر…

أصحّح الجملة الأخيرة: ويجب أن يصوّت ثمانية عشر من أصل ستة وعشرين لتثبيت كتلة على السلسلة 20. شغّل NTP على كل مدقِّق وتحقق منه قبل بدء العقدة:

timedatectl                     # want "System clock synchronized: yes" and "NTP service: active"
chronyc tracking
apt-get install -y chrony && systemctl enable --now chrony    # if it is not synchronised

النظراء المحجوزون

منذ v0.6.8 تقبل العقدة 256 اتصالًا واردًا مستقرًا و64 اتصالًا نصف مفتوح كحد أقصى، وإنشاء هوية libp2p لا يكلّف شيئًا، فكان بإمكان الغرباء شغل كل الخانات. تُحجز ثلاثة أنواع من النظراء، فتُقبل متجاوزة السقف وتُخدَم من حصة المدقِّقين في ميزانية التزامن: كل نظير --bootstrap، وكل --reserved-peer، وكل هوية مدقِّق عُرفت من ربط نظير موقَّع. توقّع كل عقدة --validator هويتها في libp2p بمفتاح المدقِّق وتبثّها بـ gossip؛ والعقدة التي تعرف المفتاح من مجموعة مدقِّقين تحجز ذلك النظير وتحتفظ بالسجل عبر إعادة التشغيل. لا يحوي مخزن سلسلة حديثة القطع أي ارتباطات، فإلى أن تصل الإعلانات الأولى لا يُحجز إلا النوعان الأولان: عند القطع، مرّر معرّفات نظراء مدقِّقي الأسطول بـ --reserved-peer أو أبقها في قائمة bootstrap (الأمر rand-node address --key <file> يطبع معرّف نظير المفتاح). يعدّها الحقل rand_status.reserved_peers؛ وعلى عقدة في الأسطول ينبغي أن يبلغ عدد المدقِّقين خلال دقيقة من البدء.

تحقق منه

rand-node status                # rand_status verbatim
rand --rpc http://127.0.0.1:8545 status
rand peers

يُبلغ rand_status عن height وview وsyncing وsync_target وpeer_count وconnected_peers وreserved_peers وmempool_size وis_validator وactive_validator وfaucet وconfidential وtestnet وfri_profile وprograms وnotes وnullifiers وtree_root وhc_bundle وhc_auth وbinding_domain وgas_prices، وaddress وpeer_id الخاصين بالعقدة، وتشخيصات التزامن (sync_inflight_age_ms وsync_failures وsync_late_batches)، والقرص (disk_free_bytes وdisk_low)، وحدّ الاحتفاظ (prune_floor، وقيمته 0 على عقدة تحتفظ بكل شيء؛ وprune_history_secs، وقيمته null عند عدم الضبط). على السلسلة 20 توقّع hc_bundle 60af094a… وhc_auth 1e4e347f… وfaucet true وconfidential true وtestnet true وbinding_domain 1 وfri_profile "production"، وgas_prices بين 100 و10,000 لكل gas وبين 800 و80,000 لكل KiB. ويجب أن يجيب rand_getGenesisHash بـ 6210cf07…5135 وrand_getVersion بـ 0.6.8.

يجيب rand_getHealth بـ disk_low (مع free_bytes) قبل ok أو syncing أو behind حين تقل المساحة الحرة عن أربعة أمثال --min-free-disk-mb.

تقليم التاريخ

العقدة التي تبدأ بـ --prune-history 24h تُبقي دفتر الأستاذ (الملاحظات والمُبطِلات والمراسي وسجل المدقِّقين والبرامج) كاملًا وتحذف الكتل الأقدم وشهاداتها ومعاملاتها وإيصالاتها. تجري عملية التقليم عند كل كتلة مثبَّتة سادسة عشرة، وتحذف حتى 512 كتلة أقدم من الطابع الزمني للرأس مطروحًا منه النافذة؛ ولا يُحذف genesis ولا الرأس ولا أبوه أبدًا، ولا يرتفع الحد إلا صعودًا. تعود المساحة بعد أن يضغط RocksDB بياناته. على السلسلة 20، كما على السلسلة 19، يشغّل 24 من المدقِّقين الـ 26 القيمة 24h ويحتفظون بنحو يوم من الكتل. عندما فُعّل التقليم للسلسلة 14 (2026-09-25)، انخفضت جداول الكتل لدى كل مدقِّق من 19 GB إلى 3.3–4.4 GB بعد تصريف المتراكم؛ أما الآخران، obs1 وrand-archive-2، وهما مدقِّقان أيضًا منذ 2026-09-27، فيعملان بلا العلَم ويحتفظان بكل شيء. عقدة mainnet لا تمرّر العلَم أبدًا.

على عقدة مقلَّمة، يجيب البحث المعنون بالارتفاع دون الحد (rand_getBlockByHeight، وrand_getFinality بالارتفاع، ونطاق rand_getBlocks أو rand_getCompactBlocks الذي يبلغه) بالخطأ -32010 مع data.floor: اسأل أرشيفًا. أما البحث المعنون بالتجزئة فيجيب بـ null عن كتلة لم تعد العقدة تحتفظ بها، كما لو لم توجد قط. ولا يتأثر مسح المحفظة، لأن الملاحظات والمُبطِلات لا تُقلَّم أبدًا.

فحص البدء في العقدة المقلَّمة بنيوي (الكتلة 0 والكتل المحتفظ بها وQCs الخاصة بها وروابط الآباء والقادة)، وليس إعادة تشغيل من genesis، ولا يصلح نفسه: إن فشل، أعد التزامن من أرشيف. لا تفتح دليل بيانات مقلَّمًا ببناء أقدم من v0.5.7 ما لم يعمل بـ --verify-chain off: فاختباره الافتراضي يعيد التشغيل من genesis، فيجد الكتلة 1 مفقودة، ويبتر دفتر الأستاذ إلى genesis.

استضافة مُثبِت

على السلسلة 20 تُنشئ المحفظة إثباتين لكل حزمة، ويحتاج الأكبر منهما إلى نحو 6 GB من الذاكرة. والمحفظة التي لا تتسع له يمكنها تسليم ذلك الإثبات إلى مُثبِت مفوَّض مقترن بها: الملف التنفيذي المستقل rand-prover، أو الخدمة نفسها تستضيفها عقدة.

rand-prover --home /root/prover keygen
rand-prover --home /root/prover pair --name laptop --url https://prover.example.net
rand-node run --datadir ./data --key node.key.json --prover 127.0.0.1:8600 --prover-home /root/prover

تطبع pair رابطًا من الشكل randprover:. تأخذه المحفظة بالأمر rand prover pair <link> ثم تُنشئ الإثباتات عبره بالخيار العام --prover. المنفذ الذي يستمع عليه المُثبِت منفذه الخاص، وليس أبدًا إحدى طرق RPC: يُرفض أي عنوان يساوي --rpc. ومع --prover تمتنع العقدة عن البدء ما لم يوجد <prover-home>/prover.key.json (الافتراضي <datadir>/prover) وما لم يتوفر 5.74 GB لكل خانة إثبات إضافة إلى 1 GiB من الذاكرة؛ ويحدد --prover-max-parallel عدد الخانات، وهي خانة واحدة افتراضيًا.

في السلسلة 20 يُرسَل إلى المُثبِت مفتاح العرض الخاص بالمحفظة وملح جديد (salt)، لا مفتاح الإنفاق. وتُنشئ المحفظة بنفسها إثبات التفويض على مفتاح الإنفاق، ولذلك يستطيع المُثبِت المقترن أن يقرأ سجل تلك المحفظة كاملًا ولا يستطيع أن ينفق. أبقِ المنفذ على loopback ما لم يكن أمامه وكيل ينهي TLS، ولا تستضفه على جهاز يخدم RPC عامًا. وينتظر الإيقاف انتهاء الإثبات الجاري، فاضبط في وحدة systemd القيمة TimeoutStopSec=180.

التحقق والإصلاح

rand-node verify --datadir ./data                  # full: hashes, QCs, signatures, proofs, ledger replay, the supply counters
rand-node verify --datadir ./data --mode quick     # structure and ledger replay
rand-node verify --datadir ./data --repair         # truncate a damaged tail; peers resync the rest

أوقف العقدة أولًا. رمز الخروج 0 إذا كانت الحالة متسقة، و2 إذا وُجدت مشكلة ولم يُعطَ --repair. تعيد إعادة التشغيل (replay) التحقق من إثبات كل حزمة، ولذلك فإن أي بناء تختلف مجموعة قيوده عن المجموعة التي أنتجت السلسلة يتوقف عند أول حزمة.

أن تصبح مدقِّقًا (validator)

ينضم المدقِّق إلى سلسلة قيد التشغيل بالربط (bonding) لا بتكوين أولي (genesis) جديد: شغّل العقدة بالخيار --validator، واطبع تسجيلًا بالأمر rand-node register --key node.key.json --payout <rand1…> --v2 (ترفض السلسلة 20 تسجيل v1)، واجعل محفظة تربط ما لا يقل عن 1,000 RAND بالأمر rand bond <address> 1000 --registration <hex>، وتبدأ العقدة بالاقتراح حين يتفعّل الربط: في السلسلة 20 بعد ثلاث حدود حقب (epochs) من 1,000 كتلة بعد الربط على أقرب تقدير. وفي السلسلة 20 يأتي الربط ثانيًا. فالتكوين الأولي لها يضبط staking.admission_by_vote، ولذلك يُرفض الربط الذي يسجّل مفتاحًا جديدًا إلى أن يصوّت لقبول المفتاح مدقِّقون يملكون أكثر من ثلثي وزن التصويت: يوقّع كل منهم بالأمر rand-node admit sign --candidate <key or registration> --key <validator key> --genesis-hash 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135، ويرسل أحدهم الأصوات بالأمر rand-node admit submit (سطر الأوامر). وتسرد rand_getAdmitted المفاتيح التي صُوِّت لقبولها ولم تُسجَّل بعد. ولا يصير أكثر من 2,500 bps من الوزن الفعّال وزنًا جديدًا عند حد حقبة واحد. ويشرح الرهن ذلك خطوة بخطوة. وأما لسلسلة اختبار خاصة بك، فيُنشئ rand-node genesis تكوينًا أوليًا:

rand-node genesis --chain-id 88 \
    --validator a.key.json,1000,rand1<a's payout address> \
    --validator <hex public key of b>,1000,rand1<b's payout address> \
    --alloc rand1<address>=1000 \
    --epoch-blocks 1000 --faucet --fri-profile production \
    --out genesis.json

ويشغّل scripts/local-testnet.sh مدقِّقَين على جهاز واحد مع RPC على المنفذين 8545 و8546. وبلا خيارات إضافية لا يحتوي التكوين الأولي على hc_auth ولا على قسم gas ولا على memo. وقد قُطعت السلسلة 20 بالخيارات --hardening-v6 --bundle-guest v3 --auth-guest --gas-price 100 --byte-price 800 --bundle-gas-limit 20479 --gas-dynamic 10485760,262144,1250 --max-gas-price 10000 --max-byte-price 80000 --gas-byte-load paying --envelope-bytes 1860 --testnet --binding-domain 1 --proof-window-blocks 1024 --program-state-cell-fee 10000000 فوق ذلك (وكانت للسلسلتين 18 و19 الخيارات حتى --envelope-bytes)، أما قسما bridge وstaking وconsensus_domain فقد أُدرجت بنص القطع (cut script). وينبغي لسلسلة جديدة خاصة بك أن تمرّر --binding-domain 1: فمحفظة v0.6.8 تُنشئ الإثبات بالصيغة المرتبطة بالتكوين الأولي على كل معرّف سلسلة خارج النطاق من 14 إلى 19.

النشر على خادم

يحتوي المجلد deploy/ في المستودع على النصوص التي يستخدمها الأسطول: يجهّز deploy/push-to-vps.sh <ip> <letter> "<bootstraps>" [validator|observer] خادم Linux (ينسخ المصدر بـ rsync، ثم يبني، ويثبّت /usr/local/bin/{rand-node,rand}، ويهيّئ datadir مفهرسًا بتجزئة التكوين الأولي، ويثبّت خدمة systemd باسم rand-node)، ويعيد deploy/rebuild-vps.sh <ip> البناء عند وجود commit جديد ويعيد التشغيل مع الإبقاء على البيانات. وهناك تنبيهان. فنص التجهيز يهيّئ من deploy/genesis.json، وهذا ليس ملف السلسلة 20، ولذلك تُعدّ عقدة الـ testnet يدويًا من deploy/genesis-chain20.json (على main، انظر أعلاه). وكلا النصّين ينسخ /root/fullnode بـ rsync مع --delete، ولذلك يُحذف أي مفتاح محفوظ داخل تلك الشجرة عند إعادة البناء التالية: احفظه في /root/keys كما يفعل الأسطول وكما يفعل الآن نص التجهيز في v0.6.8 افتراضيًا (أما نص v0.6.7 فكان يكتب المفتاح تحت /root/fullnode/deploy/). وإدارة الخدمة تكون بـ systemctl status rand-node وjournalctl -u rand-node -f. ويحتاج الخادم إلى build-essential clang cmake pkg-config libssl-dev وسلسلة أدوات Rust. ولا يستطيع خادم بمعالج افتراضي واحد وذاكرة 2 GB بناء الملفات التنفيذية؛ فابنِها في مكان آخر وانسخها إليه. ويتضمن تشغيل مدقِّق ومُجمِّع الأحجام والإعداد خطوة بخطوة.

المستكشف

يعمل randscan.org بجوار المدقِّق E ويفهرس السلسلة 20؛ وتُعدّ واجهته REST وتغذية WebSocket أيسر طريق لقراءة السلسلة دون عقدة (واجهة Explorer API). والمستكشف مفتوح المصدر (randprotocol/randscan)، ولا يحتاج مفهرسه إلا إلى rand_* JSON-RPC لدى عقدة وإلى قاعدة بيانات PostgreSQL، ولذلك يمكن تشغيله على عقدتك أنت.

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