- Add WELIST_PING_SIG_VERSION (1 legacy, 2 canonical JSON); default 1
- Sign WELIST-PING-V2\n + compact sorted JSON covering url, chain, height,
median_time, last_block_hash, info, base_fee, version and sig_version
- Fetch info/base_fee/version from the local /{chain}/info endpoint and sign them
- Fall back to null metadata on fetch failure; skip the fetch for onion URLs
- Normalize the advertised URL and bound metadata to match the WeTime service
- Activate v2 in bal-pusher.sh and document the TXT record setup
- Add unit tests for canonical payloads, URL normalization, metadata and onion detection
Includes previously uncommitted local deployment hardening:
- pg-server.sh configurable loopback bind address, volume and recreate handling
- .env loading in bal-server.sh and bal-pusher.sh
- second bal-server/bal-pusher development scripts
3.8 KiB
3.8 KiB
Architecture and Data Flow
Quick Reference
- What this file contains: high-level architecture, data flow, state machine, and error handling strategy.
- See also: 01_project_overview.md, 04_modules_detail.md, 05_api_reference.md, 06_database_schema.md
High-Level Architecture
User
|
| HTTP POST (raw hex transactions)
v
+-----------------+
| bal-server | (actix-web 4.9.0 + actix-governor, async)
| (src/bin/bal-server.rs) |
+-----------------+
| SQLite insert (db.rs, Arc<Mutex<Connection>>)
v
bal.db (WAL mode)
| (transactions with status=0, waiting locktime)
|
| ZMQ (hashblock)
v
+-----------------+
| bal-pusher | (tokio, ZMQ + RPC + reqwest)
| (src/bin/bal-pusher.rs)
+-----------------+
| bitcoincore-rpc
| sendrawtransaction
v
Bitcoin Network
Data Flow (Transaction Lifecycle)
- Submission: A client sends one or more raw hex transactions to the
pushtxsendpoint (newline-separated). - Validation: The
bal-serverparses each transaction usingbitcoin::Transactionviaconsensus::deserialize. It checks for the fee output, extracts inputs/outputs, and validates the locktime. - Storage: Valid transactions are stored in
tbl_txwithstatus = 0(waiting). The inputs and outputs are stored intbl_inpandtbl_out. Batch inserts useUNION ALL SELECTfor efficiency. - Monitoring: The
bal-pusherlistens to the ZMQhashblocktopic with a 5-second receive timeout. When a new block is detected, it fetches blockchain info via RPC. - Evaluation: The pusher queries the database for transactions with
status=0and compares their locktime against the blockchain's best block height or median time (for timestamp-based locktimes aboveLOCKTIME_THRESHOLD). - Broadcast: If the locktime is satisfied, the pusher sends the transaction via
sendrawtransactionand updates the status to1(sent) or2(failed with error stored inpush_err). - Statistics: The pusher periodically calculates statistics and sends them to a remote
welistserver using an Ed25519-signed POST request. The signature scheme is selected byWELIST_PING_SIG_VERSION: legacy v1, or v2 over a canonical JSON payload whoseinfo,base_feeandversioncome from the local/{chain}/infoendpoint. The server also exposes stats via theGET /:network/statsendpoint ifexpose_statsis enabled.
State Machine
[Submitted] -> status=0 (waiting)
|
| locktime satisfied
v
[Push attempt] -> status=1 (sent) or status=2 (failed)
The status field in tbl_tx is an integer:
0: Waiting for locktime.1: Successfully sent to the network.2: Failed (e.g., RPC error-25 bad-txns-inputs-missingorspent). Error details stored inpush_err.
Error Handling Strategy
The codebase has been hardened with comprehensive error handling:
bal-server: Usesactix-web's built-in error handling. Allunwrap()/expect()calls have been replaced with safematch/if leterror propagation, returning appropriate HTTP status codes (400, 404, 500).bal-pusher: ZMQrecvusesset_rcvtimeo(5000)with a match/timeout handler. RPC connection failures log errors and retry with a sleep interval instead of panicking. The pusher logs warnings for consecutive ZMQ timeouts (~1 hour threshold).db.rs: Database operations useResulttypes. Theopen_dbfunction validates paths before opening. WAL mode is set with retry logic.
Logging and Monitoring
The project uses env_logger and log. By default, RUST_LOG=info is set. The bal-pusher sends signed statistics to a remote server. The server exposes a stats endpoint (/<network>/stats) if expose_stats is enabled. The actix-web Logger::default() middleware logs all HTTP requests/responses.