4646 ErrMissingPreviousWithdrawn = errors .New ("can't bump fee for subset " +
4747 "of clustered deposits" )
4848
49+ // ErrMissingFinalizedTx is returned if previously withdrawn deposits
50+ // don't have a finalized withdrawal tx attached.
51+ ErrMissingFinalizedTx = errors .New ("deposit does not have a " +
52+ "finalized withdrawal tx, can't bump fee" )
53+
4954 // MinConfs is the minimum number of confirmations we require for a
5055 // deposit to be considered withdrawn.
5156 MinConfs int32 = 3
@@ -89,7 +94,7 @@ type ManagerConfig struct {
8994 Store * SqlStore
9095}
9196
92- // newWithdrawalRequest is used to send withdrawal request to the manager main
97+ // newWithdrawalRequest is used to send a withdrawal request to the manager main
9398// loop.
9499type newWithdrawalRequest struct {
95100 outpoints []wire.OutPoint
@@ -115,7 +120,7 @@ type Manager struct {
115120 mu sync.Mutex
116121
117122 // newWithdrawalRequestChan receives a list of outpoints that should be
118- // withdrawn. The request is forwarded to the managers main loop.
123+ // withdrawn. The request is forwarded to the managers' main loop.
119124 newWithdrawalRequestChan chan newWithdrawalRequest
120125
121126 // exitChan signals subroutines that the withdrawal manager is exiting.
@@ -219,9 +224,9 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
219224}
220225
221226func (m * Manager ) recoverWithdrawals (ctx context.Context ) error {
222- // To recover withdrawals we cluster those with equal withdrawal
223- // addresses and publish their withdrawal tx. Each cluster represents a
224- // separate withdrawal intent by the user.
227+ // To recover withdrawals, we cluster those with equal withdrawal
228+ // addresses and publish their withdrawal tx. Each cluster represents
229+ // one separate withdrawal intent by the user.
225230 withdrawingDeposits , err := m .cfg .DepositManager .GetActiveDepositsInState (
226231 deposit .Withdrawing ,
227232 )
@@ -294,7 +299,7 @@ func (m *Manager) recoverWithdrawals(ctx context.Context) error {
294299 return nil
295300}
296301
297- // WithdrawDeposits starts a deposits withdrawal flow. If the amount is set to 0
302+ // WithdrawDeposits starts a deposit withdrawal flow. If the amount is set to 0,
298303// the full amount of the selected deposits will be withdrawn.
299304func (m * Manager ) WithdrawDeposits (ctx context.Context ,
300305 outpoints []wire.OutPoint , destAddr string , satPerVbyte int64 ,
@@ -309,6 +314,16 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
309314 deposits []* deposit.Deposit
310315 allDeposited bool
311316 allWithdrawing bool
317+ lockDeposits = func (deposits []* deposit.Deposit ) {
318+ for _ , d := range deposits {
319+ d .Lock ()
320+ }
321+ }
322+ unlockDeposits = func (deposits []* deposit.Deposit ) {
323+ for _ , d := range deposits {
324+ d .Unlock ()
325+ }
326+ }
312327 )
313328
314329 // Ensure that the deposits are in a state in which they can be
@@ -325,20 +340,26 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
325340 deposits , allWithdrawing = m .cfg .DepositManager .AllOutpointsActiveDeposits (
326341 outpoints , deposit .Withdrawing ,
327342 )
328-
329343 if ! allWithdrawing {
330344 return "" , "" , ErrWithdrawingMixedDeposits
331345 }
346+ }
347+
348+ // Lock the deposits to prevent concurrent deposit access.
349+ lockDeposits (deposits )
332350
351+ // If the user requested a fee bump, we'll sanity check the selected
352+ // deposits to ensure that they are all part of the same withdrawal.
353+ if ! allDeposited {
333354 // Ensure that all previously withdrawn deposits reference their
334355 // finalized withdrawal tx.
335356 for _ , d := range deposits {
336357 if d .FinalizedWithdrawalTx == nil {
337- return "" , "" , ErrMissingPreviousWithdrawn
358+ return "" , "" , ErrMissingFinalizedTx
338359 }
339360 }
340361
341- // If republishing of an existing withdrawal is requested we
362+ // If republishing of an existing withdrawal is requested, we
342363 // ensure that all deposits remain clustered in the context of
343364 // the same withdrawal tx. We do this by checking that they have
344365 // the same previous withdrawal tx hash. This ensures that the
@@ -351,7 +372,7 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
351372 }
352373 }
353374
354- // We also avoid that the user selects a subset of previously
375+ // We also avoid it that the user selects a subset of previously
355376 // clustered deposits for a fee bump. This would result in a
356377 // different transaction shape.
357378 outpointMap := make (map [wire.OutPoint ]struct {})
@@ -443,9 +464,7 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
443464 // If a previous withdrawal existed across the selected deposits, and
444465 // it isn't the same as the new withdrawal, we remove it from the
445466 // finalized withdrawals to stop republishing it on block arrivals.
446- deposits [0 ].Lock ()
447467 prevTx := deposits [0 ].FinalizedWithdrawalTx
448- deposits [0 ].Unlock ()
449468
450469 if prevTx != nil && prevTx .TxHash () != finalizedTx .TxHash () {
451470 m .mu .Lock ()
@@ -454,13 +473,11 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
454473 }
455474
456475 // Attach the finalized withdrawal tx to the deposits. After a client
457- // restart we can use this address as an indicator to republish the
476+ // restarts, we can use this address as an indicator to republish the
458477 // withdrawal tx and continue the withdrawal.
459478 // Deposits with the same withdrawal tx are part of the same withdrawal.
460479 for _ , d := range deposits {
461- d .Lock ()
462480 d .FinalizedWithdrawalTx = finalizedTx
463- d .Unlock ()
464481 }
465482
466483 // Add the new withdrawal tx to the finalized withdrawals to republish
@@ -469,8 +486,12 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
469486 m .finalizedWithdrawalTxns [finalizedTx .TxHash ()] = finalizedTx
470487 m .mu .Unlock ()
471488
489+ // Unlock the deposits before calling TransitionDeposits, because this
490+ // method locks the deposits itself.
491+ unlockDeposits (deposits )
492+
472493 // Transition the deposits to the withdrawing state. If the user fee
473- // bumped a withdrawal this results in a NOOP transition.
494+ // bumped a withdrawal, this results in a NOOP transition.
474495 err = m .cfg .DepositManager .TransitionDeposits (
475496 ctx , deposits , deposit .OnWithdrawInitiated , deposit .Withdrawing ,
476497 )
@@ -479,6 +500,10 @@ func (m *Manager) WithdrawDeposits(ctx context.Context,
479500 err )
480501 }
481502
503+ // Re-lock the deposits.
504+ lockDeposits (deposits )
505+ defer unlockDeposits (deposits )
506+
482507 // Update the deposits in the database.
483508 for _ , d := range deposits {
484509 err = m .cfg .DepositManager .UpdateDeposit (ctx , d )
0 commit comments