Skip to content

Seamless BTC + Liquid regtest harness, Boltz chain-swap coverage#51

Closed
tobomobo wants to merge 2 commits into
mainfrom
claude/seamless-regtest-boltz
Closed

Seamless BTC + Liquid regtest harness, Boltz chain-swap coverage#51
tobomobo wants to merge 2 commits into
mainfrom
claude/seamless-regtest-boltz

Conversation

@tobomobo
Copy link
Copy Markdown
Contributor

Summary

Layers a senior-dev-grade live-sync test bed over the initial Bitcoin regtest work in #50. Includes everything from PR #50 plus the additions described below — opening this as a separate PR so PR #50 stays untouched while this one supersedes it. Close whichever you don't want.

The base branch already contains @tobomobo's commit Add local live sync testing harness; this PR adds one commit on top.

What's new vs. PR #50

Three-layer testing model (docs/reference/testing.md)

  • Layer 1 — fixtures (every PR): the existing seed-fake-wallets.sh demo plus a new seed-boltz-swaps.sh Boltz round-trip. No infra.
  • Layer 2 — live regtest (daily + manual): session-scoped Bitcoin Core and Liquid (Elements + electrs-liquid) stacks. Both ad-hoc docker run, no docker-compose / Nigiri wrapper.
  • Layer 3 — manual compat: documented but explicitly off-gate; public Electrum/Esplora servers leak watched scripts so signet/mutinynet stay opt-in only.

Session-scoped harness (tests/live_sync/)

  • One bitcoind and one elementsd + electrs-liquid stack per test module instead of per test method. Each test still gets a fresh Kassiber --data-root.
  • RPC creds randomized per session (no static kassiber:kassiber).
  • rpcallowip scoped to 172.16.0.0/12 (Docker bridge), not 0.0.0.0/0.
  • All host port binds are 127.0.0.1::<container-port>.
  • On any test failure, recent docker logs from every container in the stack are dumped to stderr along with the test id.

Liquid regtest, seamless

  • tests/test_live_sync_liquid.py brings up ghcr.io/vulpemventures/elements + ghcr.io/vulpemventures/electrs-liquid (env-overridable) on a dedicated Docker bridge.
  • Mints a real ct(slip77(...), elwpkh(...)) descriptor wallet via elementsd's createwallet + listdescriptors. Handles both unified <0;1> and legacy split forms, splitting the unified one with fresh getdescriptorinfo checksums.
  • Resolves the elementsregtest policy asset id at runtime via dumpassetlabels, so LBTC labeling does not depend on a hardcoded genesis (Kassiber's hardcoded id assumes one specific config; ours uses different consensus params).
  • The user-parameterized Liquid path from PR Add local live sync harness: Bitcoin, Liquid, and Boltz chain-swaps #50 is removed in favor of this seamless one.

Boltz BTC ↔ LBTC chain-swap coverage

  • New chain-swap value in TRANSFER_PAIR_KINDS distinct from federation pegs (peg-in / peg-out) and Lightning submarine swaps.
  • Forward (BTC → LBTC) and reverse (LBTC → BTC) Boltz swap fixtures with the service-fee spread baked into the amounts; both legs paired via --kind chain-swap --policy taxable.
  • tests/test_boltz_swap_fixture.py asserts reports.summary and journals.transfers.list shape end-to-end through the CLI (no engine-level shortcuts).

CI topology

  • .github/workflows/live-sync.yml becomes daily at 05:00 UTC + manual dispatch with a suite selector (bitcoin / liquid / all).
  • Two parallel jobs so Bitcoin and Liquid failures stay independent.
  • Concurrency group prevents pile-ups.

Bitcoin path hardening

  • Same session-scoped harness, randomized creds, narrowed rpcallowip.
  • Idempotency assertion folded into the address-wallet test instead of being a separate setUp per test.

Docs + TODO

  • AGENTS.md, README.md, docs/reference/tax.md, and the kassiber skill bundle now mention chain-swap alongside the existing swap kinds.
  • TODO.md checks off the items this PR completes and adds tracked follow-ups: live-layer reorg, gap-limit, zero-conf, descriptor-type matrix, digest-pinned images, and a future real Boltz-backend integration (deferred — fixture-level coverage is sufficient until proven otherwise).

Validation

  • ./scripts/quality-gate.sh — full pass (compile, sync backends, liquid electrum sync, fake wallet, Boltz swap fixture, CLI smoke, review regressions, live-sync import-only check, CLI help smoke).
  • uv run python -m unittest tests.test_boltz_swap_fixture -v — passes (~2s) end-to-end through the CLI.
  • Live-sync layer not exercised in this Codex session (no Docker daemon visible). The daily live-sync workflow will iron out any first-run bugs in the elementsd / electrs-liquid CLI args; both daemons accept overrides via KASSIBER_ELEMENTSD_EXTRA_ARGS / KASSIBER_ELECTRS_LIQUID_EXTRA_ARGS.

Test plan

  • CI green on the existing fast lane (ci workflow)
  • Trigger live-sync workflow manually with suite=bitcoin and confirm green
  • Trigger live-sync workflow manually with suite=liquid and confirm green (this is the first run of the new Liquid harness; expect to iron out Vulpem image specifics here)
  • After both green, let the daily cron run for a week before considering the weekly cadence

Notes for review

  • Image pinning is by tag, not digest. Listed in TODO.md as the next hardening pass — easy follow-up once the workflow has run once and we have known-good digests.
  • The Liquid live test deliberately avoids snapshotting numeric output beyond "amount = 1.5 LBTC, direction = inbound" because Elements regtest fee math drifts between versions; structural assertions catch what matters without coupling to a specific build.

🤖 Generated with Claude Code

tobomobo and others added 2 commits April 23, 2026 22:49
… coverage

Layers a senior-dev-grade live-sync test bed over the initial Bitcoin
regtest work in PR #50:

* tests/live_sync/ — session-scoped harness package. Bitcoin and Liquid
  stacks each start once per test module (setUpModule / tearDownModule);
  every test method gets a fresh Kassiber --data-root but reuses the
  chain. RPC creds are randomized per session, container ports bind to
  127.0.0.1 only, and rpcallowip is scoped to the Docker bridge range
  (172.16.0.0/12) instead of 0.0.0.0/0.
* tests/test_live_sync_bitcoin.py — refactored Bitcoin test on top of
  the new harness, with idempotency assertion folded in and docker logs
  auto-captured to stderr on failure.
* tests/test_live_sync_liquid.py — new live Liquid test driving
  elementsd + electrs-liquid (Vulpem images by default, env-overridable)
  with a real ct(slip77(...), elwpkh(...)) descriptor wallet exported
  from elementsd. Handles both unified <0;1> and legacy split
  descriptors, and fetches the elementsregtest policy asset id at
  runtime so LBTC labeling does not depend on a hardcoded genesis.
* tests/test_live_sync_regtest.py removed — superseded by the two split
  files above; the user-parameterized Liquid backend path goes away
  because the regtest harness is now seamless.
* kassiber/cli/handlers.py — TRANSFER_PAIR_KINDS gains 'chain-swap'
  for Boltz-style BTC <-> LBTC atomic swaps (distinct from Liquid
  federation pegs and from Lightning submarine swaps).
* tests/fixtures/fake_wallets/boltz_*.csv + scripts/seed-boltz-swaps.sh
  + tests/test_boltz_swap_fixture.py — deterministic fixture covering a
  full Boltz chain-swap round trip (forward BTC -> LBTC and reverse
  LBTC -> BTC) with the Boltz service-fee spread baked in, paired with
  --kind chain-swap --policy taxable, plus end-to-end CLI-level
  assertions on the resulting reports.summary and
  journals.transfers.list envelopes.
* .github/workflows/live-sync.yml — daily cron (05:00 UTC) plus manual
  dispatch with a suite selector (bitcoin / liquid / all). Two parallel
  jobs so Bitcoin and Liquid failures stay independent. Concurrency
  group prevents pile-ups.
* scripts/live-sync-tests.sh — gains --suite {bitcoin,liquid,all} and
  --require-liquid-regtest; runs the new split test modules.
* scripts/quality-gate.sh — adds tests.test_boltz_swap_fixture and
  swaps the disabled-import check to the new module names.
* docs/reference/testing.md — three-layer model (fixtures / live
  regtest / manual compat), Boltz section, privacy posture.
* AGENTS.md, README.md, docs/reference/tax.md, skills/kassiber/* —
  cross-link testing.md and add chain-swap alongside the existing
  swap kinds wherever they are listed.
* TODO.md — checks off completed items, adds tracked follow-ups for
  reorg/gap-limit/zero-conf live tests, descriptor-type matrix,
  digest-pinned images, and a future real Boltz backend integration.

Verified locally with ./scripts/quality-gate.sh (full pass) and
KASSIBER_LIVE_SYNC_TESTS=0 import-only checks for both new live modules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@tobomobo
Copy link
Copy Markdown
Contributor Author

Superseded — folded the new commit into #50 instead. Closing this in favor of the single PR.

@tobomobo tobomobo closed this Apr 24, 2026
@tobomobo tobomobo deleted the claude/seamless-regtest-boltz branch April 24, 2026 07:04
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