diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 0db6166ee..f6c7f3d1e 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -524,6 +524,9 @@ func (ak *AppKeepers) InitKeepers( runtime.NewKVStoreService(keys[btcstakingtypes.StoreKey]), &btclightclientKeeper, &btcCheckpointKeeper, + // setting the finality keeper as nil for now + // need to set it after finality keeper is initiated + nil, btcNetParams, authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) @@ -539,6 +542,7 @@ func (ak *AppKeepers) InitKeepers( ) ak.BTCStakingKeeper = *ak.BTCStakingKeeper.SetHooks(btcstakingtypes.NewMultiBtcStakingHooks(ak.FinalityKeeper.Hooks())) ak.FinalityKeeper = *ak.FinalityKeeper.SetHooks(finalitytypes.NewMultiFinalityHooks(ak.BTCStakingKeeper.Hooks())) + ak.BTCStakingKeeper.FinalityKeeper = ak.FinalityKeeper // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( diff --git a/testutil/keeper/btcstaking.go b/testutil/keeper/btcstaking.go index d12d32820..a3bcad46a 100644 --- a/testutil/keeper/btcstaking.go +++ b/testutil/keeper/btcstaking.go @@ -27,6 +27,7 @@ func BTCStakingKeeper( t testing.TB, btclcKeeper types.BTCLightClientKeeper, btccKeeper types.BtcCheckpointKeeper, + finalityKeeper types.FinalityKeeper, ) (*keeper.Keeper, sdk.Context) { storeKey := storetypes.NewKVStoreKey(types.StoreKey) @@ -43,6 +44,7 @@ func BTCStakingKeeper( runtime.NewKVStoreService(storeKey), btclcKeeper, btccKeeper, + finalityKeeper, &chaincfg.SimNetParams, authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) diff --git a/x/btcstaking/genesis_test.go b/x/btcstaking/genesis_test.go index 805650c8a..2ab7d793c 100644 --- a/x/btcstaking/genesis_test.go +++ b/x/btcstaking/genesis_test.go @@ -17,7 +17,7 @@ func TestGenesis(t *testing.T) { Params: []*types.Params{&p}, } - k, ctx := keepertest.BTCStakingKeeper(t, nil, nil) + k, ctx := keepertest.BTCStakingKeeper(t, nil, nil, nil) btcstaking.InitGenesis(ctx, *k, genesisState) got := btcstaking.ExportGenesis(ctx, *k) require.NotNil(t, got) diff --git a/x/btcstaking/keeper/bench_test.go b/x/btcstaking/keeper/bench_test.go index e32acbefd..3a41a8e1c 100644 --- a/x/btcstaking/keeper/bench_test.go +++ b/x/btcstaking/keeper/bench_test.go @@ -24,7 +24,8 @@ func benchBeginBlock(b *testing.B, numFPs int, numDelsUnderFP int) { defer ctrl.Finish() btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(b, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(b, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) changeAddress, err := datagen.GenRandomBTCAddress(r, h.Net) diff --git a/x/btcstaking/keeper/btc_height_index_test.go b/x/btcstaking/keeper/btc_height_index_test.go index 326fdf39a..a099df268 100644 --- a/x/btcstaking/keeper/btc_height_index_test.go +++ b/x/btcstaking/keeper/btc_height_index_test.go @@ -23,7 +23,7 @@ func FuzzBTCHeightIndex(f *testing.F) { // mock BTC light client btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) - keeper, ctx := keepertest.BTCStakingKeeper(t, btclcKeeper, nil) + keeper, ctx := keepertest.BTCStakingKeeper(t, btclcKeeper, nil, nil) // randomise Babylon height and BTC height babylonHeight := datagen.RandomInt(r, 100) diff --git a/x/btcstaking/keeper/grpc_query_test.go b/x/btcstaking/keeper/grpc_query_test.go index 312e2dcef..888a8f8e2 100644 --- a/x/btcstaking/keeper/grpc_query_test.go +++ b/x/btcstaking/keeper/grpc_query_test.go @@ -26,7 +26,7 @@ func FuzzActivatedHeight(f *testing.F) { r := rand.New(rand.NewSource(seed)) // Setup keeper and context - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) ctx = sdk.UnwrapSDKContext(ctx) // not activated yet @@ -51,7 +51,7 @@ func FuzzFinalityProviders(f *testing.F) { r := rand.New(rand.NewSource(seed)) // Setup keeper and context - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) ctx = sdk.UnwrapSDKContext(ctx) // Generate random finality providers and add them to kv store @@ -116,7 +116,7 @@ func FuzzFinalityProvider(f *testing.F) { f.Fuzz(func(t *testing.T, seed int64) { r := rand.New(rand.NewSource(seed)) // Setup keeper and context - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) ctx = sdk.UnwrapSDKContext(ctx) // Generate random finality providers and add them to kv store @@ -172,7 +172,7 @@ func FuzzPendingBTCDelegations(f *testing.F) { btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) btccKeeper.EXPECT().GetParams(gomock.Any()).Return(btcctypes.DefaultParams()).AnyTimes() - keeper, ctx := testkeeper.BTCStakingKeeper(t, btclcKeeper, btccKeeper) + keeper, ctx := testkeeper.BTCStakingKeeper(t, btclcKeeper, btccKeeper, nil) // covenant and slashing addr covenantSKs, covenantPKs, covenantQuorum := datagen.GenCovenantCommittee(r) @@ -274,7 +274,7 @@ func FuzzFinalityProviderPowerAtHeight(f *testing.F) { r := rand.New(rand.NewSource(seed)) // Setup keeper and context - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) // random finality provider fp, err := datagen.GenRandomFinalityProvider(r) @@ -323,7 +323,7 @@ func FuzzFinalityProviderCurrentVotingPower(f *testing.F) { r := rand.New(rand.NewSource(seed)) // Setup keeper and context - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) // random finality provider fp, err := datagen.GenRandomFinalityProvider(r) @@ -375,7 +375,7 @@ func FuzzActiveFinalityProvidersAtHeight(f *testing.F) { btclcKeeper.EXPECT().GetTipInfo(gomock.Any()).Return(&btclctypes.BTCHeaderInfo{Height: 10}).AnyTimes() btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) btccKeeper.EXPECT().GetParams(gomock.Any()).Return(btcctypes.DefaultParams()).AnyTimes() - keeper, ctx := testkeeper.BTCStakingKeeper(t, btclcKeeper, btccKeeper) + keeper, ctx := testkeeper.BTCStakingKeeper(t, btclcKeeper, btccKeeper, nil) // covenant and slashing addr covenantSKs, covenantPKs, covenantQuorum := datagen.GenCovenantCommittee(r) @@ -494,7 +494,7 @@ func FuzzFinalityProviderDelegations(f *testing.F) { btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) btccKeeper.EXPECT().GetParams(gomock.Any()).Return(btcctypes.DefaultParams()).AnyTimes() - keeper, ctx := testkeeper.BTCStakingKeeper(t, btclcKeeper, btccKeeper) + keeper, ctx := testkeeper.BTCStakingKeeper(t, btclcKeeper, btccKeeper, nil) // covenant and slashing addr covenantSKs, covenantPKs, covenantQuorum := datagen.GenCovenantCommittee(r) diff --git a/x/btcstaking/keeper/incentive_test.go b/x/btcstaking/keeper/incentive_test.go index 9b49da27f..9c827b785 100644 --- a/x/btcstaking/keeper/incentive_test.go +++ b/x/btcstaking/keeper/incentive_test.go @@ -23,7 +23,8 @@ func FuzzRecordVotingPowerDistCache(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) diff --git a/x/btcstaking/keeper/keeper.go b/x/btcstaking/keeper/keeper.go index 51515ae6a..e1d38689d 100644 --- a/x/btcstaking/keeper/keeper.go +++ b/x/btcstaking/keeper/keeper.go @@ -19,8 +19,9 @@ type ( cdc codec.BinaryCodec storeService corestoretypes.KVStoreService - btclcKeeper types.BTCLightClientKeeper - btccKeeper types.BtcCheckpointKeeper + btclcKeeper types.BTCLightClientKeeper + btccKeeper types.BtcCheckpointKeeper + FinalityKeeper types.FinalityKeeper hooks types.BtcStakingHooks @@ -37,6 +38,7 @@ func NewKeeper( btclcKeeper types.BTCLightClientKeeper, btccKeeper types.BtcCheckpointKeeper, + finalityKeeper types.FinalityKeeper, btcNet *chaincfg.Params, authority string, @@ -45,8 +47,9 @@ func NewKeeper( cdc: cdc, storeService: storeService, - btclcKeeper: btclcKeeper, - btccKeeper: btccKeeper, + btclcKeeper: btclcKeeper, + btccKeeper: btccKeeper, + FinalityKeeper: finalityKeeper, hooks: nil, diff --git a/x/btcstaking/keeper/keeper_test.go b/x/btcstaking/keeper/keeper_test.go index 157f6cc7b..10d2c5937 100644 --- a/x/btcstaking/keeper/keeper_test.go +++ b/x/btcstaking/keeper/keeper_test.go @@ -33,13 +33,19 @@ type Helper struct { BTCStakingKeeper *keeper.Keeper BTCLightClientKeeper *types.MockBTCLightClientKeeper BTCCheckpointKeeper *types.MockBtcCheckpointKeeper + FinalityKeeper *types.MockFinalityKeeper BTCStakingHooks *types.MockBtcStakingHooks MsgServer types.MsgServer Net *chaincfg.Params } -func NewHelper(t testing.TB, btclcKeeper *types.MockBTCLightClientKeeper, btccKeeper *types.MockBtcCheckpointKeeper) *Helper { - k, ctx := keepertest.BTCStakingKeeper(t, btclcKeeper, btccKeeper) +func NewHelper( + t testing.TB, + btclcKeeper *types.MockBTCLightClientKeeper, + btccKeeper *types.MockBtcCheckpointKeeper, + finalityKeeper *types.MockFinalityKeeper, +) *Helper { + k, ctx := keepertest.BTCStakingKeeper(t, btclcKeeper, btccKeeper, finalityKeeper) ctx = ctx.WithHeaderInfo(header.Info{Height: 1}) msgSrvr := keeper.NewMsgServerImpl(*k) diff --git a/x/btcstaking/keeper/msg_server_test.go b/x/btcstaking/keeper/msg_server_test.go index 0fd5853b4..4bc130c78 100644 --- a/x/btcstaking/keeper/msg_server_test.go +++ b/x/btcstaking/keeper/msg_server_test.go @@ -37,7 +37,8 @@ func FuzzMsgCreateFinalityProvider(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters h.GenAndApplyParams(r) @@ -143,7 +144,8 @@ func FuzzCreateBTCDelegation(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters h.GenAndApplyParams(r) @@ -187,7 +189,8 @@ func TestProperVersionInDelegation(t *testing.T) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters h.GenAndApplyParams(r) @@ -254,7 +257,8 @@ func FuzzAddCovenantSigs(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -318,7 +322,8 @@ func FuzzBTCUndelegate(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -390,7 +395,8 @@ func FuzzSelectiveSlashing(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -456,7 +462,8 @@ func FuzzSelectiveSlashing_StakingTx(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -532,7 +539,8 @@ func TestDoNotAllowDelegationWithoutFinalityProvider(t *testing.T) { btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) btccKeeper.EXPECT().GetParams(gomock.Any()).Return(btcctypes.DefaultParams()).AnyTimes() - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set covenant PK to params _, covenantPKs := h.GenAndApplyParams(r) @@ -699,7 +707,8 @@ func TestCorrectUnbondingTimeInDelegation(t *testing.T) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters _, _ = h.GenAndApplyCustomParams(r, tt.finalizationTimeout, tt.minUnbondingTime) @@ -771,7 +780,8 @@ func TestMinimalUnbondingRate(t *testing.T) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters, by default minimal unbonding value is 80% of staking value _, _ = h.GenAndApplyParams(r) diff --git a/x/btcstaking/keeper/params_test.go b/x/btcstaking/keeper/params_test.go index fc484dd3a..fcd589bd0 100644 --- a/x/btcstaking/keeper/params_test.go +++ b/x/btcstaking/keeper/params_test.go @@ -13,7 +13,7 @@ import ( ) func TestGetParams(t *testing.T) { - k, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + k, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) params := types.DefaultParams() err := k.SetParams(ctx, params) @@ -23,7 +23,7 @@ func TestGetParams(t *testing.T) { } func TestGetParamsVersions(t *testing.T) { - k, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + k, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) params := types.DefaultParams() pv := k.GetParamsWithVersion(ctx) @@ -56,7 +56,7 @@ func FuzzParamsVersioning(f *testing.F) { datagen.AddRandomSeedsToFuzzer(f, 10) f.Fuzz(func(t *testing.T, seed int64) { r := rand.New(rand.NewSource(seed)) - k, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + k, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) numVersionsToGenerate := r.Intn(100) + 1 params0 := k.GetParams(ctx) var generatedParams []*types.Params diff --git a/x/btcstaking/keeper/power_dist_change.go b/x/btcstaking/keeper/power_dist_change.go index bde774ce7..04f4e9385 100644 --- a/x/btcstaking/keeper/power_dist_change.go +++ b/x/btcstaking/keeper/power_dist_change.go @@ -113,6 +113,7 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( events []*types.EventPowerDistUpdate, maxActiveFps uint32, ) *types.VotingPowerDistCache { + height := uint64(sdk.UnwrapSDKContext(ctx).HeaderInfo().Height) // a map where key is finality provider's BTC PK hex and value is a list // of BTC delegations that newly become active under this provider activeBTCDels := map[string][]*types.BTCDelegation{} @@ -196,6 +197,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // add this finality provider to the new cache if it has voting power if fp.TotalVotingPower > 0 { + // voting power is not assigned if it does not have timestamped + // public randomness for this height + if k.FinalityKeeper.HasTimestampedPubRand(ctx, fp.BtcPk, height) { + fp.TotalVotingPower = 0 + } newDc.AddFinalityProviderDistInfo(&fp) } } @@ -232,6 +238,11 @@ func (k Keeper) ProcessAllPowerDistUpdateEvents( // add this finality provider to the new cache if it has voting power if fpDistInfo.TotalVotingPower > 0 { + // voting power is not assigned if it does not have timestamped + // public randomness for this height + if k.FinalityKeeper.HasTimestampedPubRand(ctx, fpBTCPK, height) { + fpDistInfo.TotalVotingPower = 0 + } newDc.AddFinalityProviderDistInfo(fpDistInfo) } } diff --git a/x/btcstaking/keeper/power_dist_change_test.go b/x/btcstaking/keeper/power_dist_change_test.go index 373063aaa..8a942dc3d 100644 --- a/x/btcstaking/keeper/power_dist_change_test.go +++ b/x/btcstaking/keeper/power_dist_change_test.go @@ -24,7 +24,8 @@ func FuzzProcessAllPowerDistUpdateEvents_Determinism(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters h.GenAndApplyParams(r) @@ -75,7 +76,8 @@ func FuzzFinalityProviderEvents(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -152,7 +154,8 @@ func FuzzBTCDelegationEvents(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) diff --git a/x/btcstaking/keeper/query_params_test.go b/x/btcstaking/keeper/query_params_test.go index a4a4282a8..1e4624c4a 100644 --- a/x/btcstaking/keeper/query_params_test.go +++ b/x/btcstaking/keeper/query_params_test.go @@ -10,7 +10,7 @@ import ( ) func TestParamsQuery(t *testing.T) { - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) params := types.DefaultParams() err := keeper.SetParams(ctx, params) @@ -22,7 +22,7 @@ func TestParamsQuery(t *testing.T) { } func TestParamsByVersionQuery(t *testing.T) { - keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil) + keeper, ctx := testkeeper.BTCStakingKeeper(t, nil, nil, nil) // starting with `1` as BTCStakingKeeper creates params with version 0 params1 := types.DefaultParams() diff --git a/x/btcstaking/keeper/voting_power_table_test.go b/x/btcstaking/keeper/voting_power_table_test.go index 48a68ff1b..f95b1aca7 100644 --- a/x/btcstaking/keeper/voting_power_table_test.go +++ b/x/btcstaking/keeper/voting_power_table_test.go @@ -24,7 +24,8 @@ func FuzzVotingPowerTable(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -162,7 +163,8 @@ func FuzzVotingPowerTable_ActiveFinalityProviders(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) @@ -246,7 +248,8 @@ func FuzzVotingPowerTable_ActiveFinalityProviderRotation(f *testing.F) { // mock BTC light client and BTC checkpoint modules btclcKeeper := types.NewMockBTCLightClientKeeper(ctrl) btccKeeper := types.NewMockBtcCheckpointKeeper(ctrl) - h := NewHelper(t, btclcKeeper, btccKeeper) + finalityKeeper := types.NewMockFinalityKeeper(ctrl) + h := NewHelper(t, btclcKeeper, btccKeeper, finalityKeeper) // set all parameters covenantSKs, _ := h.GenAndApplyParams(r) diff --git a/x/btcstaking/types/expected_keepers.go b/x/btcstaking/types/expected_keepers.go index 04e85989d..18122ef5c 100644 --- a/x/btcstaking/types/expected_keepers.go +++ b/x/btcstaking/types/expected_keepers.go @@ -20,6 +20,10 @@ type BtcCheckpointKeeper interface { GetParams(ctx context.Context) (p btcctypes.Params) } +type FinalityKeeper interface { + HasTimestampedPubRand(ctx context.Context, fpBtcPK *bbn.BIP340PubKey, height uint64) bool +} + type BtcStakingHooks interface { AfterFinalityProviderActivated(ctx context.Context, fpPk *bbn.BIP340PubKey) error } diff --git a/x/btcstaking/types/mocked_keepers.go b/x/btcstaking/types/mocked_keepers.go index a8b740fd0..2a0dd7bc2 100644 --- a/x/btcstaking/types/mocked_keepers.go +++ b/x/btcstaking/types/mocked_keepers.go @@ -131,6 +131,43 @@ func (mr *MockBtcCheckpointKeeperMockRecorder) GetPowLimit() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPowLimit", reflect.TypeOf((*MockBtcCheckpointKeeper)(nil).GetPowLimit)) } +// MockFinalityKeeper is a mock of FinalityKeeper interface. +type MockFinalityKeeper struct { + ctrl *gomock.Controller + recorder *MockFinalityKeeperMockRecorder +} + +// MockFinalityKeeperMockRecorder is the mock recorder for MockFinalityKeeper. +type MockFinalityKeeperMockRecorder struct { + mock *MockFinalityKeeper +} + +// NewMockFinalityKeeper creates a new mock instance. +func NewMockFinalityKeeper(ctrl *gomock.Controller) *MockFinalityKeeper { + mock := &MockFinalityKeeper{ctrl: ctrl} + mock.recorder = &MockFinalityKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockFinalityKeeper) EXPECT() *MockFinalityKeeperMockRecorder { + return m.recorder +} + +// HasTimestampedPubRand mocks base method. +func (m *MockFinalityKeeper) HasTimestampedPubRand(ctx context.Context, fpBtcPK *types.BIP340PubKey, height uint64) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasTimestampedPubRand", ctx, fpBtcPK, height) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasTimestampedPubRand indicates an expected call of HasTimestampedPubRand. +func (mr *MockFinalityKeeperMockRecorder) HasTimestampedPubRand(ctx, fpBtcPK, height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasTimestampedPubRand", reflect.TypeOf((*MockFinalityKeeper)(nil).HasTimestampedPubRand), ctx, fpBtcPK, height) +} + // MockBtcStakingHooks is a mock of BtcStakingHooks interface. type MockBtcStakingHooks struct { ctrl *gomock.Controller diff --git a/x/finality/keeper/msg_server.go b/x/finality/keeper/msg_server.go index 8282074fc..7fdb6172e 100644 --- a/x/finality/keeper/msg_server.go +++ b/x/finality/keeper/msg_server.go @@ -97,18 +97,11 @@ func (ms msgServer) AddFinalitySig(goCtx context.Context, req *types.MsgAddFinal return &types.MsgAddFinalitySigResponse{}, nil } - // find the public randomness commitment for this height from this finality provider - prCommit, err := ms.GetPubRandCommitForHeight(ctx, req.FpBtcPk, req.BlockHeight) + // find the timestamped public randomness commitment for this height from this finality provider + prCommit, err := ms.GetTimestampedPubRandCommitForHeight(ctx, req.FpBtcPk, req.BlockHeight) if err != nil { return nil, err } - // ensure the finality provider's last randomness commit is already finalised by BTC timestamping - finalizedEpoch := ms.GetLastFinalizedEpoch(ctx) - if finalizedEpoch < prCommit.EpochNum { - return nil, types.ErrPubRandCommitNotBTCTimestamped. - Wrapf("the finality provider %s last committed epoch number: %d, last finalized epoch number: %d", - fp.BtcPk.MarshalHex(), prCommit.EpochNum, finalizedEpoch) - } // verify the finality signature message w.r.t. the public randomness commitment // including the public randomness inclusion proof and the finality signature diff --git a/x/finality/keeper/public_randomness.go b/x/finality/keeper/public_randomness.go index 68cb87e84..1fef0066e 100644 --- a/x/finality/keeper/public_randomness.go +++ b/x/finality/keeper/public_randomness.go @@ -7,9 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" "cosmossdk.io/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + bbn "github.com/babylonlabs-io/babylon/types" "github.com/babylonlabs-io/babylon/x/finality/types" - sdk "github.com/cosmos/cosmos-sdk/types" ) /* @@ -33,6 +34,30 @@ func (k Keeper) GetPubRandCommitForHeight(ctx context.Context, fpBtcPK *bbn.BIP3 return nil, types.ErrPubRandNotFound } +// GetTimestampedPubRandCommitForHeight finds the public randomness commitment that includes the given +// height for the given finality provider +func (k Keeper) GetTimestampedPubRandCommitForHeight(ctx context.Context, fpBtcPK *bbn.BIP340PubKey, height uint64) (*types.PubRandCommit, error) { + prCommit, err := k.GetPubRandCommitForHeight(ctx, fpBtcPK, height) + if err != nil { + return nil, err + } + + // ensure the finality provider's last randomness commit is already finalised by BTC timestamping + finalizedEpoch := k.GetLastFinalizedEpoch(ctx) + if finalizedEpoch < prCommit.EpochNum { + return nil, types.ErrPubRandCommitNotBTCTimestamped. + Wrapf("the finality provider %s last committed epoch number: %d, last finalized epoch number: %d", + fpBtcPK.MarshalHex(), prCommit.EpochNum, finalizedEpoch) + } + + return prCommit, nil +} + +func (k Keeper) HasTimestampedPubRand(ctx context.Context, fpBtcPK *bbn.BIP340PubKey, height uint64) bool { + _, err := k.GetTimestampedPubRandCommitForHeight(ctx, fpBtcPK, height) + return err != nil +} + // SetPubRandCommit adds the given public randomness commitment for the given public key func (k Keeper) SetPubRandCommit(ctx context.Context, fpBtcPK *bbn.BIP340PubKey, prCommit *types.PubRandCommit) { store := k.pubRandCommitFpStore(ctx, fpBtcPK) diff --git a/x/finality/types/errors.go b/x/finality/types/errors.go index 6e3b89eea..12a2966d8 100644 --- a/x/finality/types/errors.go +++ b/x/finality/types/errors.go @@ -10,12 +10,11 @@ var ( ErrVoteNotFound = errorsmod.Register(ModuleName, 1101, "vote is not found") ErrHeightTooHigh = errorsmod.Register(ModuleName, 1102, "the chain has not reached the given height yet") ErrPubRandNotFound = errorsmod.Register(ModuleName, 1103, "public randomness is not found") - ErrPubRandCommitNotFound = errorsmod.Register(ModuleName, 1104, "public randomness commitment is not found") - ErrNoPubRandYet = errorsmod.Register(ModuleName, 1105, "the finality provider has not committed any public randomness yet") - ErrTooFewPubRand = errorsmod.Register(ModuleName, 1106, "the request contains too few public randomness") - ErrInvalidPubRand = errorsmod.Register(ModuleName, 1107, "the public randomness list is invalid") - ErrEvidenceNotFound = errorsmod.Register(ModuleName, 1108, "evidence is not found") - ErrInvalidFinalitySig = errorsmod.Register(ModuleName, 1109, "finality signature is not valid") - ErrNoSlashableEvidence = errorsmod.Register(ModuleName, 1110, "there is no slashable evidence") - ErrPubRandCommitNotBTCTimestamped = errorsmod.Register(ModuleName, 1111, "the public randomness commit is not BTC timestamped yet") + ErrNoPubRandYet = errorsmod.Register(ModuleName, 1104, "the finality provider has not committed any public randomness yet") + ErrTooFewPubRand = errorsmod.Register(ModuleName, 1105, "the request contains too few public randomness") + ErrInvalidPubRand = errorsmod.Register(ModuleName, 1106, "the public randomness list is invalid") + ErrEvidenceNotFound = errorsmod.Register(ModuleName, 1107, "evidence is not found") + ErrInvalidFinalitySig = errorsmod.Register(ModuleName, 1108, "finality signature is not valid") + ErrNoSlashableEvidence = errorsmod.Register(ModuleName, 1109, "there is no slashable evidence") + ErrPubRandCommitNotBTCTimestamped = errorsmod.Register(ModuleName, 1110, "the public randomness commit is not BTC timestamped yet") )