Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sweep: remove possible RBF when sweeping new inputs #8091

Merged
merged 11 commits into from
Oct 25, 2023
47 changes: 23 additions & 24 deletions sweep/sweeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1124,38 +1124,39 @@ func (s *UtxoSweeper) sweep(inputs inputSet, feeRate chainfee.SatPerKWeight,
return fmt.Errorf("notify publish tx: %v", err)
}

// Publish sweep tx.
// Reschedule the inputs that we just tried to sweep. This is done in
// case the following publish fails, we'd like to update the inputs'
// publish attempts and rescue them in the next sweep.
s.rescheduleInputs(tx.TxIn, currentHeight)

log.Debugf("Publishing sweep tx %v, num_inputs=%v, height=%v",
tx.TxHash(), len(tx.TxIn), currentHeight)

log.Tracef("Sweep tx at height=%v: %v", currentHeight,
newLogClosure(func() string {
return spew.Sdump(tx)
}),
)

// Publish the sweeping tx with customized label.
err = s.cfg.Wallet.PublishTransaction(
tx, labels.MakeLabel(labels.LabelTypeSweepTransaction, nil),
)

// In case of an unexpected error, don't try to recover.
if err != nil && err != lnwallet.ErrDoubleSpend {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this try to explicitly catch the double spend error any longer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the rationale that since we reschedule everything above, we don't need to specially handle this control flow?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly we want to make sure, that even unexpected errors increase their attempt counter allowing them to be removed after the default of 10 attempts (default value). Moreover we use the error to signal, that we try to publish all the new inputs in a separate transaction when the combined one (combination of retried and new inputs) failed.

return fmt.Errorf("publish tx: %v", err)
}

// Otherwise log the error.
if err != nil {
log.Errorf("Publish sweep tx %v got error: %v", tx.TxHash(),
err)
} else {
// If there's no error, remove the output script. Otherwise
// keep it so that it can be reused for the next transaction
// and causes no address inflation.
s.currentOutputScript = nil
return err
}

// If there's no error, remove the output script. Otherwise keep it so
// that it can be reused for the next transaction and causes no address
// inflation.
s.currentOutputScript = nil

return nil
}

// rescheduleInputs updates the pending inputs with the given tx inputs. It
// increments the `publishAttempts` and calculates the next broadcast height
// for each input. When the publishAttempts exceeds MaxSweepAttemps(10), this
// input will be removed.
func (s *UtxoSweeper) rescheduleInputs(inputs []*wire.TxIn,
currentHeight int32) {

// Reschedule sweep.
for _, input := range tx.TxIn {
for _, input := range inputs {
pi, ok := s.pendingInputs[input.PreviousOutPoint]
if !ok {
// It can be that the input has been removed because it
Expand Down Expand Up @@ -1196,8 +1197,6 @@ func (s *UtxoSweeper) sweep(inputs inputSet, feeRate chainfee.SatPerKWeight,
})
}
}

return nil
}

// monitorSpend registers a spend notification with the chain notifier. It
Expand Down