Rand Protocol
문서
레퍼런스

JSON-RPC

노드가 제공하는 모든 rand_* 메서드의 매개변수, 결과 형식, 오류와 함께 배치 요청, WebSocket 구독, 트랜잭션 와이어 형식을 다룹니다.

노드는 --rpc(기본값 127.0.0.1:8545)에서 HTTP 기반 JSON-RPC 2.0을 제공하고, 같은 포트에서 구독용 WebSocket도 제공합니다. v0.6.8부터는 두 번째 공개 리스너(--public-rpc, 아래)도 열 수 있습니다. randprotocol_client::RpcClient(Rust)는 아래의 모든 메서드를 감쌉니다. 이 페이지는 체인 20이 실행하는 빌드인 v0.6.8(c9c9bd3c)이 제공하는 메서드 목록입니다. 코드에는 있으나 체인 20에서는 동작하지 않는 메서드는 그렇게 명시합니다.

curl -s http://127.0.0.1:8545 -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"rand_getHead","params":[]}'

공개 엔드포인트

https://rpc.randprotocol.org(같은 프록시가 https://randprotocol.org/api/rpc에도 있습니다)는 모든 블록을 보관하는 체인 20 아카이브 노드로 요청을 전달하며, 자체 노드가 없는 지갑과 페이지를 위한 것입니다(rand --rpc https://rpc.randprotocol.org …). HTTP POST만 지원하고, CORS는 열려 있으며 WebSocket은 없고, 노드보다 범위가 좁습니다.

  • 호출당 요청 하나입니다. 배치는 -32600으로 거부됩니다.
  • 허용 목록에 있는 메서드만 사용할 수 있습니다. 2026-10-01부터 노드의 자체 공개 리스너와 같은 집합(v0.6.8의 rpc::PUBLIC_METHODS)이므로, rand program invoke에 필요한 프로그램 상태 읽기, rand_getAdmitted, 집계 읽기, 베스팅 읽기가 포함되며 rand_checkTransaction과 rand_sendTransaction도 포함됩니다. rand_mint, rand_importViewingKey, rand_getViewingNotes, rand_removeViewingKey, rand_getPeers는 포함되지 않으며, 노드에 도달하기 전에 -32601 method not allowed here로 응답합니다. 공개 faucet은 남용 경로가 되고, 조회 키(viewing key)는 직접 운영하는 노드에만 보내야 하기 때문입니다.
  • 요청 본문은 최대 12 MiB입니다. 이는 모든 전송, 토큰 동작, 배포와, 증명이 약 3.4 MB까지인 호출을 담을 수 있는 크기입니다(트랜잭션은 16진수로 인코딩되며, 번들 증명과 인증 증명만 호출의 증명에 앞서 약 2.85 MB를 차지합니다). 더 큰 호출은 자체 노드로 보내야 합니다. 한도를 넘으면 HTTP 413과 -32600이 반환됩니다.
  • 주소당 분당 1,200건, rand_sendTransaction은 분당 6건입니다. 초과하면 HTTP 429와 -32005가 반환됩니다. 읽기 한도는 지갑의 최초 동기화에 맞춰 산정되었으며, 이는 한 번에 몰리는 수백 건의 요청입니다(체인 18의 높이 99,000에서 645건).
  • 뒤에 있는 노드가 응답하지 않으면 -32000 upstream unavailable이 반환됩니다.

이 페이지의 나머지 내용은 모두 노드 자체에 대한 설명입니다.

노드의 두 리스너

v0.6.8(감사 v6)부터 노드에는 JSON-RPC 리스너가 두 개 있습니다.

  • --rpc <ADDR>, 운영자용 리스너. 모든 메서드, 배치, WebSocket을 제공합니다. 호출자를 소켓 주소로 식별하며 루프백을 신뢰합니다. 조회 키 메서드는 루프백에서만 응답하고, 루프백은 계량되지 않습니다. 127.0.0.1에 두어야 합니다. 리버스 프록시나 SSH 포워드는 루프백으로 도착하므로, 그 뒤에서는 모든 방문자가 운영자가 됩니다. 공개 엔드포인트를 이 포트로 향하게 해서는 안 됩니다.
  • --public-rpc <ADDR>, 공개 리스너. 바로 그 중계 구간을 위한 것입니다. 지갑, 탐색기, 페이지에 필요한 읽기와 rand_sendTransaction으로 이루어진 고정된 메서드 집합(rpc::PUBLIC_METHODS)을 제공합니다. rand_importViewingKey, rand_getViewingNotes, rand_removeViewingKey, rand_mint, rand_getPeers는 이 리스너에서 제공되지 않으며, 나중에 추가되는 메서드도 목록에 오르기 전에는 제공되지 않습니다. 이런 호출은 -32000 <method> is not served on this node's public listener로 응답합니다. 배치는 -32600이고 WebSocket 경로는 없습니다. 모든 호출자를 합쳐 하나의 계량기가 적용되어, 한꺼번에 600건, 초당 150건까지 허용되며, 이를 넘으면 -32000 본문과 함께 HTTP 429가 반환됩니다. 방문자별 한도는 방문자를 볼 수 있는 프록시의 몫입니다. 이 리스너의 호출자는 노드의 블로킹 읽기 슬롯 중 최대 절반만 점유하므로, 운영자용 리스너가 고갈되는 일은 없습니다.

두 리스너는 두 가지 읽기 한도를 공유합니다. 30초 안에 반환되지 않은 블로킹 읽기는 -32000 this read took longer than 30 s on this node; retry with a smaller range로 응답합니다. rand_getBlocks는 블록을 64 MiB만큼 읽으면 해당 페이지를 끝냅니다.

--rpc-viewing-token-file <PATH>는 --rpc의 조회 키 메서드에 베어러 토큰을 요구하도록 합니다. 토큰은 파일의 첫 줄이며 32자 이상이어야 하고, Authorization: Bearer <token>으로 전송합니다. 이를 설정하면 루프백만으로는 충분하지 않고, 어디에서든 이 토큰을 제시하는 호출자가 응답을 받습니다.

규칙

  • 밸리데이터 주소는 base58 문자열(32바이트)입니다. 해시는 0x가 있든 없든 64개의 16진수 문자입니다. 차폐된 값(커밋먼트, 널리파이어, 앵커, 트리 루트, 증인 레벨)은 Word8입니다. 즉 리틀 엔디언 u32 워드 8개를 소문자 16진수 64자로 나타낸 것입니다.
  • 차폐 주소는 rand1 + base58이며 1,667자입니다. 2,000자보다 긴 매개변수는 파싱하기 전에 길이만으로 거부됩니다.
  • 모든 u64 금액은 10진수 문자열입니다("1500000000" = 1.5 RAND, 1 RAND = 10⁹ 단위). RAND 단위든 토큰 단위든, 체인 상태든 디코딩된 트랜잭션 자체의 필드든 마찬가지입니다. JSON 숫자는 2⁵³를 넘으면 정확한 정수가 아니며, 소수 9자리 토큰의 공급량은 수천만 단위에서 이를 넘습니다. 이로 인해 무엇이 바뀌었는지는 아래의 날짜가 붙은 설명을 참고하십시오.
  • 인덱스, 논스, 높이, 리프 인덱스, 뷰, 길이, 소수 자릿수, 일 단위 카운터(mint_day)는 금액이 아니며 전반에 걸쳐 JSON 정수입니다.
  • 모든 요청에는 id 멤버가 있어야 합니다. 이것이 없는 객체는 알림(notification)이며 -32600으로 거부됩니다. 명시적인 "id": null은 일반 요청입니다.
  • 잔액 메서드도 계정 메서드도 없습니다. 지갑은 조회 키로 rand_getCommitments와 rand_getNullifiers를 스캔하여 잔액을 계산합니다. rand_getBalance, rand_getAccount, rand_getAssetBalance는 -32601로 응답합니다.

호환성을 깨는 변경, 2026-09-20(체인 14): 모든 금액이 10진수 문자열

체인 14 이전에는 디코딩된 트랜잭션 안의 금액이 JSON 정수였습니다. 그 예외는 사라졌습니다. 다음 필드는 의미나 위치의 다른 변경 없이 JSON 숫자에서 10진수 문자열로 바뀌었습니다.

  • rand_getTransaction의 tx와 rand_getBlockByHeight / rand_getBlockByHash의 transactions[]에 있는 bundle.fee
  • kind = mint, bond, unbond, withdraw, bridge_attest인 경우의 action.amount(같은 세 메서드)
  • kind = bridge_burn인 경우의 action.amount와 action.relayer_fee(같은 세 메서드)
  • rand_getAssets의 행과 rand_getBridgeState.assets[]의 행에 있는 locked

이 필드 중 하나라도 숫자로 읽는 클라이언트는 문자열을 파싱해야 합니다. rand_status의 aggregation.subsidy_base(집계 체인에만 해당)도 같은 변경에서 문자열이 되었습니다. 그 밖의 모든 금액은 이미 문자열이었습니다. rand_getSupply, rand_getEmission, rand_getValidators, 조회 노트, 그리고 체인 14와 함께 도입된 모든 필드, 즉 번들의 burn_a와 burn_r, 토큰 공급량, 각 백킹의 locked, mint_cap_per_day, minted_today, registration_fee, 그리고 token_mint, token_burn, register_token의 amount(initial_amount, initial.amount)가 그렇습니다.

배치

POST 본문은 최대 20개의 요청 객체로 이루어진 배열일 수 있으며, 오류를 포함해 요청 순서대로 같은 길이의 배열로 응답합니다. 요청은 차례로 실행됩니다. 빈 배열, 20개를 넘는 배열, 객체도 배열도 아닌 본문은 id가 null인 단일 -32600입니다. 본문 전체는 여전히 증명이 포함된 트랜잭션 하나에 맞춰진 노드의 요청 본문 한도의 제약을 받습니다. 증명이 포함된 rand_sendTransaction 호출 두 건으로 이루어진 배치는 413으로 거부됩니다. 배치는 증명된 제출이 아니라 읽기에 사용하십시오.

체인과 노드

rand_chainId

매개변수 []. 결과: 체인 id(정수). 테스트넷에서는 20입니다.

rand_tokenInfo

매개변수 []. 결과 { "symbol": "RAND", "decimals": 9 }.

rand_getHead

매개변수 []. 결과 { "height": 1998, "hash": "…", "view": 2251 }. view는 노드의 현재 합의 뷰이며, 뷰가 시간 초과되면 높이보다 앞서 나갑니다.

rand_status (별칭 rand_syncStatus)

매개변수 []. 결과:

{
  "height": 1998, "head_hash": "…", "view": 2251, "high_qc_view": 2250,
  "syncing": false, "sync_target": 1998,
  "sync_inflight_age_ms": null, "sync_failures": 0, "sync_late_batches": 0,
  "peer_count": 26, "connected_peers": 26, "reserved_peers": 25, "ws_clients": 0, "refused_cache": 0,
  "verify_queue": 0, "mempool_size": 0,
  "is_validator": true, "active_validator": true, "faucet": true, "confidential": true,
  "testnet": true, "fri_profile": "production", "programs": 10, "viewing_keys": 0,
  "notes": 197, "nullifiers": 160, "tree_root": "72b9…1197", "hc_bundle": "60af…3fce", "hc_auth": "1e4e…39c1",
  "binding_domain": 1,
  "address": "5TAofR…", "peer_id": "12D3KooW…",
  "gas_prices": { "gas_price": "100", "byte_price": "800" }
}

is_validator: 이 노드가 밸리데이터 키를 보유합니다. active_validator: 그 키가 현재 에포크를 실행하는 집합에 속합니다. reserved_peers(v0.6.8)는 인바운드 연결 상한을 넘어 허용된 피어의 수로, 부트스트랩, 모든 --reserved-peer, 서명된 피어 바인딩에서 알게 된 모든 밸리데이터 신원을 각각 한 번씩 셉니다. 플릿 노드에서는 시작 후 1분 안에 밸리데이터 수에 도달해야 합니다. viewing_keys는 노드 측 스캔을 위해 노드가 메모리에 보유한 조회 키의 수입니다. verify_queue는 네 개의 증명 검증 워커 중 하나를 기다리는 트랜잭션의 수입니다(최대 64개). hc_bundle은 이 체인의 증명이 기준으로 삼는 번들 게스트이고, hc_auth는 제네시스가 고정하는 인증 게스트(체인 17부터 분리된 인가)이며, 이것이 없는 체인에서는 null입니다. 빌드가 둘 중 하나와 일치하지 않는 노드는 시작을 거부합니다. testnet과 binding_domain은 rand_getLimits가 제공하는 것과 같은 이름의 제네시스 필드입니다. gas_prices는 팁 원장의 현재 가스 가격으로, 커밋마다 갱신되며 10진수 문자열입니다. gas 섹션이 없는 체인에서는 null입니다. 체인 20의 가격은 동적이며 블록의 채움 정도에 따라 블록마다 움직이고, 하한인 100과 800 아래로 내려가지 않으며 상한인 10,000과 80,000 위로 올라가지 않으므로, 하드코딩하지 말고 여기나 rand_getLimits에서 읽으십시오. 이 객체에는 aggregation 객체(subsidy_base는 10진수 문자열, 나머지는 정수)도 있으며, 체인 20처럼 aggregation 섹션이 없는 체인에서는 모두 0으로 읽힙니다.

이 객체에는 disk_free_bytes(숫자)와 disk_low, 그리고 보존 설정 한 쌍도 있습니다. prune_floor는 이 노드가 아직 보유한 가장 낮은 높이(아카이브에서는 0)이고, prune_history_secs는 --prune-history로 시작한 노드가 유지하는 구간입니다(모든 것을 유지하면 null). 체인 20에서는 체인 19와 마찬가지로 26개 밸리데이터 중 24개가 24시간 분량의 블록을 유지하고, 두 개의 아카이브는 모든 블록을 유지합니다. 프루닝된 노드를 참고하십시오.

rand_getPeers

매개변수 []. 결과: { "peer_id": "12D3KooW…", "addrs": ["/ip4/…/tcp/30303"], "connected_secs": 1241 }의 배열.

rand_getBlockByHeight / rand_getBlockByHash

매개변수 [height] 또는 [hash]. 알 수 없으면 결과는 null이고, 그렇지 않으면 다음과 같습니다.

{
  "hash": "647b…", "height": 50, "view": 92, "parent": "2d41…",
  "proposer": "3v3VBJ…", "timestamp_ms": 1788000123456,
  "tx_root": "0000…", "state_root": "a1b2…", "justify_view": 91,
  "tx_count": 0, "transactions": [ ]
}

커밋된 블록만 제공됩니다. transactions는 rand_getTransaction의 tx와 같은 형태를 가집니다. 블록에는 sealed도 있고, 블록의 각 트랜잭션에는 sealed_by가 있습니다. 집계(aggregation)가 없는 체인에서는 각각 false와 null로 읽힙니다.

rand_getBlocks

매개변수는 [from_height, to_height]입니다. 결과는 오래된 것부터 정렬된 블록 헤더이며, from_height부터 최대 1,024개입니다(2026-09-24 이전의 노드에서는 128개). 필드는 transactions가 없는 rand_getBlockByHeight의 필드와 같습니다. 상한보다 넓거나 헤드를 넘어서는 범위는 거부되지 않고 잘리며, v0.6.8부터는 페이지가 64 MiB의 블록을 읽은 시점에도 끝납니다. 반환된 마지막 높이부터 이어서 진행하십시오. to_height가 from_height보다 작으면 -32602입니다.

v0.6.8부터 모든 헤더에는 public_notes도 포함됩니다. 이는 블록의 bridge_attest, token_mint, register_token 트랜잭션이며, 브리지 수수료가 있는 체인에서는 bridge_burn 트랜잭션도 포함하고, 형식은 [{ "hash", "raw" }]입니다(rand_getRawTransaction이 제공하는 인코딩). 그 밖의 블록에서는 비어 있습니다. burn은 증명을 비우고 "proofs_stripped": true를 붙여 제공되며, 그 hash는 실제 트랜잭션 id입니다. 지갑의 최초 동기화는 이 페이지들을 읽으며, 공개 노트를 재구성하는 데 다른 것은 필요하지 않습니다.

rand_getFinality

매개변수는 [height] 또는 [hash]입니다. 결과는 { "status": "committed", "height", "hash" }, { "status": "certified", "height", "hash", "qc_view" }, { "status": "proposed", "height", "hash" }, { "status": "unknown" } 중 하나입니다. 높이는 커밋된 체인에 대해서만 확인되므로 committed 또는 unknown으로 응답합니다. 해시는 certified(레플리카의 미커밋 트리에 있고 쿼럼 인증서가 있음) 또는 proposed(트리에 있으나 쿼럼 인증서가 없음)로도 읽힐 수 있습니다.

rand_getProposer

매개변수는 [view] 또는 [from_view, to_view]이며, 최대 64개의 뷰입니다. 결과는 { "epoch": 3, "proposers": [ { "view": 2251, "proposer": "2nRdFC…" } ] }입니다. 각 뷰의 리더는 해당 뷰에서 과거에 운영되던 집합이 아니라 현재 검증자 집합을 기준으로 정해집니다. 범위가 거꾸로이거나 64개를 넘는 뷰에는 -32602입니다.

rand_getVersion

매개변수는 []입니다. 결과는 { "version", "git_sha", "chain_id", "hc_bundle", "hc_auth", "fri_profile" }입니다. version은 워크스페이스 크레이트 버전이고, git_sha는 빌드 시점에 기록된 커밋 해시이며 추적 대상 파일이 달랐다면 -dirty가 붙고, 그렇지 않으면 "unknown"입니다. hc_auth는 rand_status와 같이 제네시스 auth 게스트이거나 null입니다. 2026-10-01 기준 체인 20의 공개 엔드포인트는 다음과 같습니다.

{ "version": "0.6.8", "git_sha": "c9c9bd3c1903aa4cc5833b7ab8c62fc3e6942017", "chain_id": 20,
  "hc_bundle": "60af094acfe65d85fdb18fb3d06cf9085dcf28c96e59e87f1ee527226e6e3fce",
  "hc_auth": "1e4e347f44cf86750b30a9a4bdf9ec9256efe353d4ff8017451eca7d195639c1",
  "fri_profile": "production" }

rand_getGenesisHash

매개변수는 []입니다. 결과는 16진수 제네시스 해시이며, 체인 20에서는 "6210cf071a390d7ac61d8cbea5dd9d139d1a493a862b54a45a498f36af2d5135"입니다(체인 19의 해시는 a3defc93…228a였습니다). 체인 id만으로는 두 체인 컷을 구분할 수 없지만, 이 값으로는 구분할 수 있습니다. 체인 20에서는 이 값이 모든 트랜잭션 바인딩과 서명된 모든 액션 메시지에도 포함됩니다(binding_domain: 1, rand_getLimits 참조).

rand_getHealth

매개변수는 []입니다. 결과는 { "status": "disk_low", "free_bytes": "3221225472" }, { "status": "ok" }, { "status": "syncing", "behind": 412 }, { "status": "behind", "behind": 30 } 중 하나입니다. disk_low는 다른 모든 상태보다 우선하며, 데이터 디렉터리가 있는 파일 시스템의 여유 공간이 노드의 --min-free-disk-mb(기본값 1024, 즉 4 GB 미만)의 네 배보다 적을 때 나타납니다. free_bytes는 십진수 문자열입니다. ok는 sync_target - height가 2 이하이고 처리 중인 동기화 배치 요청이 없을 때, syncing은 그런 요청이 있는 동안, behind는 노드가 동기화 중이 아닌데 지연이 여전히 2를 넘을 때입니다.

rand_getMempoolInfo

매개변수는 []입니다. 결과는 { "count": 2, "bytes": 2611200, "oldest_ms": 1450, "max_count": 10000 }입니다. bytes는 풀에 있는 모든 트랜잭션의 인코딩된 길이의 합이고, oldest_ms는 풀이 비어 있으면 null입니다. v0.6.8부터 풀은 바이트 기준으로도 상한이 있으며, 제네시스 max_block_bytes의 여덟 배입니다(체인 20에서는 160 MiB). 이 상한을 넘으면 KiB당 최소 수수료 초과분을 더 많이 내는 트랜잭션이 가장 저렴한 트랜잭션을 밀어내고, 같거나 적게 내는 트랜잭션은 mempool full로 거부됩니다. 거버넌스 액션은 두 상한을 모두 통과합니다.

제출

rand_sendTransaction

매개변수는 [hex]이며, hex는 bincode(Transaction)입니다. 결과는 트랜잭션 해시입니다. 노드는 승인 순서(트랜잭션)에 따라 검증한 뒤 풀에 넣고 가십으로 전파합니다. 오류는 사유와 함께 -32000으로 반환됩니다. 사유는 다음과 같습니다. nullifier already spent, anchor is not one of the last 1024 roots, time 12 is outside [1500, 2524](두 윈도 모두 제네시스의 proof_window_blocks이며, 체인 20에서는 1,024, 체인 19까지는 256), 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. invoke의 경우 cell <key> is no longer what this transition read(상태에 대한 판정이므로 셀을 다시 읽고 증명을 다시 생성하십시오) 또는 the vault holds … of asset … and the transition pays …. 표결에 의한 승인 방식에서 Bond를 등록하는 경우 validator … has not been admitted by the validator set's vote (staking.admission_by_vote); ask the validators for an AdmitValidator first. 체인 20의 제네시스에 맞지 않는 번들의 경우 envelope is 1348 bytes, this chain requires exactly 1860, 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, auth proof: …, bundle proof declares gas limit …, this chain requires exactly 20479, non-canonical proof: … — re-prove with an up-to-date wallet. 브리지 액션의 경우 bridge: attestation already consumed, the attestation names a different recipient, the attestation deposits under asset 2, and the transaction names 1, the bundle burns 399, not the 400 the action declares. 액션이 가질 수 없는 burn을 담은 번들의 경우 the bundle burns asset 2 on an action that burns no token, a burn of 5 is not allowed on this action 또는 RAND burned through burn_a (5); a RAND burn goes through burn_r. 브리지의 상태에 관해서는 bridge minting is paused, mint cap … per backing per day, already paused, not paused, wrong pause nonce, wrong list nonce, chain N has no registered emitter. 토큰 레지스트리의 경우 wrong mint nonce와 wrong token index. 수락은 커밋이 아닙니다. rand_getTransaction 또는 rand_getTransactionStatus를 폴링하십시오.

체인의 블록 상한(rand_getLimits의 max_block_bytes)보다 큰 트랜잭션은 멤풀에 도달하기 전에 두 크기를 모두 명시한 -32000으로 거부됩니다. 요청 본문의 상한은 2 × (2 × max_proof_bytes + 4 × 2048 + max_call_envelope_bytes + 16,384 + 64 KiB) + 256 KiB이며, 시작 시 제네시스로부터 계산됩니다. 기본 체인에서는 8,867,840바이트, 체인 20의 한도에서는 17,350,656바이트이고, 이는 체인 17부터 19까지와 같습니다(증명 상한이 8 MiB였던 체인 13부터 15까지는 34,127,872바이트). 4 × 2048은 번들의 네 엔벨로프를 엔벨로프 상한 크기로 계산한 값입니다. 이를 넘는 본문은 한도를 명시한 -32600입니다.

트랜잭션에 대한 판정은 -32000(승인이 거부함)과 -32602(디코딩할 수 없음)뿐입니다. -32603을 포함한 그 밖의 실패는 트랜잭션의 운명을 알 수 없는 상태로 남깁니다. 노드는 응답하기 전에 트랜잭션을 풀에 넣고 전파하므로, 그 사이에 중단된 노드는 응답하지 못한 트랜잭션을 이미 승인했을 수 있습니다. randprotocol_client는 이 두 코드에 대해서만 전송이 거부된 것으로 처리합니다.

rand_getTransactionStatus

매개변수는 [[hash, …]]이며, 해시는 1개에서 64개입니다. 결과는 해시마다 하나씩, 순서대로 나열된 항목입니다.

[ { "hash": "…", "status": "committed", "height": 1998, "index": 0 },
  { "hash": "…", "status": "pending" },
  { "hash": "…", "status": "rejected", "reason": "bad mint signature" },
  { "hash": "…", "status": "unknown" } ]

해시별 조회 순서는 다음과 같습니다. 커밋됨(스토리지), 대기 중(멤풀), 거부됨(rand_status의 refused_cache가 세는 거부 캐시), 그 외에는 unknown입니다. rejected는 이후의 어떤 블록으로도 바뀔 수 없는, 트랜잭션 자체의 바이트에 관한 거부만 포함합니다. 유효하지 않은 증명, 증명이 공개한 값과 다른 번들 다이제스트, 잘못된 mint 서명, 잘못된 체인 id, 크기가 초과된 부분, 트랜잭션 내부의 중복된 nullifier 또는 커밋먼트, 크기가 잘못된 엔벨로프, 누락되었거나 일치하지 않는 auth 증명, 잘못된 가스 한도를 선언한 번들 또는 auth 증명이 여기에 해당합니다. 그 시점의 노드 상태에 따라 달라지는 거부, 즉 이미 사용된 nullifier, 윈도 밖의 앵커 또는 time, 최소 수수료 미만의 수수료(체인 20에서는 가스 가격에 따라 변동), 알 수 없는 프로그램, 레지스터 nonce, 오래된 invoke 읽기는 기억되지 않으며 unknown으로 읽힙니다. 목록이 비어 있거나 해시가 64개를 넘으면 -32602입니다.

rand_mint (testnet 파우셋)

매개변수는 [address] 또는 [address, amount]입니다. address는 rand1… 주소이고, amount는 최대 100000000000(100 RAND, 기본값)까지의 단위를 나타내는 문자열입니다. 결과는 mint 트랜잭션 해시입니다. 제네시스에 "faucet": true가 있는 체인에서만 동작하며, 그렇지 않으면 -32000 faucet is disabled on this chain입니다. 옵저버는 faucet mints are signed by validators; ask a validator node로 응답합니다.

제네시스에 staking.faucet_recipients가 설정된 체인(체인 20이 그러하며 지갑 16개)에서는 목록에 있는 지갑에만 지급할 수 있습니다. 그 밖의 주소로 mint하면 the faucet may not mint to this recipient (not in staking.faucet_recipients)로 거부됩니다. 체인 20의 제네시스에는 staking.faucet_minters(검증자 키 18개)도 설정되어 있어, 목록에 있는 키만 mint에 서명할 수 있습니다. 파우셋에는 에폭당 예산 staking.faucet_budget_per_epoch(체인 20에서는 1,000블록 에폭당 10,000 RAND)도 있으며, 이를 넘는 mint는 FaucetBudgetExhausted로 거부됩니다. 이는 상태에 대한 판정이므로 풀에서 빠져나가면 unknown으로 읽힙니다.

공개 faucet은 노드 프로세스별로 요청 속도가 제한됩니다. 연속 mint는 8회까지 허용되며, 이후에는 초당 1회씩 다시 채워집니다. 이 한도를 넘으면 호출은 faucet is rate limited on this node (8 mints back to back, refilling at 1/s); try again shortly로 응답합니다. 따라서 faucet 요청이 폭주하더라도 bridge PauseMints보다 먼저 풀을 가득 채울 수 없습니다. PauseMints는 나머지 세 가지 bridge 거버넌스 액션과 마찬가지로 풀의 mempool full 거부에서도 제외되며, 블록에서 가장 먼저 정렬됩니다.

chain 14부터 mint는 공개(opened) 방식입니다. Mint 액션은 cm과 amount 외에 note의 pk, time, r도 함께 담습니다. 승인 단계에서 commitment를 다시 계산하여, 이 값들로 열리지 않는 cm은 거부합니다(the mint's commitment does not open to its published note and amount). minter는 일곱 개 필드 전체에 도메인 rand-mint-2로 서명합니다. chain 20(binding_domain: 1)에서는 genesis 해시를 맨 앞에 두고 rand-mint-3으로 서명합니다. 따라서 faucet note의 소유자와 금액은 withdraw의 지급액과 마찬가지로 공개됩니다. rand_mint의 매개변수는 바뀌지 않았습니다.

rand_estimateFee

Params [spec], 다음 중 하나: {"kind":"bundle"}, {"kind":"deploy","words":n,"public_words":m}, {"kind":"call","tier":t,"bytes":b,"gas":g}. 이때 t는 10, 12, 14, 16, 18, 20 중 하나입니다. Result: 최소 수수료(단위: units)이며 문자열입니다. {"kind":"bundle"}은 "1000000"입니다. public_words(선택, 기본값 0)는 코드와 마찬가지로 word당 과금되므로, 수수료는 n + m word의 배포 수수료입니다. bytes(선택, 기본값 0)는 호출의 증명 길이와 입력 envelope의 길이를 더한 값입니다.

호출 요금이 어떻게 산정되는지는 rand_getLimits의 gas_metering에 따라 달라집니다.

  • "circuit", 자체 gas 섹션을 가진 체인(chain 20이 이에 해당합니다). gas는 호출의 증명이 선언하는 gas 한도이며 필수입니다. 이 값이 없으면 호출은 -32602 under the gas section a call estimate needs its gas로 응답합니다. 요금은 1,000,000 + gas_price × gas + byte_price × ⌈bytes / 1024⌉이며, 블록 팁의 현재 가격, 즉 rand_getLimits가 제공하는 가격을 적용합니다. chain 20의 하한 가격 100과 800에서, 20,479 gas를 선언하고 증명과 envelope이 합쳐 1,300,000 bytes인 호출은 "4063900"입니다. 가격은 블록마다 변하므로, 전송 직전에 추정하십시오.
  • "header", 해당 섹션이 없는 체인의 노드 수준 gas 정책. 호출 spec은 keccak_log_height와 sha256_log_height(선택, 기본값 0, 각각 0에서 40 사이이며 벗어나면 -32602)를 받습니다. 이는 증명 헤더가 선언하는 해시 테이블 높이이며, 응답은 원장의 tier 하한과 해당 헤더의 gas 하한 중 큰 값입니다. gas 섹션이 있으면 두 높이 값은 받아들여지지만 사용되지 않습니다.
  • null, 둘 다 아닌 경우. 원장의 tier 요금표만 적용됩니다. 무료 허용량(2,097,152 + 18,432 bytes) 이하이면 호출은 해당 tier의 수수료를 냅니다. 이를 초과하는 KiB마다, 일부만 찬 KiB도 하나로 계산하여 1,000 units가 추가됩니다.

v0.6.8부터 {"kind":"invoke", …, "created_cells": c}로 RPL-2 invoke의 요금을 산정할 수 있습니다. 호출 spec의 모든 필드에 더해 created_cells(선택, 기본값 0, 최대 max_writes, 초과하면 -32602)를 받으며, 이는 전이가 생성하게 될 cell의 수입니다. cell 하나마다 체인의 cell_fee(rand_getLimits.program_state)가 더해집니다. 호출자가 직접 개수를 셉니다. rand_getProgramCell이 0으로 읽는 cell에 0이 아닌 값을 쓰는 경우가 이에 해당합니다. chain 20에서 위 호출에 생성된 cell 두 개를 더하면 "24063900"입니다. program_state 섹션이 없는 체인에서 이 kind는 -32602입니다.

수수료에 요금표가 있습니다.

풀

rand_getTreeInfo

Params []. Result { "next_index": 41, "root": "6b1d…c4", "nullifiers": 12 }: 리프 수, 현재 루트, 사용된 note의 수입니다.

rand_getCommitments

Params [from_index] 또는 [from_index, limit]. Result: from_index부터 시작하는 리프 페이지이며 오래된 것부터 정렬됩니다. limit이 아무리 커도 최대 1,000행입니다.

[ { "index": 40, "cm": "2a9f…07", "height": 37,
    "envelope": { "kem_ct": "b41c…", "to_receiver": "77e0…", "to_sender": "0c31…", "body": "9dd2…" } } ]

rand_getNullifiers

Params [from_height] 또는 [from_height, limit]. Result: 해당 높이부터 게시된 모든 nullifier이며, 동일하게 1,000행으로 제한됩니다. 페이지가 한 높이의 중간에서 끝날 수 있으므로, 확인된 가장 높은 높이로 되돌아가 페이지를 이어 가십시오.

[ { "height": 37, "nullifier": "8c04…d1" }, { "height": 41, "nullifier": "12be…9a" } ]

rand_getCompactBlocks

Params [from_height, to_height], 둘 다 필수. Result: 블록당 한 행이며 오래된 것부터 정렬됩니다. 라이트 지갑에 필요한 정보만 담고 그 외에는 없습니다.

[ { "height": 192, "hash": "63f6…08", "timestamp_ms": 1788000123456,
    "commitments": [],
    "transactions": [
      { "hash": "4f2c…e7",
        "commitments": [ { "index": 40, "cm": "2a9f…07", "envelope": { "kem_ct": "…", "to_receiver": "…", "to_sender": "…", "body": "…" } } ],
        "nullifiers": ["8c04…d1", "5e77…20", "03aa…6f", "e19b…42"] } ] } ]

번들을 담은 모든 트랜잭션은 여기에서 note 네 개와 nullifier 네 개를 소유합니다. 이는 네 개의 슬롯이며, 어떤 독자도 실제 슬롯과 구별할 수 없는 더미 슬롯을 포함합니다(예시에는 첫 번째 commitment 행만 표시했습니다). v0.6.8부터 일부 트랜잭션은 그 네 개 뒤에 note를 더 소유합니다. invoke는 지급마다 note 하나를 소유하며 pays, mints 순서이고 각각 지급 고유의 envelope를 가지므로 수취인은 시험 복호화로 이를 찾습니다. chain 20처럼 bridge 수수료가 있는 체인에서 bridge_burn은 treasury 수수료 note를, bridge_attest는 입금 뒤에 수수료 note를 소유합니다. 수수료 note의 envelope는 비어 있으며 누구에게도 봉인되지 않습니다. treasury 지갑은 트랜잭션의 공개 필드로 note를 재구성합니다.

호출당 최대 128개 블록(더 넓은 범위는 잘립니다)이며, 항상 통째로 제공되는 첫 블록을 제외하고 note는 1,000개까지입니다. 마지막으로 반환된 height에 1을 더한 값부터 이어 가십시오. 블록 수준의 commitments 배열은 높이 0에서는 genesis 입금을 담고 그 외에는 비어 있습니다. Withdraw와 BridgeAttest가 파생하는 note는 해당 트랜잭션 아래에 나타납니다. 범위가 거꾸로이거나 한쪽 경계가 없으면 -32602입니다.

rand_getAnchor

Params []이면 헤드, 또는 [height]. Result { "height": 192, "root": "6b1d…c4" }이며, 기록된 앵커가 없는 높이에는 -32001입니다. 블록 종료 시점의 루트만 앵커입니다. 노드는 오래된 높이에 대해서도 응답할 수 있지만, 번들의 앵커는 최근 proof_window_blocks개 루트 중 하나일 때만 승인됩니다. chain 20에서는 1,024개, chain 19까지는 256개입니다. 헤드를 기준으로 빌드하십시오.

rand_getWitness

Params [index]. Result: 트리의 끝을 넘어선 인덱스이면 null이며, 그렇지 않으면 해당 리프의 Merkle 경로로 리프부터 정확히 32단계이고 트리의 현재 루트와 함께 제공됩니다.

{ "index": 40, "root": "6b1d…c4", "path": ["0000…00", "f2a1…3b", "…"] }

노드가 제공하는 읽기 중 가장 비용이 큰 요청이며(전체 깊이 32 트리를 다시 구축합니다), 호출자에 관해 무언가를 드러내는 유일한 요청입니다. 노드는 트리 재구축을 한 번에 최대 두 개까지만 실행하며, rand_getWitness와 rand_getWitnesses를 합산합니다. 슬롯을 10초 넘게 기다린 요청은 -32000 witness builds are busy on this node; retry shortly로 거부됩니다.

rand_getWitnesses

Params [[index, …]], 리프 인덱스 1개에서 32개. Result { "root": "…", "witnesses": [ { "index": 7, "path": ["…"] }, { "index": 9, "path": null } ] }: 여러 리프에 대한 rand_getWitness를 한 번의 트리 구축으로 처리한 것이므로, 여러 note를 증명하는 지갑은 재구축 비용을 한 번만 지불합니다. 트리의 끝을 넘어선 인덱스는 해당 항목에서 path: null로 읽힙니다. 목록이 비어 있거나 인덱스가 32개를 넘으면 -32602입니다.

조회 키와 공개

rand_importViewingKey

Params [viewing_key] 또는 [viewing_key, rescan_from_height], 키는 64자리 16진수 문자열입니다. Result { "imported": true, "rescan_from_height": 0, "viewing_keys": 3 }. 노드는 키를 메모리에만 보관합니다. 노드당 최대 64개이며 재시작하면 지워지고, 이미 보유한 키는 아무 동작도 하지 않습니다("imported": false). 가져오기는 스캔을 수행하지 않으며, 스캔은 다음 메서드가 구동합니다. 형식이 잘못된 키는 -32602, 65번째 키는 -32000입니다.

viewing key 메서드 세 개는 루프백 호출자에게만 응답하며, 그 외에는 -32000으로 거부합니다. 단, 노드가 인증을 수행하는 장치 뒤에서 --rpc-viewing-open으로 실행되는 경우는 예외입니다. rand_removeViewingKey([viewing_key] → { "removed": bool, "viewing_keys": n })는 슬롯을 비우고 키를 0으로 덮어씁니다. 레지스트리는 키 자체가 아니라 키의 단방향 id인 blake3("rand-viewing-registry-id-1" ‖ nk)를 색인으로 삼으므로, 가져오기가 유일한 장기 사본이며 제거하면 이를 지웁니다. 요청 자체의 JSON 텍스트와 시험 복호화가 만드는 일시적 사본은 지워지지 않습니다.

rand_getViewingNotes

Params [viewing_key] 또는 [viewing_key, from_index, limit] (limit의 기본값과 최댓값은 1,000). 호출할 때마다 키의 스캔이 최대 10,000개 리프만큼 진행된 뒤 페이지가 제공됩니다.

{ "scanned_index": 10041, "next_index": 10041, "complete": true,
  "notes": [
    { "index": 40, "cm": "2a9f…07", "height": 37, "role": "received",
      "note": { "pk": "…", "from": "…", "amount": "1500000000", "asset": 0, "time": 5, "memo": "coffee" },
      "nullifier": "8c04…d1", "spent": false },
    { "index": 43, "cm": "b310…88", "height": 39, "role": "sent",
      "note": { "pk": "…", "from": "…", "amount": "25000000", "asset": 0, "time": 9, "memo": null },
      "nullifier": null, "spent": null } ] }

role은 received(envelope가 수신자로 열렸고 note가 키의 pk를 지정함) 또는 sent(outgoing viewing key로 열림)입니다. note의 memo는 발신자의 암호화된 메모로, 최대 510 bytes의 UTF-8 텍스트입니다. 메모가 없거나 해당 필드가 잘못된 형식으로 열린 경우에는 null입니다. 잘못된 형식의 메모 때문에 수취인이 note를 잃는 일은 없습니다. 메모는 누구나 쓸 수 있는 텍스트이므로, 신뢰할 수 없는 것으로 표시하십시오. 이 노드가 가져오지 않은 키에는 -32001입니다.

rand_checkTransaction

Params [hash, key], key는 트랜잭션별 TxKey이며 64자리 16진수 문자열입니다. Result: 알 수 없는 해시이면 null, 그렇지 않으면 키가 공개하는 내용입니다.

{ "tx": "4f2c…e7", "height": 192,
  "disclosed": [ { "output": "bundle:0", "cm": "2a9f…07", "index": 40,
                   "note": { "pk": "…", "from": "…", "amount": "1500000000", "asset": 0, "time": 5, "memo": "invoice 7" } } ] }

상태 비저장 방식입니다. 키는 호출과 함께 폐기됩니다. output은 번들의 네 출력 슬롯(슬롯 0–1은 비공개 자산 출력, 슬롯 2–3은 RAND 출력이며 더미 포함)에 대한 bundle:0 … bundle:3이고, 브리지 증명(attestation)의 입금 엔벨로프에는 deposit, TokenMint의 노트에는 token_mint, RegisterToken의 초기 발행에는 initial_mint, 파우셋 발행의 단일 엔벨로프에는 mint:0, 또는 (v0.6.8) invoke가 지급한 노트에 대해 전환(transition) 내 위치, 즉 pays 다음 mints 순서로 번호를 매긴 payout:0 … payout:3입니다. asset_bundle:*은 두 번째 번들과 함께 사라졌습니다. 브리지 수수료가 있는 체인에서 deposit은 순입금액, 즉 총액에서 수수료를 뺀 금액을 엽니다. 공개된 note에는 해당 asset이 들어 있습니다. 발신자가 봉인할 때 사용한 키로 이 호출을 하는 것이, 전송이 어떤 자산을 옮겼는지를 RPC가 드러내는 유일한 경로입니다. rand_getViewingNotes와 마찬가지로 memo도 함께 들어 있습니다. 노트를 여는 키가 같은 봉인된 본문에서 메모도 엽니다. 잘못된 키는 { "disclosed": [] }를 반환하며, 이는 아무것도 공개하지 않는 트랜잭션과 구별되지 않습니다. 출금(withdraw)과 제네시스 할당(alloc)의 엔벨로프는 시도 대상이 아닙니다. 이들은 즉시 폐기되는 키로 노드 내부에서 봉인되므로 해당하는 TxKey가 존재하지 않습니다. 파우셋 발행의 엔벨로프는 시도 대상입니다. 수신자는 엔벨로프의 KEM 절반을 통해 키를 복구합니다(rand tx-key).

트랜잭션

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": 1490435, "envelope_len": [1860, 1860, 1860, 1860],
                "auth_commit": "9217…ee9e", "auth_proof_bytes": 1361161 },
    "action": { "kind": "none" }
  }
}

번들이 없는 액션에서는 bundle이 null입니다. 증명과 엔벨로프는 길이로만 보고됩니다. envelope_len은 체인 20에서 모든 슬롯에 대해 1,860이며, 이 체인의 제네시스가 노트 엔벨로프를 해당 크기로 고정합니다(rand_getLimits의 envelope_bytes). 체인 14~17에서는 1,348이었습니다. auth_commit과 auth_proof_bytes는 분리된 승인(체인 17 이후)의 값입니다. 번들 증명과 승인 증명이 모두 공개하는 공개 커밋먼트 c = H(AUTH, nk, salt), 그리고 승인 증명의 길이입니다. hc_auth가 없는 체인에서는 각각 0과 0입니다.

bundle은 숨겨진 자산 번들(체인 14 이후)입니다. 입력 슬롯 네 개와 출력 슬롯 네 개로 구성되므로, 더미를 포함해 nullifiers, commitments, envelope_len은 항상 네 개입니다. 트랜잭션마다 최대 하나만 담을 수 있으며, 두 번째 번들은 없습니다. 번들에는 asset 필드가 없습니다. 슬롯 0–1은 비공개 자산을, 슬롯 2–3은 RAND를 담으며, 슬롯 0–1이 어떤 자산을 옮겼는지는 공개적으로 알 수 없습니다. RAND 전송과 모든 RPL 토큰 전송은 모두 "kind": "none"이고 burn_a, burn_r, burn_asset이 모두 0입니다. 필드 하나하나가 같은 형태입니다. token_transfer 종류는 없습니다. 세 소각 필드는 풀에서 가치가 빠져나간다는 사실에 대해 번들이 공개적으로 밝히는 유일한 내용입니다.

  • burn_a / burn_asset — 소각된 비공개 자산의 수량과 해당 자산입니다. token_burn 또는 bridge_burn에서는 0이 아니며 액션의 amount 및 asset과 같습니다. inflow가 deposit 또는 burn인 invoke에서도 0이 아닙니다.
  • burn_r — 소각된 RAND입니다. bond(amount와 같음), register_aggregator, 그리고 프로그램의 볼트에 RAND를 예치하는 invoke에서 0이 아닙니다.
  • fee — RAND 수수료이며, 항상 슬롯 2–3에서 나옵니다.

액션 표현(모든 amount, relayer_fee, initial_amount는 십진수 문자열이며, 토큰의 수량은 RAND가 아니라 해당 토큰 자체의 단위입니다).

kindfields
none—
mintcm, amount, minter (validator base58)
deployprogram, words, public_words_len
callprogram, proof_len, input_envelope_len (호출에 없으면 null)
bondvalidator, amount, registered
unbondvalidator, amount, nonce
withdrawvalidator, amount, nonce, time
bridge_attestattestation_len, recipient, asset, asset_index, amount, time, r, commitment, pq_signers (공동 서명한 가디언의 pq_guardians 내 인덱스이며, 2,420바이트 서명은 표시되지 않음). asset_index, amount, commitment는 가디언 집합 교체에서는 null입니다. r은 파생값으로, 가디언이 서명한 다이제스트 mu에 대한 blake3("rand-deposit-r-1" ‖ mu)입니다. v0.6.8부터 deposit_amount(입금자의 노트: 가디언이 서명한 총액인 amount에서 브리지 수수료를 뺀 값)와 fee_note({ amount, asset, time, r, commitment }, 소유자를 제외한 재무부의 노트이며 브리지 수수료가 없으면 null)도 있습니다. commitment는 순입금액의 리프입니다
bridge_burnasset, amount, relayer_fee, to_chain, token (상환되는 담보), to. 하나의 번들이 소각 전체를 담습니다. 번들의 burn_asset과 burn_a는 액션의 asset과 amount입니다. v0.6.8부터 release_amount(서명된 본문이 해제하는 금액, 즉 amount에서 브리지 수수료를 뺀 값)와 증명(attest)에서와 같은 fee_note도 있습니다
register_tokenname, symbol, decimals, authority ("none", "key", "bridge" 또는 "program"), index, initial_amount, initial ({ amount, recipient, time, r } 또는 null)
token_mintasset, amount, recipient, time, r, nonce
set_authorityasset, nonce, new_authority (base58, 권한 포기의 경우 null)
token_burnasset, amount. 번들의 burn_asset / burn_a가 이를 반복합니다
pause_mintsnonce. 번들 없음, 수수료 없음, 제네시스 일시 정지 키로 서명
unpause_mintsnonce, pq_signers. 번들 없음, 수수료 없음
register_bridged_tokenname, symbol, salt, chain, token, decimals (첫 번째 담보의 원천 소수 자릿수), nonce, asset_id, pq_signers
list_backingtoken_index, chain, token, decimals, nonce, pq_signers
rotate_pq_guardiansnew_pq_guardians, nonce (소모된 rotation_nonce), pq_signers (교체 이전 PQ 집합의 인덱스). 번들 없음, 수수료 없음, 브리지 rules_v2 체인에만 해당
rotate_pause_keynew_pause_key, nonce, pq_signers. 위와 동일
rotate_pq_guardians_v2, rotate_pause_key_v2v0.6.8: v1 필드에 더해 PQ 형식에는 possession_signatures(개수)가 있습니다. 번들 없음, 수수료 없음. 제네시스 bridge.rotation이 needs_possession을 설정한 체인(체인 20이 그러함)에서는 필수입니다. 교체는 delay_secs 후에 적용됩니다(체인 20에서 86,400 s)
cancel_rotationv0.6.8: rotation_kind ("pq_guardians" 또는 "pause_key"), nonce. 현재 일시 정지 키로 서명하며, 대기 중인 교체를 폐기합니다
admit_validatorv0.6.8: candidate (주소), candidate_key (hex), voters (주소). 번들 없음, 수수료 없음. 새 키의 등록을 허용하기 위한 validator 집합의 투표이며, staking.admission_by_vote가 설정된 체인(체인 20이 그러함)에서 사용합니다
slash_equivocationv0.6.8: offender, view, first, second ({ hash, height }). staking.slashing이 설정된 체인에만 해당하며, 체인 20은 해당하지 않습니다
invokev0.6.8, RPL-2: 호출의 필드(program, proof_len, input_envelope_len)와 transition(아래 참조). program_state 섹션이 있는 체인에만 해당하며, 체인 20이 그러합니다
register_aggregator, unbond_aggregator, withdraw_aggregator, slash_aggregator, aggregate각각의 공개 필드. 애그리게이터 체인에만 해당
claim_vested, revoke_vesting, bond_vested, unbond_vestedentry (hex), amount (revoke에서는 unvested), nonce. claim 또는 revoke에는 time. bond에는 validator와 registers. v0.6.8부터 revoke에는 signers(엔트리의 revokers 내 서명자 위치). 번들 없음. 제네시스 vesting 섹션이 있는 체인에만 해당하며, 체인 20은 해당하지 않습니다

토큰의 등록과 발행은 브리지 입금과 마찬가지로 공개됩니다. 발행된 노트의 모든 워드가 액션에 들어 있으며(노트의 from은 체인의 고정값 MINT_FROM), 따라서 수신자는 아무것도 복호화하지 않고 이 필드들로 노트를 재구성합니다. 종류 문자열 bridge_attest, token_mint, register_token, invoke는 지갑의 스캔이 키로 사용하는 값이며 테스트로 고정되어 있습니다.

체인 20의 높이 3,079에서 셀 하나를 읽고 삭제한 뒤 볼트에서 노트 두 개를 지급한 invoke:

{ "kind": "invoke", "program": "aaaf…4b21", "proof_len": 1433874, "input_envelope_len": null,
  "transition": {
    "reads":  [{ "key": "0100…fa98", "value": "0000000004000000…00000000" }],
    "writes": [{ "key": "0100…fa98", "value": "0000000000000000000000000000000000000000000000000000000000000000" }],
    "inflow": "none",
    "pays":  [{ "asset": 0, "amount": "1000000000", "recipient": "rand1…", "time": 3027, "r": "87e6…9a67", "cm": "2555…6487" },
              { "asset": 4, "amount": "2000000000", "recipient": "rand1…", "time": 3027, "r": "b833…f390", "cm": "2b70…f204" }],
    "mints": [] } }

모두 설계상 공개입니다. reads는 프로그램이 읽은 셀과 읽은 값입니다. 증명은 이 값들에 대해 만들어졌고, 이 값들이 여전히 유지되지 않으면 원장은 트랜잭션을 거부합니다. writes는 프로그램이 쓴 셀이며, 64개의 0으로 된 값을 쓰면 셀이 삭제됩니다. 셀 키와 값은 Word8입니다. 들어온 것은 번들의 몫입니다. burn_r은 프로그램의 볼트에 예치된 RAND이고, burn_a는 inflow가 지정하는 토큰의 burn_asset 수량입니다. deposit은 볼트에 예치, burn은 프로그램 자체 토큰의 소각이며, burn_a가 0이면 none입니다. 나간 것은 지급마다 체인이 계산한 노트 하나입니다. 볼트에서 pays, 이어서 발행 권한이 이 프로그램인 토큰의 mints입니다. 각 노트의 모든 워드가 token_mint의 필드 이름으로 여기에 있습니다. time은 번들의 값이고, cm은 체인이 추가한 리프이며, 노트의 from은 체인의 고정값 PROGRAM_FROM입니다. 프로그램의 출력 워드 여덟 개는 호출과 마찬가지로 영수증에 있습니다.

어떤 전송 응답에도 발신자, 수신자, nonce, 수량, 자산이 담겨 있지 않습니다. 저장된 전송에는 그런 필드가 존재하지 않습니다.

rand_getRawTransaction

매개변수는 [hash]입니다. 결과는 커밋된 전체 트랜잭션을 bincode hex로 나타낸 값이며 증명 바이트를 포함합니다. 애그리게이터에게 필요하지만 rand_getTransaction은 표시하지 않는 내용입니다.

프로그램과 영수증

rand_getProgram

매개변수는 [program_id]입니다. 결과는 null 또는 { "id", "base_pc", "words_len", "code_hash", "deployed_at", "public_words_len", "public_digest" }입니다. deployer 필드는 없습니다. 배포는 번들이 지불합니다. public_words_len은 프로그램의 배포 시점 공개 입력의 길이이고(없으면 0), public_digest는 그 다이제스트로, 모든 호출의 증명이 대조되는 값이며 공개 입력이 없으면 null입니다.

rand_getProgramCode

매개변수는 [program_id]입니다. 결과는 null 또는 { "base_pc": 0, "words": [ … ] }입니다.

rand_getProgramPublic

매개변수는 [program_id]입니다. 결과는 프로그램의 배포 시점 공개 워드를 하나의 16진수 문자열로 나타낸 것이며, 각 워드는 4바이트 리틀 엔디언(워드당 16진수 8자리)으로 표현합니다. [1, 2, 0xdeadbeef]는 "0100000002000000efbeadde"입니다. 공개 입력 없이 배포된 프로그램은 "", 해당 id의 프로그램이 없으면 null입니다. 호출을 증명하는 지갑은 이 워드를 증명자(prover)에 전달하며, 원장은 증명의 커밋먼트를 프로그램의 public_digest와 대조하여 검사합니다.

rand_getProgramCell

v0.6.8, RPL-2. 매개변수는 [program_id, key]이며, key는 64자리 16진수(0x 접두사는 있어도 없어도 됨)의 Word8입니다. 결과는 { "key": "<64 hex>", "value": "<64 hex>" }입니다. 프로그램이 한 번도 쓰지 않았거나 0을 쓴(셀이 삭제됨) 셀은 “없음”의 유일한 인코딩인 64개의 0으로 읽힙니다. 배포된 적 없는 프로그램의 모든 key도 마찬가지인데, 프로그램의 존재 여부는 검사하지 않기 때문입니다. program_state 섹션이 없는 체인에서는 { "enabled": false }입니다. 셀은 설계상 공개이며, 지갑은 이를 읽어 invoke의 reads를 구성합니다.

rand_getProgramCells

v0.6.8. 매개변수는 [program_id, { "after": "<64 hex>" | null, "limit": n }]이며, 객체는 생략할 수 있습니다. 결과는 { "cells": [{ "key", "value" }, …], "next": "<64 hex>" | null }입니다. 프로그램의 셀을 key 순서(여덟 워드의 부호 없는 비교)로, after 다음부터 최대 limit개(1에서 1,000 사이로 제한)까지 반환합니다. 뒤에 더 있으면 next는 마지막으로 반환한 key이며, 이를 after로 다시 전달합니다. 마지막 페이지에서는 null입니다. 셀이 없는 프로그램은 { "cells": [], "next": null }로 응답하며, 섹션이 없으면 { "enabled": false }입니다.

rand_getProgramVault

v0.6.8. 매개변수는 [program_id]입니다. 결과는 [{ "asset": 0, "amount": "123" }, …]이며, 자산 인덱스 오름차순입니다(0은 RAND, 그 외 모든 인덱스는 토큰 레지스트리의 인덱스). 금액은 해당 자산 고유 단위의 십진수 문자열입니다. 잔액이 0인 행은 존재하지 않으므로 빈 볼트, 그리고 배포된 적 없는 프로그램은 []입니다. 섹션이 없으면 { "enabled": false }입니다. 가치는 invoke의 번들(burn_r, 그리고 inflow가 deposit일 때 burn_asset의 burn_a)을 통해 볼트에 들어가고, 트랜지션의 pays가 지정하는 노트로 볼트에서 나갑니다.

rand_getLimits

매개변수는 []입니다. 결과는 지갑이 체인의 제네시스로부터 트랜잭션을 구성하는 데 필요한 정보입니다. 다섯 가지 호출 한도, 노트 봉투(envelope) 크기, v0.6 스위치, 인증 게스트, 가스 조건, 그리고 v0.6.8부터는 audit-v6 제네시스 필드와 프로그램 상태 한도가 포함됩니다. 체인 20에서는 다음과 같습니다.

{ "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_metering": "circuit", "gas_price": "100", "byte_price": "800",
  "bundle_gas_limit": 20479, "adjust_bps": 1250,
  "max_gas_price": "10000", "max_byte_price": "80000", "byte_load": "paying",
  "admission_by_vote": true, "testnet": true, "slashing": null, "binding_domain": 1,
  "proof_window_blocks": 1024,
  "program_state": { "cell_fee": "10000000", "max_reads": 8, "max_writes": 8, "max_payouts": 4 } }

다섯 가지 한도 필드가 없는 제네시스(체인 12)는 4096, 2097152, 4194304, 18432, 0을 받습니다. max_proof_bytes는 체인 13부터 15까지 8,388,608이었습니다.

fieldmeaning
envelope_bytes제네시스가 노트를 생성하는 모든 봉투를 정확히 그 길이로 고정하면 1860이며, 메모를 담는 형식입니다. 해당 필드가 없는 제네시스(체인 14~17)에서는 null이며, 이때 지갑은 메모 없는 1,348바이트 봉투를 봉인합니다. 다른 값은 존재하지 않습니다
hardening_v6제네시스가 v0.6 유효성 규칙을 적용하면 true입니다. 이 경우 지갑은 공개 입력만이 아니라 프로그램의 공개 입력에 이어 트랜잭션의 호출 바인딩(call binding)을 대상으로 호출을 증명합니다. 수수료 번들의 노트를 먼저 고르고, 호출을 두 번째로 증명하며, 번들을 마지막에 증명합니다. 이 플래그가 있는 체인은 이전 증명을 거부하고, 플래그가 없는 체인은 새 증명을 거부합니다
hc_auth제네시스가 고정한 인증 게스트(16진수) 또는 null입니다. 설정되어 있으면 hc_bundle은 번들 게스트 v3이고 모든 번들이 auth_commit과 인증 증명을 포함합니다. 지갑은 번들 게스트에 nk와 새 솔트를 주고, 지출 키에 대해 인증 게스트를 증명합니다
gas_metering제네시스에 gas 섹션이 있는 체인(회로 내 미터)에서는 "circuit", 섹션이 없는 체인에서 노드가 자체 가스 정책(--gas-price, --byte-price)을 운영하면 "header", 둘 다 없으면 null입니다
gas_price, byte_price가스당 단위 수, 그리고 호출의 증명 및 입력 봉투 KiB당 단위 수이며, 십진수 문자열입니다. gas 섹션이 있으면 합의 상태이며 모든 노드에서 같습니다. gas.dynamic이 있으면(체인 20처럼) 팁(tip)의 현재 가격으로, 블록마다 점유율에 따라 움직이며 제네시스 하한(100과 800) 아래로 내려가지 않고 상한 위로 오르지 않습니다. 없으면 섹션의 고정 가격입니다. 섹션이 없으면 해당 노드 자체의 정책이므로 두 노드의 응답이 다를 수 있습니다
bundle_gas_limit모든 번들 증명이 선언해야 하는 고정 가스이며 제네시스 gas 섹션에서 옵니다. 섹션이 없으면 null입니다
adjust_bps동적 컨트롤러가 한 블록에서 움직일 수 있는 최대 가격 변동폭이며, 베이시스 포인트 단위입니다. gas.dynamic이 없는 체인에서는 null입니다
max_gas_price, max_byte_pricev0.6.8: 컨트롤러가 가격을 올리지 않는 상한이며, 십진수 문자열입니다. 체인 20에서는 "10000"과 "80000"이고, 제네시스가 상한을 두지 않은 곳(체인 18과 19)에서는 null입니다
byte_loadv0.6.8: 호출의 증명과 입력 봉투만 byte_price를 움직여 전송 블록이 가격을 전혀 움직이지 않으면 "paying"이며, 체인 20이 그렇습니다. 모든 트랜잭션의 바이트가 반영되는 곳(체인 18과 19)에서는 null입니다
admission_by_votev0.6.8: 새 검증인 키를 등록하는 본드(bond)가 먼저 검증인 집합의 투표(rand_getAdmitted)를 필요로 하는지 여부이며, 체인 20에서는 true입니다
testnetv0.6.8: 제네시스의 testnet 표식이며, 파우셋(faucet)이 브리지 섹션과 공존할 수 있게 합니다. 체인 20에서는 true이고 그 이전의 모든 체인에서는 false입니다
slashingv0.6.8: 리더의 이중 서명(equivocation)에 대한 대가를 나타내는 { "equivocation_bps", "jail_epochs" } 또는 null입니다. 체인 20에서는 null입니다
binding_domainv0.6.8: 트랜잭션의 바인딩과 서명되는 모든 액션 메시지가 체인 id만 바인딩하면 0(체인 1419), 제네시스 해시도 함께 담으면 1(체인 20)이며, 이 경우 한 체인용으로 만든 증명이나 서명은 다른 어떤 체인에서도 검증되지 않습니다. 지갑은 이 응답이 아니라 체인 id로 어느 형식을 증명할지 결정합니다. v0.6.8 rand 지갑은 체인 id 1419에는 체인 id 형식을, 그 외 모든 id에는 제네시스 바인딩 형식을 사용하며, 이 필드는 일찍 거부하기 위해서만 읽습니다. v0.6.8 이전 지갑은 체인 20에서 전송할 수 없습니다
proof_window_blocksv0.6.8: 번들의 앵커가 몇 블록까지 오래되어도 되는지, 그리고 time이 높이보다 몇 블록까지 뒤처져도 되는지를 나타내며, 둘에 같은 윈도가 적용됩니다. 체인 20에서는 1024이고, 체인 19까지는 null(256)입니다. 느리거나 위임된 증명자를 쓰는 지갑은 증명에 허용되는 시간을 알기 위해 이 값을 읽습니다
program_statev0.6.8, RPL-2: 제네시스의 program_state 섹션과 그 invoke 한도, 또는 null이며, null이면 모든 invoke가 거부되고 프로그램 토큰을 등록할 수 없습니다. cell_fee는 invoke가 셀을 생성할 때마다(0으로 읽히는 셀에 0이 아닌 값을 쓸 때) 수수료 하한에 더해지는 RAND 단위(십진수 문자열)입니다. 다시 쓰기, 삭제, 0 쓰기에는 비용이 들지 않습니다. max_reads, max_writes, max_payouts(pays와 mints 합산)는 하드 상한입니다. 실제로는 세그먼트 규칙이 먼저 걸립니다. 트랜지션의 컨텍스트 워드(11 + 읽기 또는 쓰기당 16 + 지급당 3)는 zkVM의 공개 테이블이 커지지 않는 범위에서 프로그램의 공개 입력 및 8개의 바인딩 워드와 함께 들어가야 합니다. 공개 입력이 없는 프로그램의 경우 이 테이블은 128행이며, 컨텍스트 워드는 119개가 남습니다

필드가 도입되기 이전의 노드는 해당 필드 없이 응답합니다. 이 응답의 어떤 것도 인증되지 않으므로, 지갑은 노드의 말만으로 envelope_bytes를 받아들이지 않습니다. rand 지갑은 노드의 응답과 무관하게 체인 id 14~17에서는 레거시 봉투를 봉인하며, 다른 클라이언트도 그렇게 해야 합니다.

rand_getReceipt

매개변수는 [tx_hash]입니다. 결과는 호출이 커밋될 때까지 null이고, 이후 { "tx", "program", "tier": 14, "outputs": [1, 0, 25, 0, 0, 0, 0, 0], "height": 17, "index": 0, "h_in": "9c0e…7f", "h_pub": null }입니다. effect 필드는 없습니다. h_pub은 호출의 증명이 대조된 프로그램의 배포 시점 공개 입력의 다이제스트이며, 공개 입력이 없는 프로그램에서는 null입니다. invoke(v0.6.8)도 호출의 영수증을 가지며, rand_getReceipts와 receipts 토픽은 이를 그대로 전달합니다.

rand_getReceipts

매개변수는 [program_id, from_height, to_height, limit?]입니다. 결과는 { "receipts": [ … ], "next_height": 2051 }이며, from_height <= height <= to_height인 program_id의 영수증을 높이순, 이어서 인덱스순으로 담고 각각은 정확히 rand_getReceipt의 객체입니다. limit의 기본값이자 상한은 256이며 한 높이를 나누지 않습니다. 페이지가 limit개의 영수증을 채운 뒤에도 해당 높이의 나머지를 모두 반환합니다. next_height는 반환되지 않은 첫 높이이며, to_height에서 페이지가 끝나면 null입니다. to_height가 from_height보다 작으면 -32602입니다.

rand_getCallEnvelope

매개변수는 [tx_hash]입니다. 결과는 null 또는 16진수의 { "tx", "h_in", "kem_ct", "to_sender", "to_auditor", "body" }이며, 호출의 봉인된 입력 트랜스크립트를 그대로 제공합니다. 노드는 이를 열 수 있는 키를 갖고 있지 않습니다. 호출이 아무것도 게시하지 않았거나(--no-envelope), 트랜잭션이 호출이 아니거나, 영수증이 없으면 null입니다.

스테이킹과 공급량

rand_getValidators

매개변수는 []입니다. 결과는 레지스터 항목당 한 행이며, 주소순이고 금액은 십진수 문자열입니다.

[{ "address": "…", "stake": "1000000000000",
   "pending": [{ "release_epoch": 41, "amount": "5000000000" }],
   "rewards": "4000000", "payout": "rand1…", "nonce": 3, "active": true, "jailed_until": null }]

jailed_until(v0.6.8)은 슬래싱된 키가 다시 집합에 들어갈 수 있는 첫 에포크(영구적이면 18446744073709551615)이며, 수감 상태가 아니면 null입니다. 체인 20에는 staking.slashing이 없으므로 그곳에서는 항상 null입니다.

rand_getAdmitted

v0.6.8. 매개변수 []. 결과 { "admission_by_vote": true, "max": 256, "admitted": ["<address>", …] }: 밸리데이터 집합이 AdmitValidator로 투표하여 받아들였으나 아직 등록하지 않은 키를 주소 순서로 나열합니다. 제네시스가 staking.admission_by_vote를 설정하는 체인(chain 20이 그러합니다)에서는 새 키를 등록하는 Bond가 이 목록에 포함되어 있어야 합니다. max는 원장이 한 번에 보관하는 키의 수입니다. 이 플래그가 없는 체인에서는 admission_by_vote가 false이고 목록은 항상 비어 있으며 등록에 투표가 필요하지 않습니다. chain 20은 2026-10-01에 "admitted": []로 응답했습니다.

rand_getEpoch

매개변수 []. 결과 { "epoch": 41, "epoch_blocks": 1000, "next_set": ["…", "…"] }; next_set은 예측값입니다.

rand_getSupply

매개변수 []. 결과:

{ "height": 1998,
  "genesis_deposited": "…", "genesis_staked": "…", "faucet_minted": "…",
  "faucet_epoch": "…", "faucet_minted_in_epoch": "…",
  "withdraw_deposited": "…", "fees_paid": "…", "burned": "…",
  "subsidised": "…", "sealed_blocks": "…", "aggregator_bonds": "…", "slashed": "…",
  "registration_fees_burned": "…",
  "vesting_issued": "…", "vesting_released": "…", "vesting_in_register": "…", "vesting_locked": "…",
  "program_rand_out": "…", "program_rand_held": "…",
  "pool_value": "…", "register_total": "…", "total_supply": "…", "invariant_holds": true }

subsidised, sealed_blocks, aggregator_bonds, slashed는 집계 체인에서만 변동합니다. faucet_epoch와 faucet_minted_in_epoch는 staking.faucet_budget_per_epoch에 대한 faucet의 에포크별 카운터입니다(chain 20에서는 합의 상태입니다). 네 개의 vesting_* 필드는 제네시스 베스팅의 카운터이며, vesting 섹션이 없는 체인에서는 모두 "0"입니다. chain 20이 그러합니다. program_rand_out과 program_rand_held(v0.6.8, RPL-2; program_state 섹션이 없으면 "0")는 각각 invoke가 프로그램 금고에서 노트로 지급한 RAND(풀 측, pool_value에 포함)와 금고가 아직 보유한 RAND(레지스터 측, total_supply에 포함)입니다. 이 RAND는 invoke의 burn_r를 통해 들어왔으므로 풀 측에서는 burned에 포함됩니다. registration_fees_burned는 제네시스의 tokens.burn_registration_fee에 따라 소각된 토큰 등록 수수료의 합계 Σ이며, chain 20이 이를 설정합니다. invariant_holds는 이 값을 slashed와 함께 체인이 발행한 양에서 뺍니다. Supply가 이 항등식을 설명합니다.

rand_getEmission

매개변수 []. 결과 { "inflation": "0", "subsidy": null, "faucet": true }. inflation은 고정값 "0"입니다. subsidy는 블록 집계 스케줄(current, base, halving_blocks, sealed_blocks, next_halving_at)이며, aggregation 섹션이 없는 체인에서는 null입니다. chain 20이 그러합니다. faucet은 rand_status의 값을 그대로 반영합니다.

브리지

네 가지 모두 어느 체인에서나 응답합니다. bridge 섹션이 없는 체인에서는 상태가 { "enabled": false }이고 레지스트리는 []입니다. chain 20의 제네시스에는 이 섹션이 있습니다. 가디언 집합 1(guardian_set_index 1)에 가디언 8명, PQ 가디언 8명, 일시 중지 키 하나가 있고, 제네시스 시점의 burn_sequence는 13이며, 재생 하한(min_inbound_sequence)은 소스 체인 2, 3, 4에 대해 3, 소스 체인 5에 대해 7입니다. 또한 모든 백킹을 통틀어 24시간 구간당 4,000 zUSD의 전역 발행 한도를 두는 브리지 rules_v2가 있고, v0.6.8에서 새로 생긴 두 그룹이 있습니다. rotation(PQ 가디언 또는 일시 중지 키의 교체에는 새 키의 소유 증명이 필요하며 커밋 후 86,400초가 지나야 효력이 발생합니다)과 fees(모든 입금의 10 bps와 모든 소각의 10 bps를 Rand에서 treasury 주소 앞으로 zUSD 노트로 보관합니다)입니다. chain 19는 burn_sequence가 8이었고 하한은 1과 4였으며 두 그룹 모두 없었습니다. 이 체인의 tokens 섹션에는 1 RAND의 registration_fee(소각됨), 백킹별 mint_cap_per_day 10000000000000(소수점 8자리 기준 100,000 zUSD)이 있고, zUSD 자체도 목록에 있습니다. 제네시스에서 chain 14로부터 이월되었으며 asset id가 같고 인덱스는 1이며 백킹은 일곱 개입니다.

rand_getBridgeState

매개변수 []. 결과 { "enabled": false } 또는 다음과 같습니다.

{
  "enabled": true,
  "emitter": "01…",
  "emitters": { "2": "02…" },
  "guardian_set_index": 0,
  "guardians": ["aabb…"],
  "pq_guardians": ["…"],
  "mint_paused": false,
  "pause_nonce": 0,
  "list_nonce": 0,
  "pause_key": "…",
  "registration_fee": "1000000000",
  "burn_sequence": 1,
  "rotation_nonce": 0,
  "rules_v2": { "global_mint_cap_per_window": "…", "cap_window_secs": 86400,
                "global_minted_in_window": "…", "global_mint_headroom": "…" },
  "min_inbound_sequence": { "2": 2, "3": 2, "4": 2, "5": 2 },
  "rotation_rules": { "delay_secs": 86400, "needs_possession": true },
  "pending_rotations": [],
  "fees": { "mint_bps": 10, "burn_bps": 10, "recipient": "rand1…" },
  "assets": [ … ]
}
필드의미
emitter이 체인의 아웃바운드 emitter 주소, 32바이트 hex
emitters소스 체인 id → 해당 체인에서 신뢰하는 emitter 주소
guardians현재 집합의 20바이트 주소, hex
pq_guardiansPQ 집합: Dilithium2 공개 키(1,312바이트), hex이며 현재 가디언 집합(chain 20에서는 집합 1)과 인덱스가 정렬되어 있습니다. 모든 BridgeAttest에는 이 집합의 정족수 공동 서명이 포함됩니다. 가디언 집합 교체로는 이 집합이 바뀌지 않으며, rules_v2 체인에서는 rotate_pq_guardians만이 바꿉니다
mint_pausedtrue인 동안 모든 전송 attest는 bridge minting is paused로 거부됩니다. 소각과 교체는 계속 열려 있습니다
pause_nonce다음 일시 중지 또는 해제가 담아야 하는 값이며, 둘 다 이 값을 증가시킵니다
list_nonce다음 register_bridged_token 또는 list_backing이 담아야 하는 값이며, 둘 다 이 값을 증가시킵니다
pause_key발행을 일시 중지할 수 있는 유일한 Dilithium2 키, hex. 이 키는 일시 중지만 할 수 있으며, 해제에는 PQ 가디언 정족수가 필요합니다
registration_feeRegisterBridgedToken이 번들 기본 요금 외에 부담하는 금액, RAND 단위, 십진 문자열
burn_sequence지금까지 내보낸 아웃바운드 메시지의 수
rotation_nonce다음 rotate_pq_guardians / rotate_pause_key가 담아야 하는 값
rules_v2전역 발행 한도와 그 롤링 구간. 브리지 규칙 v2가 없는 체인에서는 null입니다. 이 규칙 아래에서는 백킹별 한도도 롤링 구간이며, 발행이 일시 중지된 동안에는 등재가 거부됩니다. v0.6.8부터는 십진 문자열인 global_minted_in_window와 global_mint_headroom도 담습니다
min_inbound_sequence제네시스 재생 하한: 소스 체인 id → 해당 체인의 전송이 담을 수 있는 가장 낮은 시퀀스, 일반 숫자. 하한이 없는 체인(chain 15 이전)에서는 null입니다. 이보다 낮은 bridge_attest는 BelowReplayFloor로 거부되며 이는 영구적인 판정입니다. 릴레이어는 이 체인이 분기된 원래 체인이 이미 발행한 lock을 걸러내기 위해 이 값을 읽습니다
rotation_rulesv0.6.8: 제네시스 bridge.rotation의 { "delay_secs", "needs_possession" }, 또는 null. 이 규칙 아래에서 교체는 _v2 액션이며 새 키의 소유 서명을 담고, 효력이 발생하기까지 delay_secs를 기다립니다
pending_rotationsv0.6.8: 커밋되었으나 아직 효력이 발생하지 않은 교체. 각각 { "kind": "pq_guardians", "new_pq_guardians", "effective_at_secs" } 또는 { "kind": "pause_key", "new_pause_key", "effective_at_secs" }이며, rotation_rules가 없으면 null입니다. 현재 일시 중지 키가 서명한 cancel_rotation이 하나를 취소합니다
feesv0.6.8: 제네시스 bridge.fees의 { "mint_bps", "burn_bps", "recipient" }, 또는 null(chain 14부터 19). 체인은 모든 입금과 모든 소각에서 그 비율만큼을 백킹의 정수 릴리스 단위로 내림하여, recipient 앞으로 zUSD 노트로 보관합니다. 입금은 총액에서 수수료를 뺀 금액을 적립하고, 소각의 서명된 본문은 그 금액에서 수수료를 뺀 값을 릴리스합니다. 지갑은 자신의 입금 가치를 계산하기 위해, 그리고 자신이 recipient일 때 수수료 노트를 재구성하기 위해 이 값을 읽습니다
assetsrand_getAssets의 행들

잔액은 없습니다. 브리지된 가치는 노트입니다. next_index는 더 이상 없습니다: 브리지된 토큰은 입금되기 전에, 등록 시점에 이미 정해진 인덱스로 등재되므로 예측할 인덱스가 남아 있지 않습니다. 등재된 토큰의 인덱스는 assets 또는 rand_getTokens에서 읽으십시오.

rand_getAssets

매개변수 []. 결과: 브리지의 자산 레지스트리를 인덱스 오름차순으로, 또는 []:

[{ "index": 1, "chain": 2, "token": "aaaa…", "asset_id": "…", "decimals": 6, "locked": "600",
   "mint_cap_per_day": "10000000000000", "minted_today": "1000", "mint_day": 20350,
   "minted_in_window": "1000", "mint_window_secs": 86400, "mint_headroom": "390000000000" }]

v0.6.8부터 백킹이 제공되는 모든 곳(rand_getBridgeState.assets, rand_getToken, rand_getTokens, rand_getTokenSupply의 backings)의 모든 백킹 행은 minted_in_window(십진 문자열)와 mint_window_secs를 담으며, 둘 다 일 단위 카운터 체인에서는 null입니다. 또한 mint_headroom을 담습니다. 이는 헤드의 블록 시각에서 한도가 허용하는 해당 백킹에 대한 최대 입금액으로, 백킹별 한도에서 이미 발행된 양을 뺀 값이며, 규칙 v2에서는 레지스트리 전체 구간의 남은 양을 넘지 않습니다. 전역 한도를 무시하는 mint_cap_per_day − minted_today가 아니라 mint_headroom을 읽으십시오. chain 20처럼 규칙 v2에서는 minted_today가 롤링 구간의 집계이며, 백킹별 한도가 대조되는 수치입니다. 아래의 일 단위 카운터 설명은 chain 14의 것입니다.

백킹(소스 코인)마다 한 행이므로, 백킹이 일곱 개인 토큰은 하나의 index 아래 일곱 행입니다. index는 해당 자산의 노트가 담는 asset 워드입니다. 인덱스 0은 RAND이며 레지스트리에는 절대 없습니다. decimals는 백킹의 소스 소수 자릿수입니다. locked, mint_cap_per_day, minted_today는 RAND가 아니라 토큰 자체의 소수점 8자리 단위로 표시한 십진 문자열이며, mint_day는 UTC 일 번호인 일반 정수입니다. mint_cap_per_day는 제네시스의 tokens.mint_cap_per_day로, 블록 시각 기준 UTC 하루 동안 한 백킹이 발행할 수 있는 최대량입니다. minted_today는 헤드 블록의 UTC 일(timestamp_ms / 86,400,000)인 mint_day에 해당 백킹이 발행한 양이므로, 이전 날짜에 남은 카운터는 헤드가 자정을 넘기면 "0"으로 읽힙니다. 한도를 넘는 입금은 MintCapExceeded로 거부되며 다음 날 허용됩니다. chain과 token은 가디언이 서명하는 와이어 상의 식별자이고, asset_id는 이 둘의 blake3로 rand_bridgeAssetId가 계산하는 값입니다.

rand_bridgeAssetId

매개변수 [token_chain, token_address](정수, 32바이트 hex). 결과: asset id, 64개의 hex 문자. 순수한 산술입니다.

rand_getBridgeBurn

매개변수 [sequence]. 결과 null 또는 { "sequence": 0, "body_hex": "…", "digest": "…", "tx": "…", "height": 2, "amount": "…", "release_amount": "…", "fee": "…" }.

마지막 세 가지는 v0.6.8에서 추가되었으며 모든 체인에 있고, 토큰의 소수점 8자리 단위로 표시한 십진 문자열입니다. release_amount는 서명된 본문이 담는 금액으로 body_hex 자체에서 읽으며, 소스 컨트랙트가 릴리스하는 금액이고 여기서 본문의 릴레이어 수수료가 지급됩니다. fee는 체인이 treasury 노트로 보관한 브리지 수수료이고, amount는 번들이 소각한 양으로 release_amount + fee입니다. bridge.fees가 없으면(chain 14부터 19) fee는 "0"입니다. chain 20의 시퀀스 13, 0.999 zUSD의 소각은 "amount": "99900000", "fee": "99900", "release_amount": "99800100"입니다.

토큰 (RPL)

RPL 토큰 레지스트리: 브리지된 토큰과 네이티브 토큰을 모두 포함한 모든 토큰입니다. Tokens가 이 표준을 설명합니다.

rand_getTokens

매개변수 [from_index, limit], 둘 다 선택 사항입니다(0과 1000; limit은 1,000으로 제한됩니다). 결과: from_index부터 인덱스 오름차순으로 범위 읽기를 한 레지스트리:

{ "enabled": true, "registration_fee": "1000000000", "next_index": 3, "max_tokens": 4096,
  "burn_registration_fee": true, "bound_note_value": true,
  "tokens": [
    { "index": 2, "id": "<64 hex>", "id_text": "rpl1…", "name": "Test Coin", "symbol": "TST",
      "decimals": 6,
      "authority": { "kind": "key", "key": "<Dilithium2 key, hex>", "address": "<base58>" },
      "mint_nonce": 1, "total_supply": "5700", "registered_at": 3 }
  ] }

On a chain without a tokens section: { "enabled": false, "tokens": [] }. index는 해당 토큰의 노트가 담고 있는 asset 워드입니다(0은 RAND이며 목록에 나타나지 않습니다). id는 토큰의 asset id이고 id_text는 체크섬이 포함된 텍스트 형식입니다. 32바이트 id에 대한 bech32m이며 HRP는 rpl, 길이는 62자입니다. authority는 다음 중 하나입니다.

kind기타 필드
none— (고정 공급량이거나 권한을 포기한 경우)
keykey, address
bridgebackings: [{ "chain", "token", "decimals", "locked", "mint_cap_per_day", "minted_today", "mint_day" }], rand_getAssets의 필드이며 담보(backing)마다 한 행입니다
programprogram

공급량, locked, mint_cap_per_day, minted_today, registration_fee는 10진수 문자열입니다(registration_fee는 RAND 단위, 나머지는 토큰 단위). next_index, mint_day, max_tokens는 숫자입니다. max_tokens는 레지스트리에 대한 제네시스 상한입니다(chain 20에서는 4,096이며, 상한이 없으면 null입니다). 이를 넘는 등록은 RegistryFull로 거부됩니다. burn_registration_fee는 등록 수수료를 제안자(proposer)에게 지급하지 않고 소각하는지 여부를 나타내고, bound_note_value는 2⁶³ 이상의 발행 또는 입금이 유효성 규칙인지 여부를 나타냅니다(어느 체인에서든 admission 단계에서 이러한 건은 규칙과 무관하게 거부됩니다). 세 필드 모두 chain 20에서 설정되어 있습니다. limit보다 짧은 페이지가 마지막 페이지입니다.

program authority({ "kind": "program", "program": "<id>" })는 chain 20과 같이 program_state 섹션이 있는 체인에서만 등록할 수 있습니다(v0.6.8). 이 토큰은 공급량 0에서 시작하며, 해당 프로그램의 invoke만이 토큰을 발행하거나 소각할 수 있습니다.

지갑은 토큰 id를 rand_getToken이 아니라 이 목록을 통해 확인합니다. 전송의 asset은 체인상에서 비공개이며, 어떤 토큰을 의도했든 레지스트리 전체를 읽는 비용은 동일하기 때문입니다.

rand_getToken

Params [token]: 레지스트리 인덱스(숫자 또는 10진수 문자열), 64자리 16진수 id(0x 유무와 대소문자 무관) 또는 rpl1… 텍스트 형식(모두 소문자이거나 모두 대문자)입니다. Result: 해당 토큰의 rand_getTokens 행 또는 null입니다. 잘못된 형식의 id(체크섬 오류, 다른 HRP, 잘못된 길이, 대소문자 혼용, 16진수가 아닌 값)는 -32602이므로, 오타가 다른 토큰으로 해석되는 일은 없습니다. 토큰별 조회는 호출자가 어떤 토큰에 관심이 있는지 노드에 알려 주므로, 탐색기(explorer)와 일회성 조회용입니다.

rand_getTokenSupply

Params [token], 같은 형식입니다. Result는 null 또는 다음과 같습니다.

{ "total_supply": "600",
  "backings": [{ "chain": 2, "token": "<32 bytes hex>", "decimals": 6, "locked": "600",
                 "mint_cap_per_day": "10000000000000", "minted_today": "1000", "mint_day": 20350 }] }

backings는 네이티브 토큰의 경우 비어 있으며, 브리지된 토큰의 경우 locked 금액의 합이 total_supply와 같습니다. rand_getToken과 같은 프라이버시 유의 사항이 적용됩니다.

블록 집계 (chain 20에서는 비활성)

이 메서드들은 제네시스에 aggregation 섹션이 있는 체인을 위해 노드에 존재합니다. chain 20에서는 레지스터가 비어 있으며 봉인 해제되는 것은 없습니다.

methodparamsresult
rand_getAggregate[hash]봉인하는 집계의 covers, aggregator, subsidy, proving_share, n, height이며, 그 외의 트랜잭션에는 null입니다
rand_getAggregators[]애그리게이터 레지스터: 행마다 address, bond, payout, nonce, unbonding
rand_getUnsealed[from, limit]{ "bundles": [{ "hash", "height", "excess" }], "next_from" }, 애그리게이터가 아직 처리할 수 있는 번들입니다

Aggregate는 다른 트랜잭션과 마찬가지로 rand_sendTransaction을 통해 제출합니다.

제네시스 베스팅 (chain 20에서는 비활성)

이 메서드들은 제네시스에 vesting 섹션이 있는 체인을 위해 노드에 존재합니다. 아직 해당 섹션을 가진 체인은 없으며, chain 20에서는 각각 { "enabled": false }로 응답합니다. 공개 엔드포인트는 2026-10-01부터 이 메서드들을 전달합니다.

methodparamsresult
rand_getVesting[id] 또는 [id, at_ms], 항목의 64자리 16진수 id해당 항목: 분류(class), 수혜자, 스케줄(amount, start_ms, cliff_ms, linear_ms, step_ms), 청구·취소·본딩된 내역, 그리고 as_of_ms 시점(기본값은 헤드 블록의 시각)의 vested_now, claimable_now, unvested_now입니다. 알 수 없는 id에는 null입니다. v0.6.8부터 취소 가능한 항목은 revokers, 취소에 필요한 이들의 threshold, 취소 시 지급받는 treasury를 나열하며(단일 revoker를 대체합니다), 항목에는 revoke_nonce와 locked_now가 포함됩니다
rand_getVestingSummary[]{ "enabled": true, "height", "as_of_ms", "entries", "issued", "released", "locked", "classes": [ … ] }: 키나 소유자 없이 분류별 합계를 제공합니다
rand_getVestingSchedule[from_ms, to_ms, step_ms], 최대 1,000개 지점{ "enabled": true, "issued", "points": [{ "t_ms", "locked" }] }: 시간에 따른 레지스터의 잠금 총액입니다

금액은 10진수 문자열입니다. 네 가지 베스팅 액션은 rand_sendTransaction을 통해 제출합니다.

구독 (WebSocket)

ws://127.0.0.1:8545/ 또는 /ws. 이 소켓은 rand_subscribe와 rand_unsubscribe만 처리하며, 그 외에는 -32601로 응답합니다. 세 가지 토픽은 서로 독립된 스트림이며 그 사이의 순서는 보장되지 않습니다.

  • newHeads — rand_getHead의 형태이며, 동기화 중에도 커밋된 블록마다 순서대로 한 번씩 전송됩니다. 여기서 view는 해당 블록 자체의 view입니다.
  • receipts 또는 receipts <program_id> — 일치하는 호출 영수증을 하나 이상 포함하는 커밋된 블록마다 알림 하나: { "height", "hash", "receipts": [ … ] }. 각 영수증은 rand_getReceipt의 형태입니다.
  • transaction <hash> — 알림이 한 번 전송된 후 노드가 구독을 제거합니다. { "status": "committed", "height", "index" }, 또는 트랜잭션 자체의 바이트에 대한 거부인 경우 { "status": "rejected", "reason" }입니다(rand_getTransactionStatus가 가진 한계와 같습니다). 상태에 의존하는 거부는 통지되지 않으므로 타임아웃과 함께 사용하십시오.
{ "jsonrpc": "2.0", "id": 1, "method": "rand_subscribe",   "params": ["newHeads"] }
{ "jsonrpc": "2.0", "id": 2, "method": "rand_unsubscribe", "params": ["1"] }
{ "jsonrpc": "2.0", "id": 3, "method": "rand_subscribe",   "params": ["receipts", "<program_id>"] }
{ "jsonrpc": "2.0", "id": 4, "method": "rand_subscribe",   "params": ["transaction", "<hash>"] }

{ "jsonrpc": "2.0", "id": 1, "result": "1" }
{ "jsonrpc": "2.0", "id": 2, "result": true }
{ "jsonrpc": "2.0", "method": "rand_subscription",
  "params": { "subscription": "1", "result": { "height": 1998, "hash": "…", "view": 2251 } } }

한도: 노드당 연결 64개(65번째 연결은 업그레이드 단계에서 503으로 거부됩니다), 연결당 구독 8개, 클라이언트 프레임당 64 KiB, 30 s마다 ping을 보내 5 s 이내에 응답해야 하며, 스트림당 백로그 256개 항목입니다. 구독 중인 스트림에서 이보다 더 뒤처진 구독자는 버퍼링되지 않고 코드 1008로 종료됩니다. 다시 연결한 후 누락분은 rand_getCompactBlocks(헤드), rand_getReceipts(영수증) 또는 rand_getTransactionStatus(트랜잭션)로 채우십시오. 업그레이드 헤더 없는 일반 GET /에는 400으로 응답합니다.

오류

code의미
-32601알 수 없는 메서드(폐기된 계정 메서드 포함)
-32602잘못되었거나 누락된 매개변수
-32000거부됨: 멤풀이 거부한 트랜잭션, 속도 제한이 걸린 faucet 호출, 10 s를 넘겨 대기한 witness 빌드, 30 s를 넘긴 읽기, 공개 리스너가 제공하지 않는 메서드 또는 한도를 넘은 구독
-32001참조된 객체를 찾을 수 없음
-32010프루닝됨: 이 노드의 보존 하한보다 낮은 높이이며, data.floor가 그 값을 나타냅니다(아래 참조)
-32603내부 오류
-32600잘못된 요청: 본문이 크기 제한을 초과했거나, JSON이 아니거나, 형식이 잘못된 배치이거나, 알림(notification)인 경우
{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32000, "message": "…" } }

rand_sendTransaction의 경우 -32000과 -32602만이 트랜잭션에 대한 판정입니다. 다른 코드가 반환되면 트랜잭션의 운명은 알 수 없습니다(rand_sendTransaction 참조).

프루닝된 노드: 오류 -32010

--prune-history <window>로 시작한 노드는 전체 원장(노트, 널리파이어, 앵커, 레지스터)을 보관하지만 블록, 트랜잭션, 영수증은 마지막 <window> 분량만 보관합니다. rand_status.prune_floor는 노드가 여전히 보유한 가장 낮은 높이입니다. chain 20에서는 26개 검증자(validator) 중 24개가 --prune-history 24h로 실행됩니다. 나머지 두 아카이브 노드는 이 플래그 없이 실행되어 모든 블록을 보관하며, 공개 엔드포인트는 그중 하나로 전달합니다.

  • 하한보다 낮은 높이로 조회하는 경우(제네시스 제외): rand_getBlockByHeight, 높이로 조회하는 rand_getFinality, 그리고 하한 아래에 걸치는 rand_getBlocks, rand_getCompactBlocks, rand_getReceipts 범위는 -32010 pruned: height h is below this node's retention floor f와 data: { "floor": f }로 응답합니다. 아카이브 노드에 문의하십시오. [0, 0]은 여전히 제네시스를 제공합니다.
  • 해시로 조회하는 경우: rand_getBlockByHash, rand_getReceipt, rand_getRawTransaction, rand_getCallEnvelope, rand_getAggregate는 프루닝된 해시에 대해 존재한 적 없는 해시와 마찬가지로 null로 응답하며, 둘을 구별할 수 있는 것은 아카이브 노드뿐입니다. rand_getTransaction과 rand_checkTransaction도 null로 응답하고, 하한보다 낮은 높이를 가리키는 위치 행이 남아 있는 경우에만 -32010으로 응답합니다. rand_getTransactionStatus는 프루닝된 노드에서 모든 unknown 항목에 floor를 추가합니다.
  • 월렛 스캔은 영향을 받지 않습니다: rand_getCommitments, rand_getNullifiers, rand_getAnchor 및 witness 메서드는 프루닝되지 않는 패밀리를 읽습니다.

와이어상의 트랜잭션

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>,
  auth_commit: Word8, auth_proof: Vec<u8>,      // since chain 17 (v0.6.3): split authorisation's c and
}                                               //   its proof; zeros and empty without hc_auth
Envelope { kem_ct: Vec<u8>, to_receiver: Vec<u8>, to_sender: Vec<u8>, body: Vec<u8> }

Action::None
Action::Mint { cm: Word8, pk: Word8, time: u32, r: Word8, envelope: Envelope, amount: u64,
               minter: PublicKey, signature: Signature }
Action::Deploy { base_pc: u32, words: Vec<u32>, public: Vec<u32> }
Action::Call { program: Hash, proof: Vec<u8>, input_envelope: Option<CallEnvelope> }
Action::Bond { validator: Address, amount: u64, registration: Option<Registration> }
Action::Unbond { validator: Address, amount: u64, nonce: u64, signature: Signature }
Action::Withdraw { validator: Address, amount: u64, nonce: u64, time: u32, r: Word8,
                   envelope: Envelope, signature: Signature }
Action::BridgeAttest { attestation: Vec<u8>, recipient: ShieldedAddress, r: Word8, time: u32,
                       asset: u32, envelope: Envelope, pq_signatures: Vec<PqSignature> }
Action::BridgeBurn { asset: u32, amount: u64, relayer_fee: u64, to_chain: u16,
                     token: [u8; 32], to: [u8; 32] }
// the five aggregation variants sit here in the enum's declared order
Action::RegisterToken { name: String, symbol: String, decimals: u8, authority: MintAuthority,
                        initial: Option<InitialMint>, salt: [u8; 32], index: u32 }
Action::TokenMint { asset: u32, amount: u64, recipient: ShieldedAddress, r: Word8, time: u32,
                    envelope: Envelope, nonce: u64, signature: Signature }
Action::SetAuthority { asset: u32, new: Option<PublicKey>, nonce: u64, signature: Signature }
Action::TokenBurn { asset: u32, amount: u64 }
Action::PauseMints { nonce: u64, signature: Signature }               // bundle-less, fee-less
Action::UnpauseMints { nonce: u64, pq_signatures: Vec<PqSignature> }  // bundle-less
Action::RegisterBridgedToken { name: String, symbol: String, salt: [u8; 32], chain: u16,
                               token: [u8; 32], decimals: u8, nonce: u64,
                               pq_signatures: Vec<PqSignature> }
Action::ListBacking { token_index: u32, chain: u16, token: [u8; 32], decimals: u8, nonce: u64,
                      pq_signatures: Vec<PqSignature> }
Action::RotatePqGuardians { new_pq_guardians: Vec<PublicKey>, nonce: u64,
                            pq_signatures: Vec<PqSignature> }         // bundle-less, fee-less
Action::RotatePauseKey { new_pause_key: PublicKey, nonce: u64,
                         pq_signatures: Vec<PqSignature> }            // bundle-less, fee-less
// the four vesting variants (ClaimVested, RevokeVesting, BondVested, UnbondVested) follow, tags 24 to 27;
// since v0.6.8 RevokeVesting carries `signatures: Vec<RevokerSignature>` in place of one `signature`
Action::AdmitValidator { candidate: PublicKey, signatures: Vec<(PublicKey, Signature)> }   // tag 28, v0.6.8
Action::SlashEquivocation { first: Box<SignedHeader>, second: Box<SignedHeader> }         // tag 29
Action::RotatePqGuardiansV2 { new_pq_guardians: Vec<PublicKey>, possession: Vec<Vec<u8>>,
                              nonce: u64, pq_signatures: Vec<PqSignature> }                // tag 30
Action::RotatePauseKeyV2 { new_pause_key: PublicKey, possession: Vec<u8>, nonce: u64,
                           pq_signatures: Vec<PqSignature> }                               // tag 31
Action::CancelRotation { kind: u8, nonce: u64, signature: Signature }                      // tag 32
Action::Invoke { program: Hash, proof: Vec<u8>, input_envelope: Option<CallEnvelope>,
                 transition: Transition }                                                  // tag 33, RPL-2

MintAuthority = None | Key(PublicKey) | Bridge { backings: Vec<Backing> } | Program(Hash)
InitialMint { amount: u64, recipient: ShieldedAddress, r: Word8, time: u32, envelope: Envelope }
Transition { reads: Vec<Cell>, writes: Vec<Cell>, inflow: Inflow, pays: Vec<Payout>, mints: Vec<Payout> }
Cell { key: Word8, value: Word8 }               // keys strictly ascending in each list
Inflow = None | Deposit | Burn                  // what the bundle's burn_a of burn_asset is to the program
Payout { asset: u32, amount: u64, recipient: ShieldedAddress, r: Word8, envelope: Envelope }
Registration { public_key: PublicKey, payout: ShieldedAddress, signature: Signature }
CallEnvelope { kem_ct: Vec<u8>, to_sender: Vec<u8>, to_auditor: Vec<u8>, body: Vec<u8> }
PqSignature { index: u8, signature: Vec<u8> }   // one guardian's Dilithium2 co-signature, by set index

bincode의 기본 설정입니다: 고정 폭 정수, 8바이트 길이 접두사, 선언 순서의 u32 열거형 태그. 다섯 가지 집계 변형은 열거형에서 BridgeBurn 뒤, RegisterToken 앞에 옵니다(Transactions). chain 20은 이를 허용하지 않으며 네 가지 베스팅 변형이나 SlashEquivocation도 허용하지 않지만, 태그 번호를 하드코딩하는 인코더는 여전히 이들을 세어야 합니다.

번들의 마지막 두 필드는 v0.6.3 및 chain 17과 함께 도입되었습니다. bincode는 위치 기반이므로 chain 16 이하용으로 작성된 인코더는 이 체인이 디코딩하는 트랜잭션을 만들어 내지 못하며, 이와 함께 모든 트랜잭션 id가 바뀌었습니다. id의 도메인은 이제 rand-txid-3이며, auth_commit과 auth proof의 다이제스트를 바인딩합니다. id를 로컬에서 다시 계산하는 클라이언트도 이에 맞춰 바꿔야 합니다. chain 20에서는 모든 번들이 auth proof를 담고 있으며, 자체 증명이든 위임 증명이든 마찬가지입니다. v0.6.8은 Transaction이나 Bundle 레이아웃을 바꾸지 않으며, 액션 28~33을 추가합니다.

모든 트랜잭션은 최대 하나의 번들을 담습니다. Bond는 burn_r이 amount와 같고 burn_a와 burn_asset이 0인 번들을 담습니다. BridgeBurn과 TokenBurn은 번들을 통해 소각합니다. burn_asset은 액션의 asset이어야 하며(0은 불가), burn_a는 액션의 amount, burn_r은 0이어야 하고, fee는 슬롯 2–3에서 RAND로 지불됩니다. 그 밖의 모든 액션은 토큰을 소각하지 않으며, RAND는 오직 burn_r을 통해서만 소각됩니다. burn_asset이 0이면서 burn_a가 0이 아닌 번들은 어디서나 거부됩니다. BridgeAttest의 r은 선택하는 값이 아니라 도출되는 값입니다. 승인(admission)을 위해서는 가디언이 서명한 다이제스트 mu에 대해 blake3("rand-deposit-r-1" ‖ mu)가 필요하며, 다른 값은 모두 거부됩니다(WrongDepositBlinding, 영구적 거부). 브리지된 토큰은 제네시스에서, 또는 RegisterBridgedToken / ListBacking으로 등재되어야 그 토큰의 어떤 증명(attestation)도 승인될 수 있습니다. 등재되지 않은 코인의 증명은 UnlistedToken으로 거부됩니다.

모든 번들 증명은 그것이 포함된 트랜잭션을 대상으로 생성되고 그 트랜잭션에 대해 검증됩니다. 여기서 트랜잭션은 증명을 비운 전체 트랜잭션이며, 새로운 태그 아래에서 체인 ID에, 그리고 체인 20(binding_domain: 1)에서는 제네시스 해시에 결합됩니다. 체인 1419에서는 결합 대상이 체인 ID뿐이었으므로, 체인 19용으로 만든 증명은 체인 20에서 검증되지 않으며 v0.6.8보다 오래된 지갑은 그곳에서 전송할 수 없습니다. 체인 1820에서 두 증명이 없는 번들은 7,936바이트로, 증명이 없는 전송 트랜잭션은 7,949바이트로 인코딩됩니다(체인 14~16에서는 5,848바이트와 5,861바이트이며, 엔벨로프는 1,348바이트이고 인증 필드가 없습니다). 와이어 상의 전송 트랜잭션은 프로덕션 프로파일에서 약 2.85 MB이며 거의 전부가 증명입니다. 번들 증명이 약 1.49 MB, 인증 증명이 약 1.36 MB입니다. 분할 인증 이전에는 약 1.43 MB였습니다.

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