π Complete Manual Walkthrough
This section provides a step-by-step guide to manually run the Zenith network, deploy a Virtual Blockchain, and execute transactions. This replicates the automated end-to-end test but with detailed explanations for each step.
Phase 1: Building Components
First, we need to build all the necessary components:
# Build all Rust components (VB runtimes, guest programs, tools)# This compiles the Substrate VB example, genesis generator, input generator, and librariescargo build --release# Build the Zenith daemon (the main node software)go build -o target/release/zenithd ./cmd/zenithdWhat's happening:
- Cargo builds the Substrate VB runtime compiled for RISC-V target
- Genesis generator creates initial blockchain state
- Input generator creates transaction data for testing
- Zenith daemon (
zenithd) is the main node software for the network
Verify the build was successful:
ls target/release/genesis-gen # Genesis state generatorls target/release/input-gen # Transaction input generator ls target/release/zenithd # Zenith daemonls target/release/libzenith.so # Zenith library with RISC0 bindingsls target/riscv-guest/substrate-vb/method/riscv32im-risc0-zkvm-elf/release/method.bin # VB imagePhase 2: Local Testing (Optional but Recommended)
Before deploying to the network, let's test everything works locally:
# Create a temporary directory for our testTEMP_DIR=$(mktemp -d)cd $TEMP_DIR# Generate genesis state for the Substrate VB$PROJECT_DIR/target/release/genesis-genWhat's happening: The genesis generator creates the initial state for our Substrate VB, including the merkle tree root that represents the blockchain's starting state.
You should see files created:
ls -la# genesis.bin - Binary genesis state# genesis.json - Human-readable genesis info (after next step)Apply the genesis configuration:
bash $PROJECT_DIR/examples/substrate-vb/genesis-gen/apply_genesis.shWhat's happening: This script creates a local merkle tree from the genesis state:
- Initializes a merkle tree in
./treedirectory usingzenithd merkletree init - Extracts key-value pairs from
genesis.jsonand populates the tree - Calculates the merkle root (state root) from the populated tree
- Adds the
state_rootandgenesis_hashback togenesis.json
Extract the important values:
GENESIS_STATE_ROOT=$(cat genesis.json | jq -r '.state_root')GENESIS_HASH=$(cat genesis.json | jq -r '.genesis_hash')echo "Genesis State Root: $GENESIS_STATE_ROOT"echo "Genesis Hash: $GENESIS_HASH"Generate test transaction input:
$PROJECT_DIR/target/release/input-gen --state-root $GENESIS_STATE_ROOT --genesis-hash $GENESIS_HASHWhat's happening: This creates sample transactions (extrinsics) that our VB will process in the first block.
Test local execution (this proves everything works):
VB_IMAGE="$PROJECT_DIR/target/riscv-guest/substrate-vb/method/riscv32im-risc0-zkvm-elf/release/method.bin"$PROJECT_DIR/target/release/zenithd prove -e $VB_IMAGE -i input.bin -o output.bin -r receipt.bin -t ./treeWhat's happening: This executes the VB locally in the RISC0 environment and generates a zero-knowledge proof. If successful, you'll see messages like "Extrinsic 0 executed successfully".
Phase 3: Network Deployment
Now let's start the actual Zenith network:
3.1 Start Zenith Validator Node
In a new terminal, start the validator:
# Create validator configuration directorymkdir -p ./tests/assets/validator-root# Start the containerized Zenith validator with IPFSpodman run -d --name validator \ -p 26657:26657 -p 1317:1317 -p 5001:5001 -p 9090:9090 \ -v ./tests/assets/validator-root:/root/.zenith \ -e WORKER_MNEMONIC="horn edge entire mask sock belt modify fever fit people throw cargo tone accident bike below goat sudden cup sure opinion room flavor style" \ -e RISC0_DEV_MODE=1 \ -e RISC0_INFO=1 \ -e RUST_LOG=info \ -e RUST_BACKTRACE=1 \ -e LOG_LEVEL=info \ quay.io/zenith/node:latest start --log_level infoWhat's happening: This starts a Zenith validator node with:
- Port 26657: Tendermint RPC (for blockchain operations)
- Port 1317: REST API (for queries)
- Port 5001: IPFS API (for data storage)
- Port 9090: gRPC API (for advanced queries)
- Volume mount: Persists validator state and keys
- Environment variables: Configure RISC0 development mode and logging
Wait for the node to start and create the first block:
# Wait for the node to be readysleep 10# Check if the first block has been createdcurl -s http://localhost:26657/block?height=1 | jq '.result.block.header.height'Copy validator keys to local machine (needed for transactions):
podman cp validator:/root/.zenith/keyring-test ~/.zenith/3.2 Verify IPFS is Running
Test IPFS connectivity:
echo "test" | ipfs add -q --api http://localhost:5001 # Should return: QmTest...3.3 Register a Worker Node
Workers are the compute nodes that execute VB transactions:
zenithd tx workers create-worker worker-1 "First worker" \ --from alice \ --yes \ --fees 500stake \ --keyring-backend test \ --chain-id zenith-1 \ --node http://localhost:26657What's happening: This registers a worker node on the Zenith network. Workers announce their capability to execute VB operations and generate zero-knowledge proofs.
Verify the transaction was successful:
# Get the transaction hash from the output above and check itzenithd query tx <TX_HASH> --node http://localhost:26657Phase 4: Virtual Blockchain Deployment
Now we'll deploy our Substrate VB to the network:
4.1 Compute VB Image ID
VB_IMAGE="target/riscv-guest/substrate-vb/method/riscv32im-risc0-zkvm-elf/release/method.bin"IMAGE_ID=$(zenithd compute-image-id -e $VB_IMAGE)echo "VB Image ID: $IMAGE_ID"What's happening: This computes a deterministic identifier for our VB image that workers will use to verify they're executing the correct program.
4.2 Upload Artifacts to IPFS
Upload the VB program and genesis state:
# Upload VB image (the compiled RISC-V program)IMAGE_CID=$(ipfs add -q --api http://localhost:5001 $VB_IMAGE)echo "VB Image CID: $IMAGE_CID"# Upload genesis stateGENESIS_CID=$(ipfs add -q --api http://localhost:5001 $TEMP_DIR/genesis.bin)echo "Genesis CID: $GENESIS_CID"What's happening: IPFS provides content-addressed storage. The CIDs (Content Identifiers) uniquely identify our data and ensure integrity - if the data changes, the CID changes.
4.3 Create VB On-Chain
Register the VB with the Zenith network:
VB_ID="substrate-vb-1"zenithd tx vbs create-vb \ $VB_ID $IMAGE_CID $IMAGE_ID $GENESIS_CID $GENESIS_STATE_ROOT \ --from alice \ --yes \ --fees 500stake \ --keyring-backend test \ --chain-id zenith-1 \ --node http://localhost:26657What's happening: This creates a Virtual Blockchain entry on the Zenith network with references to:
- VB ID: Human-readable identifier
- Image CID: Where to find the VB program on IPFS
- Image ID: Deterministic program identifier
- Genesis CID: Where to find the initial state on IPFS
- Genesis State Root: The merkle root of the initial state
4.4 Verify Worker Synchronization
Check that workers have fetched and initialized the VB:
# Look for log messages indicating the worker has initialized the VBpodman logs validator 2>&1 | grep "Updated merkle tree"What's happening: Workers automatically detect new VB deployments, download the artifacts from IPFS, and initialize their local merkle trees with the genesis state.
Phase 5: Execute VB Transactions
Now let's build the first block of our VB:
5.1 Upload Transaction Input
# Upload the transaction data we generated earlierINPUT_CID=$(ipfs add -q --api http://localhost:5001 $TEMP_DIR/input.bin)echo "Input CID: $INPUT_CID"What's happening: This uploads our sample transactions to IPFS so workers can fetch them for execution.
5.2 Create VB Call
Submit a request to execute transactions on our VB:
zenithd tx vbs create-call $VB_ID $INPUT_CID \ --from alice \ --yes \ --fees 500stake \ --keyring-backend test \ --chain-id zenith-1 \ --node http://localhost:26657What's happening: This creates a "call" - a request for workers to execute the transactions in input.bin on VB substrate-vb-1.
5.3 Monitor Execution
Watch the logs to see the execution process:
# Worker picks up the taskpodman logs validator 2>&1 | grep "Task ACK sent successfully"# Worker completes execution and submits proofpodman logs validator 2>&1 | grep "Task FINISH sent successfully"# Zenith verifies proof and updates VB statepodman logs validator 2>&1 | grep "VB updated"What's happening:
- ACK: Worker acknowledges the task and begins execution
- Execution: Worker downloads input from IPFS, executes transactions in RISC0 zkVM, generates proof
- FINISH: Worker uploads results to IPFS and submits proof to Zenith
- Verification: Zenith verifies the zero-knowledge proof and updates the VB state root
5.4 Verify Results
Query the VB state to see the updated state root:
# Using CLIzenithd query vbs show-vb $VB_ID --node http://localhost:26657# Using REST API (alternative method)curl -s http://localhost:1317/zenith/vbs/v1/vb/$VB_ID | jq .What's happening: The VB state root should now reflect the new state after processing the transactions. This proves that the block was successfully built and verified. You can use either the CLI or REST API to query the VB state.