این چهار برنامه هرکدام یک کاربرد کامل از فراخوانی محرمانهاند: یک مسئله، یک رابط، یک guest به زبان Rust، ابزارهای سمت میزبان، و یک استقرار و یک فراخوانی روی testnet زنده. از آموزشها طولانیترند و هرکدام بر بخش متفاوتی از ماشین تکیه دارد. نوشتن برنامه با Rust یا C راهنمای مدلی است که همهی آنها از آن استفاده میکنند. اگر read_input، قطعهی عمومی یا هشت شکاف خروجی برایتان تازه است، ابتدا آن را بخوانید.
همهی موارد اینجا نخستین بار روی زنجیرهی 18 با fullnode v0.6.7 در تاریخ 2026-09-30 اجرا شد و هر خروجی در این صفحهها از همان اجراها رونوشت شده است. برنامهها از یک برش زنجیره به برش بعدی منتقل نمیشوند؛ بنابراین در 2026-10-01 هر چهار برنامه بدون تغییر دوباره روی زنجیرهی 19 و سپس روی زنجیرهی 20 (fullnode v0.6.8) مستقر شدند و فراخوانیها هر بار تکرار شد. شناسهی برنامه هش کد و قطعهی عمومی است، نه هش زنجیره؛ پس همهی شناسهها یکساناند. هش تراکنشها در رونوشتها متعلق به زنجیرهی 18 است و جدول زیر به تراکنشهای زنجیرهی 20 پیوند میدهد. روی زنجیرهی 20 یک برنامه میتواند میان فراخوانیها وضعیت نگه دارد (RPL-2)؛ این چهار برنامه از آن استفاده نمیکنند، و وضعیت برنامه و مخزن example-programs برنامههایی را پوشش میدهند که از آن بهره میبرند.
چهار برنامه
| برنامه | آنچه یک فراخوانی ثابت میکند | تکیه بر | کلمهها | رده |
|---|---|---|---|---|
| یک رأی ناشناس | فراخواننده عضو یک فهرست منتشرشده است، بیآنکه بگوید کدام عضو، و پیشتر رأی نداده است | Keccak-256، یک قطعهی عمومی | 427 | 12 |
| یک اثبات بدهیها | موجودیهای خصوصی مشتریان روی هم از یک ذخیرهی منتشرشده بیشتر نمیشود، تحت ریشهای که هر مشتری میتواند بررسی کند | SHA-256، درختی که درون برنامه ساخته میشود | 994 | 14 |
| یک دفتر کل برونزنجیرهای | دستهای از انتقالها دفتر کل را از یک وضعیت به وضعیت بعدی میبرد، با فرستندههای مجاز و بدون خلق هیچ مقداری | Poseidon2، وضعیتی که میان فراخوانیها منتقل میشود | 773 | 14 |
| یک تصمیم اعتباری خصوصی | یک مدل منتشرشده دادههای خصوصی متقاضی را که یک گواه تأیید کرده است میپذیرد یا رد میکند | حساب صحیح، مدلی در قطعهی عمومی | 462 | 12 |
هر چهار برنامه روی زنجیرهی 20 زندهاند. هر فراخوانی در جدول، با همان ورودیها، فراخوانی زنجیرهی 18 را که در صفحهی آن برنامه آمده تکرار میکند:
| برنامه | شناسهی برنامه | مستقر شده روی زنجیرهی 20 در | نخستین فراخوانی روی زنجیرهی 20 |
|---|---|---|---|
| رأی ناشناس | ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970 | f6ae5528…0f82 | 3a304e7a…427b |
| اثبات بدهیها | fce8474dfdf80b9733e04fb72d4d8d19c40ba5ab646b3d867322daf4b9b599c0 | a8bc281b…17d9 | 6116c15f…d62a |
| دفتر کل برونزنجیرهای | c4ddd388f2d94299610c7c3409dfdfb4dcb4ae3e0bc9ec78d0c45f51d8231cab | 72cc95f2…3d51 | 9c9998bb…66eb |
| تصمیم اعتباری خصوصی | 7bbec14289f4446231b3a9a5ac18cb0613a373ca8a14fe4f046f3fde7ae6c73c | 413e6658…e42b | d3ceb306…124a |
کاوشگر همهی برنامهها و فراخوانیهایشان را در randscan.org/programs فهرست میکند. یک زنجیرهی testnet هر از چندی جایگزین میشود و برنامهها منتقل نمیشوند: پس از برش بعدی این شناسهها از میان میروند و برنامهها باید دوباره مستقر شوند.
راهاندازی
زنجیرهی ابزار. guestها با rand-guest از مخزن مدارها ساخته میشوند، در کامیتی که fullnode v0.6.7 و v0.6.8 هر دو آن را vendor میکنند:
git clone https://github.com/randprotocol/zkp-circuits circuits
cd circuits
git checkout aeacf31 # branch feat/v067-circuits
rustup toolchain install 1.98.1
rustup target add riscv32im-unknown-none-elf --toolchain 1.98.1
(cd rand-guest && cargo +1.98.1 build --release)
alias rand-guest="$PWD/rand-guest/target/release/rand-guest"
کامیت به دو دلیل اهمیت دارد. hc تابعی از کد منبع و زنجیرهی ابزار است، پس guest که در کامیت دیگری از guest-sdk بازسازی شود ممکن است hc متفاوتی بگیرد. و امضاهای SDK تغییر کردهاند: در aeacf31، keccak و sha256_compress ارجاع به آرایه میگیرند، در حالی که کامیتهای قدیمیتر اشارهگر خام میگرفتند.
منابع. هر چهار guest، اسکریپتهای میزبان و دادههای نمایشی در یک بستهی دانلودیاند. آن را درون checkout باز کنید، زیرا rand-guest build مسیر guest-sdk را با جستوجو به سمت بالا از پوشهی guest پیدا میکند:
mkdir -p my-guests
curl -sSf https://randprotocol.org/examples/rand-example-programs.tar.gz | tar -xz --strip-components=1 -C my-guests
ls my-guests
# allowlist ledger ledger-host score solvency
فایلها را میتوان یکبهیک نیز زیر https://randprotocol.org/examples/programs/ مرور کرد، برای مثال allowlist/src/main.rs.
کیف پول. استقرار و فراخوانی به کیف پول rand از fullnode v0.6.8 نیاز دارد (cargo build --release -p randprotocol-client در یک checkout از fullnode روی تگ v0.6.8، یا rand پیوستشده به انتشار v0.6.8)، به یک کلید، و به RAND. کیف پول قدیمیتر نمیتواند روی زنجیرهی 20 تراکنش بزند: زنجیرهی 20 هر اثبات و هر پیام امضاشده را به genesis خود پیوند میدهد و کیف پول v0.6.7 چنین نمیکند.
یک RPC. نقطهی پایانی عمومی، https://rpc.randprotocol.org، برای همهی کارهای این صفحهها کافی است: خواندن برنامهها و رسیدها، همگامسازی کیف پول، استقرار و فراخوانی. نخستین همگامسازی کیف پول هر سرتیتر بلوک و هر بلوکی را که یک note دارد میخواند، 645 درخواست در ارتفاع زنجیرهی 18 در 2026-09-30، و از طریق این نقطهی پایانی حدود سه دقیقه طول کشید. این نقطهی پایانی به هر نشانی 1,200 خواندن و 6 ارسال در دقیقه اجازه میدهد. گرهی خودتان (راهاندازی یک گره) چنین محدودیتهایی ندارد.
export RAND_RPC=https://rpc.randprotocol.org
export RAND_KEY=$HOME/wallet.key.json
روی زنجیرهی 18، یکی از رأیهایی که در صفحهی رأی ناشناس شمرده شد، fdbcc960…fc2b، روی یک لپتاپ اثبات شد و تنها از طریق نقطهی پایانی عمومی ارسال شد. روی زنجیرههای 19 و 20 هر بار هر سیزده تراکنش، یعنی چهار استقرار و نه فراخوانی، به همین شیوه رفت.
آنچه زنجیرهی 18 برای یک برنامه تغییر داد
یک فراخوانی سقف گاز اعلام میکند و بهای آن را میپردازد. مجموعهی قیود 8 هر اجرا را اندازهگیری میکند. یک چرخهی معمولی 1 گاز است. فراخوانیهای سیستمی هش استثنا هستند:
| دستورالعمل | گاز |
|---|---|
هر دستورالعمل RV32IM، HALT، WRITE_OUTPUT، READ_INPUT، READ_PUBLIC | 1 |
POSEIDON2 روی n کلمه | 3 + 3 × ⌈n / 4⌉ |
SHA256، یک تابع فشردهسازی | 64 |
KECCAK، یک جایگشت | 192 |
اثبات یک مقدار عمومی تازه حمل میکند، یعنی سقف اعلامشده، و مدار اجرا میکند که گاز اجرا از آن بیشتر نباشد. گاز دقیق خصوصی میماند. rand call ابتدا برنامه را در شبیهساز اجرا میکند و هر دو را چاپ میکند:
gas: 5636 (declaring 6144, tier 12)
بهطور پیشفرض کیف پول گاز دقیق را به بالا به مضربی از 2^(tier − 2) گرد میکند، یعنی 1,024 در ردهی 12 و 4,096 در ردهی 14، پس سقف اعلامشده دربارهی اجرا اطلاعات اندکی میدهد. --gas-limit max سقف رده را اعلام میکند و فراتر از رده چیزی نمیگوید. --gas-limit N مقداری دقیق اعلام میکند.
کارمزد از سقف اعلامشده و بایتها پیروی میکند.
floor = 0.001 RAND + gas price × declared limit + byte price × ⌈bytes / 1024⌉
قیمتها از 100 واحد به ازای هر گاز و 800 واحد به ازای هر KiB آغاز شدند (هر واحد 10⁻⁹ RAND است) و در هر بلوک اندکی به سمت یک هدف حرکت میکنند. rand_getLimits قیمتهای جاری را ارائه میدهد. کیف پول دو گام قیمتی فضای اطمینان اضافه میکند، ضریب 1.125²، چون یک فراخوانی دو یا سه بلوک پس از قیمتگذاری ثبت میشود.
یک نکته بیشتر کارمزد را تعیین میکند. از زنجیرهی 18 به بعد اثبات یک فراخوانی به تراکنش خودش پیوند خورده است، بنابراین کیف پول باید کارمزد را پیش از وجود اثبات تثبیت کند و اثبات را بهجای اندازهی واقعیاش با سقف زنجیره، یعنی 4 MiB، قیمتگذاری میکند. برای رأی ناشناس این میشود (1,000,000 + 100 × 6,144 + 800 × 4,097) × 1.125² = 6,191,437 واحد، یعنی 0.0062 RAND، که گاز حدود یکهشتم آن است. چهار فراخوانی این صفحهها هرکدام بین 0.0057 و 0.0075 RAND هزینه داشتند. --fee مقدار پیشفرض را بازنویسی میکند.
هر بسته دو اثبات است. زنجیرهی 18 مجوزدهی شکافته را اجرا میکند: بستهای که کارمزد میپردازد، در کنار اثبات بستهی ردهی 14، یک اثبات مجوزدهی کوچک ردهی 10 نیز دارد. کیف پول هر دو را میسازد و برای هرکدام یک خط چاپ میکند. بنابراین یک فراخوانی سه اثبات است: فراخوانی، مجوزدهی و بسته. روی یک لپتاپ Apple Silicon، چهار فراخوانی اینجا هرکدام بین سه و پنجونیم دقیقه طول کشید، با اوج مصرف حافظهی 6.1 تا 6.6 GB. اثبات بسته هر بار حدود دو دقیقه از این زمان است. اثبات فراخوانی ردهی 12 نیم دقیقه و ردهی 14 دو دقیقه به آن میافزاید.
سقفهایی که یک فراخوانی باید در آنها بگنجد.
| محدودیت | زنجیرههای 18 تا 20 |
|---|---|
| رده | حداکثر 14: 16,383 چرخه، با احتساب سطرهای digest |
| جایگشتهای Poseidon2 | 2,048 در ردهی 14، با احتساب digestهای برنامه، ورودی و عمومی |
| جایگشتهای Keccak | 128 |
| توابع فشردهسازی SHA-256 | 128 |
| اثبات فراخوانی | 4,194,304 بایت (4 MiB) |
| برنامه | 8,180 کلمه بدون قطعهی عمومی، و با آن کمی کمتر: زنجیرهی 20، مانند زنجیرههای 18 و 19، استقراری را که هیچ فراخوانی ردهی 14 نتواند آن را در خود جا دهد رد میکند (ProgramUncallable)، هرچه max_program_words (65,535) اجازه دهد |
| قطعهی عمومی | 32,768 کلمه، در زمان استقرار ثابت میشود |
| ورودی خصوصی با رونوشت مهرشده | 16,071 کلمه |
rand-guest run --tier 14 دو مورد نخست را پیش از استقرار بررسی میکند. جدول هش اثبات را بزرگتر میکند. اثبات ردهی 14 دفتر کل، بدون جدول هش، 1.50 MB است. جدول SHA-256 اثبات بدهیها را به 1.91 MB میرساند و جدول Keccak اثبات رأی را به 3.35 MB، که بخش عمدهی سقف 4 MiB است.
قراردادهای مشترک این چهار برنامه
- اسلات ۰ یک وضعیت است و ۰ هرگز وضعیت معتبری نیست. هر نتیجه، از جمله شکستها، شمارهای از ۱ به بالا دارد و شکست بهصورت تمیز متوقف میشود تا قابل اثبات باشد. رسید تماماً صفر را نمیتوان با یک نتیجه اشتباه گرفت.
- اسلات ۷ دستنخورده میماند. یک guest به زبان Rust که دچار panic شود،
0xdeadbeef(۳٬۷۳۵٬۹۲۸٬۵۵۹) را در آن مینویسد. خواننده ابتدا اسلات ۷ را بررسی میکند. - اسلاتهای ۲ تا ۶ یک مقدار ۱۶۰ بیتی را حمل میکنند: یک nullifier، یک ریشه، یک پیوند، یک تعهد. یک هش کامل ۲۵۶ بیتی هشت کلمه است و جایی برای وضعیت باقی نمیگذارد. کوتاهکردن به پنج کلمه ۸۰ بیت مقاومت در برابر برخورد را حفظ میکند، و هر صفحه میگوید این مقدار از چه چیزی محافظت میکند.
- ترتیب بایتها از هش پیروی میکند. مقادیر Keccak کلمههای little-endian و مقادیر SHA-256 کلمههای big-endian هستند، چون هر syscall بلوک خود را به همین شکل میخواند. اگر یک اسکریپت میزبان و یک guest در این مورد اختلاف داشته باشند، خلاصههایی تولید میشوند که هرگز با هم مطابقت نمیکنند.
- هر چه به ازای هر نمونه تغییر میکند در بخش عمومی است و هر چه به ازای هر فراخوانی است ورودی خصوصی است. ریشه یک نظرسنجی، یک رقم ذخیره و وزنهای یک مدل هنگام استقرار ثابت میشوند و به شناسه برنامه گره میخورند. یک فراخوانی هیچ کلمه عمومی مختص خود ندارد.
- کلمات ورودی در خط فرمان بهصورت دهدهی هستند. صفحهها یک فایل witness را با
$(sed 's/[0-9][0-9]*/--input &/g' witness.txt)به پرچمها تبدیل میکنند.
خودتان یک فراخوانی انجام دهید
پس از باز کردن سورسها، ساخت toolchain و داشتن یک کیف پول v0.6.8 دارای موجودی، رأی دادن بهعنوان یکی از اعضای نمونه چهار فرمان است:
cd my-guests/allowlist
python3 allowlist.py witness 10 1 demo-secrets.txt 6 1 > witness.txt # member 6, choice 1
rand-guest build . --max-words 65535 # only needed to run it in the emulator first
rand call ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970 \
$(sed 's/[0-9][0-9]*/--input &/g' witness.txt)
فراخوانی به image نیاز ندارد: rand call کد و بخش عمومی برنامه را از node میگیرد، بررسی میکند که هش آنها با شناسه برابر است و روی آنها اثبات میسازد.
خواندن یک نتیجه نه کیف پول لازم دارد و نه node. هر رسید با یک درخواست به نقطه پایانی عمومی در دسترس است:
$ curl -s https://rpc.randprotocol.org -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"rand_getReceipt","params":["8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666"]}'
{"id":1,"jsonrpc":"2.0","result":{"h_in":"ea71e7701e62d49cac37b239bef132178f481835027d62b34da45fd6cf2667c6","h_pub":"2296cfca8db9d38bd0b7579056c9dea3c8d8005df7b42e2b1e954a75fed67510","height":98335,"index":0,"outputs":[1,2,392974773,873526743,1921224601,3950868247,2248722827,0],"program":"ad2f719f12d01c9f3c0962092b9898b75b0914bbb817031d51be13e54c05b970","tier":12,"tx":"8aa13d1f76d28f63a46c30bb09ef44b1ba35083ca80ba7301997f98e5f783666"}}
API اکسپلورر فراخوانیهای یک برنامه را در یک درخواست میدهد: https://randscan.org/api/v1/programs/<program id> مقادیر call_count و recent_calls را برمیگرداند (Explorer API).
آنچه هیچیک از آنها انجام نمیدهند
یک برنامه در Rand اثباتی درباره یک محاسبه است و زنجیره روی هیچیک از خروجیهای آن اقدامی نمیکند. هیچیک از این برنامهها RAND یا توکنی را جابهجا نمیکند، موجودی نگه نمیدارد و فراخوانی قبلی را به یاد نمیآورد. رأی را هر کسی که رسیدها را میخواند میشمارد. بدهیها با ذخایری مقایسه میشوند که شواهد جداگانهای لازم دارند. موجودیهای دفتر کل اعدادی در یک درخت خارج از زنجیرهاند. تصمیم اعتباری یک بیت است که وامدهنده تصمیم میگیرد به آن احترام بگذارد. هر صفحه با فهرستی از آنچه اثبات آن به عهده کاربران میگذارد پایان مییابد.