Skip to main content

System Overview

captaind is built as a modular, async Rust application that coordinates off-chain Bitcoin transactions. The architecture separates concerns into distinct components that communicate through well-defined interfaces.

Core Components

Server Core

The main Server struct coordinates all components: Location: server/src/lib.rs Responsibilities:
  • Initialize and manage all subsystems
  • Handle RPC requests from clients
  • Coordinate round execution
  • Manage server state and configuration
  • Provide thread-safe access to shared resources
Key Data:
  • server_key: Server’s signing key for VTXOs
  • mailbox_key: Key for unblinding mailbox identifiers
  • rounds_wallet: BDK wallet for round funding
  • watchman_wallet: Optional wallet for forfeit claims
  • db: Database connection pool
  • bitcoind: Bitcoin Core RPC client

Round Coordinator

Manages the payment round lifecycle: Location: server/src/round/mod.rs Round States:
  1. CollectingPayments: Accept user payment submissions
  2. SigningVtxoTree: Collect user signatures on VTXO tree
  3. Finished: Round completed (success, empty, or error)
Flow: Key Functions:
  • perform_round(): Execute a single round
  • receive_payments(): Collect user payment requests
  • receive_vtxo_signatures(): Collect VTXO tree signatures
  • sign_on_chain_transaction(): Sign and broadcast round tx

Database Layer

PostgreSQL-based persistence for all server state: Location: server/src/database/ Core Tables:
  • vtxo: User VTXOs and their states
  • round: Completed rounds with funding transactions
  • virtual_transaction: Off-chain transaction data
  • lightning_invoice: Lightning payment tracking
  • wallet_changeset: BDK wallet state
  • integration_*: Integration manager tables
Key Interfaces:
// Database handle
pub struct Db { /* connection pool */ }

impl Db {
    async fn get_user_vtxos_by_id(&self, ids: &[VtxoId]) -> Result<Vec<StoredVtxo>>;
    async fn upsert_vtxos(&self, vtxos: impl IntoIterator<Item = ServerVtxo>) -> Result<()>;
    async fn finish_round(&self, seq: RoundSeq, tx: &Transaction, ...) -> Result<()>;
    // ... hundreds more methods
}

Sync Manager

Tracks Bitcoin blockchain state: Location: server/src/sync/mod.rs Responsibilities:
  • Poll Bitcoin Core for new blocks
  • Detect chain reorganizations
  • Notify listeners of chain events
  • Maintain chain tip state
Chain Event Listeners:
  • VtxoExitFrontier: Tracks VTXO exit transactions for watchman
  • (Extensible for custom listeners)

TX Index & Nursery

Transaction monitoring and broadcasting: Location: server/src/txindex/ TX Index:
  • Tracks transaction confirmation status
  • Monitors mempool state
  • Detects transaction conflicts
TX Nursery (TxNursery):
  • Broadcasts transactions to Bitcoin network
  • Handles rebroadcasting for stuck transactions
  • Manages transaction lifecycle

RPC Server

Three gRPC interfaces for different audiences: Location: server/src/rpcserver/

1. Public Ark API (port 3535)

File: ark.rs Services:
  • ArkService: Core Ark operations (info, board, rounds)
  • MailboxService: Mailbox message retrieval
  • LightningService: Lightning payments
Used by all Ark clients (wallets).

2. Admin API (port 3536)

File: admin.rs Services:
  • WalletAdminService: Query wallet status
  • RoundAdminService: Trigger rounds manually
For server operators only.

3. Integration Manager API (port 3537)

File: intman.rs Service: IntegrationManagerService API for third-party integrations (e.g., faucets, merchants).

Fee Estimator

Dynamic fee rate management: Location: server/src/fee_estimator.rs Features:
  • Polls Bitcoin Core for fee estimates
  • Provides fast/regular/slow fee rates
  • Falls back to configured rates if estimator unavailable
  • Caches estimates to reduce RPC calls
Usage:
let feerate = server.fee_estimator.regular();
let tx = wallet.build_tx().fee_rate(feerate).finish()?;

Watchman

Automated VTXO forfeit claiming: Location: server/src/watchman/ Components:
  • VtxoExitFrontier: Set of VTXOs being monitored
  • WatchmanSigner: Creates claim transactions
  • Daemon: Main processing loop
Actions:
  • Wait: VTXO not yet claimable
  • Progress: Broadcast next transaction in VTXO tree
  • Claim: Claim VTXO directly to server wallet
Can run as:
  1. Integrated with captaind (default)
  2. Standalone watchmand process (separate binary)

Lightning Integration

Core Lightning node management: Location: server/src/ln/ ClnManager:
  • Connects to multiple CLN nodes
  • Routes payments across nodes (priority-based)
  • Tracks invoice state
  • Handles hold invoices for receives
Payment Flow:

VTXO Pool

Pre-issued VTXO management: Location: server/src/vtxopool.rs Purpose: Provide instant liquidity for users Operations:
  • Issue VTXOs to pool when below target
  • Track pool utilization
  • Expire and reclaim old pool VTXOs
Configuration:
[vtxopool]
vtxo_targets = ["1000sat:10", "10000sat:10"]
vtxo_target_issue_threshold = 80

Wallet Management

BDK-based Bitcoin wallets: Location: server/src/wallet.rs Wallet Types (WalletKind):
  • Rounds: Funds round transactions and server operations
  • Watchman: Pays fees for forfeit claims
  • Forfeits: (Deprecated, merged into Rounds)
PersistedWallet:
  • Wraps BDK Wallet
  • Persists state to PostgreSQL
  • Provides transaction building helpers
  • Manages UTXO locking

Data Flow

Payment Round Data Flow

Board (Onboarding) Data Flow

Concurrency & Threading

Runtime Management

RuntimeManager (server/src/system.rs):
  • Tracks all background tasks
  • Handles graceful shutdown
  • Monitors critical vs non-critical workers

Async Architecture

Built on Tokio async runtime:
  • All I/O operations are async
  • Database queries use connection pooling
  • Round coordinator runs in dedicated task
  • Each RPC connection spawns a task

Locking Strategy

VTXOs in Flux (flux.rs):
pub struct VtxosInFlux {
    // Prevents double-spending VTXOs
    locks: RwLock<HashMap<VtxoId, ()>>
}
Wallets:
// Shared mutable wallet access
rounds_wallet: Arc<Mutex<PersistedWallet>>
Configuration:
// Immutable after init
config: Config  // No lock needed

Security Considerations

Key Management

  • Server Key: Derived from mnemonic, never leaves memory
  • Mailbox Key: Separate key for mailbox privacy
  • Ephemeral Keys: Temporary cosign keys with expiry

Access Control

  • Public API: No authentication (protocol-level security)
  • Admin API: Localhost-only by default
  • Integration API: API key required

Database Security

  • Connection pooling prevents connection exhaustion
  • Prepared statements prevent SQL injection
  • Triggers enforce data integrity

Network Security

  • TLS for CLN connections (mTLS)
  • gRPC with TLS support (configure separately)
  • Firewall rules for RPC ports

Observability

Logging

Structured logging with server-log crate:
slog!(RoundStarted, round_seq);
slog!(VtxoCreated, vtxo_id, amount);

Metrics

OpenTelemetry metrics:
  • Round counts and durations
  • Wallet balances
  • Lightning payment volumes
  • Database connection pool stats

Tracing

Distributed tracing for:
  • Round execution
  • RPC requests
  • Payment processing
See Monitoring for setup details.

Scalability Considerations

Bottlenecks

  1. Database: Most queries are indexed, but round storage can be slow
  2. Round Coordinator: Single-threaded, processes rounds sequentially
  3. Bitcoin Core RPC: Network calls can add latency

Optimization Strategies

  • Connection pooling: Reuse database and RPC connections
  • Async I/O: Non-blocking network operations
  • Batch operations: Group database writes
  • Caching: Fee estimates, block height

Horizontal Scaling

Not currently supported. Each captaind instance:
  • Must have exclusive database access
  • Runs independent rounds
  • Cannot share state with other instances
Future work may enable read replicas or sharding.

Development Resources

Code Organization

server/
├── src/
│   ├── lib.rs              # Server core
│   ├── bin/captaind/       # Binary entry point
│   ├── config.rs           # Configuration
│   ├── database/           # Database layer
│   ├── rpcserver/          # gRPC servers
│   ├── round/              # Round coordinator
│   ├── ln/                 # Lightning integration
│   ├── watchman/           # Forfeit watcher
│   ├── wallet.rs           # BDK wallet wrapper
│   ├── sync/               # Blockchain sync
│   ├── txindex/            # TX monitoring
│   └── ...                 # Supporting modules
├── Cargo.toml              # Dependencies
├── captaind.default.toml   # Default config
└── schema.sql              # Database schema

Key Dependencies

  • ark-lib: Core Ark protocol implementation
  • bitcoin: Bitcoin primitives
  • bdk_wallet: Bitcoin wallet functionality
  • tokio: Async runtime
  • tonic: gRPC framework
  • tokio-postgres: PostgreSQL client
  • tracing: Observability

Building & Testing

# Build
cargo build --release --bin captaind

# Run tests
cargo test --package bark-server

# Check
cargo clippy --package bark-server

Build docs developers (and LLMs) love