Skip to content

Provide a node-side transaction validation utility (dedup pool-context/validate_tx across server protocols) #1075

Description

@dsbaars

Summary

libbitcoin-server duplicates standalone transaction validation and pool context logic across its bitcoind RPC and electrum protocols. Both implement identical get_pool_context, validate_tx, and broadcast_tx helpers. This logic belongs in a shared node side utility, alongside the transaction chaser that will own unconfirmed transaction handling. This issue requests exposing that utility from libbitcoin-node so server protocols can call through instead of reimplementing it, and tracks the node dependency for full transaction submission.

Background

The node already scaffolds a transaction chaser (include/bitcoin/node/chasers/chaser_transaction.hpp, described as "Chase down unconfirmed transactions"), but its methods are stubs. In src/chasers/chaser_transaction.cpp the key methods carry TODOs, including "validate and store transaction" in do_store and "Push new checked tx into store and update DAG. Issue transaction event" in store. Until the chaser owns transaction validation and the unconfirmed pool, server protocols each reimplement the validation pipeline against confirmed chain state.

Current duplication in libbitcoin-server

The same logic exists twice, each with a "move this to node utility and pass through" TODO: in src/protocols/bitcoind/protocol_bitcoind_rpc.cpp and in src/protocols/electrum/protocol_electrum_transactions.cpp (get_pool_context, validate_tx, broadcast_tx).

get_pool_context derives a chain::context from the confirmed tip:

top = query.get_top_confirmed();
state = query.get_chain_state(settings, query.get_header_key(to_confirmed(top)));
pool = chain::chain_state(*state, settings).context();

validate_tx validates a standalone transaction against that context:

tx.check();
tx.check(ctx);
query.populate_with_metadata(tx, true);
tx.accept(ctx);
tx.confirm(ctx);
tx.connect(ctx);
tx.check_guard();        // block consensus guards (DoS guard for a
tx.check_guard(ctx);     // transaction validated outside of a block)
tx.accept_guard(ctx);

Separately, transaction submission cannot archive or broadcast in v4. The server's sendrawtransaction validates and broadcasts only, with a comment that archiving must move through the transaction chaser in v5. Full submission (archive so the tx out relay can serve getdata) therefore also depends on the chaser.

Requested change

Provide, from libbitcoin-node, a single entry point that server protocols can call to:

  1. Obtain the current pool (mempool) context.
  2. Validate a standalone transaction against that context (the pipeline above), returning a code.
  3. Submit a validated transaction: broadcast it and, in v5, archive it via the transaction chaser so the tx out relay can serve getdata.

This gives a single owner for standalone transaction validation and lets both server protocols drop their duplicate helpers.

Downstream follow up (libbitcoin-server)

Once available, replace get_pool_context, validate_tx, and broadcast_tx in protocol_bitcoind_rpc and protocol_electrum with calls to the node utility, removing both "move this to node utility" TODOs. Re-enable archive on submit in sendrawtransaction via the chaser, removing the commented v4 block and its "contextual validation (populate_with_metadata + connect) for policy" TODO.

Scope decision needed

Whether this issue covers only the shared standalone validation and pool context utility (which enables the server dedup immediately), or also the full chaser_transaction implementation (unconfirmed pool, mempool message support). The dedup utility can land first and reuse the existing confirmed chain state; full archive and relay on submit depend on the chaser being implemented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions