diff --git a/x/btcstaking/keeper/grpc_query.go b/x/btcstaking/keeper/grpc_query.go index d7455786c..1ca23dac7 100644 --- a/x/btcstaking/keeper/grpc_query.go +++ b/x/btcstaking/keeper/grpc_query.go @@ -5,14 +5,15 @@ import ( "encoding/hex" errorsmod "cosmossdk.io/errors" - bbn "github.com/babylonchain/babylon/types" - "github.com/babylonchain/babylon/x/btcstaking/types" "github.com/btcsuite/btcd/chaincfg/chainhash" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/query" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + bbn "github.com/babylonchain/babylon/types" + "github.com/babylonchain/babylon/x/btcstaking/types" ) var _ types.QueryServer = Keeper{} @@ -118,6 +119,18 @@ func (k Keeper) FinalityProviderPowerAtHeight(ctx context.Context, req *types.Qu return nil, status.Errorf(codes.InvalidArgument, "failed to unmarshal finality provider BTC PK hex: %v", err) } + if !k.HasFinalityProvider(ctx, *fpBTCPK) { + return nil, types.ErrFpNotFound + } + + store := k.votingPowerStore(ctx, req.Height) + iter := store.ReverseIterator(nil, nil) + defer iter.Close() + + if !iter.Valid() { + return nil, types.ErrVotingPowerTableNotUpdated.Wrapf("height: %d", req.Height) + } + sdkCtx := sdk.UnwrapSDKContext(ctx) power := k.GetVotingPower(sdkCtx, fpBTCPK.MustMarshal(), req.Height) diff --git a/x/btcstaking/keeper/grpc_query_test.go b/x/btcstaking/keeper/grpc_query_test.go index 353a1a910..37d4da2b6 100644 --- a/x/btcstaking/keeper/grpc_query_test.go +++ b/x/btcstaking/keeper/grpc_query_test.go @@ -285,13 +285,34 @@ func FuzzFinalityProviderPowerAtHeight(f *testing.F) { randomPower := datagen.RandomInt(r, 100) + 1 keeper.SetVotingPower(ctx, fp.BtcPk.MustMarshal(), randomHeight, randomPower) - req := &types.QueryFinalityProviderPowerAtHeightRequest{ + // happy case + req1 := &types.QueryFinalityProviderPowerAtHeightRequest{ FpBtcPkHex: fp.BtcPk.MarshalHex(), Height: randomHeight, } - resp, err := keeper.FinalityProviderPowerAtHeight(ctx, req) + resp, err := keeper.FinalityProviderPowerAtHeight(ctx, req1) require.NoError(t, err) require.Equal(t, randomPower, resp.VotingPower) + + // case where the voting power store is not updated in + // the given height + requestHeight := datagen.RandomIntOtherThan(r, int(randomHeight), 100) + 1 + req2 := &types.QueryFinalityProviderPowerAtHeightRequest{ + FpBtcPkHex: fp.BtcPk.MarshalHex(), + Height: requestHeight, + } + _, err = keeper.FinalityProviderPowerAtHeight(ctx, req2) + require.ErrorIs(t, err, types.ErrVotingPowerTableNotUpdated) + + // case where the given fp pk does not exist + randPk, err := datagen.GenRandomBIP340PubKey(r) + require.NoError(t, err) + req3 := &types.QueryFinalityProviderPowerAtHeightRequest{ + FpBtcPkHex: randPk.MarshalHex(), + Height: randomHeight, + } + _, err = keeper.FinalityProviderPowerAtHeight(ctx, req3) + require.ErrorIs(t, err, types.ErrFpNotFound) }) } diff --git a/x/btcstaking/types/errors.go b/x/btcstaking/types/errors.go index 8f65379e5..5a66ca43b 100644 --- a/x/btcstaking/types/errors.go +++ b/x/btcstaking/types/errors.go @@ -6,25 +6,26 @@ import ( // x/btcstaking module sentinel errors var ( - ErrFpNotFound = errorsmod.Register(ModuleName, 1100, "the finality provider is not found") - ErrBTCDelegatorNotFound = errorsmod.Register(ModuleName, 1101, "the BTC delegator is not found") - ErrBTCDelegationNotFound = errorsmod.Register(ModuleName, 1102, "the BTC delegation is not found") - ErrFpRegistered = errorsmod.Register(ModuleName, 1103, "the finality provider has already been registered") - ErrFpAlreadySlashed = errorsmod.Register(ModuleName, 1104, "the finality provider has already been slashed") - ErrBTCStakingNotActivated = errorsmod.Register(ModuleName, 1105, "the BTC staking protocol is not activated yet") - ErrBTCHeightNotFound = errorsmod.Register(ModuleName, 1106, "the BTC height is not found") - ErrReusedStakingTx = errorsmod.Register(ModuleName, 1107, "the BTC staking tx is already used") - ErrInvalidCovenantPK = errorsmod.Register(ModuleName, 1108, "the BTC staking tx specifies a wrong covenant PK") - ErrInvalidStakingTx = errorsmod.Register(ModuleName, 1109, "the BTC staking tx is not valid") - ErrInvalidSlashingTx = errorsmod.Register(ModuleName, 1110, "the BTC slashing tx is not valid") - ErrInvalidCovenantSig = errorsmod.Register(ModuleName, 1111, "the covenant signature is not valid") - ErrCommissionLTMinRate = errorsmod.Register(ModuleName, 1112, "commission cannot be less than min rate") - ErrCommissionGTMaxRate = errorsmod.Register(ModuleName, 1113, "commission cannot be more than one") - ErrInvalidDelegationState = errorsmod.Register(ModuleName, 1114, "Unexpected delegation state") - ErrInvalidUnbondingTx = errorsmod.Register(ModuleName, 1115, "the BTC unbonding tx is not valid") - ErrRewardDistCacheNotFound = errorsmod.Register(ModuleName, 1116, "the reward distribution cache is not found") - ErrEmptyFpList = errorsmod.Register(ModuleName, 1117, "the finality provider list is empty") - ErrInvalidProofOfPossession = errorsmod.Register(ModuleName, 1118, "the proof of possession is not valid") - ErrDuplicatedFp = errorsmod.Register(ModuleName, 1119, "the staking request contains duplicated finality provider public key") - ErrInvalidBTCUndelegateReq = errorsmod.Register(ModuleName, 1120, "invalid undelegation request") + ErrFpNotFound = errorsmod.Register(ModuleName, 1100, "the finality provider is not found") + ErrBTCDelegatorNotFound = errorsmod.Register(ModuleName, 1101, "the BTC delegator is not found") + ErrBTCDelegationNotFound = errorsmod.Register(ModuleName, 1102, "the BTC delegation is not found") + ErrFpRegistered = errorsmod.Register(ModuleName, 1103, "the finality provider has already been registered") + ErrFpAlreadySlashed = errorsmod.Register(ModuleName, 1104, "the finality provider has already been slashed") + ErrBTCStakingNotActivated = errorsmod.Register(ModuleName, 1105, "the BTC staking protocol is not activated yet") + ErrBTCHeightNotFound = errorsmod.Register(ModuleName, 1106, "the BTC height is not found") + ErrReusedStakingTx = errorsmod.Register(ModuleName, 1107, "the BTC staking tx is already used") + ErrInvalidCovenantPK = errorsmod.Register(ModuleName, 1108, "the BTC staking tx specifies a wrong covenant PK") + ErrInvalidStakingTx = errorsmod.Register(ModuleName, 1109, "the BTC staking tx is not valid") + ErrInvalidSlashingTx = errorsmod.Register(ModuleName, 1110, "the BTC slashing tx is not valid") + ErrInvalidCovenantSig = errorsmod.Register(ModuleName, 1111, "the covenant signature is not valid") + ErrCommissionLTMinRate = errorsmod.Register(ModuleName, 1112, "commission cannot be less than min rate") + ErrCommissionGTMaxRate = errorsmod.Register(ModuleName, 1113, "commission cannot be more than one") + ErrInvalidDelegationState = errorsmod.Register(ModuleName, 1114, "Unexpected delegation state") + ErrInvalidUnbondingTx = errorsmod.Register(ModuleName, 1115, "the BTC unbonding tx is not valid") + ErrRewardDistCacheNotFound = errorsmod.Register(ModuleName, 1116, "the reward distribution cache is not found") + ErrEmptyFpList = errorsmod.Register(ModuleName, 1117, "the finality provider list is empty") + ErrInvalidProofOfPossession = errorsmod.Register(ModuleName, 1118, "the proof of possession is not valid") + ErrDuplicatedFp = errorsmod.Register(ModuleName, 1119, "the staking request contains duplicated finality provider public key") + ErrInvalidBTCUndelegateReq = errorsmod.Register(ModuleName, 1120, "invalid undelegation request") + ErrVotingPowerTableNotUpdated = errorsmod.Register(ModuleName, 1121, "voting power table has not been updated") )