Files
bal-server/docs/04_modules_detail.md
svatantrya df8effcc60 refactor: remove bal-pusher-enhanced and update docs/env
- Remove src/bin/bal-pusher-enhanced.rs (synchronous pusher variant)
- Remove bal-pusher.env and bal-pusher.sh from git tracking (now in .gitignore)
- Update all documentation to remove references to bal-pusher-enhanced:
  * 01_project_overview.md
  * 02_glossary_and_bitcoin_domain.md
  * 03_architecture_and_data_flow.md
  * 04_modules_detail.md
  * 05_api_reference.md (remove rawblock ZMQ section, update references)
  * 08_security_audit.md (remove references to bal-pusher-enhanced in DoS and ZMQ sections)
  * 09_references_and_links.md
- Build verified: cargo check passes for bal-pusher and bal-server binaries
2026-07-16 14:32:59 -04:00

6.6 KiB

Module Details

Quick Reference


lib.rs

Location: src/lib.rs

This is the root of the library crate. It simply exports two public modules:

  • pub mod db; — the database interface
  • pub mod xpub; — the extended public key utilities

It contains no application logic.


db.rs (Database Interface)

Location: src/db.rs

This module contains all the logic for interacting with the SQLite database.

Key Functions

  • create_table: Creates the full database schema if it does not exist. See src/db.rs for the CREATE TABLE statements.
  • execute_insert: A batched, atomic SQL wrapper function that performs multiple insert operations inside a transaction.
  • insert_tx: Inserts a transaction into tbl_tx.
  • insert_inp: Inserts an input into tbl_inp.
  • insert_out: Inserts an output into tbl_out.
  • insert_xpub: Inserts an xpub into tbl_xpub.
  • insert_address: Inserts a new derived address into tbl_address.
  • get_pending_txs: Queries tbl_tx for transactions with status=0 and valid locktime conditions.
  • update_tx_status: Updates status to 1 (sent) or 2 (failed) after a broadcast attempt.
  • get_stats: Aggregates statistics for the tbl_stats table.
  • get_address_by_ip: A query that joins tbl_address with tbl_xpub to find addresses by IP for rate limiting or reuse logic.

Design Notes

SQL queries are built using format! in many places. The execute_insert function attempts to batch inserts to reduce transaction overhead, but this is dependent on the SQLite version.


xpub.rs (Extended Public Key Utilities)

Location: src/xpub.rs

This module handles the derivation of Bitcoin addresses from extended public keys (xpub/zpub) and the creation of P2WPKH descriptors.

Key Functions

  • parse_xpub: Parses a Base58-encoded xpub/zpub string into a bitcoin::bip32::Xpub.
  • derive_address: Derives a P2WPKH (Bech32) address at a given address index from the xpub. Uses the BIP-84 path (m/84'/coin_type'/account'/0/index). Uses Secp256k1 from the secp256k1 crate for elliptic curve math.
  • get_descriptor: Generates a Bitcoin descriptor string for the xpub (e.g., wpkh(.../0/*)), which is useful for wallet integration.
  • checksum_verify: Verifies the Base58 checksum of an xpub/zpub string to prevent data corruption during entry.

Dependencies

  • bitcoin::bip32::Xpub
  • secp256k1::Secp256k1
  • bs58 for Base58 decoding
  • bitcoin::Address::p2wpkh for address creation

bal-server.rs (HTTP Server / API)

Location: src/bin/bal-server.rs

The main application binary that provides an async HTTP server.

Architecture

  • Runtime: tokio::main with rt-multi-thread.
  • HTTP Framework: hyper (low-level) + hyper-util + http-body-util. Each connection is spawned as a new tokio::task.
  • Routing: Routes are matched using path regex and a simple match on the HTTP method. The router is implemented manually in main.

Key Routes (implemented in source code)

  • GET /, GET /version: Returns static strings (name and version).
  • GET /.pub_key.pem: Returns the Ed25519 public key PEM file for signature verification.
  • GET /:network/info: Returns JSON with fee, address, and chain info. Networks: bitcoin, testnet, testnet4, signet, regtest.
  • GET /:network/stats: Returns per-chain statistics if expose_stats is enabled.
  • POST /:network/pushtxs: Accepts one or more raw hex transactions. It validates them, checks the fee output to the our_address for that network, and stores the transaction in the database. See src/bin/bal-server.rs for the pushtxs request body parsing logic.
  • POST /searchtx: Accepts a txid in the request body and returns the transaction details, status, and fee breakdown.

Configuration

  • The server reads environment variables and/or a config file (confy). Default config is hardcoded for regtest development.
  • db_file: The path to the SQLite database (e.g., bal.db).
  • bind_address: The address to listen on (e.g., 127.0.0.1:3031).
  • expose_stats: A boolean flag to enable/disable the stats endpoint.

Error Handling

  • WARNING: This binary uses unwrap() and expect() on many critical paths (e.g., sqlite::open, Regex::new, req.collect()). A malformed request could crash the async task or even the entire runtime. This is a known vulnerability.

Static Public Key (/.pub_key.pem)

The server serves a static public_key.pem file. The corresponding private key (privkey.pem) is used by the pusher to sign statistics before sending them to the welist server. This file is located in the project root directory.


bal-pusher.rs (Async Transaction Pusher)

Location: src/bin/bal-pusher.rs

This is the async daemon that monitors the blockchain and pushes pending transactions.

Architecture

  • Runtime: tokio::main.
  • ZMQ: zmq::Context with a SUB socket that listens to tcp://127.0.0.1:28332 (or similar per-network port). The topic is hashblock (32-byte block hash).
  • RPC: It uses the bitcoincore-rpc client to call getblockchaininfo (to get the mediantime) and sendrawtransaction for each transaction.
  • HTTP Client: reqwest with the json feature. It sends a signed JSON POST to the welist server.

Key Logic

  1. On every hashblock message, it calls main_result().
  2. main_result creates a bitcoincore-rpc client. If it fails, it panics (panic!("impossible to get client {}", e)), crashing the entire process.
  3. It fetches getblockchaininfo to get the mediantime.
  4. It queries the database for transactions with status=0 and locktime < mediantime.
  5. For each pending transaction, it calls sendrawtransaction.
  6. If send_stats is enabled, it collects statistics, signs them with privkey.pem, and sends them to the configured welist URL via reqwest.
  7. It updates the database with the new status.

Configuration

  • zmq_endpoint: The ZMQ endpoint (e.g., tcp://127.0.0.1:28332).
  • rpc_url: The URL of the Bitcoin RPC (e.g., http://127.0.0.1:18443).
  • rpc_auth: user_pass or cookie_file. The cookie path is constructed from the HOME environment variable (e.g., ~/.bitcoin/.cookie).
  • send_stats: A boolean that enables the remote server reporting.
  • welist_url: The URL to POST to.
  • ssl_key_path: The path to the Ed25519 private key (privkey.pem) for signing stats.