Rand Protocol
문서
가이드

노드 운영

바이너리를 빌드하고, 키를 생성하고, chain 20 제네시스로 데이터 디렉터리를 초기화하고, 부트스트랩 노드에 연결하고, RPC를 바인딩하고, 이력을 정리(prune)하고, 체인을 검증합니다. 옵저버 또는 validator로 운영할 수 있습니다.

이 페이지는 testnet을 대상으로 자체 rand-node를 실행하는 방법을 설명하며, 이는 지갑을 비공개로 사용하는 권장 방식이기도 합니다. 직접 운영하는 노드는 사용자가 어떤 리프를 사용하려는지 본인 외에는 누구에게서도 알지 못합니다. 옵저버는 동기화하고 모든 증명을 다시 검증하며 JSON-RPC를 제공합니다. 밸리데이터는 같은 일을 하며, 해당 키가 에포크의 집합에 포함되면 합의에도 참여합니다.

빌드

요구 사항: Rust 1.98.1(rust-toolchain.toml에 고정되어 있으며 rustup이 설치합니다), C++ 컴파일러, 그리고 RocksDB용 cmake. zkVM crate는 증명 시스템 저장소(randprotocol/zkp-circuits)의 형제 디렉터리 circuits/ 체크아웃을 경로 의존성으로 참조합니다. 이 체크아웃은 fullnode/ 옆에 있어야 하며, 릴리스가 vendoring된 커밋이어야 합니다. 해당 커밋은 crates/randprotocol-zkvm/guests-compiled/PROVENANCE.md의 circuits: 줄에 있습니다(v0.6.8은 v0.6.7과 마찬가지로 aeacf31). 첫 빌드에는 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, 플릿이 실행하는 릴리스입니다. 노드의 sha는 rand_getVersion이 보고합니다). GitHub 릴리스에는 rand-node, rand, rand-prover, SHA256SUMS가 포함되어 있으며, 플릿 호스트 한 대에서 빌드되었고 서명되지 않았습니다. 체인 20에는 이 버전이 필요합니다. 체인 20의 제네시스에는 이전 빌드가 읽지 못하는 필드(testnet, binding_domain, proof_window_blocks, program_state, 브리지의 rotation 및 fees 그룹, 가스 상한, 투표에 의한 스테이킹 승인)가 있고, v0.6.8에는 이전 노드가 실행하지 않는 합의 변경이 포함되어 있기 때문입니다. 증명은 체인 18과 19에서와 같이 여전히 제약 집합 8로 생성되며, 모든 번들에는 여전히 번들 증명과 함께 인가 증명이 포함됩니다(체인 17부터의 분리 인가). 따라서 제네시스는 동일한 두 게스트를 고정합니다. 번들 게스트 v3(hc_bundle 60af094a…)와 인증 게스트(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에서 중단되었고, 모든 노드가 v0.6.8로 체인 20을 시작했습니다. 롤링 업데이트가 아니었던 데에는 두 가지 이유가 있습니다. 체인 20은 새로운 제네시스이므로 체인 19와 공유하는 블록이 없습니다. 또한 v0.6.8에는 audit v6에서 나온 합의 변경이 포함되어 있는데, 이는 노드별로 순차 적용해서는 안 됩니다. CON-4는 밸리데이터 락의 자동 해제를 제거하고, CH-1은 타임아웃 인증서 페이스메이커를 추가합니다. 26명의 밸리데이터 전원과 이들의 키, 피어 id, 부트스트랩이 그대로 이어졌으며, 정족수는 여전히 26 중 18입니다. 체인 19와 18은 폐기되었습니다.

따라서 노드를 체인 19에서 체인 20으로 옮기려면 아래와 같이 새 바이너리, 새 제네시스 파일, 새 데이터 디렉터리가 필요합니다. 체인 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 저장소는 더 이상 어떤 키도 추적하지 않습니다(audit v3, OPS-1). 체인 8부터 13까지 커밋되어 있던 deploy/node-*.key.json 및 deploy/payout/*.key.json 파일은 공개된 시드이므로 사용해서는 안 됩니다. 체인 20의 밸리데이터 키는 저장소 밖에서 생성되었고 저장소에 포함된 적이 없습니다. 제네시스 밸리데이터 26명은 체인 14용으로 생성된 키 18개와 체인 15에서 본딩된 8개이며, 이후의 모든 전환에서 그대로 이어졌습니다.

v0.6.8부터 rand-node keygen은 이미 존재하는 --out 파일을 거부합니다. v0.6.7은 묻지 않고 덮어썼습니다. 이 파일이 시드의 유일한 사본입니다. 본드가 이 키에 의존하기 전에 백업하십시오.

제네시스로 초기화

체인의 모든 노드에는 바이트 단위로 동일한 제네시스 파일이 필요합니다. rand-node init은 이 파일을 데이터 디렉터리에 복사하고 해시를 출력하며, 체인 20의 경우 해시는 6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135여야 합니다. 파일은 deploy/genesis-chain20.json(sha256 0020247a…3a21)입니다. 이 파일은 태그 이후에 출시 기록과 함께 fullnode의 main에 커밋되었으므로(커밋 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

이 명령은 블록 0, 트리의 첫 리프가 되는 제네시스 노트 9개(체인 19의 운영자 지갑 5,184.243719258 RAND를 담은 RAND 노트 7개와, 브리지 보관분에 잠긴 99 zUSD에 해당하는 10 zUSD 및 89 zUSD의 zUSD 노트 2개), 그리고 밸리데이터 레지스터를 포함한 <datadir>/db(RocksDB)를 생성합니다. 같은 제네시스로 다시 실행하면 아무 일도 일어나지 않으며, 다른 제네시스는 거부됩니다(already initialized with a different genesis는 해당 datadir가 다른 체인에 속한다는 뜻입니다). 플릿과 같이 데이터 디렉터리의 이름에 제네시스 해시의 첫 여덟 글자를 사용하십시오(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은 모든 번들 증명이 검증되는 기준이 되는 번들 게스트를, hc_auth는 모든 인가 증명이 검증되는 기준이 되는 인증 게스트를 고정합니다. 빌드가 다른 게스트를 조립하는 노드는 시작을 거부하고 두 다이제스트를 모두 출력합니다. 다섯 개의 max_* 필드는 선택 사항이며 존재할 때만 해시에 바인딩됩니다. 체인 20은 다섯 개 모두를 설정합니다. max_proof_bytes는 4 MiB이며, 체인 13부터 16까지는 8 MiB였습니다. 체인 17부터 트랜잭션은 증명을 세 개(번들, 인가, 호출) 담을 수 있으며, hc_auth가 있는 제네시스는 max_block_bytes가 max_proof_bytes의 세 배에 1 MiB를 더한 값 이상이어야 합니다. 각 alloc 노트에는 opening(pk, time, r, 그리고 토큰 노트의 경우 asset)이 있으므로 제네시스 노트의 소유자와 금액은 의도적으로 공개됩니다. 체인 20에는 다음이 있습니다.

  • bridge 섹션: 인덱스 1의 가디언 집합 1(가디언 8명), 소스 체인 2, 3, 4, 5의 emitter(체인 19와 동일), Dilithium2 pq_guardians 8개, pause_key, burn_sequence 13, 소스 체인 2, 3, 4에 대한 min_inbound_sequence 3과 소스 체인 5에 대한 7, 그리고 rules_v2(24시간 구간당 전역 발행 한도 4,000 zUSD). 체인 20에서 새로 추가된 것은 rotation으로, PQ 가디언 또는 pause key의 교체에는 새 키의 소유 증명이 필요하며 커밋 후 86,400초가 지나 효력이 발생합니다. 또한 fees가 있어, 체인은 모든 예치금의 10 bps와 모든 소각의 10 bps를 재무 주소로 가는 zUSD 노트로 보유합니다. 따라서 예치는 수수료를 뺀 총액을 입금하고, 소각은 수수료를 뺀 금액을 해제합니다.
  • tokens 섹션: 제안자에게 지급되지 않고 소각되는 1 RAND의 등록 수수료, 백킹당 8 소수 자릿수 기준 100,000 토큰의 mint_cap_per_day, 4,096 토큰의 레지스트리 한도, 2^63의 노트 값 상한, 그리고 제네시스에 일곱 개의 백킹과 함께 등재된 zUSD. 99 zUSD가 두 개의 제네시스 zUSD 노트에 대응하여 잠겨 있습니다(Ethereum USDT 22, BSC USDT 22, Tron USDT 30, Solana USDT 25).
  • consensus_domain: 1: 모든 합의 서명은 이 제네시스에 바인딩됩니다(합의).
  • staking 섹션: 에포크당 10,000 RAND의 예산, 2에포크의 본드 지연, 3,333 bps의 가중치 상한, v2 등록과 함께 faucet은 지갑 16개와 발행 밸리데이터 키 18개로 허용 목록이 제한됩니다(체인 19와 동일). 체인 20에서 새로 추가된 것은 admission_by_vote(새 밸리데이터 키는 밸리데이터 집합이 투표로 승인한 뒤에만 등록됨)와 에포크 경계마다 활성 가중치의 2,500 bps인 진입 예산이며, 체인 19에서는 고정 10,000 RAND였습니다(스테이킹). slashing은 없습니다.
  • gas 섹션: 호출은 증명이 선언한 가스 한도와 호출의 바이트에 대해 비용을 지불합니다. 가격은 가스당 100 단위와 KiB당 800 단위에서 시작하며, 블록마다 목표치인 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: 체인 16 이후 모든 체인이 설정한 v0.6 강화 스위치입니다.
  • testnet: true: faucet을 bridge 섹션과 함께 둘 수 있게 하는 표식입니다.
  • binding_domain: 1: 모든 트랜잭션의 증명과 서명된 모든 액션 메시지에 제네시스 해시가 포함되므로, 한 체인용으로 증명하거나 서명한 것은 다른 체인에서 검증되지 않습니다.
  • proof_window_blocks: 1024: 번들의 앵커는 최근 1,024개 블록 종료 루트 중 하나일 수 있고 그 time은 높이보다 최대 1,024 블록 뒤처질 수 있습니다(체인 19에서는 256). 따라서 느리거나 위임된 증명자에게 약 20분의 여유가 주어집니다.
  • program_state, RPL-2: 프로그램 셀, 프로그램 볼트, Invoke 액션이며, invoke가 생성하는 셀당 0.1 RAND의 셀 수수료가 있습니다(한도는 JSON-RPC에 있습니다).

aggregation 섹션은 없으며, 빌드는 이를 포함한 제네시스에서 시작을 거부합니다.

timestamp_ms는 체인의 시계 기준점(clock zero)입니다. 자체 제네시스를 생성할 때는 실제 출시 시각에 가깝게 설정하고, 절대 그보다 앞서지 않게 하십시오. 너무 과거로 설정하면 블록당 60초 단계 한도가 따라잡을 수 있게 할 때까지 블록 시간이 실제 시계보다 뒤처집니다. 15초를 넘어 미래로 설정하면 블록 1이 아예 커밋되지 않습니다. 리더의 표를 포함한 모든 표가 실제 시각이 제네시스 타임스탬프에 도달할 때까지 보류되기 때문입니다. 파일을 생성한 머신이 아니라 플릿을 출시하는 머신의 시계와 대조하여 확인하십시오.

실행

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/30303libp2p 수신 multiaddr, 반복 지정 가능
--bootstrap없음시작 시와 연결이 끊어진 동안 30초마다 접속을 시도할 피어, 반복 지정 가능
--rpc127.0.0.1:8545운영자용 JSON-RPC 및 WebSocket 리스너: 모든 메서드를 제공하며 루프백을 신뢰합니다. 루프백에만 두고, 공개 엔드포인트를 이곳으로 포워딩하지 마십시오
--public-rpc <ADDR>꺼짐v0.6.8: 리버스 프록시나 SSH 포워드가 가리킬 별도의 공개 리스너: viewing key 메서드, rand_mint, rand_getPeers를 제외한 고정 메서드 집합이며, 배치와 WebSocket을 지원하지 않고 모든 호출자가 하나의 미터를 공유합니다 (JSON-RPC)
--rpc-viewing-token-file <PATH>꺼짐v0.6.8: --rpc의 viewing key 메서드에 bearer 토큰(파일의 첫 줄, 32자 이상)을 요구합니다
--reserved-peer <PEER_ID>없음v0.6.8, 반복 지정 가능: 인바운드 연결 상한을 넘어서도 허용되는 피어. 예약 피어 참조
--strict-gossip꺼짐v0.6.8: 유효한 작성자 서명, 시퀀스 번호, 출처를 갖춘 gossip만 수락합니다. 노드 단위로 순차 적용할 수 있습니다
--validator꺼짐이 노드는 검증자 키를 보유하며, 그 키가 현재 집합에 있으면 합의에 참여합니다
--no-mdns꺼짐LAN 디스커버리를 끕니다. 서버에서 권장합니다
--block-interval-ms1000제안 사이의 최소 간격
--view-timeout-ms3000기본 뷰 타임아웃이며, 연속 타임아웃마다 두 배가 되어 최대 8×까지 늘어납니다
--verify-chainquick시작 시 무결성 검사: off, quick(구조 및 원장 재실행), full(모든 서명과 QC도 포함)
--keep-raw-proofs꺼짐블록 집계를 위한 아카이브 모드. 체인 20에서는 효과가 없습니다
--prune-history꺼짐 (모두 보관)원장과 이 기간만큼의 블록 이력만 보관합니다: <n>m, <n>h 또는 <n>d, 최소 1h. 테스트넷의 검증자는 두 아카이브를 제외하고 24h로 실행합니다. 이력 정리 참조
--min-free-disk-mb1024데이터 디렉터리 파일시스템의 여유 공간이 이보다 적으면 시작을 거부합니다. 여유 공간이 이 값의 네 배 미만이면 rand_getHealth가 disk_low로 응답합니다. 0은 이 보호 장치를 해제합니다
--prover <ADDR>꺼짐이 주소에서 위임 prover를 호스팅합니다. RPC가 아닌 독립 리스너입니다. 아래 참조
--gas-price, --byte-price100, 800gas 섹션이 없는 체인에서 호출에 적용되는 풀의 가격 하한. 체인 20의 제네시스는 자체 가격을 정하므로 노드는 두 플래그를 무시하고 경고를 기록합니다

--prover-accept-spend-key는 폐기되었습니다. v0.6.8 노드에 이 플래그를 주면 시작을 거부하므로, v0.6.7에서 가져온 유닛 파일이 있다면 이 플래그를 제거하십시오.

위의 세 부트스트랩은 체인 19와 동일한 검증자 C, D, E입니다. 체인 20은 체인 14용으로 생성된 검증자 키로 실행되므로 피어 ID는 체인 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

관찰자(observer)로 실행하려면 --validator를 생략하십시오. 시작 절차: 스토리지를 열고, 이 빌드의 게스트를 제네시스의 hc_bundle 및 hc_auth와 대조하고, 무결성 검사를 실행하고(손상된 꼬리 부분은 잘라내고 투표 안전성 상태는 유지), 저장된 헤드에서 합의를 재개하고, 네트워킹과 RPC를 시작한 뒤, 앞서 있는 피어로부터 동기화합니다. RUST_LOG의 기본값은 info,libp2p=warn,libp2p_mdns=off이며, Ctrl-C 또는 systemd의 정지 신호인 SIGTERM은 노드를 정상 종료합니다. 같은 --datadir로 다시 시작하면 저장된 헤드에서 재개됩니다.

풀노드의 토폴로지 규칙: NAT 뒤의 노드는 공개 주소를 가진 노드로 접속합니다. 공개 노드에서는 TCP 30303 인바운드를 여십시오. 방화벽으로 보호하지 않는 한 RPC는 127.0.0.1에 바인딩하십시오. 접근할 수 있는 누구에게나 트랜잭션을 받아들이며, viewing key를 가져온 뒤에는 해당 포트를 키를 담고 있는 포트로 취급해야 합니다. --block-interval-ms는 1000 이상으로 유지하십시오. 번들 증명에는 약 2분이 걸리며, 그 앵커는 체인 20에서 1,024개 블록 동안 유효합니다(체인 19에서는 256개).

검증자에는 동기화된 시계가 필요합니다. 체인 14부터 실제 시각이 합의의 일부입니다(브리지 강화 B2). 타임스탬프가 부모보다 60초를 넘어 뒤인 블록은 무효이며, 검증자는 타임스탬프가 자신의 시계보다 15초를 넘어 앞선 블록에는 투표하지 않습니다. 따라서 시계가 느린 검증자는 오류를 기록하지 않은 채 투표를 멈추며, 체인 20에서는 26개 중 18개가 투표해야 커밋됩니다. 모든 검증자에서 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으로 전파하며, 검증자 집합에서 해당 키를 아는 노드는 그 피어를 예약하고 재시작 후에도 그 기록을 유지합니다. 새로 생성한 체인의 스토어에는 바인딩이 없으므로 첫 공지가 도착하기 전까지는 앞의 두 종류만 예약됩니다. 따라서 체인을 새로 만들 때는 플릿 검증자들의 피어 ID를 --reserved-peer로 전달하거나 부트스트랩 목록에 넣으십시오(rand-node address --key <file>은 키의 피어 ID를 출력합니다). rand_status.reserved_peers가 그 수를 집계하며, 플릿 노드에서는 시작 후 1분 안에 검증자 수에 도달해야 합니다.

확인

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는 가스당 10010,000, KiB당 80080,000 사이일 것입니다. rand_getGenesisHash는 6210cf07…5135를, rand_getVersion은 0.6.8을 반환해야 합니다.

rand_getHealth는 여유 공간이 --min-free-disk-mb의 네 배 미만이면 ok, syncing, behind보다 먼저 disk_low(free_bytes 포함)로 응답합니다.

이력 정리

--prune-history 24h로 시작한 노드는 원장(노트, 널리파이어, 앵커, 검증자 등록부, 프로그램)을 온전히 보관하고, 그보다 오래된 블록과 그 인증서, 트랜잭션, 영수증을 삭제합니다. 정리는 16번째 커밋 블록마다 실행되며, 헤드의 타임스탬프에서 보관 기간을 뺀 시점보다 오래된 블록을 최대 512개까지 삭제합니다. 제네시스, 헤드, 그 부모는 삭제되지 않으며 하한은 올라가기만 합니다. 디스크 공간은 RocksDB가 컴팩션한 뒤에 회수됩니다. 체인 20에서도 체인 19와 마찬가지로 26개 검증자 중 24개가 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 범위)는 data.floor가 담긴 오류 -32010으로 응답합니다. 아카이브에 문의하십시오. 해시 기반 조회는 노드가 더 이상 보유하지 않는 블록에 대해, 존재한 적 없는 블록과 마찬가지로 null로 응답합니다. 노트와 널리파이어는 정리되지 않으므로 지갑 스캔에는 영향이 없습니다.

정리된 노드의 시작 검사는 제네시스부터의 재실행이 아니라 구조 검사(블록 0과 보관된 블록, 그 QC, 부모 링크, 리더)이며, 스스로 복구하지 않습니다. 실패하면 아카이브에서 다시 동기화하십시오. v0.5.7보다 오래된 빌드로 정리된 데이터 디렉터리를 열 때는 --verify-chain off로 실행하지 않는 한 열지 마십시오. 기본 검사가 제네시스부터 재실행하다가 블록 1이 없음을 발견하고 원장을 제네시스까지 잘라냅니다.

prover 호스팅

체인 20에서 지갑은 번들마다 두 개의 증명을 만들며, 큰 쪽은 약 6 GB의 메모리가 필요합니다. 이를 감당하지 못하는 지갑은 해당 증명을 페어링된 위임 prover에게 맡길 수 있습니다. 별도의 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로 증명을 생성합니다. prover의 리스너는 RPC와 별개이며, RPC의 메서드가 아닙니다. --rpc와 같은 주소를 지정하면 거부됩니다. --prover를 지정하면 <prover-home>/prover.key.json이 존재하지 않거나(기본값은 <datadir>/prover), 증명 슬롯당 5.74 GB에 1 GiB를 더한 메모리를 사용할 수 없는 경우 노드는 시작을 거부합니다. --prover-max-parallel은 슬롯 수를 정하며, 기본값은 하나입니다.

chain 20에서 prover에는 spend key가 아니라 지갑의 viewing key와 새로운 salt가 전달됩니다. 권한 증명(authorisation proof)은 지갑이 spend key로 직접 생성하므로, 페어링된 prover는 해당 지갑의 전체 내역을 읽을 수는 있지만 자금을 사용할 수는 없습니다. TLS를 종단하는 프록시가 앞단에 있지 않다면 리스너를 루프백에 두어야 하며, 공개 RPC를 제공하는 머신에서는 prover를 운영하지 마십시오. 중지 요청은 진행 중인 증명이 끝나기를 기다리므로, 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이고, 문제가 발견되었으나 --repair가 지정되지 않았으면 2입니다. 리플레이는 모든 번들 증명을 다시 검증하므로, 제약 조건 집합이 체인을 생성한 빌드와 다른 빌드는 첫 번째 번들에서 중단됩니다.

검증자 되기

검증자는 새로운 제네시스 없이 본딩(bonding)으로 실행 중인 체인에 합류합니다. --validator로 노드를 시작하고, rand-node register --key node.key.json --payout <rand1…> --v2로 등록 정보를 출력한 뒤(chain 20은 v1 등록을 거부합니다), 지갑에서 rand bond <address> 1000 --registration <hex>로 최소 1,000 RAND를 본딩하면, 본딩이 활성화된 시점부터 노드가 블록을 제안합니다. chain 20에서는 본딩 이후 1,000블록 에포크 경계를 세 번 지나야 하므로 빨라야 그 시점입니다. chain 20에서는 본딩이 두 번째 단계입니다. 이 체인의 제네시스는 staking.admission_by_vote를 설정하므로, 새 키를 등록하는 본딩은 투표권 가중치의 3분의 2를 넘게 보유한 검증자들이 그 키에 찬성 투표를 하기 전까지 거부됩니다. 각 검증자는 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 섹션도, 메모도 없습니다. 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은 생성 스크립트가 이어 붙였습니다. 직접 운영하는 새 체인은 --binding-domain 1을 지정해야 합니다. v0.6.8 지갑은 14에서 19를 제외한 모든 chain id에서 제네시스에 바인딩된 형식으로 증명하기 때문입니다.

서버에 배포하기

저장소의 deploy/ 디렉터리에는 fleet이 사용하는 스크립트가 있습니다. deploy/push-to-vps.sh <ip> <letter> "<bootstraps>" [validator|observer]는 Linux 서버를 프로비저닝하며(소스를 rsync하고, 빌드하고, /usr/local/bin/{rand-node,rand}를 설치하고, 제네시스 해시를 키로 하는 datadir를 초기화하고, rand-node systemd 서비스를 설치합니다), deploy/rebuild-vps.sh <ip>는 새 커밋을 다시 빌드하고 데이터를 유지한 채 재시작합니다. 주의할 점이 두 가지 있습니다. 프로비저닝 스크립트는 deploy/genesis.json으로 초기화하는데 이 파일은 chain 20의 파일이 아니므로, 테스트넷용 노드는 deploy/genesis-chain20.json으로 직접 설정합니다(main에 있으며, 위 참조). 또한 두 스크립트 모두 /root/fullnode를 --delete와 함께 rsync하므로, 그 트리 안에 둔 키는 다음 재빌드 때 삭제됩니다. fleet이 하는 대로, 그리고 v0.6.8 프로비저닝 스크립트가 이제 기본으로 하는 대로 키는 /root/keys에 보관하십시오(v0.6.7은 키를 /root/fullnode/deploy/ 아래에 기록했습니다). 서비스 관리는 systemctl status rand-node, journalctl -u rand-node -f로 합니다. 서버에는 build-essential clang cmake pkg-config libssl-dev와 Rust 툴체인이 필요합니다. 1-vCPU, 2 GB 서버에서는 바이너리를 빌드할 수 없으므로, 다른 곳에서 빌드하여 복사해 넣으십시오. 검증자와 애그리게이터 운영에 사양과 단계별 설정 방법이 있습니다.

탐색기

randscan.org는 검증자 E 옆에서 실행되며 chain 20을 인덱싱합니다. REST API와 WebSocket 피드는 노드 없이 체인을 읽는 가장 쉬운 방법입니다(탐색기 API). 탐색기는 오픈 소스(randprotocol/randscan)이며, 인덱서에는 노드의 rand_* JSON-RPC와 PostgreSQL 데이터베이스만 있으면 되므로 자체 노드를 대상으로 실행할 수 있습니다.

fullnode 커밋 c0878c3f(chain 21) 기준으로 2026-10-12에 마지막으로 검증되었습니다. 코드와 이 페이지의 내용이 다를 경우 코드가 옳습니다. 알려 주시기 바랍니다.