-
Notifications
You must be signed in to change notification settings - Fork 2.3k
sweep: fix expected spending events being missed #10060
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
Changes from 1 commit
940d317
1a26723
96a6857
5502d91
ea6c132
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -20,6 +20,7 @@ import ( | |||
| "github.com/lightningnetwork/lnd/lntypes" | ||||
| "github.com/lightningnetwork/lnd/lnutils" | ||||
| "github.com/lightningnetwork/lnd/lnwallet" | ||||
| "github.com/lightningnetwork/lnd/lnwallet/btcwallet" | ||||
| "github.com/lightningnetwork/lnd/lnwallet/chainfee" | ||||
| "github.com/lightningnetwork/lnd/tlv" | ||||
| ) | ||||
|
|
@@ -344,6 +345,10 @@ type TxPublisherConfig struct { | |||
| // Notifier is used to monitor the confirmation status of the tx. | ||||
| Notifier chainntnfs.ChainNotifier | ||||
|
|
||||
| // ChainIO represents an abstraction over a source that can query the | ||||
| // blockchain. | ||||
| ChainIO lnwallet.BlockChainIO | ||||
|
|
||||
| // AuxSweeper is an optional interface that can be used to modify the | ||||
| // way sweep transaction are generated. | ||||
| AuxSweeper fn.Option[AuxSweeper] | ||||
|
|
@@ -1415,6 +1420,38 @@ func (t *TxPublisher) getSpentInputs( | |||
| "%v", op, heightHint) | ||||
| } | ||||
|
|
||||
| // Check whether the input has been spent or not. | ||||
| utxo, err := t.cfg.ChainIO.GetUtxo( | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, will this also populate the spend cache for neutrino backends? Otherwise, this can be a very expensive filter rescan depending on how far back they are. In other words, this'll block for neutrno backends. Would need to check for behavior with backends that have the txindex off.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about just moving back to the spend channel/goroutine? That way it's always active, always watching, and we can handle the notification async when needed. It would allow us to remove all these other default select cases for spend ntfns. I recall I pointed out a possibility of missed events when this change was originally added.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
FWIW this is already used in lnd/chainntnfs/neutrinonotify/neutrino.go Line 864 in 4389067
Can try that route, meanwhile there's #10117 that fixes this issue using an alternative approach. I will see if it's possible to make a new sync method when implementing SQL into btcwallet. |
||||
| &op, inp.SignDesc().Output.PkScript, heightHint, t.quit, | ||||
| ) | ||||
| if err != nil { | ||||
| // GetUtxo will return `ErrOutputSpent` when the input | ||||
| // has already been spent. In that case, the returned | ||||
| // `utxo` must be nil, which will move us to subscribe | ||||
| // its spending event below. | ||||
| if !errors.Is(err, btcwallet.ErrOutputSpent) { | ||||
| log.Errorf("Failed to get utxo for input=%v: "+ | ||||
| "%v", op, err) | ||||
|
|
||||
| // If this is an unexpected error, move to check | ||||
| // the next input. | ||||
| continue | ||||
| } | ||||
|
|
||||
| log.Tracef("GetUtxo for input=%v, err: %v", op, err) | ||||
| } | ||||
|
|
||||
| // If a non-nil utxo is returned it means this input is still | ||||
| // unspent. Thus we can continue to the next input as there's no | ||||
| // need to register spend notification for it. | ||||
| if utxo != nil { | ||||
| log.Tracef("Input=%v not spent yet", op) | ||||
| continue | ||||
| } | ||||
|
|
||||
| log.Debugf("Input=%v already spent, fetching its spending "+ | ||||
| "tx...", op) | ||||
|
|
||||
| // If the input has already been spent after the height hint, a | ||||
| // spend event is sent back immediately. | ||||
| spendEvent, err := t.cfg.Notifier.RegisterSpendNtfn( | ||||
|
|
@@ -1424,7 +1461,7 @@ func (t *TxPublisher) getSpentInputs( | |||
| log.Criticalf("Failed to register spend ntfn for "+ | ||||
| "input=%v: %v", op, err) | ||||
|
yyforyongyu marked this conversation as resolved.
|
||||
|
|
||||
| return nil | ||||
| return spentInputs | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So initially we return A follow-up question is: what happens when we have multiple inputs (I guess that's a possibility), and one fails? Does that affect where we call the method since no error will be returned, and the only check I see is for the length of the returned result?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning
What do you mean one fails? If there's a failure here, then we'd shut down
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ah, I now understand that |
||||
| } | ||||
|
|
||||
| // Remove the subscription when exit. | ||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the
GetUtxocall is probably just added here to save us time? because I noticedRegisterSpendNtfnalso checks this internally.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah correct, it creates a shortcut here so we don't need to make unnecessary subscriptions. We only attempt to subscribe for spending when we know it's not in the utxo set, which means either the input has been spent or it's an orphan.