For the complete documentation index, see llms.txt
Using the Midnight node toolkit
node toolkit, 즉 midnight-node-toolkit은 Midnight node 릴리스마다 함께 제공되는 명령줄 도구입니다. 노드에서 블록과 ledger state를 읽고, seed에서 주소와 키를 도출합니다. 또한 NIGHT 전송, DUST 등록, 컨트랙트 배포와 호출 같은 트랜잭션을 만들어 제출합니다. 노드 운영자는 블록을 살펴보고 노드를 스모크 테스트하는 데 사용합니다. DApp 개발자는 테스트 지갑에 자금을 넣고 로컬 네트워크에서 컨트랙트를 시험해 보는 데 사용합니다. 이는 테스트와 운영을 위한 도구입니다. DApp은 Midnight.js와 wallet SDK로 트랜잭션을 만듭니다. 이 가이드는 Preview, Preprod, Mainnet이 구동하는 런타임과 맞는 버전인 toolkit 1.0.300을 다룹니다. 각 작업은 제대로 동작했음을 보여주는 확인으로 끝납니다.
Prerequisites
다음은 이 가이드의 모든 절차에 적용됩니다.
-
toolkit 이미지와 로컬 노드를 실행할 Docker. Linux 서버에서는 릴리스 바이너리가 Docker 없이도 대부분의 명령을 실행합니다. Installing the toolkit binary on Linux를 참고하세요.
-
JSON-RPC 및 GraphQL 호출과 JSON 출력을 읽는 데 쓸
curl과jq. -
Preprod에서 읽는 절차를 위해
BLOCKFROST_PROJECT_ID환경 변수에 담긴 Blockfrost Midnight Preprod 프로젝트 토큰. Blockfrost는 Preprod 노드 RPC와 indexer를 제공합니다. Getting a Blockfrost project token을 참고하세요. -
테스트 자금만 보유한 seed. toolkit은 seed를 명령줄 인자로 받으므로, seed가 셸 히스토리와 프로세스 목록에 남을 수 있습니다.
-
toolkit의 출력을 wallet SDK와 비교하는 두 가지 확인을 실행하려면 Node.js 22 이상. 이들은 support matrix의 버전으로 SDK와 ledger 패키지를 둔
toolkit-checks폴더에서 실행됩니다.mkdir toolkit-checks && cd toolkit-checksnpm install @midnightntwrk/wallet-sdk@1.2.0 @midnight-ntwrk/midnight-js-protocol@4.1.1wallet SDK의 npm 스코프
@midnightntwrk은@midnight-ntwrk/midnight-js-protocol과 달리 하이픈이 없습니다.
How the node toolkit works
toolkit은 한 번에 하나의 체인을 다룹니다. WebSocket으로 노드에서 블록을 읽거나, 파일에서 트랜잭션을 읽습니다. 만든 트랜잭션을 노드로 보내거나 파일에 씁니다. 명령이 체인에서 무엇을 필요로 하는지에 따라 실제로 어디에서 실행할 수 있는지가 정해집니다.
wallet 또는 ledger state가 필요한 명령은 체인을 재생합니다. 여기에는 show-wallet, dust-balance, contract-state, send-intent, 그리고 노드에서 읽는 모든 generate-txs 빌더가 포함됩니다. 각 명령은 genesis부터 모든 블록을 내려받아 로컬 ledger 사본으로 재생합니다. 새 로컬 체인에서는 몇 초면 됩니다. 공개 네트워크에서는 몇 시간이 걸립니다. 이 가이드의 테스트 실행 중 Preview에는 블록이 110만 개가 넘었고, 한 측정에서 toolkit은 초당 약 85개 블록을 가져왔습니다. 그래서 이 가이드는 읽기 전용 명령은 Preview와 Preprod를 대상으로, 모든 트랜잭션은 로컬 노드를 대상으로 실행합니다. show-block은 지정한 블록만 가져오고, show-ledger-parameters는 현재 파라미터만 읽으며, show-address 같은 명령은 노드가 전혀 필요 없습니다. command reference에 각 명령이 무엇을 필요로 하는지 정리되어 있습니다.
재생은 모든 블록에서 상태를 읽습니다. 오래된 상태를 가지치기하는 노드는 더 오래된 블록에 대해 State already discarded로 응답하고, 재생이 실패합니다. 재생을 위해 toolkit을 여러분 자신의 노드로 향하게 한다면, 그 노드를 archive node로 실행하세요.
캐시가 작업 결과를 보관합니다. toolkit은 가져온 블록과 재생한 ledger의 스냅샷을 저장하므로, 다음 명령은 새 블록만 가져옵니다. toolkit은 블록 1의 해시로 캐시를 키잉하므로, 하나의 캐시가 Preview, Preprod, 그리고 잇따른 로컬 체인을 섞지 않고 담습니다. 재생은 가장 최근의 finalized 블록에서 멈춥니다.
각 toolkit은 자신이 아는 런타임만 읽습니다. Toolkit 1.0.300은 런타임 스펙 버전 21000, 22000, 1000000, 1000300의 블록을 디코딩하고, 그 외에는 UnsupportedBlockVersion으로 멈춥니다. 네트워크가 런타임을 업그레이드하면, 그 런타임을 가져오는 node 릴리스의 toolkit으로 전환하세요.
toolkit은 트랜잭션을 직접 증명합니다. shielded 전송이나 컨트랙트 호출 같은 트랜잭션에 필요한 영지식 증명을 자신의 프로세스 안에서 생성합니다. 대신 proof server를 사용하려면 -p로 그 URL을 전달하세요.
결과는 stdout으로, 로그는 stderr로 나갑니다. 진행 줄은 터미널에 남겨 두고 깔끔한 JSON을 얻으려면, 명령의 출력을 파일로 리다이렉트하거나 jq로 파이프하세요.
금액은 기본 단위로 표기됩니다. NIGHT 금액은 STAR 단위이며, 1 NIGHT은 10^6 STAR입니다. DUST 금액은 SPECK 단위이며, 1 DUST는 10^15 SPECK입니다. NIGHT and DUST를 참고하세요.
Toolkit versions and networks
toolkit을 설치하기 전에, 그리고 네트워크 업그레이드 후에 다시 이 값들을 확인하세요. toolkit은 노드와 함께, 노드의 버전 번호로 제공됩니다.
- Networks: 2026년 10월 3일 기준으로 Preview, Preprod, Mainnet은 모두 런타임 스펙 버전 1000300을 구동합니다. 셋 모두와, 로컬 노드 1.0.300에는 toolkit 1.0.300을 사용하세요. Preview와 Preprod 노드는
system_version을1.0.400-c338b9ac로 보고하는데, 이는 공개 릴리스나 toolkit 이미지가 없는 빌드입니다. Toolkit 1.0.300은 이 노드들이 제공하는 블록을 읽습니다. - Docker image:
linux/amd64와linux/arm64용midnightntwrk/midnight-node-toolkit:1.0.300. 이미지에는latest태그가 없습니다. node 저장소는latest-main태그를 릴리스가 아니라 main 브랜치에서 빌드하므로,1.0.300으로 고정하세요. - Release binaries:
SHA256SUMS파일과 함께 node-1.0.300 release에 첨부된midnight-node-toolkit-1.0.300-linux-amd64.tar.gz와midnight-node-toolkit-1.0.300-linux-arm64.tar.gz. toolkit에는 자체 릴리스 페이지가 없습니다. - Older chains: toolkit 1.0.300은 node 1.0.0에서 돌아가는 개발 체인도 읽는데, 2026년 10월 3일 기준으로 midnight-local-dev가 이를 구동합니다. Toolkit 1.0.0은 런타임 1000300의 블록을 읽지 못합니다.
- Contract compiler: 이미지의
toolkit-js는compact-runtime0.15.0을 번들로 포함합니다. toolkit으로 배포하는 컨트랙트에는 Compact compiler 0.30.0을 사용하고, 그 컴파일러가 구현하는 언어 버전 0.22에 맞춰 작성하세요. support matrix에 실린 버전인 컴파일러 0.31.1은 언어 버전 0.23을 구현하고compact-runtime0.16.0용 코드를 내놓는데, toolkit은 이를 거부합니다. - The
versioncommand:Node: 1.0.300,Ledger: =7.0.3,Compactc: 0.30.0을 출력합니다.Ledger줄은 toolkit이 함께 담고 있는 더 오래된 ledger 라이브러리를 가리킵니다. 네트워크는 ledger 8.1.2를 구동하며 이는 네트워크의midnight_ledgerVersionRPC 메서드가 보고하므로,Node줄을 기준으로 삼으세요. - Tested: 이 페이지의 모든 명령은 2026년 10월 3일에 toolkit 1.0.300으로, 로컬 노드 1.0.300과 공개 Preview·Preprod 엔드포인트를 대상으로 실행했습니다. Docker 명령은 macOS의 Docker Desktop으로, 바이너리 단계는 amd64와 arm64의 Ubuntu 24.04 컨테이너에서 실행했습니다. Mainnet은 이 실행에 포함되지 않았습니다. 2026년 10월 8일에는 Inspecting a block과 Reading a network's ledger parameters의 Preprod 예제를 Blockfrost Preprod 엔드포인트를 대상으로 다시 실행했고, 결과는 같았습니다.
Running the toolkit with Docker
셸 함수를 통해 toolkit 이미지를 실행하면, 이 페이지의 모든 명령이 로컬 명령처럼 읽힙니다. 이미지는 Docker가 돌아가는 곳이면 어디서든 실행되며, 여러분 자신의 컨트랙트용 intent를 만들 수 있는 유일한 형태의 toolkit입니다.
Procedure
-
이미지를 가져옵니다.
docker pull midnightntwrk/midnight-node-toolkit:1.0.300 -
toolkit이 기록하는 파일을 담을 폴더와 캐시용 named volume을 만듭니다.
mkdir -p "$HOME/midnight-toolkit"docker volume create midnight-toolkit-cache볼륨은 toolkit이 가져오는 블록, ledger 스냅샷, 그리고 첫 증명을 위해 내려받는 proving 파라미터를 보관합니다.
-
이미지를 실행하는 셸 함수를 정의합니다. bash와 zsh에서 동작합니다.
midnight-node-toolkit() {docker run --rm \-e RESTORE_OWNER="$(id -u):$(id -g)" \-v midnight-toolkit-cache:/.cache \-v "$HOME/midnight-toolkit:/out" \midnightntwrk/midnight-node-toolkit:1.0.300 "$@"}컨테이너 안에서
$HOME/midnight-toolkit은/out이므로, 파일을 읽거나 쓰는 옵션에는/out아래 경로를 전달하세요. 이미지는 시작할 때마다/out아래의 모든 것을 자신의 사용자 소유로 만듭니다.RESTORE_OWNER는 명령이 종료될 때 파일을 다시 여러분에게 돌려줍니다. toolkit 파일만 담은 폴더를 마운트하세요. 새 터미널에서도 함수를 유지하려면~/.bashrc나~/.zshrc같은 셸 프로필에 추가하세요.한 번에 하나의 명령만다른 명령이 캐시 볼륨을 열어 둔 사이에 시작하는 명령은
DatabaseAlreadyOpen으로 실패합니다. 둘 중 한 명령이 종료되면, 이미지는 볼륨도 여러분의 사용자에게 돌려줍니다. 그러면 다른 명령이Permission denied로 캐시 저장에 실패할 수 있습니다. 명령을 병렬로 실행하려면 각 명령에 자체 캐시 볼륨을 주세요.
Verification
version 명령은 toolkit의 node 버전을 출력합니다.
midnight-node-toolkit version
Node: 1.0.300
Ledger: =7.0.3
Compactc: 0.30.0
Installing the toolkit binary on Linux
예를 들어 노드를 구동하는 서버에서 Docker 없이 toolkit을 실행하려면 릴리스 바이너리를 설치하세요. 릴리스에는 x86-64(amd64)와 arm64 Linux용 바이너리가 있으며, glibc 2.34 이상이 필요합니다. macOS나 Windows 빌드는 없습니다. tarball에는 midnight-node-toolkit 바이너리만 들어 있습니다. generate-intent 명령은 toolkit-js와 Node.js도 필요한데, 이들은 Docker 이미지에만 제공되므로, deploy your own contract에는 이미지를 사용하세요.
Procedure
-
curl과, 바이너리가wss://엔드포인트에 필요로 하는 CA 인증서를 설치합니다. Ubuntu에서는 다음과 같습니다.sudo apt-get updatesudo apt-get install -y curl ca-certificates -
사용하는 아키텍처에 맞는 tarball과 체크섬 파일을 node-1.0.300 릴리스에서 내려받습니다.
VERSION=1.0.300ARCH=amd64 # or arm64curl -fsSLO "https://github.com/midnightntwrk/midnight-node/releases/download/node-${VERSION}/midnight-node-toolkit-${VERSION}-linux-${ARCH}.tar.gz"curl -fsSLO "https://github.com/midnightntwrk/midnight-node/releases/download/node-${VERSION}/SHA256SUMS" -
tarball을
SHA256SUMS와 대조해 확인합니다.sha256sum -c --ignore-missing SHA256SUMSmidnight-node-toolkit-1.0.300-linux-amd64.tar.gz: OK -
바이너리를 추출해 설치합니다.
tar -xzf "midnight-node-toolkit-${VERSION}-linux-${ARCH}.tar.gz"sudo install -m 0755 midnight-node-toolkit /usr/local/bin/
arm64 바이너리는 Ubuntu 24.04에 포함된 OpenSSL 3(libssl.so.3와 libcrypto.so.3)도 링크합니다. Docker가 없으면 toolkit은 실행한 디렉터리 아래의 toolkit_cache 폴더에 캐시를 보관합니다. --fetch-cache와 --ledger-state-db 옵션으로 위치를 옮깁니다.
Verification
바이너리는 버전을 출력하고 wss://로 Preview 블록을 읽습니다.
midnight-node-toolkit version
midnight-node-toolkit show-block -s wss://rpc.preview.midnight.network -b 1133548 --json
Node: 1.0.300
Ledger: =7.0.3
Compactc: 0.30.0
[
{
"number": 1133548,
"hash": "59744f9c5b96ad856c5d6ef3969cbef8645b850fef6f8fe9364b9568735c2380",
"parent_hash": "fa3df5e68c23bd95f37189aaf0362606b0b0c0626ce7af4c018f0f71fdd9cd43",
"ledger_version": "Ledger8",
"timestamp_secs": 1791020244,
"timestamp_utc": "2026-10-03T09:37:24Z",
"timestamp_err_secs": 30,
"last_block_time_secs": 1791020244,
"state_root": "6d69646e696768743a73746f726167652d6b6579286c65646765722d73746174655b7631335d293a00135dd1958b84ef41f76df20b552b24b123e80728a0a9804b373175fd6fad6182",
"transactions": []
}
]
Connection and cache options
toolkit을 노드로 향하게 하거나 캐시 보관 위치를 바꿀 때 이 표들을 참고하세요. 노드에서 읽는 명령은 -s를, 보내는 명령은 -d를 받으며, 둘 다 기본값은 ws://127.0.0.1:9944입니다. show-ledger-parameters는 대신 -r(--read-from-rpc-url)로 노드에서 읽는데, 이 옵션에는 기본값이 없습니다. -r이 없으면 네트워크의 파라미터가 아니라 ledger의 초기 파라미터를 출력합니다. 예를 들어 Preprod는 global_ttl이 1209600인데, 초기 파라미터는 3600초입니다.
| 노드 위치 | 전달할 URL | 추가 docker run 옵션 |
|---|---|---|
| 공개 Preview 엔드포인트 | wss://rpc.preview.midnight.network | 없음 |
| 공개 Preprod 엔드포인트 | Blockfrost Midnight Preprod 프로젝트 토큰을 넣은 wss://rpc.midnight-preprod.blockfrost.io?project_id=<token>. Node endpoints를 참고하세요. | 없음 |
| 사용자 정의 Docker 네트워크의 노드 컨테이너 | ws://<container-name>:9944 | --network <network-name> |
| 네트워크를 공유하는 노드 컨테이너 | 기본값인 ws://127.0.0.1:9944이므로 -s와 -d를 생략 | --network container:<container-name> |
Docker Desktop에서 호스트의 127.0.0.1에 게시된 노드 | ws://host.docker.internal:<port> | 없음 |
| Mainnet, 이 가이드에서는 테스트하지 않음 | Node endpoints에서 가져온, 프로젝트 토큰을 넣은 Blockfrost WebSocket URL | 없음 |
| 옵션 | 기본값 | 환경 변수 | 기능 |
|---|---|---|---|
-s, --src-url | ws://127.0.0.1:9944 | MN_SRC_URL | 블록을 읽어올 노드. |
--src-file | 설정 안 됨 | 없음 | 노드 대신 파일에서 블록이나 트랜잭션을 읽습니다. |
-d, --dest-url | ws://127.0.0.1:9944 | MN_DEST_URL | 트랜잭션을 보낼 노드. 여러 노드로 보내려면 반복합니다. |
--dest-file | 설정 안 됨 | 없음 | 트랜잭션을 보내는 대신 파일에 씁니다. -d, -r, --no-watch-progress와 함께 쓸 수 없습니다. |
-r, --rate | 1 | 없음 | 초당 보내는 트랜잭션 수. |
--no-watch-progress | 꺼짐 | MN_DONT_WATCH_PROGRESS | finalization을 기다리지 않고 반환합니다. |
-p, --proof-server | 설정 안 됨. 그래서 toolkit이 자체 프로세스에서 증명함 | 없음 | 사용할 proof server. |
--dry-run | 꺼짐 | 없음 | seed를 가린 채 설정을 출력하고 종료합니다. |
--fetch-cache | 이미지: redb:/.cache/toolkit_fetch_cache.db. 바이너리: redb:toolkit_cache/fetch_cache.db | MN_FETCH_CACHE | 블록 캐시: inmemory, 한 번에 한 프로세스용 redb:<file>, 또는 여러 프로세스용 postgres:// URL. |
--ledger-state-db | 이미지: /.cache/toolkit_ledger_cache_db. 바이너리: toolkit_cache/ledger_cache_db | MN_LEDGER_CACHE_DB | ledger 스냅샷과 wallet state용 폴더. 빈 문자열이면 끕니다. |
--fetch-concurrency | 20 | 없음 | 병렬로 가져오는 블록 수. |
--fetch-only-cached | 꺼짐 | 없음 | 캐시된 블록만 사용합니다. 그래도 toolkit은 체인을 식별하기 위해 노드에 연결합니다. |
- 연결 옵션은
generate-txs빌더 이름 앞이나 뒤에 올 수 있습니다. - 노드에 도달하지 못하면 toolkit은 종료하기 전에 최대 60초 동안 재시도합니다.
- 지갑의 캐시를 미리 구축하려면, 지갑마다
--seeds옵션을 하나씩 주어fetch를 실행하세요. 그러면 해당 seed에 대한 이후의show-wallet은 새 블록만 가져옵니다.
Inspecting a block
블록과 그 트랜잭션을 디코딩합니다. 예를 들어 트랜잭션이 무엇을 담았는지 보거나, 노드가 무엇을 제공하는지 확인할 때 씁니다. show-block은 지정한 블록만 가져오므로, 공개 엔드포인트를 대상으로도 몇 초면 실행됩니다.
Procedure
-
블록 번호를 찾습니다. 노드의 현재 best block으로 시작하면 좋습니다.
curl -s -H 'Content-Type: application/json' \-d '{"jsonrpc":"2.0","id":1,"method":"chain_getHeader","params":[]}' \"https://rpc.midnight-preprod.blockfrost.io?project_id=$BLOCKFROST_PROJECT_ID" | jq -r '.result.number' | xargs printf '%d\n'2817120 -
블록을 디코딩합니다. 예제는 트랜잭션 하나를 담은 Preprod 블록 2817111을 사용합니다.
midnight-node-toolkit show-block -s "wss://rpc.midnight-preprod.blockfrost.io?project_id=$BLOCKFROST_PROJECT_ID" -b 2817111출력은 블록 헤더로 시작한 다음 각 트랜잭션을 디코딩합니다.
Block #2817111Hash: 0x5983961a09811310493419a8246478efb50a2e6c9e1c0c39dd746c9381587b32Parent Hash: 0x5c6fe928045dbd79d9cb66ce594f40bcaaa16f16dad2f5ab22af61f64a472870Ledger Version: Ledger8Timestamp: 1791020472 (1791020472, err: 2026-10-03T09:41:12Zs)Parent Block Timestamp: 1791020472State Root: 0x6d69646e696768743a73746f726167652d6b6579286c65646765722d73746174655b7631335d293a005e170a30ebf269bbf95ac57f149b0b1e4a42f42ceabc0cba98099514c594dcc0Transactions: 1[0] Midnight (9510 bytes) hash: 0x24d212027962baaa816ed98dbf79538a5ec0885ca226af99427a942e53bca1e0Timestamp줄은 초를 두 번 출력하고, 오차 범위가 들어갈 자리에 UTC 시각을 넣습니다. 시각은 대신 JSON 출력에서 읽으세요. -
블록을 JSON으로 쓰고 필요한 필드를 골라냅니다.
--src-file이 블록 여러 개를 담을 수 있으므로 JSON은 배열입니다. 따라서jq필터를.[0]으로 시작하세요.midnight-node-toolkit show-block -s "wss://rpc.midnight-preprod.blockfrost.io?project_id=$BLOCKFROST_PROJECT_ID" -b 2817111 --json > block.jsonjq '.[0] | {number, hash, timestamp_utc, transactions: [.transactions[] | {index, tx_type, hash}]}' block.json{"number": 2817111,"hash": "5983961a09811310493419a8246478efb50a2e6c9e1c0c39dd746c9381587b32","timestamp_utc": "2026-10-03T09:41:12Z","transactions": [{"index": 0,"tx_type": "Midnight","hash": "24d212027962baaa816ed98dbf79538a5ec0885ca226af99427a942e53bca1e0"}]}각 블록에는
parent_hash,ledger_version,timestamp_secs,timestamp_err_secs,last_block_time_secs,state_root도 있습니다. 각 트랜잭션에는size_bytes와,debug_str에 담긴 디코딩된 형태도 있습니다.
Verification
indexer는 해당 높이에 대해 같은 블록 해시와 트랜잭션 해시를 보고합니다.
curl -s -H 'Content-Type: application/json' \
-d '{"query":"{ block(offset: {height: 2817111}) { height hash timestamp transactions { hash __typename } } }"}' \
"https://midnight-preprod.blockfrost.io/api/v0?project_id=$BLOCKFROST_PROJECT_ID" | jq -c .
{"data":{"block":{"height":2817111,"hash":"5983961a09811310493419a8246478efb50a2e6c9e1c0c39dd746c9381587b32","timestamp":1791020472000,"transactions":[{"hash":"24d212027962baaa816ed98dbf79538a5ec0885ca226af99427a942e53bca1e0","__typename":"RegularTransaction"}]}}}
indexer는 타임스탬프를 밀리초로 제공합니다. 이는 toolkit JSON의 timestamp_secs와 같은 시점입니다.
Reading a network's ledger parameters
네트워크의 ledger가 구동하는 파라미터, 즉 DUST 생성 값, 수수료 가격, 트랜잭션 한도, 전역 time-to-live를 읽습니다. toolkit은 이를 JSON이 아니라 Rust 디버그 텍스트로 출력하므로, 섹션을 찾으려면 grep을, 인코딩된 형태를 보려면 --serialize를 사용하세요.
Procedure
-
Preprod의 파라미터를 파일에 저장합니다.
midnight-node-toolkit show-ledger-parameters -r "wss://rpc.midnight-preprod.blockfrost.io?project_id=$BLOCKFROST_PROJECT_ID" > params.txt -
DUST 파라미터를 읽습니다.
grep -A 6 'dust: DustParameters' params.txtdust: DustParameters {night_dust_ratio: 5000000000,generation_decay_rate: 8267,dust_grace_period: Duration(10800,),},DUST generation parameters에서 각 필드와 그 단위를 설명합니다.
-
전역 time-to-live와 트랜잭션 크기 한도를 읽습니다.
grep -A 2 'global_ttl' params.txtgrep 'transaction_byte_limit' params.txtglobal_ttl: Duration(1209600,),transaction_byte_limit: 1048576,global_ttl은 1,209,600초로 14일이고,transaction_byte_limit은 1,048,576바이트로 1 MiB입니다.fee_prices값은 시간이 지나면 바뀌므로, 복사해 두지 말고 필요할 때 읽으세요. -
파라미터를 인코딩된 형태로 출력합니다. 이는 indexer가 블록의
ledgerParameters필드로 반환하는 형식입니다.midnight-node-toolkit show-ledger-parameters -r "wss://rpc.midnight-preprod.blockfrost.io?project_id=$BLOCKFROST_PROJECT_ID" --serialize출력은
6d69646e696768743a6c65646765722d706172616d65746572735b76355d3a로 시작하는 한 줄의 16진수이며, 이는midnight:ledger-parameters[v5]:의 인코딩입니다.
Verification
ledger 패키지는 toolkit의 파라미터와 indexer의 파라미터를 같은 DUST 값으로 디코딩합니다. toolkit-checks 폴더에 이 스크립트를 check-parameters.mjs로 저장하세요.
// Decode serialized ledger parameters and print the DUST values.
// Usage: node check-parameters.mjs <file with hex> [<file with hex> ...]
import { readFileSync } from 'node:fs';
import { LedgerParameters } from '@midnight-ntwrk/midnight-js-protocol/ledger';
for (const file of process.argv.slice(2)) {
const hex = readFileSync(file, 'utf8').trim();
const { dust } = LedgerParameters.deserialize(Buffer.from(hex, 'hex'));
console.log(file, JSON.stringify({
nightDustRatio: dust.nightDustRatio.toString(),
generationDecayRate: dust.generationDecayRate.toString(),
dustGracePeriodSeconds: dust.dustGracePeriodSeconds.toString(),
timeToCapSeconds: dust.timeToCapSeconds.toString(),
}));
}
그런 다음 두 인코딩을 모두 그 폴더에 저장하고 디코딩합니다.
midnight-node-toolkit show-ledger-parameters -r "wss://rpc.midnight-preprod.blockfrost.io?project_id=$BLOCKFROST_PROJECT_ID" --serialize > toolkit.hex
curl -s -H 'Content-Type: application/json' \
-d '{"query":"{ block { height ledgerParameters } }"}' \
"https://midnight-preprod.blockfrost.io/api/v0?project_id=$BLOCKFROST_PROJECT_ID" | jq -r .data.block.ledgerParameters > indexer.hex
node check-parameters.mjs toolkit.hex indexer.hex
toolkit.hex {"nightDustRatio":"5000000000","generationDecayRate":"8267","dustGracePeriodSeconds":"10800","timeToCapSeconds":"604815"}
indexer.hex {"nightDustRatio":"5000000000","generationDecayRate":"8267","dustGracePeriodSeconds":"10800","timeToCapSeconds":"604815"}
timeToCapSeconds, 즉 DUST UTXO가 가득 차는 데 걸리는 시간은 약 7일입니다. 두 16진수 문자열 자체는 다를 수 있는데, 두 번의 읽기 사이에 수수료 가격이 움직이기 때문입니다.
Deriving addresses and keys from a seed
seed에 속하는 주소와 키를 출력합니다. 테스트 지갑에 자금을 넣거나, DUST용으로 주소를 등록하거나, seed가 어느 지갑을 여는지 확인하는 데 사용하세요. 이 명령들은 오프라인에서 동작합니다. toolkit은 seed를 세 가지 형태로 받습니다.
- 16, 32, 64바이트의 16진수.
..가 들어간 짧은 16진수로, toolkit이 가운데를 0으로 채웁니다.00..01은 0 바이트 31개 뒤에01이 오는 값입니다.- BIP-39 복구 구문.
Procedure
-
테스트 seed를 만듭니다.
SEED=$(openssl rand -hex 32) -
사용하는 네트워크에 대해 seed의 모든 주소와 키를 출력합니다. 예제는
preprod를 사용합니다.midnight-node-toolkit show-address --network preprod --seed $SEED{"shielded": "mn_shield-addr_preprod1a4aykv8z0ghss2fj7892ug7392g73dal4dz3v35yjzx5unz6mx8t5udpkknzg3rhy2wyxjtgws7qypft8sccwe4x72pm934guhshcxsyp2my7","unshielded": "mn_addr_preprod13qy0l5anhzkvzec4wcpv08cpgtn4c586zn7kc43gaes4chc4trrqt5r89m","dust": "mn_dust_preprod1wd4dyzvj26msk6c6hth9yen5jwmk8y0rjss5qtlz93723kpdrj7pvllw20q","dustPublic": "736ad2099256b70b6b1abaee52667493b76391e39421402fe22c7ca8d82d1cbc16","coinPublic": "ed7a4b30e27a2f082932f1caae23d12a91e8b7bfab45164684908d4e4c5ad98e","coinPublicTagged": "6d69646e696768743a7a737761702d636f696e2d7075626c69632d6b65795b76325d3aed7a4b30e27a2f082932f1caae23d12a91e8b7bfab45164684908d4e4c5ad98e","verifyingKey": "d43a7f08b3f875fc30c58da8581f3c3253cb43ffe57ce620d6519f168ffacd19","userAddress": "8808ffd3b3b8acc167157602c79f0142e75c50fa14fd6c5628ee615c5f1558c6","unshieldedUserAddressUntagged": "8808ffd3b3b8acc167157602c79f0142e75c50fa14fd6c5628ee615c5f1558c6"}값은 여러분의 seed에서 나오므로 서로 다릅니다.
unshielded주소는 NIGHT을 받고,shielded주소는 shielded 토큰을 받으며,dust는 NIGHT이 DUST를 생성해 줄 수 있는 주소입니다.generate-intent는coinPublic을 요구합니다. -
플래그로 값 하나를 출력합니다:
--unshielded,--shielded,--dust,--dust-public,--coin-public,--coin-public-tagged,--verifying-key,--user-address.midnight-node-toolkit show-address --network preprod --seed $SEED --unshieldedmn_addr_preprod13qy0l5anhzkvzec4wcpv08cpgtn4c586zn7kc43gaes4chc4trrqt5r89m -
seed의 viewing key를 출력합니다. 이를 가진 사람은 누구든 지갑의 shielded 트랜잭션 내역을 읽을 수 있으므로, 비공개로 유지하세요.
midnight-node-toolkit show-viewing-key --network preprod --seed $SEEDmn_shield-esk_preprod1wwycjs08eklms3hn83c4jt5vsc2er3dkly5f03wx699c85z0ywaqwwg6fef -
복구 구문을 사용하려면 따옴표로 감싸 전달하세요. toolkit은 빈 passphrase로 구문을 64바이트 BIP-39 seed로 변환하고,
show-seed가 그 seed를 출력합니다. 이 예제는 공개된 BIP-39 테스트 구문을 사용하며, 이 구문은 절대 자금을 보유해서는 안 됩니다.midnight-node-toolkit show-seed --seed "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art"408b285c123836004f4b8842c89324c1f01382450c0d439af345ba7fc49acf705489c6fc77dbd4e3dc1dd8cc6bc9f043db8ada1e243c4a0eafb290d399480840show-address는 구문과 그 16진수 seed에 대해 같은 출력을 줍니다. 지갑 앱에서 구문을 가져올 경우, 그것을 신뢰하기 전에 toolkit의 unshielded 주소와 앱이 보여주는 주소를 비교하세요.
toolkit은 --network 값을 검사하지 않습니다. --network foo는 mn_addr_foo1 주소를 출력합니다. preview, preprod, 로컬 네트워크용 undeployed, 또는 mainnet을 사용하세요. mainnet 주소에는 mn_addr1...처럼 네트워크 접미사가 없습니다.
Verification
wallet SDK는 seed에서 같은 주소와 viewing key를 도출합니다. toolkit-checks 폴더에 이 스크립트를 check-addresses.mjs로 저장하세요.
// Derive a seed's addresses and viewing key with the wallet SDK.
// Usage: node check-addresses.mjs <network> <seed-hex>
import {
HDWallet, Roles, createKeystore, ShieldedAddress, ShieldedCoinPublicKey,
ShieldedEncryptionPublicKey, ShieldedEncryptionSecretKey, DustAddress,
} from '@midnightntwrk/wallet-sdk';
import { ZswapSecretKeys, DustSecretKey } from '@midnight-ntwrk/midnight-js-protocol/ledger';
const [network, seedHex] = process.argv.slice(2);
const wallet = HDWallet.fromSeed(Buffer.from(seedHex, 'hex'));
if (wallet.type !== 'seedOk') throw new Error('invalid seed');
const derived = wallet.hdWallet
.selectAccount(0)
.selectRoles([Roles.NightExternal, Roles.Dust, Roles.Zswap])
.deriveKeysAt(0);
if (derived.type !== 'keysDerived') throw new Error('key derivation failed');
const zswap = ZswapSecretKeys.fromSeed(derived.keys[Roles.Zswap]);
const dust = DustSecretKey.fromSeed(derived.keys[Roles.Dust]);
const encode = (item) => item.constructor.codec.encode(network, item).asString();
console.log(JSON.stringify({
unshielded: createKeystore(derived.keys[Roles.NightExternal], network).getBech32Address().asString(),
shielded: encode(new ShieldedAddress(
new ShieldedCoinPublicKey(Buffer.from(zswap.coinPublicKey, 'hex')),
new ShieldedEncryptionPublicKey(Buffer.from(zswap.encryptionPublicKey, 'hex')),
)),
dust: encode(new DustAddress(dust.publicKey)),
viewingKey: encode(new ShieldedEncryptionSecretKey(zswap.encryptionSecretKey)),
}, null, 2));
같은 네트워크와 seed로 실행합니다.
node check-addresses.mjs preprod $SEED
{
"unshielded": "mn_addr_preprod13qy0l5anhzkvzec4wcpv08cpgtn4c586zn7kc43gaes4chc4trrqt5r89m",
"shielded": "mn_shield-addr_preprod1a4aykv8z0ghss2fj7892ug7392g73dal4dz3v35yjzx5unz6mx8t5udpkknzg3rhy2wyxjtgws7qypft8sccwe4x72pm934guhshcxsyp2my7",
"dust": "mn_dust_preprod1wd4dyzvj26msk6c6hth9yen5jwmk8y0rjss5qtlz93723kpdrj7pvllw20q",
"viewingKey": "mn_shield-esk_preprod1wwycjs08eklms3hn83c4jt5vsc2er3dkly5f03wx699c85z0ywaqwwg6fef"
}
각 값은 2단계와 4단계의 toolkit 출력과 같습니다.
Starting a local network for test transactions
Midnight node 하나를 개발 모드로 시작하고 toolkit을 거기에 연결합니다. 이 가이드의 나머지 모든 트랜잭션은 이 노드를 대상으로 실행됩니다. 재생은 몇 초면 되고, 그 genesis 지갑이 여러분의 테스트 지갑에 자금을 넣습니다.
Procedure
-
노드와 toolkit을 위한 Docker 네트워크를 만듭니다.
docker network create midnight-local -
노드를 시작합니다.
docker run -d --name midnight-dev-node --network midnight-local \-p 127.0.0.1:9944:9944 -e CFG_PRESET=dev midnightntwrk/midnight-node:1.0.300dev프리셋은 모의 Cardano 연결로 단일 노드 체인을 시작하므로, Cardano node나 db-sync가 필요 없습니다. 모든 블록의 상태를 유지하고, 다른 컨테이너의 RPC 연결을 받으며, 6초마다 블록 하나를 생성합니다.-p옵션은 RPC 포트를127.0.0.1에서만 게시합니다. 여러분의 컴퓨터에서 midnight-local-dev가 돌아가고 있다면, 그 노드가 이미 9944 포트를 차지하고 있으므로 먼저 중지하세요. -
컨테이너가 같은 네트워크에 참여하도록 toolkit 함수를 다시 정의합니다.
midnight-node-toolkit() {docker run --rm \--network midnight-local \-e RESTORE_OWNER="$(id -u):$(id -g)" \-v midnight-toolkit-cache:/.cache \-v "$HOME/midnight-toolkit:/out" \midnightntwrk/midnight-node-toolkit:1.0.300 "$@"}toolkit에게 노드는 이제
ws://midnight-dev-node:9944입니다. 공개wss://엔드포인트는 이 함수로도 계속 동작합니다. -
노드가 블록 1을 finalize할 때까지 약 20초 기다립니다. 그 전에 체인을 재생하는 명령은
Error: NodeClientError(OnlyGenesisFinalized)로 실패합니다. 몇 초 뒤에 다시 실행하세요.
새 노드 컨테이너는 저마다 같은 genesis 상태에서 새 체인을 시작합니다. genesis 지갑은 다시 가득 차고, 여러분이 자금을 넣은 지갑들은 비어 있습니다. 끝나면 docker rm -f midnight-dev-node로 노드를 제거한 다음, docker network rm midnight-local로 그 네트워크를 제거하세요.
Verification
genesis 지갑, 즉 seed 00..01은 체인의 시작 자금을 보유합니다. show-wallet은 그 NIGHT UTXO를 utxos 아래에, shielded 코인을 coins 아래에, DUST를 dust_utxos 아래에 나열합니다.
midnight-node-toolkit show-wallet -s ws://midnight-dev-node:9944 --seed 00..01
utxos 목록에는 각각 50,000,000,000,000 STAR(50,000,000 NIGHT)인 NIGHT UTXO 다섯 개가 있습니다. 다음은 그 첫 번째입니다.
{
"id": "01c5ad3ff58d687dfe27fc779726188adfe777de5efa8f938a014d7fd7045c59#0",
"initial_nonce": "f5e761a22c22f362f1e62435c303c3f6210d93cde80f4ada80465002a172ecc9",
"value": 50000000000000,
"user_address": "bc610dd07c52f59012a88c2f9f1c5f34cbacc75b868202975d6f19beaf37284b",
"token_type": "0000000000000000000000000000000000000000000000000000000000000000",
"intent_hash": "01c5ad3ff58d687dfe27fc779726188adfe777de5efa8f938a014d7fd7045c59",
"output_number": 0
},
dust-balance는 total이 capacity와 같으므로 그 DUST가 가득 찼음을 보여줍니다.
midnight-node-toolkit dust-balance -s ws://midnight-dev-node:9944 --seed 00..01
출력은 다음 줄들로 끝납니다.
"total": 1250000000000000000000000,
"capacity": 1250000000000000000000000
}
Sending NIGHT to a test wallet
로컬 노드의 genesis 지갑에서 새 테스트 지갑에 자금을 넣습니다. single-tx 빌더는 각 --destination-address마다 출력 하나씩을 담은 트랜잭션 하나를 보냅니다.
Prerequisites
- Starting a local network for test transactions의 로컬 노드와 toolkit 함수.
Procedure
-
새 지갑의 seed를 만들고, 다음 절차를 위해 보관합니다.
WALLET_SEED=$(openssl rand -hex 32)echo $WALLET_SEED -
네트워크 이름이
undeployed인 로컬 네트워크에서 지갑의 unshielded 주소를 가져옵니다.ADDR=$(midnight-node-toolkit show-address --network undeployed --seed $WALLET_SEED --unshielded) -
genesis 지갑에서 10,000 NIGHT, 즉 10,000,000,000 STAR를 보냅니다.
midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \single-tx --source-seed 00..01 --unshielded-amount 10000000000 --destination-address $ADDR명령은 체인을 재생한 다음, 트랜잭션을 만들고, 보내고, 최종 확정될 때까지 기다립니다. 로그는 트랜잭션 해시와 트랜잭션이 도달한 단계들로 끝납니다.
Sending batch 0...SENDING url="ws://midnight-dev-node:9944" midnight_tx_hash="0x7ad9e3e3d4c097570040079b3d4d0b14da72902f8d88be0bd402886e54ff2a35"SENTBEST_BLOCKFINALIZEDDUST가 수수료를 내므로, genesis 지갑의 NIGHT은 보낸 금액만큼 정확히 줄어듭니다.
--destination-address를 반복하면 반복할 때마다 같은 금액의 출력 하나씩을 보냅니다. -
shielded 코인도 보내려면, 지갑의 shielded 주소를 가져와
--shielded-amount를 전달하세요.SHIELDED_ADDR=$(midnight-node-toolkit show-address --network undeployed --seed $WALLET_SEED --shielded)midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \single-tx --source-seed 00..01 --shielded-amount 5000000 --destination-address $SHIELDED_ADDR
Verification
3단계 뒤에, 새 지갑은 보낸 금액이 담긴 NIGHT UTXO 하나를 보유합니다.
midnight-node-toolkit show-wallet -s ws://midnight-dev-node:9944 --seed $WALLET_SEED
{
"coins": {},
"utxos": [
{
"id": "2a00abac2c5de456171a44917ccc46eff5d7f71e0f3cebbf8c819662ca814741#0",
"initial_nonce": "40411e8967ae1a81e0c39fbbe11a69af729eec10bf35f8721c4c91c0e725473a",
"value": 10000000000,
"user_address": "91143d09e50de76a6486af9c2b92483aaee5ef63bed33df403ec0864e88fb829",
"token_type": "0000000000000000000000000000000000000000000000000000000000000000",
"intent_hash": "2a00abac2c5de456171a44917ccc46eff5d7f71e0f3cebbf8c819662ca814741",
"output_number": 0
}
],
"dust_utxos": []
}
4단계 뒤에, shielded 코인이 coins 아래에 나타납니다.
Registering NIGHT for DUST generation
지갑의 NIGHT이 트랜잭션 수수료를 내는 자원인 DUST를 생성하도록 등록합니다. register-dust-address는 지갑의 모든 NIGHT UTXO를 소비하고 각각을 같은 소유자에게 같은 값으로 다시 만드는 트랜잭션 하나를 구성합니다. 같은 트랜잭션이 그 UTXO들에 대한 DUST 주소를 등록합니다. 등록이 지갑에 어떤 의미인지는 Registration rules를 참고하세요.
Prerequisites
- Sending NIGHT to a test wallet에서 만든 것처럼, 로컬 노드에 NIGHT을 보유한 지갑.
Procedure
-
지갑의 NIGHT UTXO, 즉
utxos아래 항목들의 개수를 셉니다.midnight-node-toolkit show-wallet -s ws://midnight-dev-node:9944 --seed $WALLET_SEED -
지갑에 NIGHT UTXO가 하나면, 자금 전송이 finalize된 뒤 약 30초 기다렸다가 등록하세요.
midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \register-dust-address --wallet-seed $WALLET_SEED로그는
FINALIZED로 끝납니다. 등록은 UTXO가 생성된 시점부터 가장 최근의 finalized 블록 사이에 생성했을 DUST로 자체 수수료를 냅니다. 전송 직후에는 그 DUST가 0이라, 명령이Insufficient DUST로 실패합니다. Sending NIGHT to a test wallet의 10,000 NIGHT보다 작은 UTXO는 더 오래 기다려야 합니다. DUST 상한이 수수료보다 낮은 UTXO는 결코 수수료를 낼 수 없습니다. -
지갑에 NIGHT UTXO가 둘 이상이면, toolkit 1.0.300은 그 방식으로 수수료를 내지 못합니다.
InsufficientDustForRegistrationFee로 실패하며, UTXO가 생긴 지 몇 초밖에 안 됐을 때는Insufficient DUST로 실패합니다. 대신 genesis 지갑처럼 DUST를 보유한 지갑에서 수수료를 내세요.midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \register-dust-address --wallet-seed $WALLET_SEED --funding-seed 00..01
한 지갑의 NIGHT이 다른 지갑을 위해 DUST를 생성하게 하려면, mn_dust_로 시작하는 그 지갑의 DUST 주소를 --destination-dust에 넣어 등록하세요. 주소는 다른 지갑의 seed로 show-address --dust를 실행해 가져옵니다. 2단계나 3단계를 거친 여러분의 지갑처럼 이미 등록된 지갑은, DUST를 보유한 지갑을 넣은 --funding-seed도 필요합니다.
midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \
register-dust-address --wallet-seed $WALLET_SEED \
--destination-dust <mn_dust_undeployed1...> --funding-seed 00..01
그러면 지갑 자신의 생성 항목에는 종료 시각이 붙고, 다른 지갑의 dust-balance에는 새 항목이 나열됩니다. 한 번도 등록한 적 없는 지갑은 2단계와 3단계에서처럼 수수료를 냅니다.
Verification
dust-balance는 등록된 NIGHT UTXO마다 생성 항목 하나를 보여줍니다.
midnight-node-toolkit dust-balance -s ws://midnight-dev-node:9944 --seed $WALLET_SEED
{
"generation_infos": [
{
"dust_output": {
"initial_value": 10392374052349955,
"dust_public": "73867cfa0586565ff9b4f6c573a51e4f3e4763aae093d3e088d76e90295e07f447",
"nonce": "734a0003d44d570fa389f87b7283de726c659406776acaeb73441fd2f28f4fa409",
"seq": 0,
"ctime": 1791021072,
"backing_night": "a041d323677a3121ef7f37e29fd28c4129598a5cbb8b5a7146dd6d96e4e596d6",
"mt_index": 90
},
"generation_info": {
"value": 10000000000,
"owner_dust_public_key": "73867cfa0586565ff9b4f6c573a51e4f3e4763aae093d3e088d76e90295e07f447",
"nonce": "a041d323677a3121ef7f37e29fd28c4129598a5cbb8b5a7146dd6d96e4e596d6",
"dtime": 18446744073709551615
}
}
],
"source": {
"734a0003d44d570fa389f87b7283de726c659406776acaeb73441fd2f28f4fa409": 13037814052349955
},
"total": 13037814052349955,
"capacity": 50000000000000000000
}
capacity는 STAR 단위 NIGHT 금액에night_dust_ratio5,000,000,000을 곱한 값이므로, 10,000 NIGHT은 50,000 DUST를 담을 수 있습니다.dtime은 64비트 최댓값인 18446744073709551615이며, 이는 생성에 종료 시각이 없다는 뜻입니다.total은 매초 STAR당 8,267 SPECK씩 늘어납니다. 명령을 다시 실행하면 증가하는 것을 볼 수 있습니다. 이 가이드의 실행에서는total이 13초 만에 13037814052349955에서 14112524052349955 SPECK으로 올랐습니다.
이 숫자들은 JavaScript number가 정확히 담기에 너무 커서, 텍스트나 BigInt 값으로 비교하세요.
Stopping DUST generation
지갑의 NIGHT이 DUST를 생성하지 못하도록 그 지갑의 DUST 주소를 등록 해제합니다. 그러면 지갑이 이미 보유한 DUST는 늘어나던 속도로 감소합니다.
Prerequisites
- Registering NIGHT for DUST generation에서 등록한 지갑.
Procedure
-
지갑을 등록 해제하고, 그 자신의 DUST로 수수료를 냅니다.
midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \deregister-dust-address --wallet-seed $WALLET_SEED --funding-seed $WALLET_SEED--funding-seed이 없으면 genesis 지갑00..01이 수수료를 냅니다. 지갑을 다른 지갑의 DUST 주소로 등록했다면 그 뒤로 지갑 자신의 DUST가 감소해 소진되므로, 이 기본값을 사용하세요. 그 경우 등록 해제는 다른 지갑의 생성 항목을 종료시킵니다.
Verification
이제 생성 항목에 종료 시각이 붙습니다.
midnight-node-toolkit dust-balance -s ws://midnight-dev-node:9944 --seed $WALLET_SEED
"generation_info": {
"value": 10000000000,
"owner_dust_public_key": "73867cfa0586565ff9b4f6c573a51e4f3e4763aae093d3e088d76e90295e07f447",
"nonce": "a041d323677a3121ef7f37e29fd28c4129598a5cbb8b5a7146dd6d96e4e596d6",
"dtime": 1791021168
}
이제 dtime은 생성이 멈춘 시점인 Unix 타임스탬프입니다. 나중에 명령을 다시 실행하면 total이 늘어나던 속도로 줄어듭니다. 이 가이드의 실행에서는 88초 간격의 두 읽기 사이에 17070894763543442에서 9795934763543442 SPECK으로 줄었습니다. 지갑을 다른 지갑의 DUST 주소로 등록했다면, 종료 시각은 그 지갑 seed에 대한 dust-balance에 나타납니다.
Smoke-testing a node with the built-in contract
노드가 컨트랙트 배포와 호출을 받아들이는지 확인하려면 toolkit의 내장 테스트 컨트랙트를 배포하고 호출하세요. 컨트랙트는 toolkit 안에 함께 제공되므로 컴파일러가 필요 없습니다. 배포를 먼저 파일에 쓰면, 보내기 전에 contract address를 얻을 수 있습니다.
Prerequisites
- Starting a local network for test transactions의 로컬 노드와 toolkit 함수.
Procedure
-
배포 트랜잭션을 파일로 구성합니다. genesis 지갑이 수수료를 냅니다.
midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 \--dest-file /out/simple_deploy.mn contract-simple deployCONTRACT ADDRESS: ContractAddress(e77c1615d3ce847e32bf18da993df7dbd5c6af62e31290c455930ab44548c923) -
파일에서 contract address를 읽습니다.
CONTRACT=$(midnight-node-toolkit contract-address --src-file /out/simple_deploy.mn)echo $CONTRACTe77c1615d3ce847e32bf18da993df7dbd5c6af62e31290c455930ab44548c923배포마다 새 주소가 생기므로, 여러분의 출력에 있는 주소는 다릅니다.
-
파일을 보냅니다. 로그는
FINALIZED로 끝납니다.midnight-node-toolkit generate-txs --src-file /out/simple_deploy.mn -d ws://midnight-dev-node:9944 send -
컨트랙트의
store연산을 호출합니다. 로그는FINALIZED로 끝납니다.midnight-node-toolkit generate-txs -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \contract-simple call --call-key store --contract-address $CONTRACT -
컨트랙트의 상태를 읽어 파일에 저장합니다.
midnight-node-toolkit contract-state -s ws://midnight-dev-node:9944 \--contract-address $CONTRACT --dest-file /out/simple_state.bin로그는 컨트랙트의 연산과, genesis 지갑의 verifying key인 maintenance authority를 나열합니다.
Contract address: e77c1615d3ce847e32bf18da993df7dbd5c6af62e31290c455930ab44548c923Op: check (636865636b)Op: store (73746f7265)Authority VerifyingKey: 86f71b8a7a21bfe16a2bb2eab74475073fa5b773854f151ed548dba77a2c5815Authority Threshold: 1Authority Counter: 0
배포 파일에 무엇이 들어 있는지 보려면, show-transaction --src-file /out/simple_deploy.mn으로 디코딩하세요.
Verification
상태 파일은 노드가 midnight_contractState로 반환하는 상태와 일치합니다. 둘을 16진수로 해시하세요.
curl -s -H 'Content-Type: application/json' \
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"midnight_contractState\",\"params\":[\"$CONTRACT\"]}" \
http://127.0.0.1:9944 | jq -r .result | tr -d '\n' | shasum -a 256
xxd -p "$HOME/midnight-toolkit/simple_state.bin" | tr -d '\n' | shasum -a 256
39549201a8b4e2dca31c138c255ec209587b0376e49d9a299307e46d050304a6 -
39549201a8b4e2dca31c138c255ec209587b0376e49d9a299307e46d050304a6 -
Deploying your own contract with the toolkit
DApp을 작성하지 않고, 여러분이 컴파일한 컨트랙트를 배포하고 명령줄에서 그 circuit을 호출합니다. generate-intent 명령은 Docker 이미지 안의 toolkit-js로 컴파일된 컨트랙트를 실행하고, send-intent는 그 결과를 트랜잭션으로 바꿉니다.
Prerequisites
-
Starting a local network for test transactions의 로컬 노드와 toolkit 함수.
-
Compact compiler 0.30.0. 기본값을 바꾸지 말고 기본 컴파일러 옆에 설치하세요.
compact update --no-set-default 0.30.0
Procedure
-
toolkit의 출력 폴더 안에 컨트랙트 폴더를 만듭니다.
mkdir -p "$HOME/midnight-toolkit/contract"cd "$HOME/midnight-toolkit"컨트랙트를
$HOME/midnight-toolkit아래에 두세요. 명령이 실행되는 동안 이미지의 사용자가 그 폴더를 소유하므로,toolkit-js가 거기에 설정의 컴파일된 사본을 쓸 수 있습니다. -
이 카운터 컨트랙트를
contract/counter.compact로 저장합니다.contract/counter.compactpragma language_version 0.22;import CompactStandardLibrary;export ledger round: Counter;export circuit increment(): [] {round.increment(1);}export circuit add(n: Uint<16>): [] {round.increment(disclose(n));} -
컴파일러 0.30.0으로 컴파일합니다.
compact compile +0.30.0 contract/counter.compact contract/managed/counter컴파일러는
contract/managed/counter아래에 컨트랙트 코드, proving key와 verifier key, circuit 파일을 생성합니다. 컴파일러 0.31.1은 언어 버전 0.23을 구현하므로, 이 컨트랙트를language version 0.23.0 mismatch로 거부합니다. 언어 버전 0.23에 맞춰 작성한 컨트랙트는 0.31.1로 컴파일되지만, 그러면generate-intent가Version mismatch: compiled code expects 0.16.0, runtime is 0.15.0으로 실패합니다. -
이 설정을
contract/contract.config.ts로 저장합니다. 이 설정은toolkit-js를 컴파일된 컨트랙트로 향하게 하고, 컨트랙트에 witness가 없음을 선언하고, 빈 초기 private state를 설정하고,undeployed네트워크를 선택합니다.contract/contract.config.tsimport { CompiledContract, ContractExecutable } from '@midnight-ntwrk/compact-js/effect';import { Contract as C_ } from './managed/counter/contract/index.js';type PrivateState = Record<string, never>;type CounterContract = C_<PrivateState>;const CounterContract = C_;export default {contractExecutable: CompiledContract.make<CounterContract>('CounterContract', CounterContract).pipe(CompiledContract.withVacantWitnesses,CompiledContract.withCompiledFileAssets('./managed/counter'),ContractExecutable.make),createInitialPrivateState: (): PrivateState => ({}),config: {network: 'undeployed'}}; -
toolkit-js가 컨트랙트 폴더를 찾는 위치인/toolkit-js/contract에 그 폴더를 마운트하도록 toolkit 함수를 다시 정의합니다.midnight-node-toolkit() {docker run --rm \--network midnight-local \-e RESTORE_OWNER="$(id -u):$(id -g)" \-v midnight-toolkit-cache:/.cache \-v "$HOME/midnight-toolkit:/out" \-v "$HOME/midnight-toolkit/contract:/toolkit-js/contract" \midnightntwrk/midnight-node-toolkit:1.0.300 "$@"} -
컨트랙트를 배포하는 지갑의 coin public key를 가져옵니다. 이 가이드는 수수료도 내는 genesis 지갑을 사용합니다.
CP=$(midnight-node-toolkit show-address --network undeployed --seed 00..01 --coin-public) -
배포 intent를 생성합니다.
--authority-seed은 그 seed의 키를 컨트랙트의 maintenance authority로 만듭니다. 이것이 없으면 authority는 아무도 보유하지 않는 무작위 키가 됩니다.midnight-node-toolkit generate-intent deploy -c /toolkit-js/contract/contract.config.ts \--coin-public $CP --authority-seed 00..01 \--output-intent /out/deploy.bin --output-private-state /out/ps0.json --output-zswap-state /out/zswap0.jsonwritten: /out/deploy.bin, /out/ps0.json, /out/zswap0.json -
배포 트랜잭션을 파일로 구성하고, contract address를 읽고, 트랜잭션을 보냅니다.
midnight-node-toolkit send-intent -s ws://midnight-dev-node:9944 --intent-file /out/deploy.bin \--compiled-contract-dir /toolkit-js/contract/managed/counter --dest-file /out/deploy-tx.mnCONTRACT=$(midnight-node-toolkit contract-address --src-file /out/deploy-tx.mn)midnight-node-toolkit generate-txs --src-file /out/deploy-tx.mn -d ws://midnight-dev-node:9944 send -
컨트랙트의 상태를 읽습니다. 로그는 그 circuit과, seed
00..01의 verifying key인 authority를 나열합니다.midnight-node-toolkit contract-state -s ws://midnight-dev-node:9944 \--contract-address $CONTRACT --dest-file /out/state0.binContract address: 8a5c277b7470660f868748451c281fbc7fc9e77e8a5270d46e8945e11e395aedOp: increment (696e6372656d656e74)Op: add (616464)Authority VerifyingKey: 86f71b8a7a21bfe16a2bb2eab74475073fa5b773854f151ed548dba77a2c5815Authority Threshold: 1Authority Counter: 0내장 컨트랙트에서와 마찬가지로, 여러분의 contract address는 다릅니다.
-
increment를 호출합니다.generate-intent circuit은 여러분이 읽은 상태를 대상으로 circuit을 실행하고, intent, 새 private state, 그리고 예상되는 on-chain 상태를 씁니다. 그런 다음send-intent가 호출을 보냅니다.midnight-node-toolkit generate-intent circuit -s ws://midnight-dev-node:9944 \-c /toolkit-js/contract/contract.config.ts --coin-public $CP --contract-address $CONTRACT \--input-onchain-state /out/state0.bin --input-private-state /out/ps0.json \--output-intent /out/increment.bin --output-private-state /out/ps1.json --output-zswap-state /out/zswap1.json \--output-onchain-state /out/state1-expected.bin --output-result /out/result1.json \incrementmidnight-node-toolkit send-intent -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \--intent-file /out/increment.bin --compiled-contract-dir /toolkit-js/contract/managed/counter--output-result은 circuit의 반환값을 씁니다.increment은 아무것도 반환하지 않으므로, 파일에는[]이 담깁니다. -
새 상태를 읽은 다음, 인자
5로add를 호출합니다. circuit 인자는 circuit 이름 뒤에 옵니다.midnight-node-toolkit contract-state -s ws://midnight-dev-node:9944 \--contract-address $CONTRACT --dest-file /out/state1.binmidnight-node-toolkit generate-intent circuit -s ws://midnight-dev-node:9944 \-c /toolkit-js/contract/contract.config.ts --coin-public $CP --contract-address $CONTRACT \--input-onchain-state /out/state1.bin --input-private-state /out/ps1.json \--output-intent /out/add.bin --output-private-state /out/ps2.json --output-zswap-state /out/zswap2.json \--output-onchain-state /out/state2-expected.bin --output-result /out/result2.json \add 5midnight-node-toolkit send-intent -s ws://midnight-dev-node:9944 -d ws://midnight-dev-node:9944 \--intent-file /out/add.bin --compiled-contract-dir /toolkit-js/contract/managed/counter
Verification
각 호출 뒤 체인 상의 상태는 generate-intent이 예측한 상태입니다. add 5 뒤의 상태를 읽어 두 파일을 비교하세요.
midnight-node-toolkit contract-state -s ws://midnight-dev-node:9944 \
--contract-address $CONTRACT --dest-file /out/state2.bin
cmp "$HOME/midnight-toolkit/state2-expected.bin" "$HOME/midnight-toolkit/state2.bin"
cmp은 파일이 동일하면 아무것도 출력하지 않고 상태 0으로 종료합니다. 같은 확인이 state1-expected.bin과 state1.bin에 대해서도 통과합니다. 컴파일된 컨트랙트의 ledger() 함수로 디코딩하면, 카운터는 배포 뒤 0, increment 뒤 1, add 5 뒤 6을 가리킵니다.
Command reference
각 toolkit 1.0.300 명령이 무엇을 하고 무엇을 필요로 하는지 찾아보세요. 명령의 전체 옵션 목록을 보려면 아무 명령이나 --help와 함께 실행하세요.
| 명령 | 기능 | 노드 접근 | 체인 재생 |
|---|---|---|---|
version | toolkit의 node 버전, ledger 라이브러리 버전, 그리고 맞는 Compact 컴파일러 버전을 출력합니다. | 불필요 | 아니요 |
show-address | 네트워크에 대한 seed의 주소와 공개 키를 출력합니다. | 불필요 | 아니요 |
show-seed | 복구 구문의 64바이트 seed를 포함해, seed를 16진수로 출력합니다. | 불필요 | 아니요 |
show-viewing-key | 네트워크에 대한 seed의 viewing key를 출력합니다. | 불필요 | 아니요 |
random-address | 네트워크에 대한 무작위 unshielded 주소를, 또는 --shielded를 주면 shielded 주소를 출력합니다. | 불필요 | 아니요 |
show-token-type | contract address와 domain separator에 대한 token type을 출력합니다. | 불필요 | 아니요 |
show-transaction | 트랜잭션 파일을 디코딩합니다. | 불필요 | 아니요 |
contract-address | 배포 트랜잭션 파일 안의 contract address를 출력합니다. | 불필요 | 아니요 |
generate-genesis | 새 체인의 genesis 트랜잭션과 상태를 생성합니다. | 불필요 | 아니요 |
show-block | 블록 하나와 그 트랜잭션을 디코딩합니다. --json은 JSON을 출력합니다. | --src-file을 읽지 않는 한, 블록 하나를 가져옴 | 아니요 |
show-ledger-parameters | ledger 파라미터를 출력하며, -r을 주면 노드의 현재 파라미터를 출력합니다. --serialize는 인코딩된 형태를 출력합니다. | -r을 줄 때 | 아니요 |
show-wallet | --seed에 대한 지갑의 NIGHT UTXO, shielded 코인, DUST UTXO를, 또는 --address에 대한 public state를 보여줍니다. | 예 | 예 |
dust-balance | 지갑의 DUST 생성 항목, total, capacity를 보여줍니다. | 예 | 예 |
contract-state | 컨트랙트의 연산과 authority를 출력하고, --dest-file로 그 상태를 저장합니다. | 예 | 예 |
fetch | 블록을 캐시로 가져옵니다. --seeds는 해당 지갑들의 캐시도 구축합니다. | 예 | 예 |
generate-txs | 다음 표의 빌더 중 하나로 트랜잭션을 구성한 다음, -d로 보내거나 --dest-file로 씁니다. | --src-file과 --dest-file을 둘 다 쓰지 않는 한, 예 | --src-file을 읽지 않는 한, 예 |
send-intent | intent 파일로 트랜잭션을 구성한 다음 보내거나, --dest-file로 씁니다. | 예 | 예 |
generate-intent | 하위 명령 deploy, circuit, maintain-contract, maintain-circuit를 통해 toolkit-js로 컨트랙트 intent를 구성합니다. Docker 이미지가 필요합니다. | circuit은 ledger 파라미터를 읽음 | circuit, --wallet-seed를 줄 때 |
generate-sample-intent | 하위 명령 deploy, call, maintenance를 통해 샘플 intent 파일을 --dest-dir에 씁니다. | 예 | 예 |
update-ledger-parameters | 거버넌스를 통해 ledger 파라미터를 변경합니다. | 예 | 아니요 |
runtime-upgrade | 거버넌스를 통해 런타임을 업그레이드합니다. | 예 | 아니요 |
root-call | 거버넌스를 통해 Root origin으로 호출을 실행합니다. | 예 | 아니요 |
체인을 읽는 명령은 기본적으로 -s의 노드에서, 또는 --src-file로 파일에서 블록을 가져옵니다. 세 가지 거버넌스 명령에는 체인의 Council과 Technical Committee 구성원의 비밀 키가 필요합니다. 이 명령들은 여러분이 직접 운영하는 체인처럼 거버넌스 키를 보유한 체인에서만 사용할 수 있습니다.
generate-txs 빌더 | 구성하는 것 | 기본적으로 수수료를 내는 주체 |
|---|---|---|
single-tx | shielded 또는 unshielded 토큰으로, 각 --destination-address마다 출력 하나씩을 담은 트랜잭션 하나. | --source-seed 지갑 |
batch-single-tx | --transfers-file이나 --transfers의 JSON 전송 목록에서 만든 단일 출력 트랜잭션 여러 개. | 각 전송의 funding_seed, 설정되지 않았으면 source_seed |
batches | 부하 테스트 트래픽: 자금 트랜잭션 하나, 그다음 -n개 트랜잭션으로 된 -b개 배치. | 00..01 |
register-dust-address | --wallet-seed의 모든 NIGHT UTXO에 대한 DUST 등록. | --funding-seed을 생략하면, 등록된 NIGHT |
deregister-dust-address | --wallet-seed에 대한 DUST 등록 해제. | 00..01 |
contract-simple | 하위 명령 deploy, call, maintenance를 통해, 내장 테스트 컨트랙트에 대한 배포·호출·유지 관리 트랜잭션. | 00..01 |
contract-custom | 여러분 자신의 컨트랙트 intent 파일로 만든 트랜잭션. | 00..01 |
claim-rewards | --amount만큼의 보상 청구. | 00..01 |
send | 새로 만드는 것 없음: --src-file로 읽은 트랜잭션을 보냅니다. | toolkit이 각 트랜잭션을 구성할 때 자금을 댄 지갑 |
--funding-seed 옵션이 있는 모든 빌더는 그것을 사용해 수수료를 냅니다. 이 옵션에 기본값이 있는 경우, 그 기본값은 로컬 개발 체인의 genesis 지갑인 00..01입니다. 공개 네트워크에서는 DUST를 보유한 여러분 자신의 seed를 전달하세요. 표에서 보듯이, single-tx는 --source-seed로, register-dust-address는 등록된 NIGHT으로 넘어갑니다. send-intent도 기본값이 00..01입니다.
| 전역 옵션 | 환경 변수 | 효과 |
|---|---|---|
-q, --quiet | MN_QUIET | 정보 로그를 숨깁니다. 경고와 오류는 여전히 출력됩니다. |
-v, --verbose | MN_VERBOSE | 디버그 로그를 출력합니다. |
--verbose-ledger | MN_VERBOSE_LEDGER | ledger의 디버그 추적을 출력합니다. |
--verbose-fetch | MN_VERBOSE_FETCH | 블록 페처의 디버그 로그를 출력합니다. |
--log-json | MN_LOG_JSON | 각 로그 줄을 stderr에 JSON 객체로 출력합니다. |
--replay-concurrency | MN_REPLAY_CONCURRENCY | 지갑을 재생하는 스레드 수를 설정합니다. 기본값은 CPU 코어 수입니다. |
Toolkit troubleshooting
오류 메시지를 찾아 그 원인과 해결책을 확인하세요. 각 메시지는 toolkit 1.0.300에서 나온 것입니다.
| 메시지 | 원인 | 해결 |
|---|---|---|
Error: ComputeTaskError(RuntimeVersionError(UnsupportedBlockVersion(1000300))) | 예를 들어 Preprod의 toolkit 1.0.0처럼, toolkit이 체인의 런타임보다 오래됨. | 네트워크가 구동하는 node 릴리스의 toolkit을 사용하세요. Toolkit versions and networks를 참고하세요. |
error creating client 다음 Error: NodeClientError(OnlyGenesisFinalized) | 예를 들어 로컬 노드를 막 시작한 직후처럼, 노드가 블록 1을 finalize하기 전에 재생 명령이 실행됨. | 몇 초 기다렸다가 명령을 다시 실행하세요. |
최대 60초 동안 rpc connection attempt failed, retrying: ..., 그다음 Error: RpcClientError(...). 체인을 재생하는 명령은 대신 error creating client 다음 Error: NodeClientError(RpcClientError(...))를 출력함. | URL이나 호스트 이름이 잘못됐거나, 노드가 꺼져 있거나, 바이너리의 시스템에 CA 인증서가 없음. | URL과 노드 실행 여부를 확인하세요. Docker에서는 공유 네트워크에서 노드 컨테이너에 이름으로 접근하세요. Connection and cache options를 참고하세요. |
No CA certificates were loaded from the system | 릴리스 바이너리가 CA 인증서가 없는 시스템에서 실행됨. | ca-certificates 패키지를 설치하세요. |
failed to create database - is it already open?: DatabaseAlreadyOpen | 두 toolkit 명령이 하나의 캐시를 동시에 사용함. | 한 번에 한 명령씩 실행하거나, 각 명령에 자체 캐시 볼륨을 주세요. |
Failed to write ledger snapshot file: Permission denied (os error 13) | 같은 캐시 볼륨을 쓰던 다른 명령이 이 명령 실행 중에 종료되었고, 이미지가 볼륨을 여러분의 사용자에게 돌려줌. | 한 번에 한 명령씩 실행하거나, 각 명령에 자체 캐시 볼륨을 주세요. |
rpc fetch failed, retrying: ... State already discarded for 0x..., 그다음 Error: FetchTaskError(OnlineClientAtBlockError(CannotGetSpecVersion {...})) | 노드가 오래된 상태를 가지치기하는데, 재생이나 오래된 블록의 show-block처럼 명령이 더 오래된 블록을 필요로 함. | archive node를 사용하세요. |
Balancing TX failed: InsufficientDustForRegistrationFee | NIGHT UTXO가 둘 이상인 지갑, 또는 예를 들어 --destination-dust을 바꾸려는 이미 등록된 지갑에 대해 --funding-seed 없이 실행한 register-dust-address. | DUST를 보유한 지갑을 넣어 --funding-seed을 추가하세요. |
Balancing TX failed: "Insufficient DUST (trying to spend ..., need ... more)" | 수수료를 낼 DUST가 없음. 자금 전송이나 지갑의 이전 등록처럼 지갑의 NIGHT UTXO를 만든 트랜잭션으로부터 몇 초 안에 --funding-seed 없이 register-dust-address를 실행하면 발생함. DUST가 소진된 --funding-seed 지갑에서도, 그리고 --dust-warp 없이 genesis 파일로 구성한 트랜잭션에서도 발생함. | DUST를 보유한 --funding-seed 지갑을 사용하세요. NIGHT UTXO가 하나인 지갑의 첫 등록이라면, 대신 약 30초 기다렸다가 명령을 다시 실행해도 됩니다. genesis 파일로 구성할 때는 --dust-warp를 추가하세요. |
failed to decode dust address: AddressNotDust | --destination-dust 값이 DUST 주소가 아님. 예를 들어 mn_addr_ 주소이거나 mn_dust-addr_ 접두사가 붙은 주소임. | show-address가 주는 dust 값을 사용하세요. 이 값은 mn_dust_로 시작합니다. |
error: unexpected argument '--src-files' found | 옵션 이름은 끝에 s가 없는 --src-file임. | --src-file을 사용하세요. |
error: the argument '--dest-url <DEST_URLS>' cannot be used with '--dest-file <DEST_FILE>' | 명령이 보낼 노드와 쓸 파일을 둘 다 받음. | 둘 다가 아니라 -d나 --dest-file 중 하나를 전달하세요. |
error: unrecognized subcommand 'get-tx-from-context' 또는 'claim-mint' | toolkit README가 toolkit 1.0.300에 없는 명령을 설명함. | midnight-node-toolkit --help와 midnight-node-toolkit generate-txs --help를 확인하세요. |
Version mismatch: compiled code expects 0.16.0, runtime is 0.15.0 | 컴파일러 0.31.1이 언어 버전 0.23에 맞춰 작성된 소스로 컨트랙트를 빌드함. | 컨트랙트를 언어 버전 0.22에 맞춰 작성하고 compact compile +0.30.0으로 컴파일하세요. |
Exception: counter.compact line 1 char 1: 다음 language version 0.23.0 mismatch | 이 페이지의 카운터처럼 pragma language_version 0.22;를 선언한 컨트랙트를, 언어 버전 0.23을 구현하는 컴파일러 0.31.1로 컴파일함. | compact compile +0.30.0으로 컴파일하세요. |
error: invalid value '...' for '--seed <SEED>' | seed의 길이가 잘못됐거나, 복구 구문의 체크섬이 잘못됨. | 16, 32, 64바이트의 16진수나 유효한 구문을 전달하세요. |
Additional resources
- Node endpoints: Blockfrost Mainnet RPC를 포함한 공개 RPC 엔드포인트.
- Set up full node: archive node로 실행하는 경우를 포함해, 여러분 자신의 노드를 운영하기.
- Networks and environments: 네트워크 이름, 엔드포인트, 그리고 midnight-local-dev 로컬 네트워크.
- Managing DUST for transaction fees: DUST 파라미터, 등록 규칙, 그리고 wallet SDK의 DUST 오류.
- Funding a wallet: faucet, 그리고 Lace나 wallet SDK로 하는 DUST 등록.
- Node release notes: 각 node 및 toolkit 릴리스의 변경 사항.
- Support matrix: 각 네트워크의 구성 요소 버전.
- Toolkit README at node-1.0.300: upstream 명령 가이드. 일부 예제는 1.0.300 명령과 맞지 않으므로,
--help와 대조해 확인하세요. - Node toolkit image on Docker Hub: 게시된 태그.