sweep: only remove the other input from the exclusive group

We now make sure when removing inputs identified by the exclusive group
ID, we only remove the other one, not the one that invoked the removal.
This commit is contained in:
yyforyongyu
2025-07-31 07:58:24 +08:00
committed by Oliver Gugger
parent 28af39cd03
commit 3796c99bd0

View File

@@ -740,15 +740,23 @@ func (s *UtxoSweeper) collector() {
} }
} }
// removeExclusiveGroup removes all inputs in the given exclusive group. This // removeExclusiveGroup removes all inputs in the given exclusive group except
// function is called when one of the exclusive group inputs has been spent. The // the input specified by the outpoint. This function is called when one of the
// other inputs won't ever be spendable and can be removed. This also prevents // exclusive group inputs has been spent or updated. The other inputs won't ever
// them from being part of future sweep transactions that would fail. In // be spendable and can be removed. This also prevents them from being part of
// addition sweep transactions of those inputs will be removed from the wallet. // future sweep transactions that would fail. In addition sweep transactions of
func (s *UtxoSweeper) removeExclusiveGroup(group uint64) { // those inputs will be removed from the wallet.
func (s *UtxoSweeper) removeExclusiveGroup(group uint64, op wire.OutPoint) {
for outpoint, input := range s.inputs { for outpoint, input := range s.inputs {
outpoint := outpoint outpoint := outpoint
// Skip the input that caused the exclusive group to be removed.
if outpoint == op {
log.Debugf("Skipped removing exclusive input %v", input)
continue
}
// Skip inputs that aren't exclusive. // Skip inputs that aren't exclusive.
if input.params.ExclusiveGroup == nil { if input.params.ExclusiveGroup == nil {
continue continue
@@ -767,6 +775,8 @@ func (s *UtxoSweeper) removeExclusiveGroup(group uint64) {
continue continue
} }
log.Debugf("Removing exclusive group for input %v", input)
// Signal result channels. // Signal result channels.
s.signalResult(input, Result{ s.signalResult(input, Result{
Err: ErrExclusiveGroupSpend, Err: ErrExclusiveGroupSpend,
@@ -1367,22 +1377,19 @@ func (s *UtxoSweeper) decideRBFInfo(
func (s *UtxoSweeper) handleExistingInput(input *sweepInputMessage, func (s *UtxoSweeper) handleExistingInput(input *sweepInputMessage,
oldInput *SweeperInput) { oldInput *SweeperInput) {
// Before updating the input details, check if an exclusive group was // Before updating the input details, check if a previous exclusive
// set. In case the same input is registered again without an exclusive // group was set. In case the same input is registered again, the
// group set, the previous input and its sweep parameters are outdated // previous input and its sweep parameters are outdated hence need to be
// hence need to be replaced. This scenario currently only happens for // replaced. This scenario currently only happens for anchor outputs.
// anchor outputs. When a channel is force closed, in the worst case 3 // When a channel is force closed, in the worst case 3 different sweeps
// different sweeps with the same exclusive group are registered with // with the same exclusive group are registered with the sweeper to bump
// the sweeper to bump the closing transaction (cpfp) when its time // the closing transaction (cpfp) when its time critical. Receiving an
// critical. Receiving an input which was already registered with the // input which was already registered with the sweeper means none of the
// sweeper but now without an exclusive group means non of the previous // previous inputs were used as CPFP, so we need to make sure we update
// inputs were used as CPFP, so we need to make sure we update the // the sweep parameters but also remove all inputs with the same
// sweep parameters but also remove all inputs with the same exclusive // exclusive group because they are outdated too.
// group because the are outdated too.
var prevExclGroup *uint64 var prevExclGroup *uint64
if oldInput.params.ExclusiveGroup != nil && if oldInput.params.ExclusiveGroup != nil {
input.params.ExclusiveGroup == nil {
prevExclGroup = new(uint64) prevExclGroup = new(uint64)
*prevExclGroup = *oldInput.params.ExclusiveGroup *prevExclGroup = *oldInput.params.ExclusiveGroup
} }
@@ -1401,7 +1408,7 @@ func (s *UtxoSweeper) handleExistingInput(input *sweepInputMessage,
oldInput.listeners = append(oldInput.listeners, input.resultChan) oldInput.listeners = append(oldInput.listeners, input.resultChan)
if prevExclGroup != nil { if prevExclGroup != nil {
s.removeExclusiveGroup(*prevExclGroup) s.removeExclusiveGroup(*prevExclGroup, input.input.OutPoint())
} }
} }
@@ -1493,7 +1500,9 @@ func (s *UtxoSweeper) markInputsSwept(tx *wire.MsgTx, isOurTx bool) {
// Remove all other inputs in this exclusive group. // Remove all other inputs in this exclusive group.
if input.params.ExclusiveGroup != nil { if input.params.ExclusiveGroup != nil {
s.removeExclusiveGroup(*input.params.ExclusiveGroup) s.removeExclusiveGroup(
*input.params.ExclusiveGroup, outpoint,
)
} }
} }
} }
@@ -1908,7 +1917,9 @@ func (s *UtxoSweeper) markInputSwept(inp *SweeperInput, tx *wire.MsgTx) {
// Remove all other inputs in this exclusive group. // Remove all other inputs in this exclusive group.
if inp.params.ExclusiveGroup != nil { if inp.params.ExclusiveGroup != nil {
s.removeExclusiveGroup(*inp.params.ExclusiveGroup) s.removeExclusiveGroup(
*inp.params.ExclusiveGroup, inp.OutPoint(),
)
} }
} }