@@ -20,6 +20,7 @@ import (
2020 "github.com/lightninglabs/loop/loopdb"
2121 "github.com/lightninglabs/loop/swap"
2222 "github.com/lightninglabs/loop/utils"
23+ "github.com/lightningnetwork/lnd/chainntnfs"
2324 "github.com/lightningnetwork/lnd/clock"
2425 "github.com/lightningnetwork/lnd/input"
2526 "github.com/lightningnetwork/lnd/lntypes"
@@ -280,6 +281,8 @@ type addSweepsRequest struct {
280281 parentBatch * dbBatch
281282}
282283
284+ // SpendDetail is a notification that is send to the user of sweepbatcher when
285+ // a batch gets the first confirmation.
283286type SpendDetail struct {
284287 // Tx is the transaction that spent the outpoint.
285288 Tx * wire.MsgTx
@@ -291,6 +294,19 @@ type SpendDetail struct {
291294 OnChainFeePortion btcutil.Amount
292295}
293296
297+ // ConfDetail is a notification that is send to the user of sweepbatcher when
298+ // a batch is fully confirmed, i.e. gets batchConfHeight confirmations.
299+ type ConfDetail struct {
300+ // TxConfirmation has data about the confirmation of the transaction.
301+ * chainntnfs.TxConfirmation
302+
303+ // OnChainFeePortion is the fee portion that was paid to get this sweep
304+ // confirmed on chain. This is the difference between the value of the
305+ // outpoint and the value of all sweeps that were included in the batch
306+ // divided by the number of sweeps.
307+ OnChainFeePortion btcutil.Amount
308+ }
309+
294310// SpendNotifier is a notifier that is used to notify the requester of a sweep
295311// that the sweep was successful.
296312type SpendNotifier struct {
@@ -300,6 +316,14 @@ type SpendNotifier struct {
300316 // SpendErrChan is a channel where spend errors are received.
301317 SpendErrChan chan <- error
302318
319+ // ConfChan is a channel where the confirmation details are received.
320+ // This channel is optional.
321+ ConfChan chan <- * ConfDetail
322+
323+ // ConfErrChan is a channel where confirmation errors are received.
324+ // This channel is optional.
325+ ConfErrChan chan <- error
326+
303327 // QuitChan is a channel that can be closed to stop the notifier.
304328 QuitChan <- chan bool
305329}
@@ -1114,7 +1138,9 @@ func (b *Batcher) FetchUnconfirmedBatches(ctx context.Context) ([]*batch,
11141138}
11151139
11161140// monitorSpendAndNotify monitors the spend of a specific outpoint and writes
1117- // the response back to the response channel.
1141+ // the response back to the response channel. It is called if the batch is fully
1142+ // confirmed and we just need to deliver the data back to the caller though
1143+ // SpendNotifier.
11181144func (b * Batcher ) monitorSpendAndNotify (ctx context.Context , sweep * sweep ,
11191145 parentBatchID int32 , notifier * SpendNotifier ) error {
11201146
@@ -1172,6 +1198,16 @@ func (b *Batcher) monitorSpendAndNotify(ctx context.Context, sweep *sweep,
11721198 select {
11731199 // Try to write the update to the notification channel.
11741200 case notifier .SpendChan <- spendDetail :
1201+ err := b .monitorConfAndNotify (
1202+ ctx , sweep , notifier , spendTx ,
1203+ onChainFeePortion ,
1204+ )
1205+ if err != nil {
1206+ b .writeToErrChan (
1207+ ctx , fmt .Errorf ("monitor conf " +
1208+ "failed: %w" , err ),
1209+ )
1210+ }
11751211
11761212 // If a quit signal was provided by the swap, continue.
11771213 case <- notifier .QuitChan :
@@ -1215,6 +1251,84 @@ func (b *Batcher) monitorSpendAndNotify(ctx context.Context, sweep *sweep,
12151251 return nil
12161252}
12171253
1254+ // monitorConfAndNotify monitors the confirmation of a specific transaction and
1255+ // writes the response back to the response channel. It is called if the batch
1256+ // is fully confirmed and we just need to deliver the data back to the caller
1257+ // though SpendNotifier.
1258+ func (b * Batcher ) monitorConfAndNotify (ctx context.Context , sweep * sweep ,
1259+ notifier * SpendNotifier , spendTx * wire.MsgTx ,
1260+ onChainFeePortion btcutil.Amount ) error {
1261+
1262+ // If confirmation notifications were not requested, stop.
1263+ if notifier .ConfChan == nil && notifier .ConfErrChan == nil {
1264+ return nil
1265+ }
1266+
1267+ batchTxid := spendTx .TxHash ()
1268+
1269+ if len (spendTx .TxOut ) != 1 {
1270+ return fmt .Errorf ("unexpected number of outputs in batch: %d, " +
1271+ "want %d" , len (spendTx .TxOut ), 1 )
1272+ }
1273+ batchPkScript := spendTx .TxOut [0 ].PkScript
1274+
1275+ reorgChan := make (chan struct {})
1276+
1277+ confCtx , cancel := context .WithCancel (ctx )
1278+
1279+ confChan , errChan , err := b .chainNotifier .RegisterConfirmationsNtfn (
1280+ confCtx , & batchTxid , batchPkScript , batchConfHeight ,
1281+ sweep .initiationHeight , lndclient .WithReOrgChan (reorgChan ),
1282+ )
1283+ if err != nil {
1284+ cancel ()
1285+ return err
1286+ }
1287+
1288+ b .wg .Add (1 )
1289+ go func () {
1290+ defer cancel ()
1291+ defer b .wg .Done ()
1292+
1293+ select {
1294+ case conf := <- confChan :
1295+ if notifier .ConfChan != nil {
1296+ confDetail := & ConfDetail {
1297+ TxConfirmation : conf ,
1298+ OnChainFeePortion : onChainFeePortion ,
1299+ }
1300+
1301+ select {
1302+ case notifier .ConfChan <- confDetail :
1303+ case <- notifier .QuitChan :
1304+ case <- ctx .Done ():
1305+ }
1306+ }
1307+
1308+ case err := <- errChan :
1309+ if notifier .ConfErrChan != nil {
1310+ select {
1311+ case notifier .ConfErrChan <- err :
1312+ case <- notifier .QuitChan :
1313+ case <- ctx .Done ():
1314+ }
1315+ }
1316+
1317+ b .writeToErrChan (ctx , fmt .Errorf ("confirmations " +
1318+ "monitoring error: %w" , err ))
1319+
1320+ case <- reorgChan :
1321+ // A re-org has been detected, but the batch is fully
1322+ // confirmed and this is unexpected. Crash the batcher.
1323+ b .writeToErrChan (ctx , fmt .Errorf ("unexpected reorg" ))
1324+
1325+ case <- ctx .Done ():
1326+ }
1327+ }()
1328+
1329+ return nil
1330+ }
1331+
12181332func (b * Batcher ) writeToErrChan (ctx context.Context , err error ) {
12191333 select {
12201334 case b .errChan <- err :
0 commit comments