Skip to content

Commit 8dec47e

Browse files
committed
staticaddr: split withdrawal tx creation/publishing
In this commit we separate the withdrawal tx creation and publication in order to avoid the coop signing process on each re-publishing.
1 parent ae3a983 commit 8dec47e

File tree

1 file changed

+68
-37
lines changed

1 file changed

+68
-37
lines changed

staticaddr/withdraw/manager.go

Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
1212
"github.com/btcsuite/btcd/btcutil"
1313
"github.com/btcsuite/btcd/chaincfg"
14+
"github.com/btcsuite/btcd/chaincfg/chainhash"
1415
"github.com/btcsuite/btcd/txscript"
1516
"github.com/btcsuite/btcd/wire"
1617
"github.com/lightninglabs/lndclient"
@@ -89,14 +90,19 @@ type Manager struct {
8990
// activeWithdrawals stores pending withdrawals by their withdrawal
9091
// address.
9192
activeWithdrawals map[string][]*deposit.Deposit
93+
94+
// finalizedWithdrawalTxns are the finalized withdrawal transactions
95+
// that are published to the network and re-published on block arrivals.
96+
finalizedWithdrawalTxns map[chainhash.Hash]*wire.MsgTx
9297
}
9398

9499
// NewManager creates a new deposit withdrawal manager.
95100
func NewManager(cfg *ManagerConfig) *Manager {
96101
return &Manager{
97-
cfg: cfg,
98-
initChan: make(chan struct{}),
99-
activeWithdrawals: make(map[string][]*deposit.Deposit),
102+
cfg: cfg,
103+
initChan: make(chan struct{}),
104+
activeWithdrawals: make(map[string][]*deposit.Deposit),
105+
finalizedWithdrawalTxns: make(map[chainhash.Hash]*wire.MsgTx),
100106
}
101107
}
102108

@@ -187,12 +193,21 @@ func (m *Manager) recover() error {
187193
return err
188194
}
189195

190-
err = m.publishWithdrawal(m.runCtx, deposits, withdrawalAddress)
196+
finalizedTx, err := m.createFinalizedWithdrawalTx(
197+
m.runCtx, deposits, withdrawalAddress,
198+
)
199+
if err != nil {
200+
return err
201+
}
202+
203+
err = m.publishFinalizedWithdrawalTx(finalizedTx)
191204
if err != nil {
192205
return err
193206
}
194207

195-
err = m.handleWithdrawal(deposits, withdrawalAddress)
208+
err = m.handleWithdrawal(
209+
deposits, finalizedTx.TxHash(), withdrawalAddress,
210+
)
196211
if err != nil {
197212
return err
198213
}
@@ -261,12 +276,21 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
261276
return err
262277
}
263278

264-
err = m.publishWithdrawal(ctx, deposits, withdrawalAddress)
279+
finalizedTx, err := m.createFinalizedWithdrawalTx(
280+
ctx, deposits, withdrawalAddress,
281+
)
282+
if err != nil {
283+
return err
284+
}
285+
286+
err = m.publishFinalizedWithdrawalTx(finalizedTx)
265287
if err != nil {
266288
return err
267289
}
268290

269-
err = m.handleWithdrawal(deposits, withdrawalAddress)
291+
err = m.handleWithdrawal(
292+
deposits, finalizedTx.TxHash(), withdrawalAddress,
293+
)
270294
if err != nil {
271295
return err
272296
}
@@ -278,23 +302,24 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
278302
return nil
279303
}
280304

281-
func (m *Manager) publishWithdrawal(ctx context.Context,
282-
deposits []*deposit.Deposit, withdrawalAddress btcutil.Address) error {
305+
func (m *Manager) createFinalizedWithdrawalTx(ctx context.Context,
306+
deposits []*deposit.Deposit, withdrawalAddress btcutil.Address) (
307+
*wire.MsgTx, error) {
283308

284309
// Create a musig2 session for each deposit.
285310
withdrawalSessions, clientNonces, err := m.createMusig2Sessions(
286311
ctx, deposits,
287312
)
288313
if err != nil {
289-
return err
314+
return nil, err
290315
}
291316

292317
// Get the fee rate for the withdrawal sweep.
293318
withdrawalSweepFeeRate, err := m.cfg.WalletKit.EstimateFeeRate(
294319
m.runCtx, defaultConfTarget,
295320
)
296321
if err != nil {
297-
return err
322+
return nil, err
298323
}
299324

300325
outpoints := toOutpoints(deposits)
@@ -307,14 +332,14 @@ func (m *Manager) publishWithdrawal(ctx context.Context,
307332
},
308333
)
309334
if err != nil {
310-
return err
335+
return nil, err
311336
}
312337

313338
addressParams, err := m.cfg.AddressManager.GetStaticAddressParameters(
314339
ctx,
315340
)
316341
if err != nil {
317-
return fmt.Errorf("couldn't get confirmation height for "+
342+
return nil, fmt.Errorf("couldn't get confirmation height for "+
318343
"deposit, %v", err)
319344
}
320345

@@ -325,12 +350,12 @@ func (m *Manager) publishWithdrawal(ctx context.Context,
325350
withdrawalSweepFeeRate,
326351
)
327352
if err != nil {
328-
return err
353+
return nil, err
329354
}
330355

331356
coopServerNonces, err := toNonces(resp.ServerNonces)
332357
if err != nil {
333-
return err
358+
return nil, err
334359
}
335360

336361
// Next we'll get our sweep tx signatures.
@@ -340,40 +365,47 @@ func (m *Manager) publishWithdrawal(ctx context.Context,
340365
withdrawalSessions, coopServerNonces,
341366
)
342367
if err != nil {
343-
return err
368+
return nil, err
344369
}
345370

346371
// Now we'll finalize the sweepless sweep transaction.
347-
finalizedWithdrawalTx, err := m.finalizeMusig2Transaction(
372+
finalizedTx, err := m.finalizeMusig2Transaction(
348373
m.runCtx, outpoints, m.cfg.Signer, withdrawalSessions,
349374
withdrawalTx, resp.Musig2SweepSigs,
350375
)
351376
if err != nil {
352-
return err
377+
return nil, err
353378
}
354379

355-
txLabel := fmt.Sprintf("deposit-withdrawal-%v",
356-
finalizedWithdrawalTx.TxHash())
380+
m.finalizedWithdrawalTxns[finalizedTx.TxHash()] = finalizedTx
381+
382+
return finalizedTx, nil
383+
}
384+
385+
func (m *Manager) publishFinalizedWithdrawalTx(tx *wire.MsgTx) error {
386+
if tx == nil {
387+
return errors.New("can't publish, finalized withdrawal tx is " +
388+
"nil")
389+
}
390+
391+
txLabel := fmt.Sprintf("deposit-withdrawal-%v", tx.TxHash())
357392

358393
// Publish the withdrawal sweep transaction.
359-
err = m.cfg.WalletKit.PublishTransaction(
360-
m.runCtx, finalizedWithdrawalTx, txLabel,
361-
)
394+
err := m.cfg.WalletKit.PublishTransaction(m.runCtx, tx, txLabel)
362395

363396
if err != nil {
364397
if !strings.Contains(err.Error(), "output already spent") {
365398
log.Errorf("%v: %v", txLabel, err)
366399
}
367400
}
368401

369-
log.Debugf("published deposit withdrawal with txid: %v",
370-
finalizedWithdrawalTx.TxHash())
402+
log.Debugf("published deposit withdrawal with txid: %v", tx.TxHash())
371403

372404
return nil
373405
}
374406

375407
func (m *Manager) handleWithdrawal(deposits []*deposit.Deposit,
376-
withdrawalAddress btcutil.Address) error {
408+
txHash chainhash.Hash, withdrawalAddress btcutil.Address) error {
377409

378410
withdrawalPkScript, err := txscript.PayToAddrScript(withdrawalAddress)
379411
if err != nil {
@@ -382,7 +414,7 @@ func (m *Manager) handleWithdrawal(deposits []*deposit.Deposit,
382414

383415
m.Lock()
384416
confChan, errChan, err := m.cfg.ChainNotifier.RegisterConfirmationsNtfn(
385-
m.runCtx, nil, withdrawalPkScript, MinConfs,
417+
m.runCtx, &txHash, withdrawalPkScript, MinConfs,
386418
int32(m.initiationHeight),
387419
)
388420
m.Unlock()
@@ -402,9 +434,12 @@ func (m *Manager) handleWithdrawal(deposits []*deposit.Deposit,
402434
err)
403435
}
404436

405-
// Remove the withdrawal from the active withdrawals.
437+
// Remove the withdrawal from the active withdrawals and
438+
// remove its finalized to stop republishing it on block
439+
// arrivals.
406440
m.Lock()
407441
delete(m.activeWithdrawals, withdrawalAddress.String())
442+
delete(m.finalizedWithdrawalTxns, txHash)
408443
m.Unlock()
409444

410445
case err := <-errChan:
@@ -710,17 +745,13 @@ func (m *Manager) toPrevOuts(deposits []*deposit.Deposit,
710745
}
711746

712747
func (m *Manager) republishWithdrawals() error {
713-
for withdrawalAddress, deposits := range m.activeWithdrawals {
714-
address, err := btcutil.DecodeAddress(
715-
withdrawalAddress, m.cfg.ChainParams,
716-
)
717-
if err != nil {
718-
log.Errorf("Error decoding withdrawal address: %v", err)
719-
720-
return err
748+
for _, finalizedTx := range m.finalizedWithdrawalTxns {
749+
if finalizedTx == nil {
750+
log.Warnf("Finalized withdrawal tx is nil")
751+
continue
721752
}
722753

723-
err = m.publishWithdrawal(m.runCtx, deposits, address)
754+
err := m.publishFinalizedWithdrawalTx(finalizedTx)
724755
if err != nil {
725756
log.Errorf("Error republishing withdrawal: %v", err)
726757

0 commit comments

Comments
 (0)