mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-13 11:09:23 +01:00
sweep: add new method handleInputSpent
This commit is contained in:
parent
39a7cc6434
commit
f1d0f9f74e
1 changed files with 77 additions and 81 deletions
158
sweep/sweeper.go
158
sweep/sweeper.go
|
@ -616,87 +616,7 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) {
|
||||||
// A spend of one of our inputs is detected. Signal sweep
|
// A spend of one of our inputs is detected. Signal sweep
|
||||||
// results to the caller(s).
|
// results to the caller(s).
|
||||||
case spend := <-s.spendChan:
|
case spend := <-s.spendChan:
|
||||||
// For testing purposes.
|
s.handleInputSpent(spend, bestHeight)
|
||||||
if s.testSpendChan != nil {
|
|
||||||
s.testSpendChan <- *spend.SpentOutPoint
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query store to find out if we ever published this
|
|
||||||
// tx.
|
|
||||||
spendHash := *spend.SpenderTxHash
|
|
||||||
isOurTx, err := s.cfg.Store.IsOurTx(spendHash)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("cannot determine if tx %v "+
|
|
||||||
"is ours: %v", spendHash, err,
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this isn't our transaction, it means someone else
|
|
||||||
// swept outputs that we were attempting to sweep. This
|
|
||||||
// can happen for anchor outputs as well as justice
|
|
||||||
// transactions. In this case, we'll notify the wallet
|
|
||||||
// to remove any spends that a descent from this
|
|
||||||
// output.
|
|
||||||
if !isOurTx {
|
|
||||||
err := s.removeLastSweepDescendants(
|
|
||||||
spend.SpendingTx,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Warnf("unable to remove descendant "+
|
|
||||||
"transactions due to tx %v: ",
|
|
||||||
spendHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("Detected spend related to in flight inputs "+
|
|
||||||
"(is_ours=%v): %v",
|
|
||||||
newLogClosure(func() string {
|
|
||||||
return spew.Sdump(spend.SpendingTx)
|
|
||||||
}), isOurTx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal sweep results for inputs in this confirmed
|
|
||||||
// tx.
|
|
||||||
for _, txIn := range spend.SpendingTx.TxIn {
|
|
||||||
outpoint := txIn.PreviousOutPoint
|
|
||||||
|
|
||||||
// Check if this input is known to us. It could
|
|
||||||
// probably be unknown if we canceled the
|
|
||||||
// registration, deleted from pendingInputs but
|
|
||||||
// the ntfn was in-flight already. Or this could
|
|
||||||
// be not one of our inputs.
|
|
||||||
input, ok := s.pendingInputs[outpoint]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return either a nil or a remote spend result.
|
|
||||||
var err error
|
|
||||||
if !isOurTx {
|
|
||||||
err = ErrRemoteSpend
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal result channels.
|
|
||||||
s.signalAndRemove(&outpoint, Result{
|
|
||||||
Tx: spend.SpendingTx,
|
|
||||||
Err: err,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Remove all other inputs in this exclusive
|
|
||||||
// group.
|
|
||||||
if input.params.ExclusiveGroup != nil {
|
|
||||||
s.removeExclusiveGroup(
|
|
||||||
*input.params.ExclusiveGroup,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that an input of ours is spent, we can try to
|
|
||||||
// resweep the remaining inputs.
|
|
||||||
if err := s.scheduleSweep(bestHeight); err != nil {
|
|
||||||
log.Errorf("schedule sweep: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A new external request has been received to retrieve all of
|
// A new external request has been received to retrieve all of
|
||||||
// the inputs we're currently attempting to sweep.
|
// the inputs we're currently attempting to sweep.
|
||||||
|
@ -1670,6 +1590,82 @@ func (s *UtxoSweeper) handleExistingInput(input *sweepInputMessage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleInputSpent takes a spend event of our input and updates the sweeper's
|
||||||
|
// internal state to remove the input.
|
||||||
|
func (s *UtxoSweeper) handleInputSpent(spend *chainntnfs.SpendDetail,
|
||||||
|
bestHeight int32) {
|
||||||
|
|
||||||
|
// For testing purposes.
|
||||||
|
if s.testSpendChan != nil {
|
||||||
|
s.testSpendChan <- *spend.SpentOutPoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query store to find out if we ever published this tx.
|
||||||
|
spendHash := *spend.SpenderTxHash
|
||||||
|
isOurTx, err := s.cfg.Store.IsOurTx(spendHash)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("cannot determine if tx %v is ours: %v",
|
||||||
|
spendHash, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this isn't our transaction, it means someone else swept outputs
|
||||||
|
// that we were attempting to sweep. This can happen for anchor outputs
|
||||||
|
// as well as justice transactions. In this case, we'll notify the
|
||||||
|
// wallet to remove any spends that descent from this output.
|
||||||
|
if !isOurTx {
|
||||||
|
err := s.removeLastSweepDescendants(spend.SpendingTx)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("unable to remove descendant transactions "+
|
||||||
|
"due to tx %v: ", spendHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Detected third party spend related to in flight "+
|
||||||
|
"inputs (is_ours=%v): %v",
|
||||||
|
newLogClosure(func() string {
|
||||||
|
return spew.Sdump(spend.SpendingTx)
|
||||||
|
}), isOurTx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal sweep results for inputs in this confirmed tx.
|
||||||
|
for _, txIn := range spend.SpendingTx.TxIn {
|
||||||
|
outpoint := txIn.PreviousOutPoint
|
||||||
|
|
||||||
|
// Check if this input is known to us. It could probably be
|
||||||
|
// unknown if we canceled the registration, deleted from
|
||||||
|
// pendingInputs but the ntfn was in-flight already. Or this
|
||||||
|
// could be not one of our inputs.
|
||||||
|
input, ok := s.pendingInputs[outpoint]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return either a nil or a remote spend result.
|
||||||
|
var err error
|
||||||
|
if !isOurTx {
|
||||||
|
err = ErrRemoteSpend
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal result channels.
|
||||||
|
s.signalAndRemove(&outpoint, Result{
|
||||||
|
Tx: spend.SpendingTx,
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Remove all other inputs in this exclusive group.
|
||||||
|
if input.params.ExclusiveGroup != nil {
|
||||||
|
s.removeExclusiveGroup(*input.params.ExclusiveGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that an input of ours is spent, we can try to resweep the
|
||||||
|
// remaining inputs.
|
||||||
|
if err := s.scheduleSweep(bestHeight); err != nil {
|
||||||
|
log.Errorf("schedule sweep: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// init initializes the random generator for random input rescheduling.
|
// init initializes the random generator for random input rescheduling.
|
||||||
func init() {
|
func init() {
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
|
|
Loading…
Add table
Reference in a new issue