Skip to content

Commit 50bc191

Browse files
committed
sweep: handle unknown spent in processRecords
This commit refactors the `processRecords` to always handle the inputs spent when processing the records. We now make sure to handle unknown spends for all backends (previously only neutrino), and rely solely on the spending notification to give us the onchain status of inputs.
1 parent 61cec43 commit 50bc191

File tree

2 files changed

+290
-82
lines changed

2 files changed

+290
-82
lines changed

sweep/fee_bumper.go

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,6 @@ func (t *TxPublisher) processRecords() {
897897

898898
// failedRecords stores a map of records which has inputs being spent
899899
// by a third party.
900-
//
901-
// NOTE: this is only used for neutrino backend.
902900
failedRecords := make(map[uint64]*monitorRecord)
903901

904902
// initialRecords stores a map of records which are being created and
@@ -908,32 +906,55 @@ func (t *TxPublisher) processRecords() {
908906
// visitor is a helper closure that visits each record and divides them
909907
// into two groups.
910908
visitor := func(requestID uint64, r *monitorRecord) error {
911-
if r.tx == nil {
912-
initialRecords[requestID] = r
913-
return nil
914-
}
909+
log.Tracef("Checking monitor recordID=%v", requestID)
910+
911+
// Check whether the inputs have already been spent.
912+
spends := t.getSpentInputs(r)
913+
914+
// If the any of the inputs has been spent, the record will be
915+
// marked as failed or confirmed.
916+
if len(spends) != 0 {
917+
// When tx is nil, it means we haven't tried the initial
918+
// broadcast yet the input is already spent. This could
919+
// happen when the node shuts down, a previous sweeping
920+
// tx confirmed, then the node comes back online and
921+
// reoffers the inputs. Another case is the remote node
922+
// spends the input quickly before we even attempt the
923+
// sweep. In either case we will fail the record and let
924+
// the sweeper handles it.
925+
if r.tx == nil {
926+
failedRecords[requestID] = r
927+
return nil
928+
}
915929

916-
log.Tracef("Checking monitor recordID=%v for tx=%v", requestID,
917-
r.tx.TxHash())
930+
// Check whether the inputs has been spent by a unknown
931+
// tx.
932+
if t.isThirdPartySpent(r, spends) {
933+
failedRecords[requestID] = r
934+
935+
// Move to the next record.
936+
return nil
937+
}
918938

919-
// If the tx is already confirmed, we can stop monitoring it.
920-
if t.isConfirmed(r.tx.TxHash()) {
939+
// The tx is ours, we can move it to the confirmed queue
940+
// and stop monitoring it.
921941
confirmedRecords[requestID] = r
922942

923943
// Move to the next record.
924944
return nil
925945
}
926946

927-
// Check whether the inputs has been spent by a third party.
928-
//
929-
// NOTE: this check is only done for neutrino backend.
930-
if t.isThirdPartySpent(r) {
931-
failedRecords[requestID] = r
947+
// This is the first time we see this record, so we put it in
948+
// the initial queue.
949+
if r.tx == nil {
950+
initialRecords[requestID] = r
932951

933-
// Move to the next record.
934952
return nil
935953
}
936954

955+
// We can only get here when the inputs are not spent and a
956+
// previous sweeping tx has been attempted. In this case we will
957+
// perform an RBF on it in the current block.
937958
feeBumpRecords[requestID] = r
938959

939960
// Return nil to move to the next record.
@@ -1265,17 +1286,10 @@ func (t *TxPublisher) isConfirmed(txid chainhash.Hash) bool {
12651286
// isThirdPartySpent checks whether the inputs of the tx has already been spent
12661287
// by a third party. When a tx is not confirmed, yet its inputs has been spent,
12671288
// then it must be spent by a different tx other than the sweeping tx here.
1268-
//
1269-
// NOTE: this check is only performed for neutrino backend as it has no
1270-
// reliable way to tell a tx has been replaced.
1271-
func (t *TxPublisher) isThirdPartySpent(r *monitorRecord) bool {
1272-
// Skip this check for if this is not neutrino backend.
1273-
if !t.isNeutrinoBackend() {
1274-
return false
1275-
}
1289+
func (t *TxPublisher) isThirdPartySpent(r *monitorRecord,
1290+
spends map[wire.OutPoint]*wire.MsgTx) bool {
12761291

12771292
txid := r.tx.TxHash()
1278-
spends := t.getSpentInputs(r)
12791293

12801294
// Iterate all the spending txns and check if they match the sweeping
12811295
// tx.

0 commit comments

Comments
 (0)