diff --git a/x/btcstaking/keeper/inclusion_proof.go b/x/btcstaking/keeper/inclusion_proof.go index 2405c304..d3f7163d 100644 --- a/x/btcstaking/keeper/inclusion_proof.go +++ b/x/btcstaking/keeper/inclusion_proof.go @@ -17,11 +17,14 @@ type DelegationTimeRangeInfo struct { // VerifyInclusionProofAndGetHeight verifies the inclusion proof of the given staking tx // and returns the start height and end height +// Note: the `minUnbondingTime` passed here should be from the corresponding params +// of the staking tx func (k Keeper) VerifyInclusionProofAndGetHeight( ctx sdk.Context, stakingTx *btcutil.Tx, confirmationDepth uint32, stakingTime uint32, + minUnbondingTime uint32, inclusionProof *types.ParsedProofOfInclusion, ) (*DelegationTimeRangeInfo, error) { // Check: @@ -59,7 +62,6 @@ func (k Keeper) VerifyInclusionProofAndGetHeight( } // ensure staking tx's timelock has more than unbonding BTC blocks left - minUnbondingTime := k.GetParamsWithVersion(ctx).Params.MinUnbondingTimeBlocks if btcTip.Height+minUnbondingTime >= endHeight { return nil, types.ErrInvalidStakingTx. Wrapf("staking tx's timelock has no more than unbonding(=%d) blocks left", minUnbondingTime) diff --git a/x/btcstaking/keeper/inclusion_proof_test.go b/x/btcstaking/keeper/inclusion_proof_test.go index 2ff5f896..05066d17 100644 --- a/x/btcstaking/keeper/inclusion_proof_test.go +++ b/x/btcstaking/keeper/inclusion_proof_test.go @@ -16,7 +16,7 @@ import ( ) func FuzzVerifyInclusionProofAndGetHeight(f *testing.F) { - datagen.AddRandomSeedsToFuzzer(f, 10) + datagen.AddRandomSeedsToFuzzer(f, 100) f.Fuzz(func(t *testing.T, seed int64) { r := rand.New(rand.NewSource(seed)) @@ -77,6 +77,7 @@ func FuzzVerifyInclusionProofAndGetHeight(f *testing.F) { stakingTx, confirmationDepth, stakingTime, + params.MinUnbondingTimeBlocks, proof, ) @@ -95,6 +96,7 @@ func FuzzVerifyInclusionProofAndGetHeight(f *testing.F) { stakingTx, confirmationDepth, stakingTime, + params.MinUnbondingTimeBlocks, proof, ) @@ -112,6 +114,7 @@ func FuzzVerifyInclusionProofAndGetHeight(f *testing.F) { stakingTx, confirmationDepth, stakingTime, + params.MinUnbondingTimeBlocks, ©Proof, ) @@ -131,6 +134,7 @@ func FuzzVerifyInclusionProofAndGetHeight(f *testing.F) { stakingTx, confirmationDepth, stakingTime, + params.MinUnbondingTimeBlocks, proof, ) @@ -150,6 +154,30 @@ func FuzzVerifyInclusionProofAndGetHeight(f *testing.F) { stakingTx, confirmationDepth, stakingTime, + params.MinUnbondingTimeBlocks, + proof, + ) + + require.ErrorContains(t, err, "staking tx's timelock has no more than unbonding") + }) + + t.Run("invalid min unbonding time", func(t *testing.T) { + // Set the tip height to be in the range of valid min and max tip height + tipHeight := datagen.RandomInt(r, int(maxValidTipHeight)-int(minValidTipHeight)+1) + uint64(minValidTipHeight) + mockTipHeaderInfo := &btclctypes.BTCHeaderInfo{Height: uint32(tipHeight)} + + btclcKeeper.EXPECT().GetHeaderByHash(gomock.Any(), headerHash).Return(inclusionHeader).Times(1) + btclcKeeper.EXPECT().GetTipInfo(gomock.Any()).Return(mockTipHeaderInfo).Times(1) + + // an invalid min_unbonding_time should be >= end_height - tip_height + invalidMinUnbondingTime := uint32(datagen.RandomInt(r, 1000)) + inclusionHeight + stakingTime - uint32(tipHeight) + + _, err = h.BTCStakingKeeper.VerifyInclusionProofAndGetHeight( + h.Ctx, + stakingTx, + confirmationDepth, + stakingTime, + invalidMinUnbondingTime, proof, ) diff --git a/x/btcstaking/keeper/msg_server.go b/x/btcstaking/keeper/msg_server.go index 454bdab1..61b2e839 100644 --- a/x/btcstaking/keeper/msg_server.go +++ b/x/btcstaking/keeper/msg_server.go @@ -215,6 +215,7 @@ func (ms msgServer) CreateBTCDelegation(goCtx context.Context, req *types.MsgCre btcutil.NewTx(parsedMsg.StakingTx.Transaction), btccParams.BtcConfirmationDepth, uint32(parsedMsg.StakingTime), + vp.Params.MinUnbondingTimeBlocks, parsedMsg.StakingTxProofOfInclusion) if err != nil { return nil, fmt.Errorf("invalid inclusion proof: %w", err) @@ -314,6 +315,7 @@ func (ms msgServer) AddBTCDelegationInclusionProof( btcutil.NewTx(stakingTx), btccParams.BtcConfirmationDepth, btcDel.StakingTime, + minUnbondingTime, parsedInclusionProof, )