Skip to content

Commit eb1fca6

Browse files
committed
Adjusted safety margin calculations when moving funds
1 parent 8c2fc66 commit eb1fca6

File tree

5 files changed

+125
-28
lines changed

5 files changed

+125
-28
lines changed

pkg/tbtc/chain.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,23 @@ type BridgeChain interface {
223223
movingFundsTxHash bitcoin.Hash,
224224
movingFundsTxOutpointIndex uint32,
225225
) (*MovedFundsSweepRequest, bool, error)
226+
227+
// GetMovingFundsParameters gets the current value of parameters relevant
228+
// for the moving funds process.
229+
GetMovingFundsParameters() (
230+
txMaxTotalFee uint64,
231+
dustThreshold uint64,
232+
timeoutResetDelay uint32,
233+
timeout uint32,
234+
timeoutSlashingAmount *big.Int,
235+
timeoutNotifierRewardMultiplier uint32,
236+
commitmentGasOffset uint16,
237+
sweepTxMaxTotalFee uint64,
238+
sweepTimeout uint32,
239+
sweepTimeoutSlashingAmount *big.Int,
240+
sweepTimeoutNotifierRewardMultiplier uint32,
241+
err error,
242+
)
226243
}
227244

228245
// NewWalletRegisteredEvent represents a new wallet registered event.

pkg/tbtc/chain_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,23 @@ func buildMovedFundsSweepProposalValidationKey(
10991099
return sha256.Sum256(buffer.Bytes()), nil
11001100
}
11011101

1102+
func (lc *localChain) GetMovingFundsParameters() (
1103+
txMaxTotalFee uint64,
1104+
dustThreshold uint64,
1105+
timeoutResetDelay uint32,
1106+
timeout uint32,
1107+
timeoutSlashingAmount *big.Int,
1108+
timeoutNotifierRewardMultiplier uint32,
1109+
commitmentGasOffset uint16,
1110+
sweepTxMaxTotalFee uint64,
1111+
sweepTimeout uint32,
1112+
sweepTimeoutSlashingAmount *big.Int,
1113+
sweepTimeoutNotifierRewardMultiplier uint32,
1114+
err error,
1115+
) {
1116+
panic("unsupported")
1117+
}
1118+
11021119
// Connect sets up the local chain.
11031120
func Connect(blockTime ...time.Duration) *localChain {
11041121
operatorPrivateKey, _, err := operator.GenerateKeyPair(local_v1.DefaultCurve)

pkg/tbtc/moving_funds.go

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -313,19 +313,26 @@ func ValidateMovingFundsProposal(
313313
) error
314314

315315
GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error)
316+
317+
GetMovingFundsParameters() (
318+
txMaxTotalFee uint64,
319+
dustThreshold uint64,
320+
timeoutResetDelay uint32,
321+
timeout uint32,
322+
timeoutSlashingAmount *big.Int,
323+
timeoutNotifierRewardMultiplier uint32,
324+
commitmentGasOffset uint16,
325+
sweepTxMaxTotalFee uint64,
326+
sweepTimeout uint32,
327+
sweepTimeoutSlashingAmount *big.Int,
328+
sweepTimeoutNotifierRewardMultiplier uint32,
329+
err error,
330+
)
316331
},
317332
) error {
318333
validateProposalLogger.Infof("calling chain for proposal validation")
319334

320-
walletChainData, err := chain.GetWallet(walletPublicKeyHash)
321-
if err != nil {
322-
return fmt.Errorf(
323-
"cannot get wallet's chain data: [%w]",
324-
err,
325-
)
326-
}
327-
328-
err = ValidateMovingFundsSafetyMargin(walletChainData)
335+
err := ValidateMovingFundsSafetyMargin(walletPublicKeyHash, chain)
329336
if err != nil {
330337
return fmt.Errorf("moving funds proposal is invalid: [%v]", err)
331338
}
@@ -354,10 +361,78 @@ func ValidateMovingFundsProposal(
354361
// deposits so, it makes sense to preserve a safety margin before moving
355362
// funds to give the last minute deposits a chance to become eligible for
356363
// deposit sweep.
364+
//
365+
// Similarly, wallets that just entered the MovingFunds state may have become
366+
// target wallets for another moving funds wallets. It makes sense to preserve
367+
// a safety margin to allow the wallet to merge the moved funds from another
368+
// wallets. In this case a longer safety margin should be used.
357369
func ValidateMovingFundsSafetyMargin(
358-
walletChainData *WalletChainData,
370+
walletPublicKeyHash [20]byte,
371+
chain interface {
372+
GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error)
373+
374+
GetMovingFundsParameters() (
375+
txMaxTotalFee uint64,
376+
dustThreshold uint64,
377+
timeoutResetDelay uint32,
378+
timeout uint32,
379+
timeoutSlashingAmount *big.Int,
380+
timeoutNotifierRewardMultiplier uint32,
381+
commitmentGasOffset uint16,
382+
sweepTxMaxTotalFee uint64,
383+
sweepTimeout uint32,
384+
sweepTimeoutSlashingAmount *big.Int,
385+
sweepTimeoutNotifierRewardMultiplier uint32,
386+
err error,
387+
)
388+
},
359389
) error {
390+
// In most cases the safety margin of 24 hours should be enough. It will
391+
// allow the wallet to sweep the last deposits that were made before the
392+
// wallet entered the moving funds state.
360393
safetyMargin := time.Duration(24) * time.Hour
394+
395+
// It is possible that our wallet is the target wallet in another pending
396+
// moving funds procedure. If this is the case we must apply a longer
397+
// 14-day safety margin. This will ensure the funds moved from another
398+
// wallet can be merged with our wallet's main UTXO before moving funds.
399+
isMovingFundsTarget, err := isWalletPendingMovingFundsTarget()
400+
if err != nil {
401+
return fmt.Errorf(
402+
"cannot check if wallet is pending moving funds target: [%w]",
403+
err,
404+
)
405+
}
406+
407+
if isMovingFundsTarget {
408+
safetyMargin = time.Duration(24) * 14 * time.Hour
409+
}
410+
411+
// As the moving funds procedure is time constrained, we must ensure the
412+
// safety margin does not exceed half of the moving funds timeout parameter.
413+
// This should give the wallet enough time to complete moving funds.
414+
_, _, _, movingFundsTimeout, _, _, _, _, _, _, _, err :=
415+
chain.GetMovingFundsParameters()
416+
if err != nil {
417+
return fmt.Errorf("cannot get moving funds parameters: [%w]", err)
418+
}
419+
420+
maxAllowedSafetyMargin := time.Duration(
421+
float64(movingFundsTimeout) * 0.5 * float64(time.Second),
422+
)
423+
424+
if safetyMargin > maxAllowedSafetyMargin {
425+
safetyMargin = maxAllowedSafetyMargin
426+
}
427+
428+
walletChainData, err := chain.GetWallet(walletPublicKeyHash)
429+
if err != nil {
430+
return fmt.Errorf(
431+
"cannot get wallet's chain data: [%w]",
432+
err,
433+
)
434+
}
435+
361436
safetyMarginExpiresAt := walletChainData.MovingFundsRequestedAt.Add(safetyMargin)
362437

363438
if time.Now().Before(safetyMarginExpiresAt) {
@@ -375,6 +450,11 @@ func (mfa *movingFundsAction) actionType() WalletActionType {
375450
return ActionMovingFunds
376451
}
377452

453+
func isWalletPendingMovingFundsTarget() (bool, error) {
454+
// TODO: Implement
455+
return false, nil
456+
}
457+
378458
func assembleMovingFundsTransaction(
379459
bitcoinChain bitcoin.Chain,
380460
walletMainUtxo *bitcoin.UnspentTransactionOutput,

pkg/tbtcpg/chain.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -131,23 +131,6 @@ type Chain interface {
131131
proposal *tbtc.HeartbeatProposal,
132132
) error
133133

134-
// GetMovingFundsParameters gets the current value of parameters relevant
135-
// for the moving funds process.
136-
GetMovingFundsParameters() (
137-
txMaxTotalFee uint64,
138-
dustThreshold uint64,
139-
timeoutResetDelay uint32,
140-
timeout uint32,
141-
timeoutSlashingAmount *big.Int,
142-
timeoutNotifierRewardMultiplier uint32,
143-
commitmentGasOffset uint16,
144-
sweepTxMaxTotalFee uint64,
145-
sweepTimeout uint32,
146-
sweepTimeoutSlashingAmount *big.Int,
147-
sweepTimeoutNotifierRewardMultiplier uint32,
148-
err error,
149-
)
150-
151134
// PastMovingFundsCommitmentSubmittedEvents fetches past moving funds
152135
// commitment submitted events according to the provided filter or
153136
// unfiltered if the filter is nil. Returned events are sorted by the block

pkg/tbtcpg/moving_funds.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func (mft *MovingFundsTask) Run(request *tbtc.CoordinationProposalRequest) (
9595

9696
// Check the safety margin for moving funds early. This will prevent
9797
// commitment submission if the wallet is not safe to move funds.
98-
err = tbtc.ValidateMovingFundsSafetyMargin(walletChainData)
98+
err = tbtc.ValidateMovingFundsSafetyMargin(walletPublicKeyHash, mft.chain)
9999
if err != nil {
100100
taskLogger.Infof("source wallet moving funds safety margin validation failed: [%v]", err)
101101
return nil, false, nil

0 commit comments

Comments
 (0)