@@ -273,6 +273,10 @@ type BumpResult struct {
273
273
// Err is the error that occurred during the broadcast.
274
274
Err error
275
275
276
+ // SpentInputs are the inputs spent by another tx which caused the
277
+ // current tx to be failed.
278
+ SpentInputs map [wire.OutPoint ]* wire.MsgTx
279
+
276
280
// requestID is the ID of the request that created this record.
277
281
requestID uint64
278
282
}
@@ -812,6 +816,10 @@ type monitorRecord struct {
812
816
813
817
// outpointToTxIndex is a map of outpoint to tx index.
814
818
outpointToTxIndex map [wire.OutPoint ]int
819
+
820
+ // spentInputs are the inputs spent by another tx which caused the
821
+ // current tx failed.
822
+ spentInputs map [wire.OutPoint ]* wire.MsgTx
815
823
}
816
824
817
825
// Start starts the publisher by subscribing to block epoch updates and kicking
@@ -910,6 +918,9 @@ func (t *TxPublisher) processRecords() {
910
918
// If the any of the inputs has been spent, the record will be
911
919
// marked as failed or confirmed.
912
920
if len (spends ) != 0 {
921
+ // Attach the spending txns.
922
+ r .spentInputs = spends
923
+
913
924
// When tx is nil, it means we haven't tried the initial
914
925
// broadcast yet the input is already spent. This could
915
926
// happen when the node shuts down, a previous sweeping
@@ -1159,16 +1170,71 @@ func (t *TxPublisher) handleUnknownSpent(r *monitorRecord) {
1159
1170
"bumper, failing it now:\n %v" , r .requestID ,
1160
1171
inputTypeSummary (r .req .Inputs ))
1161
1172
1162
- // Create a result that will be sent to the resultChan which is
1163
- // listened by the caller.
1173
+ // Create a result that will be sent to the resultChan which is listened
1174
+ // by the caller.
1164
1175
result := & BumpResult {
1165
- Event : TxUnknownSpend ,
1166
- Tx : r .tx ,
1167
- requestID : r .requestID ,
1168
- Err : ErrUnknownSpent ,
1176
+ Event : TxUnknownSpend ,
1177
+ Tx : r .tx ,
1178
+ requestID : r .requestID ,
1179
+ Err : ErrUnknownSpent ,
1180
+ SpentInputs : r .spentInputs ,
1169
1181
}
1170
1182
1171
- // Notify that this tx is confirmed and remove the record from the map.
1183
+ // Get the fee function, which will be used to decided the next fee rate
1184
+ // to use if the sweeper decides to retry sweeping this input.
1185
+ feeFunc := r .feeFunction
1186
+
1187
+ // When the record is failed before the initial broadcast is attempted,
1188
+ // it will have a nil fee func. In this case, we'll create the fee func
1189
+ // here.
1190
+ //
1191
+ // NOTE: Since the current record is failed and will be deleted, we
1192
+ // don't need to update the record on this fee function. We only need
1193
+ // the fee rate data so the sweeper can pick up where we left off.
1194
+ if feeFunc == nil {
1195
+ f , err := t .initializeFeeFunction (r .req )
1196
+ // TODO(yy): The only error we would receive here is when the
1197
+ // pkScript is not recognized by the weightEstimator. What we
1198
+ // should do instead is to check the pkScript immediately after
1199
+ // receiving a sweep request so we don't need to check it again,
1200
+ // which will also save us from error checking from several
1201
+ // callsites.
1202
+ if err != nil {
1203
+ log .Errorf ("Failed to create fee func for record %v: " +
1204
+ "%v" , r .requestID , err )
1205
+
1206
+ // Overwrite the event and error so the sweeper will
1207
+ // remove this input.
1208
+ result .Event = TxFatal
1209
+ result .Err = err
1210
+
1211
+ // Notify the sweeper about this result in the end.
1212
+ t .handleResult (result )
1213
+
1214
+ return
1215
+ }
1216
+
1217
+ feeFunc = f
1218
+ }
1219
+
1220
+ // Since the sweeping tx has been replaced by another party's tx, we
1221
+ // missed this block window to increase its fee rate. To make sure the
1222
+ // fee rate stays in the initial line, we now ask the fee function to
1223
+ // give us the next fee rate as if the sweeping tx were RBFed. This new
1224
+ // fee rate will be used as the starting fee rate if the upper system
1225
+ // decides to continue sweeping the rest of the inputs.
1226
+ _ , err := feeFunc .Increment ()
1227
+ if err != nil {
1228
+ // The fee function has reached its max position - nothing we
1229
+ // can do here other than letting the user increase the budget.
1230
+ log .Errorf ("Failed to calculate the next fee rate for " +
1231
+ "Record(%v): %v" , r .requestID , err )
1232
+ }
1233
+
1234
+ // Attach the new fee rate to be used for the next sweeping attempt.
1235
+ result .FeeRate = feeFunc .FeeRate ()
1236
+
1237
+ // Notify the sweeper about this result in the end.
1172
1238
t .handleResult (result )
1173
1239
}
1174
1240
0 commit comments