Skip to content

Complete BIP300/301 enforcer integration with mempool A/R pubsequence events #74

Description

@gosunuts

Problem

The checked-in BIP300/301 Compose integration currently runs the upstream enforcer in block-only mode. bitcoin-rs publishes Core-compatible pubsequence block connect/disconnect events (C/D), but deliberately omits mempool add/remove events (A/R). As a result, Compose cannot safely enable the enforcer's mempool mode.

The missing work is not just adding two ZMQ labels. Mempool mutations currently occur through multiple direct RwLock<Mempool> call sites, while the pool exposes only a coarse mutation counter and removal paths do not retain a complete, ordered event record with explicit causes. Publishing from selected callers would permit missing, duplicated, or reordered events.

Current state

  • crates/node/src/zmq_publisher.rs implements the sequence topic and topic-local u32 transport counter for block C/D events.
  • crates/mempool/src/pool.rs maintains a u64 change counter that increments on successful insert/remove operations.
  • RPC, wallet, mining, node apply, and other paths can acquire the shared mempool write lock directly.
  • Block connection removes confirmed transactions and descendants from the mempool in crates/node/src/apply.rs.
  • tools/bip300301-enforcer/docker-compose.yaml deliberately omits --enable-mempool.
  • docs/rest-interface.md and CONCEPTS.md document this limitation.

Goal

Provide a single ordered mempool-mutation boundary that can emit Bitcoin Core-compatible pubsequence A/R events without gaps or ordering ambiguity, then enable and validate the upstream enforcer's mempool mode.

Proposed work

1. Freeze compatibility semantics

Before implementation, ground the exact Bitcoin Core and pinned upstream enforcer wire contract:

  • payload layout for A and R
  • relationship between the ZMQ topic sequence and mempool sequence
  • byte order and counter widths
  • ordering for parent/descendant removals
  • behavior for transactions confirmed in a block
  • behavior for conflicts, replacement, expiry, size/fee eviction, explicit removal, clear, reorg, and re-admission
  • expected recovery behavior after subscriber or publisher event loss

Record the chosen semantics in tests and project documentation.

2. Introduce a unified mutation result/event model

Represent each successful mutation as an ordered set of transaction-level changes, for example:

  • accepted transaction: txid plus assigned mempool sequence
  • removed transaction: txid, assigned mempool sequence, and an explicit internal removal reason

Removal reasons should distinguish at least:

  • block inclusion
  • conflict or replacement
  • descendant removal
  • fee/size policy eviction
  • explicit removal or wholesale reset
  • reorg-related removal/re-admission where applicable

The internal reason model may be richer than the ZMQ wire format, but it must be available to other validated-chain consumers and tests.

3. Centralize mempool mutation

Route every production insert/remove/clear path through one mutation gateway rather than publishing opportunistically from individual callers.

Audit at least:

  • transaction RPC admission
  • P2P transaction admission
  • wallet-originated admission
  • mining/policy eviction
  • block-connect eviction
  • reorg reconsideration
  • shutdown/reload/clear behavior

State mutation and event ordering must be serialized. ZMQ remains best-effort and must not roll back a valid mempool mutation, but later publishers must not overtake earlier mutations.

4. Extend pubsequence

Extend SequenceEvent and all publisher implementations with Core-compatible transaction A/R payloads.

Preserve:

  • existing block C/D behavior
  • one monotonically ordered topic-local transport sequence
  • reorg ordering: tip-first disconnects before replacement-branch connects
  • no external I/O while holding consensus-critical or mempool locks longer than necessary
  • no consensus/apply failure caused by notification failure

5. Enable the enforcer mempool mode

After compatibility and end-to-end tests pass:

  • add --enable-mempool to the checked-in enforcer Compose command
  • validate startup and synchronization against the pinned ENFORCER_REVISION
  • update docs/rest-interface.md, README.md, overlapping docs/solutions/ knowledge, and CONCEPTS.md

Acceptance criteria

  • The exact Core/enforcer A/R payload and sequencing contract is captured in compatibility tests.
  • Every successful production mempool insertion emits exactly one ordered A event.
  • Every transaction removed from the mempool emits exactly one ordered R event, including descendants.
  • Failed or no-op mutations emit no transaction event and consume no mempool event sequence.
  • Concurrent admission/removal cannot reorder publication relative to the committed mutation order.
  • Block connection emits the required R events without changing existing block C semantics.
  • Reorg tests cover disconnect, transaction reconsideration/re-admission, and replacement-branch connection.
  • Conflict/replacement, policy eviction, explicit removal, and clear/reset behavior are tested.
  • Topic sequence wraparound behavior is defined and tested.
  • ZMQ failure or a disconnected subscriber cannot fail consensus validation or corrupt mempool state.
  • The pinned upstream enforcer runs with --enable-mempool and follows an end-to-end transaction lifecycle.
  • Existing block-only consumers remain compatible.
  • Documentation and durable project terminology are reconciled.

Non-goals

  • Making the external enforcer a synchronous prerequisite for ordinary Bitcoin block application.
  • Calling enforcer gRPC while holding the chain-transition/apply lock.
  • Treating BIP300/301 rejection as native Bitcoin consensus failure.
  • Changing the default Bitcoin-only deployment path.
  • Implementing a fail-open/fail-closed external consensus policy in this issue.

Follow-up design: optional enforcer-backed block policy

If bitcoin-rs should later refuse a branch based on BIP300/301 validation, track that as a separate architecture issue. It requires a pre-apply candidate-block API, deterministic connect/disconnect state transitions, crash/restart reconciliation, timeout and fail-open/fail-closed policy, explicit header-status semantics, and IBD performance analysis. The current post-apply RPC/REST/ZMQ sidecar topology is not sufficient for an atomic consensus gate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    wayfinder:taskPrerequisite task for a decision

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions