Rand Protocol
مستندات
راهنماها

راه‌اندازی و اجرای یک نود

باینری‌ها را بسازید، یک کلید بسازید، یک دایرکتوری داده را از genesis زنجیرهٔ 20 مقداردهی اولیه کنید، به bootstrapها متصل شوید، RPC را متصل کنید، تاریخچه را هرس کنید و زنجیره را راستی‌آزمایی کنید - چه به‌عنوان ناظر و چه به‌عنوان validator.

از این صفحه برای اجرای rand-node خودتان روی testnet استفاده کنید. این روش توصیه‌شده برای استفادهٔ خصوصی از کیف پول هم هست: گرهٔ خودتان جز خودتان از هیچ‌کس نمی‌فهمد کدام برگ را می‌خواهید خرج کنید. یک observer همگام می‌شود، همهٔ اثبات‌ها را دوباره راستی‌آزمایی می‌کند و JSON-RPC را سرو می‌کند؛ یک اعتبارسنج همین کارها را انجام می‌دهد و پس از آنکه کلیدش در مجموعهٔ یک epoch قرار گرفت، در اجماع هم شرکت می‌کند.

ساخت

پیش‌نیازها: Rust 1.98.1 (در rust-toolchain.toml ثابت شده است و rustup آن را نصب می‌کند)، یک کامپایلر C++ و cmake برای RocksDB. کریت zkVM وابستگی‌هایی با مسیر محلی به یک checkout هم‌جوار به نام circuits/ از مخزن سامانهٔ اثبات (randprotocol/zkp-circuits) دارد. این checkout باید کنار fullnode/ قرار بگیرد و روی همان commit باشد که نسخه از آن vendor شده است: خط circuits: در crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md (برای v0.6.8 همان aeacf31 است، مانند v0.6.7). نخستین ساخت ۱۰ تا ۲۰ دقیقه طول می‌کشد.

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، commit با شناسهٔ c9c9bd3c، نسخه‌ای است که ناوگان اجرا می‌کند؛ rand_getVersion شای گره را گزارش می‌دهد). انتشار آن در GitHub شامل rand-node، rand، rand-prover و SHA256SUMS است که روی یک میزبان ناوگان ساخته شده‌اند و امضا ندارند. زنجیرهٔ 20 به آن نیاز دارد: genesis آن فیلدهایی دارد که هیچ ساخت قدیمی‌تری آن‌ها را نمی‌خواند (testnet، binding_domain، proof_window_blocks، program_state، گروه‌های rotation و fees در bridge، سقف‌های gas و پذیرش staking با رأی)، و v0.6.8 تغییرات اجماعی دارد که گرهٔ قدیمی‌تر اجرا نمی‌کند. اثبات‌ها هنوز تحت مجموعه‌قید 8 ساخته می‌شوند، مانند زنجیره‌های 18 و 19، و هر بسته (bundle) هنوز در کنار اثبات بسته‌اش یک اثبات احراز اختیار هم دارد (احراز اختیار تفکیک‌شده، از زنجیرهٔ 17)، بنابراین genesis همان دو guest را ثابت می‌کند: guest بستهٔ نسخهٔ 3 (hc_bundle 60af094a…) و guest احراز (hc_auth 1e4e347f…). genesis همچنین یک بخش gas، hardening_v6 و envelope_bytes دارد. ساخت v0.6.8 در run و در verify با بررسی هش، genesis زنجیره‌های 14، 15، 16 و 17 را رد می‌کند؛ با این حال می‌تواند genesis زنجیرهٔ 19 را اجرا کند. هر گره باید ساخت ناوگان را اجرا کند.

زنجیرهٔ 20: یک hard fork با توقف کامل

زنجیرهٔ 20 در 2026-10-01 ساعت 06:17 UTC راه‌اندازی شد. این زنجیره از یک snapshot زنجیرهٔ 19 بریده شد و با روش توقف کامل و شروع کامل اجرا شد: هر گرهٔ زنجیرهٔ 19 در ارتفاع 7,700 متوقف شد و هر گره با v0.6.8 روی زنجیرهٔ 20 شروع به کار کرد. این یک به‌روزرسانی غلتان نبود و دو دلیل داشت. زنجیرهٔ 20 یک genesis جدید است و بنابراین هیچ بلوکی با زنجیرهٔ 19 مشترک نیست. و v0.6.8 تغییرات اجماعی از audit v6 دارد که هرگز نباید گره‌به‌گره پیاده شوند: CON-4 آزادسازی خودکار قفل یک اعتبارسنج را حذف می‌کند و CH-1 یک pacemaker مبتنی بر گواهی timeout اضافه می‌کند. هر 26 اعتبارسنج، کلیدها، شناسه‌های همتا و bootstrapها منتقل شدند؛ حد نصاب همچنان 18 از 26 است. زنجیره‌های 19 و 18 بازنشسته شده‌اند.

بنابراین انتقال یک گره از زنجیرهٔ 19 به زنجیرهٔ 20 به فایل اجرایی جدید، فایل genesis جدید و یک پوشهٔ دادهٔ تازه نیاز دارد، مطابق آنچه در ادامه آمده است. کیف‌پول‌ها برای ارسال روی زنجیرهٔ 20 به v0.6.8 نیاز دارند: genesis این زنجیره هر اثبات و هر پیام امضاشده را به هش خودش وابسته می‌کند (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؛ فقط seed محرمانه است. یک observer هم به کلید نیاز دارد، چون هویت p2p است. کلید گره کلید کیف پول نیست: برای کیف پول از rand keygen استفاده کنید.

کلید خودتان را بسازید و بیرون از checkout نگه دارید. مخزن fullnode دیگر هیچ کلیدی را دنبال نمی‌کند (audit v3، OPS-1): فایل‌های deploy/node-*.key.json و deploy/payout/*.key.json که برای زنجیره‌های 8 تا 13 commit شده بودند seedهای منتشرشده‌اند و نباید استفاده شوند. کلیدهای اعتبارسنج زنجیرهٔ 20 خارج از مخزن ساخته شدند و هرگز در مخزن نبوده‌اند: 26 اعتبارسنج genesis آن هجده کلیدی هستند که برای زنجیرهٔ 14 ساخته شدند و هشت کلیدی که در زنجیرهٔ 15 bond شدند و در هر برش بعدی منتقل شده‌اند.

از v0.6.8، دستور rand-node keygen فایل --out ای را که از قبل وجود دارد رد می‌کند؛ v0.6.7 بدون پرسش آن را بازنویسی می‌کرد. این فایل تنها نسخهٔ seed است. پیش از آنکه یک bond به آن وابسته شود، از آن نسخهٔ پشتیبان بگیرید.

مقداردهی اولیه از genesis

هر گره در یک زنجیره به فایل genesis کاملاً یکسان در سطح بایت نیاز دارد؛ rand-node init آن را در پوشهٔ داده کپی می‌کند و هش آن را چاپ می‌کند، که برای زنجیرهٔ 20 باید 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135 باشد. فایل همان deploy/genesis-chain20.json است (sha256 برابر 0020247a…3a21). این فایل همراه با سابقهٔ راه‌اندازی (commit با شناسهٔ 74cfaca0) و پس از tag، در شاخهٔ main مخزن fullnode commit شد؛ بنابراین checkout نسخهٔ 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، نُه یادداشت genesis به‌عنوان نخستین برگ‌های درخت (هفت یادداشت RAND که 5,184.243719258 RAND از کیف‌پول‌های اپراتور زنجیرهٔ 19 را حمل می‌کنند، و دو یادداشت zUSD به مقدار 10 و 89 zUSD، یعنی 99 zUSD قفل‌شده در امانت‌داری bridge) و ثبت اعتبارسنج‌ها می‌سازد. اجرای دوباره با همان genesis کاری انجام نمی‌دهد؛ genesis متفاوت رد می‌شود (پیام already initialized with a different genesis یعنی پوشهٔ داده متعلق به زنجیرهٔ دیگری است). پوشهٔ داده را مانند ناوگان با هشت نویسهٔ نخست هش genesis نام‌گذاری کنید (data-<name>-6210cf07) تا هرگز با پوشهٔ زنجیرهٔ 19 (-a3defc93) برخورد نکند.

شکل فایل genesis:

{
  "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 }
}

هر فیلد در هش genesis وارد شده است. hc_bundle guest بسته‌ای را ثابت می‌کند که هر اثبات بسته در برابر آن بررسی می‌شود، و hc_auth guest احرازی را که هر اثبات احراز در برابر آن بررسی می‌شود؛ گره‌ای که ساخت آن guest متفاوتی را مونتاژ کند، از شروع به کار خودداری می‌کند و هر دو digest را نام می‌برد. پنج فیلد max_* اختیاری‌اند و فقط در صورت وجود در هش وارد می‌شوند؛ زنجیرهٔ 20 هر پنج را تنظیم می‌کند. max_proof_bytes برابر 4 MiB است، در حالی که زنجیره‌های 13 تا 16، 8 MiB داشتند: از زنجیرهٔ 17 یک تراکنش می‌تواند سه اثبات حمل کند (بسته، احراز، فراخوانی)، و genesis ای که hc_auth دارد باید max_block_bytes ای دست‌کم سه برابر max_proof_bytes به‌علاوهٔ 1 MiB داشته باشد. هر یادداشت alloc، opening خود را (pk، time، r، و برای یادداشت توکن asset) حمل می‌کند، پس مالک و مقدار یک یادداشت genesis عمداً عمومی است. زنجیرهٔ 20 این موارد را دارد:

  • بخش bridge: مجموعهٔ نگهبانان 1 در اندیس 1 با هشت نگهبان، emitterها برای زنجیره‌های مبدأ 2، 3، 4 و 5 (از زنجیرهٔ 19)، هشت pq_guardians از نوع Dilithium2، یک pause_key، burn_sequence برابر 13، یک min_inbound_sequence برابر 3 برای زنجیره‌های مبدأ 2، 3 و 4 و برابر 7 برای زنجیرهٔ مبدأ 5، و rules_v2 (سقف کلی mint برابر 4,000 zUSD در هر پنجرهٔ 24 ساعته). تازه در زنجیرهٔ 20: rotation، که طبق آن چرخش یک PQ-guardian یا pause-key به اثبات تملک کلیدهای جدید نیاز دارد و 86,400 s پس از commit اعمال می‌شود؛ و fees، که طبق آن زنجیره 10 bps از هر واریز و 10 bps از هر burn را به‌صورت یک یادداشت zUSD برای نشانی خزانه نگه می‌دارد، به‌طوری که یک واریز، مبلغ ناخالص منهای کارمزد را اعتبار می‌دهد و یک burn مبلغ خود منهای کارمزد را آزاد می‌کند؛
  • بخش tokens: هزینهٔ ثبت 1 RAND که سوزانده می‌شود و به پیشنهاددهنده پرداخت نمی‌شود؛ mint_cap_per_day برابر 100,000 توکن برای هر پشتوانه با هشت رقم اعشار؛ سقف رجیستری 4,096 توکن؛ کران 2^63 برای مقدار یادداشت؛ و zUSD که در genesis با هفت پشتوانه‌اش ثبت شده است، با 99 zUSD قفل‌شده (Ethereum USDT 22، BSC USDT 22، Tron USDT 30، Solana USDT 25) در برابر دو یادداشت zUSD ی genesis؛
  • consensus_domain: 1: هر امضای اجماع به این genesis وابسته است (اجماع)؛
  • بخش staking: faucet در فهرست مجاز 16 کیف پول و 18 کلید اعتبارسنج mint‌کننده، با بودجهٔ 10,000 RAND در هر epoch، تأخیر bond دو epoch، سقف وزن 3,333 bps و ثبت‌نام‌های v2، مانند زنجیرهٔ 19؛ تازه در زنجیرهٔ 20، admission_by_vote (یک کلید اعتبارسنج جدید فقط پس از آنکه مجموعهٔ اعتبارسنج‌ها به آن رأی دهند ثبت می‌شود) و بودجهٔ ورود برابر 2,500 bps از وزن فعال در هر مرز epoch، در حالی که زنجیرهٔ 19 مقدار ثابت 10,000 RAND داشت (Staking). slashing وجود ندارد؛
  • بخش gas: یک فراخوانی برای محدودیت gas ای که اثباتش اعلام می‌کند و برای بایت‌هایش پرداخت می‌کند، با قیمت‌هایی که از 100 واحد به ازای هر gas و 800 واحد به ازای هر KiB شروع می‌شوند و پس از هر بلوک بر اساس پر بودن آن در برابر هدف 10,485,760 بایت و 262,144 gas، حداکثر به اندازهٔ 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 کنار یک بخش bridge قرار بگیرد؛
  • binding_domain: 1: اثبات‌های هر تراکنش و هر پیام اقدام امضاشده هش genesis را شامل می‌شوند، بنابراین هر چیزی که برای یک زنجیره اثبات یا امضا شده باشد روی زنجیرهٔ دیگر راستی‌آزمایی نمی‌شود؛
  • proof_window_blocks: 1024: لنگر (anchor) یک بسته می‌تواند یکی از 1,024 ریشهٔ پایان بلوک آخر باشد و time آن تا 1,024 بلوک عقب‌تر از ارتفاع (256 در زنجیرهٔ 19)، که به یک prover کند یا تفویض‌شده حدود بیست دقیقه فرصت می‌دهد؛
  • program_state، RPL-2: سلول‌های برنامه، گاوصندوق‌های برنامه و اقدام Invoke، با کارمزد سلول 0.1 RAND برای هر سلولی که یک invoke می‌سازد (JSON-RPC محدودیت‌ها را دارد).

بخش aggregation ندارد، و ساخت از شروع روی genesis ای که چنین بخشی داشته باشد خودداری می‌کند.

timestamp_ms صفر ساعت زنجیره است. وقتی جنسیس خودتان را می‌سازید، آن را نزدیک به زمان واقعی راه‌اندازی تنظیم کنید و هرگز جلوتر از آن نگذارید. اگر بیش از حد در گذشته باشد، زمان بلاک از ساعت دیواری عقب می‌ماند تا زمانی که حد ۶۰ ثانیه برای هر گام بلاک اجازه دهد به آن برسد. اگر بیش از ۱۵ ثانیه در آینده باشد، بلاک ۱ اصلاً کامیت نمی‌شود: هر رأی، از جمله رأی لیدر، تا رسیدن ساعت دیواری به زمان جنسیس نگه داشته می‌شود. آن را با ساعت ماشینی که ناوگان را راه‌اندازی می‌کند بسنجید، نه ماشینی که فایل را ساخته است.

اجرا

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الزامیفایل کلید: هویت اعتبارسنج، هویت p2p، دریافت‌کننده‌ی کارمزد
--listen/ip4/0.0.0.0/tcp/30303multiaddr شنود libp2p، قابل تکرار
--bootstrapهیچهمتایی که در آغاز و در هر ۳۰ ثانیه تا زمان قطع بودن اتصال به آن متصل می‌شود، قابل تکرار
--rpc127.0.0.1:8545شنونده‌ی JSON-RPC و WebSocket اپراتور: همه‌ی متدها را ارائه می‌دهد و به loopback اعتماد می‌کند. آن را روی loopback نگه دارید و هرگز یک نقطه‌ی پایانی عمومی را به آن هدایت نکنید
--public-rpc <ADDR>خاموشv0.6.8: شنونده‌ی دوم و عمومی برای اشاره‌ی یک reverse proxy یا یک SSH forward: مجموعه‌ی ثابتی از متدها بدون متدهای کلید مشاهده، rand_mint یا rand_getPeers، بدون batch، بدون WebSocket، با یک شمارنده برای همه‌ی فراخوانندگان (JSON-RPC)
--rpc-viewing-token-file <PATH>خاموشv0.6.8: یک توکن bearer (خط اول فایل، حداقل ۳۲ نویسه) را روی متدهای کلید مشاهده‌ی --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>خاموشیک اثبات‌کننده‌ی واگذارشده را روی این نشانی میزبانی می‌کند، شنونده‌ای مستقل و هرگز RPC نیست؛ بخش در ادامه را ببینید
--gas-price, --byte-price100, 800کف قیمت استخر برای یک فراخوانی در زنجیره‌ای بدون بخش gas. جنسیس زنجیره‌ی 20 قیمت‌های خودش را تعیین می‌کند، بنابراین گره هر دو پرچم را در آنجا نادیده می‌گیرد و هشداری ثبت می‌کند

--prover-accept-spend-key بازنشسته شده است: گره v0.6.8 که این پرچم به آن داده شود از شروع خودداری می‌کند، پس آن را از هر فایل unit که از v0.6.7 آورده‌اید حذف کنید.

سه bootstrap بالا اعتبارسنج‌های C، D و E هستند، بدون تغییر نسبت به زنجیره‌ی 19. زنجیره‌ی 20 روی کلیدهای اعتبارسنجی اجرا می‌شود که برای زنجیره‌ی 14 تولید شده بودند، بنابراین شناسه‌های همتای آن‌ها همان‌هایی است که زنجیره‌ی 14 به کار می‌برد؛ هویت p2p از کلید اعتبارسنج مشتق می‌شود. بیشتر اعتبارسنج‌ها فقط یک روز بلاک نگه می‌دارند، پس گرهی که از جنسیس همگام می‌شود، یا بیش از یک روز عقب است، به یک همتای دارای تاریخچه‌ی کامل هم نیاز دارد. یکی از دو آرشیو را اضافه کنید:

    --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) اجرا شود. مراحل آغاز: باز کردن ذخیره‌سازی، بررسی guestهای این build در برابر hc_bundle و hc_auth جنسیس، اجرای بررسی یکپارچگی (دم آسیب‌دیده را کوتاه می‌کند و وضعیت ایمنی رأی را نگه می‌دارد)، ازسرگیری اجماع از head ذخیره‌شده، راه‌اندازی شبکه و RPC، و سپس همگام‌سازی از هر همتایی که جلوتر است. مقدار پیش‌فرض RUST_LOG برابر info,libp2p=warn,libp2p_mdns=off است؛ Ctrl-C یا SIGTERM، سیگنال توقف systemd، گره را به‌صورت تمیز خاموش می‌کند. راه‌اندازی مجدد از همان --datadir از head ذخیره‌شده ادامه می‌دهد.

قواعد توپولوژی از fullnode: گره‌های پشت NAT به گره‌های دارای نشانی عمومی وصل می‌شوند؛ TCP 30303 را روی گره‌های عمومی برای اتصال ورودی باز کنید؛ RPC را به 127.0.0.1 متصل کنید مگر آنکه فایروال داشته باشد — از هر کسی که به آن دسترسی داشته باشد تراکنش می‌پذیرد، و وقتی کلید مشاهده در آن وارد شد، آن پورت را حامل کلید بدانید. --block-interval-ms را روی 1000 یا کندتر نگه دارید: اثبات یک bundle حدود دو دقیقه طول می‌کشد و anchor آن در زنجیره‌ی 20 برای 1,024 بلاک معتبر است (در زنجیره‌ی 19 برای 256).

اعتبارسنج به ساعت همگام نیاز دارد. از زنجیره‌ی 14 به بعد، زمان ساعت دیواری بخشی از اجماع است (سخت‌سازی پل B2). بلاکی که زمانش بیش از ۶۰ ثانیه از والدش جلوتر باشد نامعتبر است، و اعتبارسنج از رأی دادن به بلاکی که زمانش بیش از ۱۵ ثانیه از ساعت خودش جلوتر است خودداری می‌کند. بنابراین اعتبارسنجی که ساعتش کند است بدون ثبت هیچ خطایی از رأی دادن باز می‌ماند، و برای کامیت در زنجیره‌ی 20 باید بیست‌وشش رأی از میان بیست‌وشش…

اصلاح: برای کامیت در زنجیره‌ی 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

همتایان رزروشده {#reserved-peers}

از v0.6.8 یک گره حداکثر ۲۵۶ اتصال ورودی برقرارشده و ۶۴ اتصال نیمه‌باز می‌پذیرد، و ساختن هویت 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 وقتی فضای آزاد کمتر از چهار برابر --min-free-disk-mb باشد، disk_low (همراه با free_bytes) را پیش از ok، syncing یا behind پاسخ می‌دهد.

هرس تاریخچه {#history-pruning}

گرهی که با --prune-history 24h شروع شود دفتر کل (یادداشت‌ها، ابطال‌کننده‌ها (nullifier)، anchorها، ثبت اعتبارسنج‌ها، برنامه‌ها) را کامل نگه می‌دارد و بلاک‌های قدیمی‌تر، گواهی‌ها، تراکنش‌ها و رسیدهای آن‌ها را حذف می‌کند. یک گذر در هر شانزدهمین بلاک کامیت‌شده اجرا می‌شود و تا ۵۱۲ بلاک قدیمی‌تر از زمان head منهای پنجره را حذف می‌کند؛ جنسیس، head و والد آن هرگز حذف نمی‌شوند، و کف فقط بالا می‌رود. پس از آنکه 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 و بلاک‌های نگه‌داشته‌شده، QCهای آن‌ها، پیوندهای والد و لیدرها)، نه بازپخش از جنسیس، و خودش را ترمیم نمی‌کند: اگر شکست بخورد، از یک آرشیو دوباره همگام شوید. دایرکتوری داده‌ی هرس‌شده را با build قدیمی‌تر از v0.5.7 باز نکنید مگر آنکه با --verify-chain off اجرا شود: بررسی پیش‌فرض آن از جنسیس بازپخش می‌کند، بلاک 1 را گم‌شده می‌یابد و دفتر کل را تا جنسیس کوتاه می‌کند.

میزبانی یک اثبات‌کننده {#hosting-a-prover}

در زنجیره‌ی 20 یک کیف پول برای هر bundle دو اثبات می‌سازد و اثبات بزرگ‌تر به حدود 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 از طریق آن اثبات می‌سازد. شنوندهٔ prover مستقل است و هرگز یکی از متدهای RPC نیست: نشانی‌ای که با --rpc یکسان باشد رد می‌شود. با --prover، گره از راه‌اندازی خودداری می‌کند مگر آن‌که <prover-home>/prover.key.json وجود داشته باشد (پیش‌فرض <datadir>/prover) و برای هر اسلات اثبات ۵٫۷۴ گیگابایت به‌علاوهٔ ۱ GiB حافظه در دسترس باشد؛ --prover-max-parallel تعداد اسلات‌ها را تعیین می‌کند و به‌طور پیش‌فرض یک است.

در chain 20، به prover کلید مشاهده‌ی کیف پول و یک salt تازه فرستاده می‌شود، نه کلید خرج. کیف پول خودش اثبات احراز مجوز را روی کلید خرج می‌سازد؛ بنابراین یک prover جفت‌شده می‌تواند کل تاریخچهٔ آن کیف پول را بخواند، اما نمی‌تواند خرج کند. شنونده را روی 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

ابتدا گره را متوقف کنید. اگر همه‌چیز سازگار باشد کد خروج ۰ است، و اگر مشکلی پیدا شود و --repair داده نشده باشد، ۲. بازپخش (replay) اعتبار هر اثبات بسته (bundle) را دوباره بررسی می‌کند؛ بنابراین نسخه‌ای که مجموعهٔ قیود آن با مجموعهٔ قیدِ سازندهٔ زنجیره فرق دارد، در همان بستهٔ اول متوقف می‌شود.

تبدیل شدن به validator

یک validator با بوند (bond) به زنجیرهٔ در حال اجرا می‌پیوندد، نه با genesis جدید: گره را با --validator راه‌اندازی کنید، با rand-node register --key node.key.json --payout <rand1…> --v2 یک ثبت‌نام چاپ کنید (chain 20 ثبت‌نام v1 را رد می‌کند)، یک کیف پول را وادار کنید دست‌کم ۱٬۰۰۰ RAND را با rand bond <address> 1000 --registration <hex> بوند کند، و گره پس از فعال‌شدن بوند پیشنهاد بلاک می‌دهد: در chain 20، زودتر از سه مرز دورهٔ ۱٬۰۰۰ بلاکی پس از بوند نیست. در chain 20 بوند در مرحلهٔ دوم می‌آید. genesis آن staking.admission_by_vote را تنظیم کرده است؛ بنابراین بوندی که کلیدی تازه ثبت می‌کند رد می‌شود، تا زمانی که validatorهایی که بیش از دو سوم وزن رأی را دارند به آن کلید رأی داده باشند: هر یک با rand-node admit sign --candidate <key or registration> --key <validator key> --genesis-hash 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135 امضا می‌کند و یکی از آن‌ها رأی‌ها را با rand-node admit submit ارسال می‌کند (خط فرمان). rand_getAdmitted کلیدهایی را فهرست می‌کند که به آن‌ها رأی داده شده و هنوز ثبت نشده‌اند. بیش از ۲٬۵۰۰ bps از وزن فعال در یک مرز دوره نمی‌تواند وزن تازه شود. Staking مراحل را گام‌به‌گام شرح می‌دهد. برای یک زنجیرهٔ آزمایشی خصوصی، 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 دو validator را روی یک ماشین با RPC روی 8545 و 8546 اجرا می‌کند. بدون پرچم‌های بیشتر، genesis فاقد hc_auth، بخش gas و memo است. chain 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 به‌علاوهٔ پرچم‌های پایه ساخته شد (chain 18 و 19 پرچم‌ها را تا --envelope-bytes داشتند)، و بخش‌های bridge و staking و consensus_domain آن را اسکریپت برش (cut) درج کرد. یک زنجیرهٔ جدید شما باید --binding-domain 1 را بدهد: کیف پول v0.6.8 روی هر شناسهٔ زنجیره خارج از ۱۴ تا ۱۹ شکل وابسته به genesis را اثبات می‌کند.

استقرار روی سرور

پوشهٔ deploy/ مخزن اسکریپت‌هایی را در بر دارد که ناوگان به کار می‌برد: deploy/push-to-vps.sh <ip> <letter> "<bootstraps>" [validator|observer] یک سرور لینوکس را آماده می‌کند (rsync کد منبع، ساخت، نصب /usr/local/bin/{rand-node,rand}، راه‌اندازی اولیهٔ datadir با کلید hash مربوط به genesis، نصب سرویس systemd با نام rand-node) و deploy/rebuild-vps.sh <ip> روی یک کامیت جدید دوباره می‌سازد و با حفظ داده‌ها راه‌اندازی مجدد می‌کند. دو هشدار. اسکریپت آماده‌سازی از deploy/genesis.json مقداردهی اولیه می‌کند که فایل chain 20 نیست؛ پس گره‌ای برای testnet با دست از deploy/genesis-chain20.json برپا می‌شود (روی main، بالا را ببینید). و هر دو اسکریپت /root/fullnode را با --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 و یک toolchain زبان Rust نیاز دارد. یک سرور با ۱ vCPU و ۲ گیگابایت حافظه نمی‌تواند باینری‌ها را بسازد؛ جای دیگری بسازید و کپی کنید. اجرای validator و aggregator اندازه‌ها و راه‌اندازی گام‌به‌گام را دارد.

اکسپلورر

randscan.org کنار validator E اجرا می‌شود و chain 20 را نمایه می‌کند؛ REST API و فید WebSocket آن ساده‌ترین راه برای خواندن زنجیره بدون گره است (Explorer API). اکسپلورر متن‌باز است (randprotocol/randscan) و نمایه‌ساز آن فقط به JSON-RPC با متدهای rand_* یک گره و یک پایگاه‌داده PostgreSQL نیاز دارد؛ پس می‌توان آن را روی گره خودتان اجرا کرد.

آخرین بار با کامیت c0878c3f از fullnode (زنجیرهٔ 21) در تاریخ 2026-10-12 بررسی شد. هرجا کد و این صفحه با هم اختلاف دارند، حق با کد است؛ به ما اطلاع دهید.