Skip to content

Commit

Permalink
Adjusted safety margin calculations when moving funds
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaszslabon committed Apr 30, 2024
1 parent 8c2fc66 commit eb1fca6
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 28 deletions.
17 changes: 17 additions & 0 deletions pkg/tbtc/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,23 @@ type BridgeChain interface {
movingFundsTxHash bitcoin.Hash,
movingFundsTxOutpointIndex uint32,
) (*MovedFundsSweepRequest, bool, error)

// GetMovingFundsParameters gets the current value of parameters relevant
// for the moving funds process.
GetMovingFundsParameters() (
txMaxTotalFee uint64,
dustThreshold uint64,
timeoutResetDelay uint32,
timeout uint32,
timeoutSlashingAmount *big.Int,
timeoutNotifierRewardMultiplier uint32,
commitmentGasOffset uint16,
sweepTxMaxTotalFee uint64,
sweepTimeout uint32,
sweepTimeoutSlashingAmount *big.Int,
sweepTimeoutNotifierRewardMultiplier uint32,
err error,
)
}

// NewWalletRegisteredEvent represents a new wallet registered event.
Expand Down
17 changes: 17 additions & 0 deletions pkg/tbtc/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,23 @@ func buildMovedFundsSweepProposalValidationKey(
return sha256.Sum256(buffer.Bytes()), nil
}

func (lc *localChain) GetMovingFundsParameters() (
txMaxTotalFee uint64,
dustThreshold uint64,
timeoutResetDelay uint32,
timeout uint32,
timeoutSlashingAmount *big.Int,
timeoutNotifierRewardMultiplier uint32,
commitmentGasOffset uint16,
sweepTxMaxTotalFee uint64,
sweepTimeout uint32,
sweepTimeoutSlashingAmount *big.Int,
sweepTimeoutNotifierRewardMultiplier uint32,
err error,
) {
panic("unsupported")
}

// Connect sets up the local chain.
func Connect(blockTime ...time.Duration) *localChain {
operatorPrivateKey, _, err := operator.GenerateKeyPair(local_v1.DefaultCurve)
Expand Down
100 changes: 90 additions & 10 deletions pkg/tbtc/moving_funds.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,19 +313,26 @@ func ValidateMovingFundsProposal(
) error

GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error)

GetMovingFundsParameters() (
txMaxTotalFee uint64,
dustThreshold uint64,
timeoutResetDelay uint32,
timeout uint32,
timeoutSlashingAmount *big.Int,
timeoutNotifierRewardMultiplier uint32,
commitmentGasOffset uint16,
sweepTxMaxTotalFee uint64,
sweepTimeout uint32,
sweepTimeoutSlashingAmount *big.Int,
sweepTimeoutNotifierRewardMultiplier uint32,
err error,
)
},
) error {
validateProposalLogger.Infof("calling chain for proposal validation")

walletChainData, err := chain.GetWallet(walletPublicKeyHash)
if err != nil {
return fmt.Errorf(
"cannot get wallet's chain data: [%w]",
err,
)
}

err = ValidateMovingFundsSafetyMargin(walletChainData)
err := ValidateMovingFundsSafetyMargin(walletPublicKeyHash, chain)
if err != nil {
return fmt.Errorf("moving funds proposal is invalid: [%v]", err)
}
Expand Down Expand Up @@ -354,10 +361,78 @@ func ValidateMovingFundsProposal(
// deposits so, it makes sense to preserve a safety margin before moving
// funds to give the last minute deposits a chance to become eligible for
// deposit sweep.
//
// Similarly, wallets that just entered the MovingFunds state may have become
// target wallets for another moving funds wallets. It makes sense to preserve
// a safety margin to allow the wallet to merge the moved funds from another
// wallets. In this case a longer safety margin should be used.
func ValidateMovingFundsSafetyMargin(
walletChainData *WalletChainData,
walletPublicKeyHash [20]byte,
chain interface {
GetWallet(walletPublicKeyHash [20]byte) (*WalletChainData, error)

GetMovingFundsParameters() (
txMaxTotalFee uint64,
dustThreshold uint64,
timeoutResetDelay uint32,
timeout uint32,
timeoutSlashingAmount *big.Int,
timeoutNotifierRewardMultiplier uint32,
commitmentGasOffset uint16,
sweepTxMaxTotalFee uint64,
sweepTimeout uint32,
sweepTimeoutSlashingAmount *big.Int,
sweepTimeoutNotifierRewardMultiplier uint32,
err error,
)
},
) error {
// In most cases the safety margin of 24 hours should be enough. It will
// allow the wallet to sweep the last deposits that were made before the
// wallet entered the moving funds state.
safetyMargin := time.Duration(24) * time.Hour

// It is possible that our wallet is the target wallet in another pending
// moving funds procedure. If this is the case we must apply a longer
// 14-day safety margin. This will ensure the funds moved from another
// wallet can be merged with our wallet's main UTXO before moving funds.
isMovingFundsTarget, err := isWalletPendingMovingFundsTarget()
if err != nil {
return fmt.Errorf(
"cannot check if wallet is pending moving funds target: [%w]",
err,
)
}

if isMovingFundsTarget {
safetyMargin = time.Duration(24) * 14 * time.Hour
}

// As the moving funds procedure is time constrained, we must ensure the
// safety margin does not exceed half of the moving funds timeout parameter.
// This should give the wallet enough time to complete moving funds.
_, _, _, movingFundsTimeout, _, _, _, _, _, _, _, err :=
chain.GetMovingFundsParameters()
if err != nil {
return fmt.Errorf("cannot get moving funds parameters: [%w]", err)
}

maxAllowedSafetyMargin := time.Duration(
float64(movingFundsTimeout) * 0.5 * float64(time.Second),
)

if safetyMargin > maxAllowedSafetyMargin {
safetyMargin = maxAllowedSafetyMargin
}

walletChainData, err := chain.GetWallet(walletPublicKeyHash)
if err != nil {
return fmt.Errorf(
"cannot get wallet's chain data: [%w]",
err,
)
}

safetyMarginExpiresAt := walletChainData.MovingFundsRequestedAt.Add(safetyMargin)

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

func isWalletPendingMovingFundsTarget() (bool, error) {
// TODO: Implement
return false, nil
}

func assembleMovingFundsTransaction(
bitcoinChain bitcoin.Chain,
walletMainUtxo *bitcoin.UnspentTransactionOutput,
Expand Down
17 changes: 0 additions & 17 deletions pkg/tbtcpg/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,23 +131,6 @@ type Chain interface {
proposal *tbtc.HeartbeatProposal,
) error

// GetMovingFundsParameters gets the current value of parameters relevant
// for the moving funds process.
GetMovingFundsParameters() (
txMaxTotalFee uint64,
dustThreshold uint64,
timeoutResetDelay uint32,
timeout uint32,
timeoutSlashingAmount *big.Int,
timeoutNotifierRewardMultiplier uint32,
commitmentGasOffset uint16,
sweepTxMaxTotalFee uint64,
sweepTimeout uint32,
sweepTimeoutSlashingAmount *big.Int,
sweepTimeoutNotifierRewardMultiplier uint32,
err error,
)

// PastMovingFundsCommitmentSubmittedEvents fetches past moving funds
// commitment submitted events according to the provided filter or
// unfiltered if the filter is nil. Returned events are sorted by the block
Expand Down
2 changes: 1 addition & 1 deletion pkg/tbtcpg/moving_funds.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (mft *MovingFundsTask) Run(request *tbtc.CoordinationProposalRequest) (

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

0 comments on commit eb1fca6

Please sign in to comment.