A DAG-based distributed ledger with tunable consistency, designed for mesh-native and partition-prone environments. Delivers CP-like checkpoint finality during normal operation, provisional availability during partitions, and deterministic merge reconciliation when connectivity is restored. Self-contained VerifiableObject proofs enable offline verification without RPC infrastructure.
- Rust (1.75+) - Install via rustup
- Node.js (18+) - For the explorer
# Clone and build
git clone <repo-url>
cd rinku
# Build the Rust node
cargo build -p rinku-node --release# Start a fresh local node
RUST_LOG=info cargo run -p rinku-node
# Or run in TUI mode (terminal interface)
RUST_LOG=info cargo run -p rinku-node --features tui -- --tuiTo sync your local node with the live Fly.io testnet validators:
# Get the P2P bootstrap info from the genesis node
curl https://rinku-genesis.fly.dev/api/bootstrapThis returns the peer ID and multiaddr needed to connect via P2P.
From the bootstrap response, extract these values:
peerId— the genesis node's libp2p peer IDgenesisValidatorEnv— theaddress:blsPublicKeystring forGENESIS_VALIDATORS
Then look up the genesis node's public IPv4 (shown in the bootstrap response's bootstrapMultiaddr field, or via fly ips list -a rinku-genesis).
# Required: P2P connection to the testnet
export P2P_BOOTSTRAP_PEERS="/ip4/<GENESIS_IP>/tcp/4001/p2p/<PEER_ID>"
# Required: Trust anchor — tells your node which validators are authorized
# Use the genesisValidatorEnv value from /api/bootstrap
# For multiple validators, separate with semicolons: "addr1:bls1;addr2:bls2;addr3:bls3"
export GENESIS_VALIDATORS="<ADDRESS>:<BLS_PUBLIC_KEY>"
# Required: Must match the testnet's chain/network identity
export CHAIN_ID="rinku-testnet"
export NETWORK_ID="testnet"
# Required: Mainnet mode enforces strict validation (the testnet runs with this enabled)
export MAINNET_MODE="true"
# Required: Your node's reachable URL (used for leader election protocol)
export PUBLIC_URL="http://localhost:3001"
# Optional: HTTP peer for fallback sync (in addition to P2P)
export NODE_PEERS="https://rinku-genesis.fly.dev"
# Logging
export RUST_LOG="rinku_node=info"
# Run in TUI mode
cargo run -p rinku-node --features tui -- --tuiOr as a single command:
P2P_BOOTSTRAP_PEERS="/ip4/<GENESIS_IP>/tcp/4001/p2p/<PEER_ID>" \
GENESIS_VALIDATORS="<ADDRESS>:<BLS_PUBLIC_KEY>" \
CHAIN_ID="rinku-testnet" \
NETWORK_ID="testnet" \
MAINNET_MODE="true" \
PUBLIC_URL="http://localhost:3001" \
NODE_PEERS="https://rinku-genesis.fly.dev" \
RUST_LOG="rinku_node=info" \
cargo run -p rinku-node --features tui -- --tuiImportant notes:
- Use
/ip4/(not/dns4/) when the bootstrap address is a raw IP CHAIN_IDandNETWORK_IDmust match the testnet — mismatches cause handshake rejection- Without
GENESIS_VALIDATORS, your node cannot verify checkpoint signatures during sync IS_GENESIS_NODEis auto-detected asfalsewhenP2P_BOOTSTRAP_PEERSis set
In the TUI, you should see:
- Checkpoint height increasing as you sync
- DAG size growing
- Peer count > 0 once connected
Or via API:
curl http://localhost:3001/api/sync/status
curl http://localhost:3001/api/dag/summary| Node | URL | Purpose |
|---|---|---|
| Genesis | https://rinku-genesis.fly.dev | Primary testnet node |
| Validator 1 | https://rinku-validator-1.fly.dev | Validator node |
| Validator 2 | https://rinku-validator-2.fly.dev | Validator node |
| Variable | Description | Default |
|---|---|---|
API_PORT |
HTTP API port | 3001 |
DATA_DIR |
Database storage path | .rinku-data |
CHAIN_ID |
Chain identifier (must match network) | rinku-mainnet |
NETWORK_ID |
Network identifier | mainnet |
RUST_LOG |
Log level (debug, info, warn, error) | info |
IS_GENESIS_NODE |
Allow creating new chain if no peers | auto-detected |
| Variable | Description | Default |
|---|---|---|
P2P_ENABLED |
Enable libp2p networking | true |
P2P_PORT |
P2P listen port | 4001 |
P2P_BOOTSTRAP_PEERS |
Comma-separated multiaddrs | "" |
P2P_MDNS |
Enable mDNS for LAN discovery | true |
P2P_MAX_PEERS |
Maximum peer connections | 50 |
| Variable | Description | Default |
|---|---|---|
NODE_PEERS |
Comma-separated HTTP peer URLs | "" |
| Variable | Description | Default |
|---|---|---|
MAINNET_MODE |
Enforce mainnet-grade security | false |
PUBLIC_URL |
Node's public URL for leader election | "" |
GENESIS_VALIDATORS |
Genesis validator set (addr:bls;...) | "" |
RATE_LIMIT_TX_MAX |
Max tx submits per IP per minute | 30 |
RATE_LIMIT_CONTRACT_MAX |
Max contract deploy/call per IP per minute | 20 |
RATE_LIMIT_GENERAL_MAX |
Max general write ops (e.g. faucet) per IP per minute | 100 |
FAUCET_ENABLED |
Enable faucet mint endpoints | true unless MAINNET_MODE |
CORS_ALLOW_ORIGINS |
Comma-separated origins for write-route CORS (* = any) |
localhost explorer ports |
The node generates an ECDSA P-256 wallet on first startup, stored encrypted at <DATA_DIR>/validator.key. This wallet holds RKU, stakes, and receives staking rewards.
# Show the wallet address only
cargo run -p rinku-node -- --show-address
# Export wallet JSON (compatible with Explorer import)
VALIDATOR_KEY_PASSWORD="your-password" cargo run -p rinku-node -- --export-keyThe wallet JSON is printed to stdout (instructions go to stderr), so you can pipe it:
VALIDATOR_KEY_PASSWORD="your-password" cargo run -p rinku-node -- --export-key > my-wallet.jsonThe exported JSON contains publicKey, privateKey (PKCS8 DER hex), and fingerprint — the same format used by the Explorer wallet.
# Import from wallet JSON (exported from Explorer or another node)
VALIDATOR_KEY_PASSWORD="your-password" cargo run -p rinku-node -- --import-key '{"publicKey":"04...","privateKey":"3081...","fingerprint":"..."}'
# Import from PKCS8 DER hex
VALIDATOR_KEY_PASSWORD="your-password" cargo run -p rinku-node -- --import-key 308187020100...
# Import from raw 32-byte private key hex
VALIDATOR_KEY_PASSWORD="your-password" cargo run -p rinku-node -- --import-key 368e9a5471...This lets you use the same wallet identity across the Explorer and your validator node. The key is encrypted with your VALIDATOR_KEY_PASSWORD before being saved.
Note: In MAINNET_MODE, VALIDATOR_KEY_PASSWORD must be explicitly set (the default dev-password is rejected).
| File | Contents |
|---|---|
<DATA_DIR>/validator.key |
Encrypted ECDSA private key (wallet for RKU transactions) |
<DATA_DIR>/validator-identity/validator_keys.json |
BLS signing keys (for checkpoint signatures) |
The TUI (Terminal User Interface) provides a real-time dashboard for monitoring node state:
# Build with TUI feature
cargo build -p rinku-node --features tui
# Run TUI
cargo run -p rinku-node --features tui -- --tuiTUI displays:
- Checkpoint height and DAG size
- Connected peers
- Transaction throughput
- Finality metrics
- Network status
The web-based block explorer runs on port 5000:
# Build core library and start explorer
npm run build -w @rinku/core
npm run dev -w @rinku/explorerVisit http://localhost:5000 to view:
- DAG visualization
- Account balances
- Transaction history
- Staking interface
- Faucet
The node exposes a REST API on port 3001:
| Endpoint | Description |
|---|---|
GET /api/dag/summary |
DAG statistics |
GET /api/accounts |
All accounts |
GET /api/account/:addr |
Account details |
GET /api/tx/:hash |
Transaction details |
POST /api/tx |
Submit transaction |
GET /api/sync/status |
Sync status |
GET /api/bootstrap |
P2P bootstrap info |
GET /api/peers |
Connected peers |
GET /api/finality/metrics |
Finality statistics |
rinku/
├── packages/
│ ├── rinku-core/ # Protocol primitives: crypto, merkle, checkpoints (Rust)
│ ├── rinku-node/ # Full node: consensus, P2P, API server (Rust)
│ ├── rinku-contract-sdk/ # WASM smart contract SDK (Rust)
│ ├── core/ # Protocol primitives (TypeScript dual of rinku-core)
│ ├── wallet/ # Wallet helpers for Explorer and clients
│ ├── zk/ # Zero-knowledge privacy layer (Circom + TS)
│ ├── explorer/ # React block explorer (includes faucet UI)
│ ├── stateless/ # Stateless dApp helpers (ContractOutput proofs)
│ └── examples/ # Sample WASM contracts
├── scripts/ # Deployment, validation, and stress-test harnesses
├── docs/ # Versioning, architecture notes, whitepaper
├── fly.toml # Fly.io node deployment config
├── Cargo.toml # Rust workspace
└── package.json # npm workspaces
# Terminal 1: Rust node
RUST_LOG=info cargo run -p rinku-node
# Terminal 2: Explorer (port 5000; faucet UI talks to the node API)
npm run build -w @rinku/core && npm run dev -w @rinku/explorer# Rust tests
cargo test
# TypeScript tests
npm testMIT