Skip to content

Commit 308dbe8

Browse files
kien6034hoank101TropicalDog17
authored
fix legacy query staking (#79)
* fix legacy query staking * bet * fix legacy params for validator delegation fallback * Bet * bet --------- Co-authored-by: Khanh Hoa <hoa@notional.ventures> Co-authored-by: Tuan Tran <tropicaldog17@gmail.com>
1 parent d5501fb commit 308dbe8

5 files changed

Lines changed: 590 additions & 5 deletions

File tree

app/modules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func appModules(
156156
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, app.GetSubspace(minttypes.ModuleName)),
157157
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(slashingtypes.ModuleName), app.InterfaceRegistry()),
158158
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.GetSubspace(distrtypes.ModuleName)),
159-
customstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.ParamsKeeper, app.GetSubspace(stakingtypes.ModuleName)),
159+
customstaking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.ParamsKeeper, app.GetSubspace(stakingtypes.ModuleName), app.GetKey(stakingtypes.StoreKey)),
160160
upgrade.NewAppModule(app.UpgradeKeeper, app.AccountKeeper.AddressCodec()),
161161
evidence.NewAppModule(app.EvidenceKeeper),
162162
params.NewAppModule(app.ParamsKeeper),

custom/staking/module.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"fmt"
66

7+
storetypes "cosmossdk.io/store/types"
78
customtypes "github.com/classic-terra/core/v4/custom/staking/types"
89
core "github.com/classic-terra/core/v4/types"
910
"github.com/cosmos/cosmos-sdk/codec"
@@ -44,9 +45,11 @@ func (am AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
4445
type AppModule struct {
4546
staking.AppModule
4647

48+
cdc codec.Codec
4749
keeper *keeper.Keeper
4850
paramsKeeper paramskeeper.Keeper
4951
ss paramtypes.Subspace
52+
storeKey storetypes.StoreKey
5053
}
5154

5255
// NewAppModule creates a new AppModule object
@@ -56,12 +59,15 @@ func NewAppModule(cdc codec.Codec,
5659
bk stakingtypes.BankKeeper,
5760
pk paramskeeper.Keeper,
5861
ss paramtypes.Subspace,
62+
storeKey storetypes.StoreKey,
5963
) AppModule {
6064
return AppModule{
6165
AppModule: staking.NewAppModule(cdc, keeper, ak, bk, ss),
66+
cdc: cdc,
6267
keeper: keeper,
6368
paramsKeeper: pk,
6469
ss: ss,
70+
storeKey: storeKey,
6571
}
6672
}
6773

@@ -72,7 +78,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
7278
querier := keeper.Querier{Keeper: am.keeper}
7379
stakingtypes.RegisterQueryServer(
7480
cfg.QueryServer(),
75-
NewLegacyQueryServer(querier, am.ss, am.keeper),
81+
NewLegacyQueryServer(querier, am.ss, am.keeper, am.cdc, am.storeKey),
7682
)
7783

7884
m := keeper.NewMigrator(am.keeper, am.ss)

custom/staking/query_server.go

Lines changed: 144 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@ package staking
22

33
import (
44
"context"
5+
"strconv"
6+
"strings"
57

68
"cosmossdk.io/math"
9+
"cosmossdk.io/store/prefix"
10+
storetypes "cosmossdk.io/store/types"
711
legacytypes "github.com/classic-terra/core/v4/custom/staking/types"
812
legacyupgrade "github.com/classic-terra/core/v4/custom/upgrade/legacy"
13+
"github.com/cosmos/cosmos-sdk/codec"
914
sdk "github.com/cosmos/cosmos-sdk/types"
15+
"github.com/cosmos/cosmos-sdk/types/query"
1016
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
1117
"github.com/cosmos/cosmos-sdk/x/staking/keeper"
1218
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
19+
"google.golang.org/grpc/codes"
20+
"google.golang.org/grpc/status"
1321
)
1422

1523
// LegacyQueryServer wraps the staking QueryServer and sets legacy parameters for pre-upgrade height queries
@@ -18,18 +26,29 @@ type LegacyQueryServer struct {
1826
stakingtypes.QueryServer
1927
keeper *keeper.Keeper
2028
legacySubspace paramtypes.Subspace
29+
cdc codec.BinaryCodec
30+
storeKey storetypes.StoreKey
2131
}
2232

23-
// NewLegacyQueryServer creates a new LegacyQueryServer instance
33+
// NewLegacyQueryServer creates a new LegacyQueryServer instance.
34+
//
35+
// `cdc` and `storeKey` are required for the pre-v5-staking-migration
36+
// ValidatorDelegations fallback path, which scans the primary DelegationKey
37+
// (0x31) prefix directly when the SDK's reverse-index (0x71) hasn't been
38+
// backfilled at the queried height.
2439
func NewLegacyQueryServer(
2540
originalServer stakingtypes.QueryServer,
2641
legacySubspace paramtypes.Subspace,
2742
keeper *keeper.Keeper,
43+
cdc codec.BinaryCodec,
44+
storeKey storetypes.StoreKey,
2845
) stakingtypes.QueryServer {
2946
return &LegacyQueryServer{
3047
QueryServer: originalServer,
3148
keeper: keeper,
3249
legacySubspace: legacySubspace,
50+
cdc: cdc,
51+
storeKey: storeKey,
3352
}
3453
}
3554

@@ -111,7 +130,92 @@ func (q *LegacyQueryServer) Validator(ctx context.Context, req *stakingtypes.Que
111130
}
112131

113132
func (q *LegacyQueryServer) ValidatorDelegations(ctx context.Context, req *stakingtypes.QueryValidatorDelegationsRequest) (*stakingtypes.QueryValidatorDelegationsResponse, error) {
114-
return q.QueryServer.ValidatorDelegations(q.ensureLegacyParams(ctx), req)
133+
ensuredCtx := q.ensureLegacyParams(ctx)
134+
sdkCtx := sdk.UnwrapSDKContext(ensuredCtx)
135+
if legacyupgrade.IsPreStakingV5(sdkCtx.ChainID(), sdkCtx.BlockHeight()) {
136+
return q.validatorDelegationsLegacy(sdkCtx, req)
137+
}
138+
return q.QueryServer.ValidatorDelegations(ensuredCtx, req)
139+
}
140+
141+
// validatorDelegationsLegacy reproduces cosmos-sdk's unexported
142+
// `getValidatorDelegationsLegacy` (x/staking/keeper/grpc_query.go): it scans
143+
// the primary DelegationKey (0x31) prefix and filters by validator. Used for
144+
// archive queries at heights before the v4→v5 staking migration backfilled the
145+
// DelegationByValIndexKey (0x71) reverse-index that the SDK's default
146+
// ValidatorDelegations now relies on.
147+
func (q *LegacyQueryServer) validatorDelegationsLegacy(
148+
ctx sdk.Context, req *stakingtypes.QueryValidatorDelegationsRequest,
149+
) (*stakingtypes.QueryValidatorDelegationsResponse, error) {
150+
if req == nil {
151+
return nil, status.Error(codes.InvalidArgument, "empty request")
152+
}
153+
if req.ValidatorAddr == "" {
154+
return nil, status.Error(codes.InvalidArgument, "validator address cannot be empty")
155+
}
156+
if _, err := sdk.ValAddressFromBech32(req.ValidatorAddr); err != nil {
157+
return nil, status.Error(codes.InvalidArgument, err.Error())
158+
}
159+
160+
store := ctx.KVStore(q.storeKey)
161+
delStore := prefix.NewStore(store, stakingtypes.DelegationKey)
162+
163+
dels, pageRes, err := query.GenericFilteredPaginate(
164+
q.cdc, delStore, req.Pagination,
165+
func(_ []byte, d *stakingtypes.Delegation) (*stakingtypes.Delegation, error) {
166+
if !strings.EqualFold(d.GetValidatorAddr(), req.ValidatorAddr) {
167+
return nil, nil
168+
}
169+
return d, nil
170+
},
171+
func() *stakingtypes.Delegation { return &stakingtypes.Delegation{} },
172+
)
173+
if err != nil {
174+
return nil, status.Error(codes.Internal, err.Error())
175+
}
176+
177+
delegations := make(stakingtypes.Delegations, 0, len(dels))
178+
for _, d := range dels {
179+
delegations = append(delegations, *d)
180+
}
181+
182+
delResps, err := q.delegationsToDelegationResponses(ctx, delegations)
183+
if err != nil {
184+
return nil, status.Error(codes.Internal, err.Error())
185+
}
186+
187+
return &stakingtypes.QueryValidatorDelegationsResponse{
188+
DelegationResponses: delResps,
189+
Pagination: pageRes,
190+
}, nil
191+
}
192+
193+
// delegationsToDelegationResponses mirrors the unexported helper of the same
194+
// name in cosmos-sdk's staking keeper: it looks up the validator for each
195+
// delegation and converts shares to bonded balance.
196+
func (q *LegacyQueryServer) delegationsToDelegationResponses(
197+
ctx sdk.Context, delegations stakingtypes.Delegations,
198+
) (stakingtypes.DelegationResponses, error) {
199+
bondDenom, err := q.keeper.BondDenom(ctx)
200+
if err != nil {
201+
return nil, err
202+
}
203+
resps := make(stakingtypes.DelegationResponses, 0, len(delegations))
204+
for _, d := range delegations {
205+
valAddr, err := sdk.ValAddressFromBech32(d.GetValidatorAddr())
206+
if err != nil {
207+
return nil, err
208+
}
209+
val, err := q.keeper.GetValidator(ctx, valAddr)
210+
if err != nil {
211+
return nil, err
212+
}
213+
balance := val.TokensFromShares(d.Shares).TruncateInt()
214+
resps = append(resps, stakingtypes.NewDelegationResp(
215+
d.GetDelegatorAddr(), d.GetValidatorAddr(), d.Shares, sdk.NewCoin(bondDenom, balance),
216+
))
217+
}
218+
return resps, nil
115219
}
116220

117221
func (q *LegacyQueryServer) ValidatorUnbondingDelegations(ctx context.Context, req *stakingtypes.QueryValidatorUnbondingDelegationsRequest) (*stakingtypes.QueryValidatorUnbondingDelegationsResponse, error) {
@@ -147,7 +251,44 @@ func (q *LegacyQueryServer) DelegatorValidator(ctx context.Context, req *staking
147251
}
148252

149253
func (q *LegacyQueryServer) HistoricalInfo(ctx context.Context, req *stakingtypes.QueryHistoricalInfoRequest) (*stakingtypes.QueryHistoricalInfoResponse, error) {
150-
return q.QueryServer.HistoricalInfo(q.ensureLegacyParams(ctx), req)
254+
ensuredCtx := q.ensureLegacyParams(ctx)
255+
sdkCtx := sdk.UnwrapSDKContext(ensuredCtx)
256+
if legacyupgrade.IsPreStakingV5(sdkCtx.ChainID(), sdkCtx.BlockHeight()) {
257+
return q.historicalInfoLegacy(sdkCtx, req)
258+
}
259+
return q.QueryServer.HistoricalInfo(ensuredCtx, req)
260+
}
261+
262+
// historicalInfoLegacy reads HistoricalInfo using the pre-v5-staking-migration
263+
// key encoding: prefix 0x50 followed by the ASCII-decimal height string. The
264+
// v5 migration (cosmos-sdk@v0.53.6/x/staking/migrations/v5/store.go:39) re-keys
265+
// every entry to a big-endian uint64; before that migration ran (block
266+
// 28214400 on Columbus, 28917279 on Rebel-2) IAVL state contains only the old
267+
// string-format keys, so the SDK's GetHistoricalInfo — which constructs the
268+
// new binary key — misses and returns NotFound.
269+
func (q *LegacyQueryServer) historicalInfoLegacy(
270+
ctx sdk.Context, req *stakingtypes.QueryHistoricalInfoRequest,
271+
) (*stakingtypes.QueryHistoricalInfoResponse, error) {
272+
if req == nil {
273+
return nil, status.Error(codes.InvalidArgument, "empty request")
274+
}
275+
if req.Height < 0 {
276+
return nil, status.Error(codes.InvalidArgument, "height cannot be negative")
277+
}
278+
279+
store := ctx.KVStore(q.storeKey)
280+
legacyKey := append([]byte{}, stakingtypes.HistoricalInfoKey...)
281+
legacyKey = append(legacyKey, []byte(strconv.FormatInt(req.Height, 10))...)
282+
bz := store.Get(legacyKey)
283+
if bz == nil {
284+
return nil, status.Errorf(codes.NotFound, "historical info for height %d not found", req.Height)
285+
}
286+
287+
var hi stakingtypes.HistoricalInfo
288+
if err := q.cdc.Unmarshal(bz, &hi); err != nil {
289+
return nil, status.Error(codes.Internal, err.Error())
290+
}
291+
return &stakingtypes.QueryHistoricalInfoResponse{Hist: &hi}, nil
151292
}
152293

153294
func (q *LegacyQueryServer) Pool(ctx context.Context, req *stakingtypes.QueryPoolRequest) (*stakingtypes.QueryPoolResponse, error) {

0 commit comments

Comments
 (0)