Skip to content

slipstream: take txs from anyone, mine them without relaying - #83

Draft
rsantacroce wants to merge 1 commit into
mainfrom
feat/slipstream-service
Draft

rsantacroce wants to merge 1 commit into
mainfrom
feat/slipstream-service

Conversation

@rsantacroce

Copy link
Copy Markdown
Collaborator

What

This adds a new service, slipstream/, alongside payout/. Anyone can POST it a raw tx, and it gets that tx into the pool's blocks without relaying it. It is meant for BIP300/301 txs the network will not relay (deposits, withdrawal bundles, BMM requests), but it takes any consensus-valid tx.

Each tx goes straight to the enforcer's block template server, which is the same :8122 endpoint the proxy mines from. The enforcer has the node check the tx for consensus validity, applies its own BIP300 rules, and keeps it in its template mempool. The tx never enters the node's mempool.

Depends on:

Neither needs a change to the proxy.

How it behaves

  • Fee rule. A tx must pay the higher of the minimum submission rate (1 sat/vB, SLIPSTREAM_MIN_FEE_RATE) and the current mineable rate. This follows Slipstream's own rule.
    • The mineable rate is read from the template being mined: the floor while the template has room, and the fee rate of its cheapest tx once it is full.
    • A tx that passes the enforcer but pays too little is removed from the enforcer again before the refusal returns, so it cannot be mined for less than was asked.
  • Every message is saved. slipstream_submissions keeps every POST exactly as it arrived, including refusals and their reasons.
  • Tracking. Nothing is relayed, so "propagated" here means two things: did the tx reach a template, and did a block carry it.
    • Each accepted tx moves through pending, in_template, mined and confirmed.
    • It can also end as dropped (with a reason such as conflict_mined or parent_removed) or expired (after 144 blocks by default).
    • mined_by_pool is taken from blocks_found.
    • Every change is appended to slipstream_events.
  • Resubmission. The enforcer forgets txs when it restarts and when a block disconnects. This service remembers them and resubmits after an enforcer restart, a reorg, or an orphaned block.
  • info.json is served here, at GET /info.json.
    • Facts come from pool_meta: mode (the exact pool_mode), fee_bps, coinbase_tag and the addresses. They are never configured here.
    • Presentation fields come from env: POOL_NAME, POOL_CHAIN (e.g. betanet), POOL_LOGO, the public URLs and so on.
    • slipstream_url is included.

Storage

The service keeps its own slipstream.db. It never writes to shares.db, and reads it only for pool_meta and blocks_found.

Also in this PR

  • Docker: Dockerfile.slipstream, a slipstream compose service bound to loopback (publish it through nginx with SLIPSTREAM_TRUST_PROXY=1), and the image in the GHCR build matrix.
  • CI: the service's unit tests run in the node-tests job.
  • scripts/regtest/start.sh: a new REGTEST_ENFORCER_EXTRA_ARGS variable, empty by default, so every existing test starts the enforcer exactly as before.
  • Docs: slipstream/README.md, plus short entries in the README and tests/README.md.

Testing

  • cd slipstream && npm test: 24 unit tests against a fake enforcer and bitcoind. They cover every status transition, the fee rule, submission logging, info.json for every mode, and the HTTP routes, including CORS and the rate limit.

  • tests/test_slipstream_regtest.sh, against patched bitcoind and an enforcer built from #642. Passed locally:

    1. A tx the node refuses (a dust output; testmempoolaccept says no) is accepted, and never enters the node's mempool.
    2. It reaches the enforcer's template, and the service reports it as in_template.
    3. generateblock mines exactly that template. The service follows the tx to mined in that block, then confirmed. Its history reads accepted, in_template, mined, confirmed.
    4. A tx at about 0.14 sat/vB is refused as fee-rate-too-low and is no longer in the enforcer's template.
    5. Both submissions are in the log, the refusal included.
    6. info.json and /api/fees answer.

    This script needs SLIPSTREAM_ENFORCER_BIN until an enforcer release ships --enable-slipstream, so it is not in CI yet.

Not in this PR

  • The dashboard /slipstream page and the admin withdraw button. That is PR 4.
  • A CHANGELOG entry. It is written at release time.

A new service, slipstream/, alongside payout/. It takes a raw tx over
HTTP and hands it straight to the enforcer's block template server --
the one the proxy mines from -- which keeps it in its template mempool
and never relays it (LayerTwo-Labs/bip300301_enforcer#642). That is how
the pool mines BIP300/301 txs the network will not carry, or any other
consensus-valid tx.

The fee rule is Slipstream's: the higher of a floor (1 sat/vB) and the
current mineable rate, read off the template being mined. A tx that
pays less is taken back out of the enforcer before the refusal returns.

Every submission is kept, refused ones included, and each accepted tx is
followed from template to block: pending, in_template, mined, confirmed,
or dropped/expired with a reason. The enforcer forgets a tx on restart
or reorg; this side remembers, so it resubmits.

It keeps its own slipstream.db and only reads shares.db, for pool_meta
and blocks_found. info.json is served here: facts from pool_meta, with
mode the exact pool_mode, presentation from env.

tests/test_slipstream_regtest.sh runs it against a real enforcer built
with --enable-slipstream. It is not in CI until an enforcer release
ships the flag; the unit tests are.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant