Skip to content

splice: coin control for funds in (outpoints, lncli --utxo) - #8

Merged
paulscode merged 2 commits into
paulscode:blake2bfrom
Kilombino:splice-utxo
Oct 22, 2026
Merged

paulscode merged 2 commits into
paulscode:blake2bfrom
Kilombino:splice-utxo

Conversation

@Kilombino

Copy link
Copy Markdown

Coin control for adding funds with a splice. EstimateSplice and SpliceChannel take outpoints (lncli splice in|estimate --utxo, repeatable): a splice in then spends only those wallet coins, the amount from them, or with use_max all of them. Without it nothing changes.

The coins left out still count towards the reserve kept for fee-bumping anchor closes (OnlyCoins lowers the reserve passed to SelectAddFunds by their value). Otherwise --max over the chosen coins would always hold the whole reserve back as change from them, though the rest of the wallet already covers it.

A coin the splice can't spend (not in the default account, unconfirmed, leased, spent) or one given twice is refused with the new refusal code unknown_coin; outpoints with a splice out is InvalidArgument.

Kilowallet wants this for its channel RESIZE, to match the coin control it has on every other on-chain spend.

Tests

TestOnlyCoins (lnwallet/splice): candidates narrowed, an amount taken from the chosen coin even when the wallet would pick a larger one first, --max spending all the chosen coin with no change while the rest covers the reserve, the reserve reduced only by what the coins left out hold, unknown and duplicated coins refused. go test ./lnwallet/splice/ passes.

Regtest, two nodes built from this branch, Knots BLAKE2b regtest backend (blake2b@150), protocol.splice=true:

  • A holds coins of 599,671, 300,000 and 200,000 sats and a 400,000 sat channel with B.
  • splice estimate in --amt 100000: fee 478 without --utxo, 499 with --utxo <200k>, so a different coin.
  • --utxo of an unknown outpoint: refusal_code: unknown_coin. splice estimate out --utxo …: outpoints are for adding funds only.
  • splice in --amt 100000 --utxo <200k>: the splice transaction's inputs are the funding output and that coin only; it locked, capacity 500,000.
  • splice in --max --utxo <300k> --utxo <97,503 change>: both spent, no change output, the 599,671 coin untouched (it covers the 10,000 anchor reserve); locked, capacity 894,631.

EstimateSplice and SpliceChannel take the wallet coins a splice in may
spend: the amount comes only from them, or with use_max all of them go in.
The coins left out count towards the reserve kept for fee-bumping anchor
closes, so the chosen ones needn't keep it back. A coin the splice can't
spend is refused with unknown_coin; outpoints with a splice out are an
invalid argument.
@paulscode

Copy link
Copy Markdown
Owner

Thanks, this is careful work: the reserve handling (coins left out still counting, and only coins the splice could actually spend counting) checks out, and so does RBF keeping the chosen inputs.

The Fork checks failure is go vet on the root package: the call to spliceRequest in rpcserver_splice_test.go (line 58, reported at 61) still lacks the new outpoints argument. Adding nil as the last argument fixes it; with that, vet and the fork.yml unit list pass here.

Two smaller things, optional:

  1. With --max, SelectAddFunds still cuts the candidates to interactivetx.MaxInputsOrOutputs - 1 (251), so choosing more coins than that spends the first 251 and quietly leaves the rest. Refusing more than 251 outpoints in OnlyCoins would make "all of them" hold.
  2. A splice can only spend P2WKH and P2TR coins, and never coinbase outputs, so choosing one of those gets unknown_coin. Miners paying to their LND wallet will hit the coinbase case; mentioning both in the ErrUnknownCoin text and the proto comment would save them a puzzle.

…y what a splice can spend

- rpcserver_splice_test.go: spliceRequest takes the outpoints too (go vet).
- OnlyCoins refuses more outpoints than a splice takes (MaxInputsOrOutputs-1,
  251): with --max, SelectAddFunds cut the candidates there and quietly left
  the rest out.
- ErrUnknownCoin and the proto comments say that a splice spends only
  confirmed P2WKH and P2TR coins of the default account, never coinbase
  outputs: miners paying to their LND wallet would otherwise meet
  unknown_coin with no clue why.
@Kilombino

Copy link
Copy Markdown
Author

Thanks Paul. Pushed 03ec9e3: the test call now passes the outpoints (vet clean), OnlyCoins refuses more than 251 outpoints instead of quietly spending the first 251, and ErrUnknownCoin plus the proto comments now say a splice only spends confirmed P2WKH/P2TR coins, never coinbase outputs.

@paulscode
paulscode merged commit 0860846 into paulscode:blake2b Oct 22, 2026
2 checks passed
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.

2 participants