Skip to content

Fix/unilateral exit preconfirmed tree sig#150

Closed
d4rp4t wants to merge 16 commits into
arkade-os:masterfrom
d4rp4t:fix/unilateral-exit-preconfirmed-tree-sig
Closed

Fix/unilateral exit preconfirmed tree sig#150
d4rp4t wants to merge 16 commits into
arkade-os:masterfrom
d4rp4t:fix/unilateral-exit-preconfirmed-tree-sig

Conversation

@d4rp4t

@d4rp4t d4rp4t commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Stacks on top of #117

Problem

Starting a unilateral exit for a VTXO whose tree-tx isn't MuSig2-co-signed yet
(PSBT_IN_TAP_KEY_SIG absent) failed the exit session immediately:

Tree tx input 0 is missing the MuSig2 taproot key-path signature
(PSBT_IN_TAP_KEY_SIG); arkd should have populated it during the batch round.

This happens for any VTXO that is still preconfirmed — arkd only co-signs the
tree during a batch round, so the signature is absent until the batch fires. The
SDK made it worse: VtxoChainAutoFetchService fetches the branch on the first
VtxosChanged event (while the VTXO is preconfirmed, so the tree-tx PSBT is
unsigned) and VirtualTxService.FetchAndStoreBranchAsync short-circuits on
HasBranchAsync, so the stale unsigned branch is never refreshed.

Fix (SDK)

Mirror go-sdk's ErrWaitingForConfirmation retry loop — wait for the tree to be
co-signed instead of failing:

  • VirtualTxService.FetchAndStoreBranchAsync gains a forceRefresh flag that
    bypasses the HasBranchAsync short-circuit, so a stale (unsigned) branch can
    be re-pulled from the indexer.
  • UnilateralExitService.ParseVirtualTx now throws a typed, transient
    TreeTxNotSignedException for the missing-signature case.
  • UnilateralExitService.ProgressBroadcastingAsync catches it, force-refreshes
    the branch, and leaves the session in Broadcasting to retry on the next
    ProgressExitsAsync — instead of moving it to Failed.

No behaviour change for already-committed VTXOs.

Tests

Moves the two exit tests blocked by this gap out of #117 (chore/e2e-coverage)
to this branch, and un-ignores the preconfirmed one:

Mirror go-sdk's ErrWaitingForConfirmation retry loop — wait for the tree to be
co-signed instead of failing:

  • VirtualTxService.FetchAndStoreBranchAsync gains a forceRefresh flag that
    bypasses the HasBranchAsync short-circuit, so a stale (unsigned) branch can
    be re-pulled from the indexer.
  • UnilateralExitService.ParseVirtualTx now throws a typed, transient
    TreeTxNotSignedException for the missing-signature case.
  • UnilateralExitService.ProgressBroadcastingAsync catches it, force-refreshes
    the branch, and leaves the session in Broadcasting to retry on the next
    ProgressExitsAsync — instead of moving it to Failed.

No behaviour change for already-committed VTXOs.

Tests

Moves the two exit tests blocked by this gap out of #117 (chore/e2e-coverage)
to this branch, and un-ignores the preconfirmed one:

  • ProgressExits_WorksForOffchainFundedVtxo
  • ProgressExits_WorksForPreconfirmedVtxo (was [Ignore]d on the same blocker)

Verified against the local regtest: the exit no longer fails on the missing
signature — it correctly detects the unsigned tree, refreshes the branch, and
waits (Broadcasting, not Failed).

⚠️ Open item: an idle preconfirmed VTXO is not auto-committed by arkd — the
owner must settle it (join a batch) to get the tree co-signed. Both tests
therefore need a settlement step before/around the exit (reusing the
SettleAVtxoAsync machinery) to go fully green. Tracking that here before merge.

d4rp4t added 16 commits June 26, 2026 17:04
Subdust rejection one may fail when tx is recoverable
BroadcastPackageAsync now passes maxfeerate=0 and maxburnamount=21e6 to
submitpackage so Ark P2A anchor outputs (non-zero value, non-standard
SegWit v1 script) are not rejected by Bitcoin Core's default
maxburnamount=0 check.

The sequential fallback switches the parent broadcast from NBXplorer's
HTTP API (which does not expose maxburnamount) to a direct RPC call via
the same maxburnamount override.

Also fix two E2E test regressions:
- CollabExit_WithBoardingInput_IsRejected: used DockerHelper.Exec with
  the old -rpcwallet= pattern, which silently dropped the sendtoaddress
  call because connection flags were missing; replaced with BitcoinCli.
- SubdustVtxo_SpendOffchain_IsRejected: mine a block before the spend
  attempt and retry up to 10× so the VTXO_RECOVERABLE window clears
  before the dust-rejection assertion runs.
fix tests too
…scription API

Replace the removed SubscribeForScriptsAsync/UnsubscribeForScriptsAsync/
GetVtxoSubscriptionStreamAsync forwards with the new OpenSubscriptionStreamAsync
and UpdateSubscriptionScriptsAsync (latest arkd protobuf subscription model).
@d4rp4t d4rp4t force-pushed the fix/unilateral-exit-preconfirmed-tree-sig branch from 046a93f to 0fd9d01 Compare June 26, 2026 15:05
@d4rp4t d4rp4t closed this Jul 7, 2026
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