From 105ea4b64a1e008afc85d2625f2aa393fab9dd55 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 18 Jan 2021 17:17:11 +0100 Subject: [PATCH 01/41] Change account store key in x/bank --- x/bank/keeper/grpc_query.go | 5 +---- x/bank/keeper/send.go | 9 ++------- x/bank/keeper/view.go | 19 +++++++++++++------ x/bank/types/key.go | 8 ++------ x/bank/types/key_test.go | 4 +++- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index bcf143b8aa14..433695d646d6 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -6,7 +6,6 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -57,9 +56,7 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances sdkCtx := sdk.UnwrapSDKContext(ctx) balances := sdk.NewCoins() - store := sdkCtx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + accountStore := k.getAccountStore(sdkCtx, addr) pageRes, err := query.Paginate(accountStore, req.Pagination, func(key []byte, value []byte) error { var result sdk.Coin diff --git a/x/bank/keeper/send.go b/x/bank/keeper/send.go index c1000b7d3025..694c43211e07 100644 --- a/x/bank/keeper/send.go +++ b/x/bank/keeper/send.go @@ -2,7 +2,6 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -233,9 +232,7 @@ func (k BaseSendKeeper) ClearBalances(ctx sdk.Context, addr sdk.AccAddress) { return false }) - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + accountStore := k.getAccountStore(ctx, addr) for _, key := range keys { accountStore.Delete(key) @@ -264,9 +261,7 @@ func (k BaseSendKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, balance.String()) } - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + accountStore := k.getAccountStore(ctx, addr) bz := k.cdc.MustMarshalBinaryBare(&balance) accountStore.Set([]byte(balance.Denom), bz) diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index d4bcabad2b62..c893c096dbb3 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -97,9 +97,7 @@ func (k BaseViewKeeper) GetAccountsBalances(ctx sdk.Context) []types.Balance { // GetBalance returns the balance of a specific denomination for a given account // by address. func (k BaseViewKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + accountStore := k.getAccountStore(ctx, addr) bz := accountStore.Get([]byte(denom)) if bz == nil { @@ -116,9 +114,7 @@ func (k BaseViewKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom s // provides the token balance to a callback. If true is returned from the // callback, iteration is halted. func (k BaseViewKeeper) IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(sdk.Coin) bool) { - store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + accountStore := k.getAccountStore(ctx, addr) iterator := accountStore.Iterator(nil, nil) defer iterator.Close() @@ -214,3 +210,14 @@ func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) er return nil } + +// getAccountStore gets the account store of the given address. +func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) prefix.Store { + store := ctx.KVStore(k.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + // Addresses are length-prefixed in the store key, the SDK also has a hard + // requirement on addresses being max 255 bytes long. + addrLen := byte(len(addr)) + + return prefix.NewStore(balancesStore, append([]byte{addrLen}, addr.Bytes()...)) +} diff --git a/x/bank/types/key.go b/x/bank/types/key.go index ec8619d00185..990d4609823e 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -1,8 +1,6 @@ package types import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -37,10 +35,8 @@ func DenomMetadataKey(denom string) []byte { // store. The key must not contain the perfix BalancesPrefix as the prefix store // iterator discards the actual prefix. func AddressFromBalancesStore(key []byte) sdk.AccAddress { - addr := key[:sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic(fmt.Sprintf("unexpected account address key length; got: %d, expected: %d", len(addr), sdk.AddrLen)) - } + addrLen := key[0] + addr := key[1 : addrLen+1] return sdk.AccAddress(addr) } diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index f3b5717fbecb..4630acc312cd 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -19,8 +19,10 @@ func cloneAppend(bz []byte, tail []byte) (res []byte) { func TestAddressFromBalancesStore(t *testing.T) { addr, err := sdk.AccAddressFromBech32("cosmos1n88uc38xhjgxzw9nwre4ep2c8ga4fjxcar6mn7") require.NoError(t, err) + addrLen := len(addr) + require.Equal(t, 20, addrLen) - key := cloneAppend(addr.Bytes(), []byte("stake")) + key := cloneAppend(append([]byte{byte(addrLen)}, addr.Bytes()...), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } From ade4a9470dd3983e007eb21e298f12fe1eba17d2 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 20 Jan 2021 15:00:19 +0100 Subject: [PATCH 02/41] Fix pagination test --- types/query/filtered_pagination_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index dbd2057da473..166c788808a2 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -143,7 +143,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr1.Bytes()) + accountStore := prefix.NewStore(balancesStore, append([]byte{byte(len(addr1))}, addr1.Bytes()...)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { From 64cfb4653c960ec353254191514f5b6cc38fd33e Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 20 Jan 2021 15:24:57 +0100 Subject: [PATCH 03/41] Fix merge master --- x/bank/keeper/grpc_query.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 1dadf63d73df..b8f69ef1275b 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -6,6 +6,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/x/bank/types" From f7c4a006018a7abe46e780feabe1570c98ca25c3 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 12:18:56 +0100 Subject: [PATCH 04/41] Fix staking keys.go --- x/staking/types/keys.go | 150 ++++++++++++++++++----------------- x/staking/types/keys_test.go | 20 ++--- 2 files changed, 88 insertions(+), 82 deletions(-) diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 40d62244a041..a8066f6c5d8d 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -48,24 +48,24 @@ var ( HistoricalInfoKey = []byte{0x50} // prefix for the historical info ) -// gets the key for the validator with address +// GetValidatorKey gets the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, operatorAddr.Bytes()...) + return append(append(ValidatorsKey, byte(len(operatorAddr))), operatorAddr.Bytes()...) } -// gets the key for the validator with pubkey +// GetValidatorByConsAddrKey gets the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, addr.Bytes()...) + return append(append(ValidatorsByConsAddrKey, byte(len(addr))), addr.Bytes()...) } -// Get the validator operator address from LastValidatorPowerKey +// AddressFromLastValidatorPowerKey gets the validator operator address from LastValidatorPowerKey func AddressFromLastValidatorPowerKey(key []byte) []byte { - return key[1:] // remove prefix bytes + return key[2:] // remove prefix bytes and address length } -// get the validator by power index. +// GetValidatorsByPowerIndexKey gets the validator by power index. // Power index is the key used in the power-store, and represents the relative // power ranking of the validator. // VALUE: validator operator address ([]byte) @@ -80,39 +80,39 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { powerBytes := consensusPowerBytes powerBytesLen := len(powerBytes) // 8 - // key is of format prefix || powerbytes || addrBytes - key := make([]byte, 1+powerBytesLen+sdk.AddrLen) - - key[0] = ValidatorsByPowerIndexKey[0] - copy(key[1:powerBytesLen+1], powerBytes) addr, err := sdk.ValAddressFromBech32(validator.OperatorAddress) if err != nil { panic(err) } operAddrInvr := sdk.CopyBytes(addr) + addrLen := len(operAddrInvr) for i, b := range operAddrInvr { operAddrInvr[i] = ^b } - copy(key[powerBytesLen+1:], operAddrInvr) + // key is of format prefix || powerbytes || addrLen (1byte) || addrBytes + key := make([]byte, 1+powerBytesLen+1+addrLen) + + key[0] = ValidatorsByPowerIndexKey[0] + copy(key[1:powerBytesLen+1], powerBytes) + key[powerBytesLen+1] = byte(addrLen) + copy(key[powerBytesLen+2:], operAddrInvr) return key } -// get the bonded validator index key for an operator address +// GetLastValidatorPowerKey gets the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, operator...) + return append(append(LastValidatorPowerKey, byte(len(operator))), operator...) } -// parse the validators operator address from power rank key +// ParseValidatorPowerRankKey parses the validators operator address from power rank key func ParseValidatorPowerRankKey(key []byte) (operAddr []byte) { powerBytesLen := 8 - if len(key) != 1+powerBytesLen+sdk.AddrLen { - panic("Invalid validator power rank key length") - } - operAddr = sdk.CopyBytes(key[powerBytesLen+1:]) + // key is of format prefix (1 byte) || powerbytes || addrLen (1byte) || addrBytes + operAddr = sdk.CopyBytes(key[powerBytesLen+2:]) for i, b := range operAddr { operAddr[i] = ^b @@ -165,55 +165,54 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { return ts, int64(height), nil } -// gets the key for delegator bond with validator +// GetDelegationKey gets the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), valAddr.Bytes()...) + return append(append(GetDelegationsKey(delAddr), byte(len(delAddr))), valAddr.Bytes()...) } -// gets the prefix for a delegator for all validators +// GetDelegationsKey gets the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, delAddr.Bytes()...) + return append(append(DelegationKey, byte(len(delAddr))), delAddr.Bytes()...) } -// gets the key for an unbonding delegation by delegator and validator addr +// GetUBDKey gets the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { return append( - GetUBDsKey(delAddr.Bytes()), - valAddr.Bytes()...) + append(GetUBDsKey(delAddr.Bytes()), byte(len(valAddr))), + valAddr.Bytes()..., + ) } -// gets the index-key for an unbonding delegation, stored by validator-index +// GetUBDByValIndexKey gets the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), delAddr.Bytes()...) + return append(append(GetUBDsByValIndexKey(valAddr), byte(len(delAddr))), delAddr.Bytes()...) } -// rearranges the ValIndexKey to get the UBDKey +// GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { addrs := indexKey[1:] // remove prefix bytes - if len(addrs) != 2*sdk.AddrLen { - panic("unexpected key length") - } - valAddr := addrs[:sdk.AddrLen] - delAddr := addrs[sdk.AddrLen:] + valAddrLen := addrs[0] + valAddr := addrs[1 : 1+valAddrLen] + delAddr := addrs[valAddrLen+2:] return GetUBDKey(delAddr, valAddr) } -// gets the prefix for all unbonding delegations from a delegator +// GetUBDsKey gets the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, delAddr.Bytes()...) + return append(append(UnbondingDelegationKey, byte(len(delAddr))), delAddr.Bytes()...) } -// gets the prefix keyspace for the indexes of unbonding delegations for a validator +// GetUBDsByValIndexKey gets the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, valAddr.Bytes()...) + return append(append(UnbondingDelegationByValIndexKey, byte(len(valAddr))), valAddr.Bytes()...) } -// gets the prefix for all unbonding delegations from a delegator +// GetUnbondingDelegationTimeKey gets the prefix for all unbonding delegations from a delegator func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { bz := sdk.FormatTimeBytes(timestamp) return append(UnbondingQueueKey, bz...) @@ -222,69 +221,76 @@ func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { // GetREDKey returns a key prefix for indexing a redelegation from a delegator // and source validator to a destination validator. func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { - key := make([]byte, 1+sdk.AddrLen*3) + // key is of the form GetREDsKey || valSrcAddrLen (1 byte) || valSrcAddr || valDstAddrLen (1 byte) || valDstAddr + key := make([]byte, 1+3+len(delAddr)+len(valSrcAddr)+len(valDstAddr)) - copy(key[0:sdk.AddrLen+1], GetREDsKey(delAddr.Bytes())) - copy(key[sdk.AddrLen+1:2*sdk.AddrLen+1], valSrcAddr.Bytes()) - copy(key[2*sdk.AddrLen+1:3*sdk.AddrLen+1], valDstAddr.Bytes()) + copy(key[0:2+len(delAddr)], GetREDsKey(delAddr.Bytes())) + key[2+len(delAddr)] = byte(len(valSrcAddr)) + copy(key[3+len(delAddr):3+len(delAddr)+len(valSrcAddr)], valSrcAddr.Bytes()) + key[3+len(delAddr)+len(valSrcAddr)] = byte(len(valDstAddr)) + copy(key[4+len(delAddr)+len(valSrcAddr):], valDstAddr.Bytes()) return key } -// gets the index-key for a redelegation, stored by source-validator-index +// GetREDByValSrcIndexKey gets the index-key for a redelegation, stored by source-validator-index // VALUE: none (key rearrangement used) func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { REDSFromValsSrcKey := GetREDsFromValSrcIndexKey(valSrcAddr) offset := len(REDSFromValsSrcKey) - // key is of the form REDSFromValsSrcKey || delAddr || valDstAddr - key := make([]byte, len(REDSFromValsSrcKey)+2*sdk.AddrLen) + // key is of the form REDSFromValsSrcKey || delAddrLen (1 byte) || delAddr || valDstAddrLen (1 byte) || valDstAddr + key := make([]byte, offset+2+len(delAddr)+len(valDstAddr)) copy(key[0:offset], REDSFromValsSrcKey) - copy(key[offset:offset+sdk.AddrLen], delAddr.Bytes()) - copy(key[offset+sdk.AddrLen:offset+2*sdk.AddrLen], valDstAddr.Bytes()) + key[offset] = byte(len(delAddr)) + copy(key[offset+1:offset+1+len(delAddr)], delAddr.Bytes()) + key[offset+1+len(delAddr)] = byte(len(valDstAddr)) + copy(key[offset+2+len(delAddr):], valDstAddr.Bytes()) return key } -// gets the index-key for a redelegation, stored by destination-validator-index +// GetREDByValDstIndexKey gets the index-key for a redelegation, stored by destination-validator-index // VALUE: none (key rearrangement used) func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { REDSToValsDstKey := GetREDsToValDstIndexKey(valDstAddr) offset := len(REDSToValsDstKey) - // key is of the form REDSToValsDstKey || delAddr || valSrcAddr - key := make([]byte, len(REDSToValsDstKey)+2*sdk.AddrLen) + // key is of the form REDSToValsDstKey || delAddrLen (1 byte) || delAddr || valSrcAddrLen (1 byte) || valSrcAddr + key := make([]byte, offset+2+len(delAddr)+len(valSrcAddr)) copy(key[0:offset], REDSToValsDstKey) - copy(key[offset:offset+sdk.AddrLen], delAddr.Bytes()) - copy(key[offset+sdk.AddrLen:offset+2*sdk.AddrLen], valSrcAddr.Bytes()) + key[offset] = byte(len(delAddr)) + copy(key[offset+1:offset+1+len(delAddr)], delAddr.Bytes()) + key[offset+1+len(delAddr)] = byte(len(valSrcAddr)) + copy(key[offset+2+len(delAddr):], valSrcAddr.Bytes()) return key } // GetREDKeyFromValSrcIndexKey rearranges the ValSrcIndexKey to get the REDKey func GetREDKeyFromValSrcIndexKey(indexKey []byte) []byte { - // note that first byte is prefix byte - if len(indexKey) != 3*sdk.AddrLen+1 { - panic("unexpected key length") - } + // note that first byte is prefix byte, which we remove + addrs := indexKey[1:] - valSrcAddr := indexKey[1 : sdk.AddrLen+1] - delAddr := indexKey[sdk.AddrLen+1 : 2*sdk.AddrLen+1] - valDstAddr := indexKey[2*sdk.AddrLen+1 : 3*sdk.AddrLen+1] + valSrcAddrLen := addrs[0] + valSrcAddr := addrs[1 : valSrcAddrLen+1] + delAddrLen := addrs[valSrcAddrLen+1] + delAddr := addrs[valSrcAddrLen+2 : valSrcAddrLen+2+delAddrLen] + valDstAddr := addrs[valSrcAddrLen+delAddrLen+3:] return GetREDKey(delAddr, valSrcAddr, valDstAddr) } // GetREDKeyFromValDstIndexKey rearranges the ValDstIndexKey to get the REDKey func GetREDKeyFromValDstIndexKey(indexKey []byte) []byte { - // note that first byte is prefix byte - if len(indexKey) != 3*sdk.AddrLen+1 { - panic("unexpected key length") - } + // note that first byte is prefix byte, which we remove + addrs := indexKey[1:] - valDstAddr := indexKey[1 : sdk.AddrLen+1] - delAddr := indexKey[sdk.AddrLen+1 : 2*sdk.AddrLen+1] - valSrcAddr := indexKey[2*sdk.AddrLen+1 : 3*sdk.AddrLen+1] + valDstAddrLen := addrs[0] + valDstAddr := addrs[1 : valDstAddrLen+1] + delAddrLen := addrs[valDstAddrLen+1] + delAddr := addrs[valDstAddrLen+2 : valDstAddrLen+2+delAddrLen] + valSrcAddr := addrs[valDstAddrLen+delAddrLen+3:] return GetREDKey(delAddr, valSrcAddr, valDstAddr) } @@ -299,25 +305,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, delAddr.Bytes()...) + return append(append(RedelegationKey, byte(len(delAddr))), delAddr.Bytes()...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, valSrcAddr.Bytes()...) + return append(append(RedelegationByValSrcIndexKey, byte(len(valSrcAddr))), valSrcAddr.Bytes()...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, valDstAddr.Bytes()...) + return append(append(RedelegationByValDstIndexKey, byte(len(valDstAddr))), valDstAddr.Bytes()...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(GetREDsToValDstIndexKey(valDstAddr), delAddr.Bytes()...) + return append(append(GetREDsToValDstIndexKey(valDstAddr), byte(len(delAddr))), delAddr.Bytes()...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. diff --git a/x/staking/types/keys_test.go b/x/staking/types/keys_test.go index 0f63617f26b3..949c7caedb66 100644 --- a/x/staking/types/keys_test.go +++ b/x/staking/types/keys_test.go @@ -37,10 +37,10 @@ func TestGetValidatorPowerRank(t *testing.T) { validator types.Validator wantHex string }{ - {val1, "2300000000000000009c288ede7df62742fc3b7d0962045a8cef0f79f6"}, - {val2, "2300000000000000019c288ede7df62742fc3b7d0962045a8cef0f79f6"}, - {val3, "23000000000000000a9c288ede7df62742fc3b7d0962045a8cef0f79f6"}, - {val4, "2300000100000000009c288ede7df62742fc3b7d0962045a8cef0f79f6"}, + {val1, "230000000000000000149c288ede7df62742fc3b7d0962045a8cef0f79f6"}, + {val2, "230000000000000001149c288ede7df62742fc3b7d0962045a8cef0f79f6"}, + {val3, "23000000000000000a149c288ede7df62742fc3b7d0962045a8cef0f79f6"}, + {val4, "230000010000000000149c288ede7df62742fc3b7d0962045a8cef0f79f6"}, } for i, tt := range tests { got := hex.EncodeToString(types.GetValidatorsByPowerIndexKey(tt.validator)) @@ -57,11 +57,11 @@ func TestGetREDByValDstIndexKey(t *testing.T) { wantHex string }{ {sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr1), - "3663d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"}, + "361463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f08609"}, {sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr2), sdk.ValAddress(keysAddr3), - "363ab62f0d93849be495e21e3e9013a517038f45bd63d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f2"}, + "36143ab62f0d93849be495e21e3e9013a517038f45bd1463d771218209d8bd03c482f69dfba57310f08609145ef3b5f25c54946d4a89fc0d09d2f126614540f2"}, {sdk.AccAddress(keysAddr2), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr3), - "363ab62f0d93849be495e21e3e9013a517038f45bd5ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f08609"}, + "36143ab62f0d93849be495e21e3e9013a517038f45bd145ef3b5f25c54946d4a89fc0d09d2f126614540f21463d771218209d8bd03c482f69dfba57310f08609"}, } for i, tt := range tests { got := hex.EncodeToString(types.GetREDByValDstIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr)) @@ -78,11 +78,11 @@ func TestGetREDByValSrcIndexKey(t *testing.T) { wantHex string }{ {sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr1), - "3563d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f0860963d771218209d8bd03c482f69dfba57310f08609"}, + "351463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f086091463d771218209d8bd03c482f69dfba57310f08609"}, {sdk.AccAddress(keysAddr1), sdk.ValAddress(keysAddr2), sdk.ValAddress(keysAddr3), - "355ef3b5f25c54946d4a89fc0d09d2f126614540f263d771218209d8bd03c482f69dfba57310f086093ab62f0d93849be495e21e3e9013a517038f45bd"}, + "35145ef3b5f25c54946d4a89fc0d09d2f126614540f21463d771218209d8bd03c482f69dfba57310f08609143ab62f0d93849be495e21e3e9013a517038f45bd"}, {sdk.AccAddress(keysAddr2), sdk.ValAddress(keysAddr1), sdk.ValAddress(keysAddr3), - "3563d771218209d8bd03c482f69dfba57310f086095ef3b5f25c54946d4a89fc0d09d2f126614540f23ab62f0d93849be495e21e3e9013a517038f45bd"}, + "351463d771218209d8bd03c482f69dfba57310f08609145ef3b5f25c54946d4a89fc0d09d2f126614540f2143ab62f0d93849be495e21e3e9013a517038f45bd"}, } for i, tt := range tests { got := hex.EncodeToString(types.GetREDByValSrcIndexKey(tt.delAddr, tt.valSrcAddr, tt.valDstAddr)) From 47abd5a5409ec5e94d52df508667dddfac0b6633 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 12:41:40 +0100 Subject: [PATCH 05/41] Use bech32 in val state change map --- x/staking/keeper/val_state_change.go | 42 +++++++++++++++++----------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index f06994f44f70..88a47ad6c01f 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// Calculate the ValidatorUpdates for the current block +// BlockValidatorUpdates calculates the ValidatorUpdates for the current block // Called in each EndBlock func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { // Calculate validator set changes. @@ -97,7 +97,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { return validatorUpdates } -// Apply and return accumulated updates to the bonded validator set. Also, +// ApplyAndReturnValidatorSetUpdates applies and return saccumulated updates to the bonded validator set. Also, // * Updates the active valset as keyed by LastValidatorPowerKey. // * Updates the total power as keyed by LastTotalPowerKey. // * Updates validator status' according to updated powers. @@ -117,7 +117,10 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab // Retrieve the last validator set. // The persistent set is updated later in this function. // (see LastValidatorPowerKey). - last := k.getLastValidatorsByAddr(ctx) + last, err := k.getLastValidatorsByAddr(ctx) + if err != nil { + return nil, err + } // Iterate over validators, highest power to lowest. iterator := k.ValidatorsPowerStoreIterator(ctx) @@ -160,10 +163,11 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab } // fetch the old power bytes - var valAddrBytes [sdk.AddrLen]byte - - copy(valAddrBytes[:], valAddr[:]) - oldPowerBytes, found := last[valAddrBytes] + valAddrStr, err := sdk.Bech32ifyAddressBytes(sdk.Bech32PrefixValAddr, valAddr) + if err != nil { + return nil, err + } + oldPowerBytes, found := last[valAddrStr] newPower := validator.ConsensusPower() newPowerBytes := k.cdc.MustMarshalBinaryBare(&gogotypes.Int64Value{Value: newPower}) @@ -174,7 +178,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab k.SetLastValidatorPower(ctx, valAddr, newPower) } - delete(last, valAddrBytes) + delete(last, valAddrStr) count++ totalPower = totalPower.Add(sdk.NewInt(newPower)) @@ -339,26 +343,30 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali return validator } -// map of operator addresses to serialized power -type validatorsByAddr map[[sdk.AddrLen]byte][]byte +// map of operator bech32-addresses to serialized power +type validatorsByAddr map[string][]byte // get the last validator set -func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) validatorsByAddr { +func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) (validatorsByAddr, error) { last := make(validatorsByAddr) iterator := k.LastValidatorsIterator(ctx) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - var valAddr [sdk.AddrLen]byte - // extract the validator address from the key (prefix is 1-byte) - copy(valAddr[:], iterator.Key()[1:]) + // extract the validator address from the key (prefix is 1-byte, addrLen is 1-byte) + valAddr := iterator.Key()[2:] + valAddrStr, err := sdk.Bech32ifyAddressBytes(sdk.Bech32PrefixValAddr, valAddr) + if err != nil { + return nil, err + } + powerBytes := iterator.Value() - last[valAddr] = make([]byte, len(powerBytes)) - copy(last[valAddr], powerBytes) + last[valAddrStr] = make([]byte, len(powerBytes)) + copy(last[valAddrStr], powerBytes) } - return last + return last, nil } // given a map of remaining validators to previous bonded power From d67029d87d8a754f7fd0e7e79d7a3399ce46703b Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 13:06:00 +0100 Subject: [PATCH 06/41] Fix sortNoLongerBonded --- x/staking/keeper/val_state_change.go | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 88a47ad6c01f..38edd43df563 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -184,7 +184,10 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab totalPower = totalPower.Add(sdk.NewInt(newPower)) } - noLongerBonded := sortNoLongerBonded(last) + noLongerBonded, err := sortNoLongerBonded(last) + if err != nil { + return nil, err + } for _, valAddrBytes := range noLongerBonded { validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes)) validator, err = k.bondedToUnbonding(ctx, validator) @@ -344,6 +347,7 @@ func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Vali } // map of operator bech32-addresses to serialized power +// We use bech32 strings here, because we can't have slices as keys: map[[]byte][]byte type validatorsByAddr map[string][]byte // get the last validator set @@ -371,14 +375,18 @@ func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) (validatorsByAddr, erro // given a map of remaining validators to previous bonded power // returns the list of validators to be unbonded, sorted by operator address -func sortNoLongerBonded(last validatorsByAddr) [][]byte { +func sortNoLongerBonded(last validatorsByAddr) ([][]byte, error) { // sort the map keys for determinism noLongerBonded := make([][]byte, len(last)) index := 0 - for valAddrBytes := range last { - valAddr := make([]byte, sdk.AddrLen) - copy(valAddr, valAddrBytes[:]) + for valAddrStr := range last { + valAddrBytes, err := sdk.ValAddressFromBech32(valAddrStr) + if err != nil { + return nil, err + } + valAddr := make([]byte, len(valAddrBytes)) + copy(valAddr, valAddrBytes) noLongerBonded[index] = valAddr index++ } @@ -388,5 +396,5 @@ func sortNoLongerBonded(last validatorsByAddr) [][]byte { return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1 }) - return noLongerBonded + return noLongerBonded, nil } From ba75256689158e6ac0c887203af2835d922f726a Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 14:04:42 +0100 Subject: [PATCH 07/41] Use length-prefix function --- types/address.go | 15 +++++++++++++++ x/bank/keeper/view.go | 5 +---- x/staking/types/keys.go | 29 +++++++++++++---------------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/types/address.go b/types/address.go index ba9e5b303b6a..d2006fccc7ff 100644 --- a/types/address.go +++ b/types/address.go @@ -256,6 +256,21 @@ func (aa AccAddress) Format(s fmt.State, verb rune) { } } +// LengthPrefixAddress prefixes the address bytes with its length, this is used +// for variable-length components in store keys. Note: All addresses should be +// max 255 bytes, or else this function panics. +func LengthPrefixAddress(bz []byte) []byte { + if len(bz) == 0 { + return bz + } + + if len(bz) > 255 { + panic("address length should be max 255 bytes") + } + + return append([]byte{byte(len(bz))}, bz...) +} + // ---------------------------------------------------------------------------- // validator operator // ---------------------------------------------------------------------------- diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index c893c096dbb3..a9e19fdcbc89 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -215,9 +215,6 @@ func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) er func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) prefix.Store { store := ctx.KVStore(k.storeKey) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - // Addresses are length-prefixed in the store key, the SDK also has a hard - // requirement on addresses being max 255 bytes long. - addrLen := byte(len(addr)) - return prefix.NewStore(balancesStore, append([]byte{addrLen}, addr.Bytes()...)) + return prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr)) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index a8066f6c5d8d..f17f2ccd0dd9 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -51,13 +51,13 @@ var ( // GetValidatorKey gets the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(append(ValidatorsKey, byte(len(operatorAddr))), operatorAddr.Bytes()...) + return append(ValidatorsKey, sdk.LengthPrefixAddress(operatorAddr)...) } // GetValidatorByConsAddrKey gets the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(append(ValidatorsByConsAddrKey, byte(len(addr))), addr.Bytes()...) + return append(ValidatorsByConsAddrKey, sdk.LengthPrefixAddress(addr)...) } // AddressFromLastValidatorPowerKey gets the validator operator address from LastValidatorPowerKey @@ -104,7 +104,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { // GetLastValidatorPowerKey gets the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(append(LastValidatorPowerKey, byte(len(operator))), operator...) + return append(LastValidatorPowerKey, sdk.LengthPrefixAddress(operator)...) } // ParseValidatorPowerRankKey parses the validators operator address from power rank key @@ -168,27 +168,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { // GetDelegationKey gets the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(append(GetDelegationsKey(delAddr), byte(len(delAddr))), valAddr.Bytes()...) + return append(GetDelegationsKey(delAddr), sdk.LengthPrefixAddress(valAddr)...) } // GetDelegationsKey gets the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(append(DelegationKey, byte(len(delAddr))), delAddr.Bytes()...) + return append(DelegationKey, sdk.LengthPrefixAddress(delAddr)...) } // GetUBDKey gets the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append( - append(GetUBDsKey(delAddr.Bytes()), byte(len(valAddr))), - valAddr.Bytes()..., - ) + return append(GetUBDsKey(delAddr.Bytes()), sdk.LengthPrefixAddress(valAddr)...) } // GetUBDByValIndexKey gets the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(append(GetUBDsByValIndexKey(valAddr), byte(len(delAddr))), delAddr.Bytes()...) + return append(GetUBDsByValIndexKey(valAddr), sdk.LengthPrefixAddress(valAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey @@ -204,12 +201,12 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { // GetUBDsKey gets the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(append(UnbondingDelegationKey, byte(len(delAddr))), delAddr.Bytes()...) + return append(UnbondingDelegationKey, sdk.LengthPrefixAddress(delAddr)...) } // GetUBDsByValIndexKey gets the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(append(UnbondingDelegationByValIndexKey, byte(len(valAddr))), valAddr.Bytes()...) + return append(UnbondingDelegationByValIndexKey, sdk.LengthPrefixAddress(valAddr)...) } // GetUnbondingDelegationTimeKey gets the prefix for all unbonding delegations from a delegator @@ -305,25 +302,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(append(RedelegationKey, byte(len(delAddr))), delAddr.Bytes()...) + return append(RedelegationKey, sdk.LengthPrefixAddress(delAddr)...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(append(RedelegationByValSrcIndexKey, byte(len(valSrcAddr))), valSrcAddr.Bytes()...) + return append(RedelegationByValSrcIndexKey, sdk.LengthPrefixAddress(valSrcAddr)...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(append(RedelegationByValDstIndexKey, byte(len(valDstAddr))), valDstAddr.Bytes()...) + return append(RedelegationByValDstIndexKey, sdk.LengthPrefixAddress(valDstAddr)...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(append(GetREDsToValDstIndexKey(valDstAddr), byte(len(delAddr))), delAddr.Bytes()...) + return append(GetREDsToValDstIndexKey(valDstAddr), sdk.LengthPrefixAddress(delAddr)...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. From 129680f132cc7a4a34e1864fc44b9032f00fa501 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 14:08:41 +0100 Subject: [PATCH 08/41] Use length prefix function --- types/query/filtered_pagination_test.go | 2 +- x/bank/types/key_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index 166c788808a2..cc4e5172c10a 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -143,7 +143,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, append([]byte{byte(len(addr1))}, addr1.Bytes()...)) + accountStore := prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr1)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index 4630acc312cd..f42e95f30060 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -22,7 +22,7 @@ func TestAddressFromBalancesStore(t *testing.T) { addrLen := len(addr) require.Equal(t, 20, addrLen) - key := cloneAppend(append([]byte{byte(addrLen)}, addr.Bytes()...), []byte("stake")) + key := cloneAppend(sdk.LengthPrefixAddress(addr), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } From e627da3708ea81008b07ac40315810b40f6203be Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 14:18:54 +0100 Subject: [PATCH 09/41] Fix test accountStore --- types/query/filtered_pagination_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index cc4e5172c10a..dd70eede8267 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -111,7 +111,7 @@ func ExampleFilteredPaginate() { pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr1.Bytes()) + accountStore := prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr1)) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { From 17d26782c02d187dfc4d429349c1399bce1e4317 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 14:38:20 +0100 Subject: [PATCH 10/41] Fix ExamplePaginate --- types/query/pagination_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index f0e1377a1e91..b440117ad642 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -193,7 +193,7 @@ func ExamplePaginate() { balResult := sdk.NewCoins() authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, addr1.Bytes()) + accountStore := prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) From bf16313b2e1b74f03744c1d0b7e735756a20b36c Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 14:51:48 +0100 Subject: [PATCH 11/41] Fix staking keys --- x/staking/types/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index f17f2ccd0dd9..d702d04ca46b 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -185,7 +185,7 @@ func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { // GetUBDByValIndexKey gets the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), sdk.LengthPrefixAddress(valAddr)...) + return append(GetUBDsByValIndexKey(valAddr), sdk.LengthPrefixAddress(delAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey From 98d67f501b610f7fd472891d37f26efc8ad2e045 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 22 Jan 2021 14:54:31 +0100 Subject: [PATCH 12/41] Use shorter balances prefix --- x/bank/types/key.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/bank/types/key.go b/x/bank/types/key.go index 990d4609823e..5a1c56aad3b4 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -20,7 +20,7 @@ const ( // KVStore keys var ( - BalancesPrefix = []byte("balances") + BalancesPrefix = []byte{0x02} SupplyKey = []byte{0x00} DenomMetadataPrefix = []byte{0x1} ) From 045905dc0820197be7373fc3d6139fe696fc277b Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 11:33:14 +0100 Subject: [PATCH 13/41] Do slashing keys --- x/slashing/types/keys.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index c9792d22085f..5811b004a50f 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -23,11 +23,11 @@ const ( // Keys for slashing store // Items are stored with the following key: values // -// - 0x01: ValidatorSigningInfo +// - 0x01: ValidatorSigningInfo // -// - 0x02: bool +// - 0x02: bool // -// - 0x03: crypto.PubKey +// - 0x03: cryptotypes.PubKey var ( ValidatorSigningInfoKeyPrefix = []byte{0x01} // Prefix for signing info ValidatorMissedBlockBitArrayKeyPrefix = []byte{0x02} // Prefix for missed block bit array @@ -36,31 +36,30 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, v.Bytes()...) + return append(ValidatorSigningInfoKeyPrefix, sdk.LengthPrefixAddress(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } + addr := key[2:] + return sdk.ConsAddress(addr) } // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, v.Bytes()...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, sdk.LengthPrefixAddress(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, uint64(i)) + return append(ValidatorMissedBlockBitArrayPrefixKey(v), b...) } // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address func AddrPubkeyRelationKey(address []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, address...) + return append(AddrPubkeyRelationKeyPrefix, sdk.LengthPrefixAddress(address)...) } From 18a2eb1dda2f30b74e927e48aee877e07475eba2 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 11:38:02 +0100 Subject: [PATCH 14/41] Fix gov keys --- x/gov/types/keys.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index 7681116fc46a..b0905c3178f6 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -33,9 +33,9 @@ const ( // // - 0x03: nextProposalID // -// - 0x10: Deposit +// - 0x10: Deposit // -// - 0x20: Voter +// - 0x20: Voter var ( ProposalsKeyPrefix = []byte{0x00} ActiveProposalQueuePrefix = []byte{0x01} @@ -154,11 +154,9 @@ func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) { } func splitKeyWithAddress(key []byte) (proposalID uint64, addr sdk.AccAddress) { - if len(key[1:]) != 8+sdk.AddrLen { - panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key), 8+sdk.AddrLen)) - } - + // Both Vote and Deposit store keys are of format: + // proposalID = GetProposalIDFromBytes(key[1:9]) - addr = sdk.AccAddress(key[9:]) + addr = sdk.AccAddress(key[10:]) return } From f0803fc15a0120f12302291023062dea9273165a Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 11:40:48 +0100 Subject: [PATCH 15/41] Fix x/gov tests --- x/gov/types/keys.go | 4 ++-- x/gov/types/keys_test.go | 10 ---------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index b0905c3178f6..06045ceccdc5 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -93,7 +93,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), depositorAddr.Bytes()...) + return append(DepositsKey(proposalID), sdk.LengthPrefixAddress(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -103,7 +103,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), voterAddr.Bytes()...) + return append(VotesKey(proposalID), sdk.LengthPrefixAddress(voterAddr.Bytes())...) } // Split keys function; used for iterators diff --git a/x/gov/types/keys_test.go b/x/gov/types/keys_test.go index 80dfa7d207a3..30266f8f4d78 100644 --- a/x/gov/types/keys_test.go +++ b/x/gov/types/keys_test.go @@ -46,11 +46,6 @@ func TestDepositKeys(t *testing.T) { proposalID, depositorAddr := SplitKeyDeposit(key) require.Equal(t, int(proposalID), 2) require.Equal(t, addr, depositorAddr) - - // invalid key - addr2 := sdk.AccAddress("test1") - key = DepositKey(5, addr2) - require.Panics(t, func() { SplitKeyDeposit(key) }) } func TestVoteKeys(t *testing.T) { @@ -63,9 +58,4 @@ func TestVoteKeys(t *testing.T) { proposalID, voterAddr := SplitKeyDeposit(key) require.Equal(t, int(proposalID), 2) require.Equal(t, addr, voterAddr) - - // invalid key - addr2 := sdk.AccAddress("test1") - key = VoteKey(5, addr2) - require.Panics(t, func() { SplitKeyVote(key) }) } From 06780ae5a85169027993bf50fc9e413d9aeba175 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 11:59:22 +0100 Subject: [PATCH 16/41] Fix x/distrib --- types/address.go | 6 +- x/distribution/types/keys.go | 120 +++++++++++++++++------------------ 2 files changed, 60 insertions(+), 66 deletions(-) diff --git a/types/address.go b/types/address.go index d2006fccc7ff..087565c095ba 100644 --- a/types/address.go +++ b/types/address.go @@ -28,8 +28,6 @@ const ( // config.SetFullFundraiserPath(yourFullFundraiserPath) // config.Seal() - // AddrLen defines a valid address length - AddrLen = 20 // Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address Bech32MainPrefix = "cosmos" @@ -110,9 +108,7 @@ func VerifyAddressFormat(bz []byte) error { if verifier != nil { return verifier(bz) } - if len(bz) != AddrLen { - return fmt.Errorf("incorrect address length (expected: %d, actual: %d)", AddrLen, len(bz)) - } + return nil } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index 12fe9b17b9ff..6d0d93908aee 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -27,19 +27,19 @@ const ( // // - 0x01: sdk.ConsAddress // -// - 0x02: ValidatorOutstandingRewards +// - 0x02: ValidatorOutstandingRewards // -// - 0x03: sdk.AccAddress +// - 0x03: sdk.AccAddress // -// - 0x04: DelegatorStartingInfo +// - 0x04: DelegatorStartingInfo // -// - 0x05: ValidatorHistoricalRewards +// - 0x05: ValidatorHistoricalRewards // -// - 0x06: ValidatorCurrentRewards +// - 0x06: ValidatorCurrentRewards // -// - 0x07: ValidatorCurrentRewards +// - 0x07: ValidatorCurrentRewards // -// - 0x08: ValidatorSlashEvent +// - 0x08: ValidatorSlashEvent var ( FeePoolKey = []byte{0x00} // key for global distribution state ProposerKey = []byte{0x01} // key for the proposer operator address @@ -53,47 +53,44 @@ var ( ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction ) -// gets an address from a validator's outstanding rewards key +// GetValidatorOutstandingRewardsAddress gets an address from a validator's outstanding rewards key. func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { + addr := key[2:] + if len(addr) != int(key[1]) { panic("unexpected key length") } + return sdk.ValAddress(addr) } -// gets an address from a delegator's withdraw info key +// GetDelegatorWithdrawInfoAddress gets an address from a delegator's withdraw info key. func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { + addr := key[2:] + if len(addr) != int(key[1]) { panic("unexpected key length") } + return sdk.AccAddress(addr) } -// gets the addresses from a delegator starting info key +// GetDelegatorStartingInfoAddresses gets the addresses from a delegator starting info key. func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) { - addr := key[1 : 1+sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - valAddr = sdk.ValAddress(addr) - addr = key[1+sdk.AddrLen:] - if len(addr) != sdk.AddrLen { + valAddrLen := int(key[1]) + valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) + delAddrLen := int(key[2+valAddrLen]) + delAddr = sdk.AccAddress(key[3+valAddrLen:]) + if len(delAddr.Bytes()) != delAddrLen { panic("unexpected key length") } - delAddr = sdk.AccAddress(addr) + return } -// gets the address & period from a validator's historical rewards key +// GetValidatorHistoricalRewardsAddressPeriod gets the address & period from a validator's historical rewards key. func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) { - addr := key[1 : 1+sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - valAddr = sdk.ValAddress(addr) - b := key[1+sdk.AddrLen:] + valAddrLen := int(key[1]) + valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) + b := key[2+valAddrLen:] if len(b) != 8 { panic("unexpected key length") } @@ -101,93 +98,94 @@ func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddr return } -// gets the address from a validator's current rewards key +// GetValidatorCurrentRewardsAddress gets the address from a validator's current rewards key. func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { + addr := key[2:] + if len(addr) != int(key[1]) { panic("unexpected key length") } + return sdk.ValAddress(addr) } -// gets the address from a validator's accumulated commission key +// GetValidatorAccumulatedCommissionAddress gets the address from a validator's accumulated commission key. func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) { - addr := key[1:] - if len(addr) != sdk.AddrLen { + addr := key[2:] + if len(addr) != int(key[1]) { panic("unexpected key length") } + return sdk.ValAddress(addr) } -// gets the height from a validator's slash event key +// GetValidatorSlashEventAddressHeight gets the height from a validator's slash event key. func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) { - addr := key[1 : 1+sdk.AddrLen] - if len(addr) != sdk.AddrLen { - panic("unexpected key length") - } - valAddr = sdk.ValAddress(addr) - startB := 1 + sdk.AddrLen + valAddrLen := int(key[1]) + valAddr = key[2 : 2+valAddrLen] + startB := 2 + valAddrLen b := key[startB : startB+8] // the next 8 bytes represent the height height = binary.BigEndian.Uint64(b) return } -// gets the outstanding rewards key for a validator +// GetValidatorOutstandingRewardsKey gets the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...) + return append(ValidatorOutstandingRewardsPrefix, sdk.LengthPrefixAddress(valAddr.Bytes())...) } -// gets the key for a delegator's withdraw addr +// GetDelegatorWithdrawAddrKey gets the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, delAddr.Bytes()...) + return append(DelegatorWithdrawAddrPrefix, sdk.LengthPrefixAddress(delAddr.Bytes())...) } -// gets the key for a delegator's starting info +// GetDelegatorStartingInfoKey gets the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, v.Bytes()...), d.Bytes()...) + return append(append(DelegatorStartingInfoPrefix, sdk.LengthPrefixAddress(v.Bytes())...), sdk.LengthPrefixAddress(d.Bytes())...) } -// gets the prefix key for a validator's historical rewards +// GetValidatorHistoricalRewardsPrefix gets the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, v.Bytes()...) + return append(ValidatorHistoricalRewardsPrefix, sdk.LengthPrefixAddress(v.Bytes())...) } -// gets the key for a validator's historical rewards +// GetValidatorHistoricalRewardsKey gets the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, v.Bytes()...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, sdk.LengthPrefixAddress(v.Bytes())...), b...) } -// gets the key for a validator's current rewards +// GetValidatorCurrentRewardsKey gets the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, v.Bytes()...) + return append(ValidatorCurrentRewardsPrefix, sdk.LengthPrefixAddress(v.Bytes())...) } -// gets the key for a validator's current commission +// GetValidatorAccumulatedCommissionKey gets the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, v.Bytes()...) + return append(ValidatorAccumulatedCommissionPrefix, sdk.LengthPrefixAddress(v.Bytes())...) } -// gets the prefix key for a validator's slash fractions +// GetValidatorSlashEventPrefix gets the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, v.Bytes()...) + return append(ValidatorSlashEventPrefix, sdk.LengthPrefixAddress(v.Bytes())...) } -// gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height) +// GetValidatorSlashEventKeyPrefix gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { heightBz := make([]byte, 8) binary.BigEndian.PutUint64(heightBz, height) + return append( ValidatorSlashEventPrefix, - append(v.Bytes(), heightBz...)..., + append(sdk.LengthPrefixAddress(v.Bytes()), heightBz...)..., ) } -// gets the key for a validator's slash fraction +// GetValidatorSlashEventKey gets the key for a validator's slash fraction. func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte { periodBz := make([]byte, 8) binary.BigEndian.PutUint64(periodBz, period) prefix := GetValidatorSlashEventKeyPrefix(v, height) + return append(prefix, periodBz...) } From 8c0c5b5f7f17ffd2b3b1af09ff95b07e6f5ec851 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 12:02:01 +0100 Subject: [PATCH 17/41] Address reviews --- types/address.go | 5 ++++- x/staking/keeper/val_state_change.go | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/types/address.go b/types/address.go index 087565c095ba..e0db59e93900 100644 --- a/types/address.go +++ b/types/address.go @@ -28,6 +28,9 @@ const ( // config.SetFullFundraiserPath(yourFullFundraiserPath) // config.Seal() + // Maximum allowed length (in bytes) for an address + maxAddrLen = 255 + // Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address Bech32MainPrefix = "cosmos" @@ -260,7 +263,7 @@ func LengthPrefixAddress(bz []byte) []byte { return bz } - if len(bz) > 255 { + if len(bz) > maxAddrLen { panic("address length should be max 255 bytes") } diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 38edd43df563..20e59a25a2db 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -188,6 +188,7 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab if err != nil { return nil, err } + for _, valAddrBytes := range noLongerBonded { validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes)) validator, err = k.bondedToUnbonding(ctx, validator) From e0f7532fbb2047d45bfc5a8d5172b6a9e60a5fbc Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 12:06:37 +0100 Subject: [PATCH 18/41] add change log entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2bc793c0511..a3821beb86a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### State Machine Breaking + +* (x/{bank,distrib,gov,slashing,staking}) [\#8363](https://github.com/cosmos/cosmos-sdk/issues/8363) Store keys have been modified to allow for variable-length addresses. + ### Improvements From 42cf5c817a9fa8b10c691887061f48a616dda391 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 12:17:02 +0100 Subject: [PATCH 19/41] Add changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3821beb86a2..7bd121554832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Client Breaking Changes + +* [\#8363](https://github.com/cosmos/cosmos-sdk/issues/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address. + ### State Machine Breaking * (x/{bank,distrib,gov,slashing,staking}) [\#8363](https://github.com/cosmos/cosmos-sdk/issues/8363) Store keys have been modified to allow for variable-length addresses. From b07a79b9f1129178aaf6c9f86588b81073c0b275 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 12:35:29 +0100 Subject: [PATCH 20/41] Fix failing tests --- types/address_test.go | 34 ++++++++++++++++++++++------------ x/bank/types/msgs_test.go | 21 +++++++++------------ 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/types/address_test.go b/types/address_test.go index 5796c891acb0..6581a4bdba99 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -364,34 +364,34 @@ func (s *addressTestSuite) TestCustomAddressVerifier() { accBech := types.AccAddress(addr).String() valBech := types.ValAddress(addr).String() consBech := types.ConsAddress(addr).String() - // Verifiy that the default logic rejects this 10 byte address + // Verifiy that the default logic doesn't reject this 10 byte address err := types.VerifyAddressFormat(addr) - s.Require().NotNil(err) + s.Require().Nil(err) _, err = types.AccAddressFromBech32(accBech) - s.Require().NotNil(err) + s.Require().Nil(err) _, err = types.ValAddressFromBech32(valBech) - s.Require().NotNil(err) + s.Require().Nil(err) _, err = types.ConsAddressFromBech32(consBech) - s.Require().NotNil(err) + s.Require().Nil(err) - // Set a custom address verifier that accepts 10 or 20 byte addresses + // Set a custom address verifier only accepts 20 byte addresses types.GetConfig().SetAddressVerifier(func(bz []byte) error { n := len(bz) - if n == 10 || n == types.AddrLen { + if n == 20 { return nil } return fmt.Errorf("incorrect address length %d", n) }) - // Verifiy that the custom logic accepts this 10 byte address + // Verifiy that the custom logic rejects this 10 byte address err = types.VerifyAddressFormat(addr) - s.Require().Nil(err) + s.Require().NotNil(err) _, err = types.AccAddressFromBech32(accBech) - s.Require().Nil(err) + s.Require().NotNil(err) _, err = types.ValAddressFromBech32(valBech) - s.Require().Nil(err) + s.Require().NotNil(err) _, err = types.ConsAddressFromBech32(consBech) - s.Require().Nil(err) + s.Require().NotNil(err) } func (s *addressTestSuite) TestBech32ifyAddressBytes() { @@ -520,3 +520,13 @@ func (s *addressTestSuite) TestGetFromBech32() { s.Require().Error(err) s.Require().Equal("invalid Bech32 prefix; expected x, got cosmos", err.Error()) } + +func (s *addressTestSuite) TestLengthPrefixAddress() { + addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + addr256byte := make([]byte, 256) + + s.Require().Equal(append([]byte{byte(10)}, addr10byte...), types.LengthPrefixAddress(addr10byte)) + s.Require().Equal(append([]byte{byte(20)}, addr20byte...), types.LengthPrefixAddress(addr20byte)) + s.Require().Panics(func() { types.LengthPrefixAddress(addr256byte) }) +} diff --git a/x/bank/types/msgs_test.go b/x/bank/types/msgs_test.go index 96132150ad4f..334d72c13243 100644 --- a/x/bank/types/msgs_test.go +++ b/x/bank/types/msgs_test.go @@ -23,7 +23,7 @@ func TestMsgSendValidation(t *testing.T) { addr1 := sdk.AccAddress([]byte("from________________")) addr2 := sdk.AccAddress([]byte("to__________________")) addrEmpty := sdk.AccAddress([]byte("")) - addrTooLong := sdk.AccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrLong := sdk.AccAddress([]byte("Purposefully long address")) atom123 := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) atom0 := sdk.NewCoins(sdk.NewInt64Coin("atom", 0)) @@ -36,12 +36,12 @@ func TestMsgSendValidation(t *testing.T) { }{ {"", NewMsgSend(addr1, addr2, atom123)}, // valid send {"", NewMsgSend(addr1, addr2, atom123eth123)}, // valid send with multiple coins + {"", NewMsgSend(addrLong, addr2, atom123)}, // valid send with long addr sender + {"", NewMsgSend(addr1, addrLong, atom123)}, // valid send with long addr recipient {": invalid coins", NewMsgSend(addr1, addr2, atom0)}, // non positive coin {"123atom,0eth: invalid coins", NewMsgSend(addr1, addr2, atom123eth0)}, // non positive coin in multicoins {"Invalid sender address (empty address string is not allowed): invalid address", NewMsgSend(addrEmpty, addr2, atom123)}, - {"Invalid sender address (incorrect address length (expected: 20, actual: 33)): invalid address", NewMsgSend(addrTooLong, addr2, atom123)}, {"Invalid recipient address (empty address string is not allowed): invalid address", NewMsgSend(addr1, addrEmpty, atom123)}, - {"Invalid recipient address (incorrect address length (expected: 20, actual: 33)): invalid address", NewMsgSend(addr1, addrTooLong, atom123)}, } for _, tc := range cases { @@ -91,7 +91,7 @@ func TestInputValidation(t *testing.T) { addr1 := sdk.AccAddress([]byte("_______alice________")) addr2 := sdk.AccAddress([]byte("________bob_________")) addrEmpty := sdk.AccAddress([]byte("")) - addrTooLong := sdk.AccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrLong := sdk.AccAddress([]byte("Purposefully long address")) someCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) multiCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 20)) @@ -109,9 +109,9 @@ func TestInputValidation(t *testing.T) { {"", NewInput(addr1, someCoins)}, {"", NewInput(addr2, someCoins)}, {"", NewInput(addr2, multiCoins)}, + {"", NewInput(addrLong, someCoins)}, {"empty address string is not allowed", NewInput(addrEmpty, someCoins)}, - {"incorrect address length (expected: 20, actual: 33)", NewInput(addrTooLong, someCoins)}, {": invalid coins", NewInput(addr1, emptyCoins)}, // invalid coins {": invalid coins", NewInput(addr1, emptyCoins2)}, // invalid coins {"10eth,0atom: invalid coins", NewInput(addr1, someEmptyCoins)}, // invalid coins @@ -132,7 +132,7 @@ func TestOutputValidation(t *testing.T) { addr1 := sdk.AccAddress([]byte("_______alice________")) addr2 := sdk.AccAddress([]byte("________bob_________")) addrEmpty := sdk.AccAddress([]byte("")) - addrTooLong := sdk.AccAddress([]byte("Accidentally used 33 bytes pubkey")) + addrLong := sdk.AccAddress([]byte("Purposefully long address")) someCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123)) multiCoins := sdk.NewCoins(sdk.NewInt64Coin("atom", 123), sdk.NewInt64Coin("eth", 20)) @@ -150,9 +150,9 @@ func TestOutputValidation(t *testing.T) { {"", NewOutput(addr1, someCoins)}, {"", NewOutput(addr2, someCoins)}, {"", NewOutput(addr2, multiCoins)}, + {"", NewOutput(addrLong, someCoins)}, {"Invalid output address (empty address string is not allowed): invalid address", NewOutput(addrEmpty, someCoins)}, - {"Invalid output address (incorrect address length (expected: 20, actual: 33)): invalid address", NewOutput(addrTooLong, someCoins)}, {": invalid coins", NewOutput(addr1, emptyCoins)}, // invalid coins {": invalid coins", NewOutput(addr1, emptyCoins2)}, // invalid coins {"10eth,0atom: invalid coins", NewOutput(addr1, someEmptyCoins)}, // invalid coins @@ -251,8 +251,6 @@ func TestMsgMultiSendGetSigners(t *testing.T) { require.Equal(t, "[696E707574313131313131313131313131313131 696E707574323232323232323232323232323232 696E707574333333333333333333333333333333]", fmt.Sprintf("%v", res)) } -/* -// what to do w/ this test? func TestMsgSendSigners(t *testing.T) { signers := []sdk.AccAddress{ {1, 2, 3}, @@ -265,8 +263,7 @@ func TestMsgSendSigners(t *testing.T) { for i, signer := range signers { inputs[i] = NewInput(signer, someCoins) } - tx := NewMsgSend(inputs, nil) + tx := NewMsgMultiSend(inputs, nil) - require.Equal(t, signers, tx.Signers()) + require.Equal(t, signers, tx.GetSigners()) } -*/ From dd432de32c67c549a72a33b639378443b1f95c0d Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 13:31:12 +0100 Subject: [PATCH 21/41] Fix sim tests --- x/staking/keeper/val_state_change.go | 2 +- x/staking/keeper/validator.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 20e59a25a2db..260f4cc91a6f 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -360,7 +360,7 @@ func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) (validatorsByAddr, erro for ; iterator.Valid(); iterator.Next() { // extract the validator address from the key (prefix is 1-byte, addrLen is 1-byte) - valAddr := iterator.Key()[2:] + valAddr := types.AddressFromLastValidatorPowerKey(iterator.Key()) valAddrStr, err := sdk.Bech32ifyAddressBytes(sdk.Bech32PrefixValAddr, valAddr) if err != nil { return nil, err diff --git a/x/staking/keeper/validator.go b/x/staking/keeper/validator.go index edb00ddba55b..9fa6a0ca0a0b 100644 --- a/x/staking/keeper/validator.go +++ b/x/staking/keeper/validator.go @@ -327,7 +327,7 @@ func (k Keeper) IterateLastValidatorPowers(ctx sdk.Context, handler func(operato defer iter.Close() for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[len(types.LastValidatorPowerKey):]) + addr := sdk.ValAddress(types.AddressFromLastValidatorPowerKey(iter.Key())) intV := &gogotypes.Int64Value{} k.cdc.MustUnmarshalBinaryBare(iter.Value(), intV) From b6f001c8f2617a295bbfc6d5b286b60f148201a2 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 13:48:54 +0100 Subject: [PATCH 22/41] fix after-export sim --- simapp/export.go | 3 ++- x/staking/types/keys.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/simapp/export.go b/simapp/export.go index 887308d30a94..bc4dd6d4fd6d 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -157,7 +158,7 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [] counter := int16(0) for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(iter.Key()[1:]) + addr := sdk.ValAddress(types.AddressFromValidatorsKey(iter.Key())) validator, found := app.StakingKeeper.GetValidator(ctx, addr) if !found { panic("expected validator, not found") diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index d702d04ca46b..0f37c3073d96 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -60,6 +60,11 @@ func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { return append(ValidatorsByConsAddrKey, sdk.LengthPrefixAddress(addr)...) } +// AddressFromValidatorsKey gets the validator operator address from ValidatorsKey +func AddressFromValidatorsKey(key []byte) []byte { + return key[2:] // remove prefix bytes and address length +} + // AddressFromLastValidatorPowerKey gets the validator operator address from LastValidatorPowerKey func AddressFromLastValidatorPowerKey(key []byte) []byte { return key[2:] // remove prefix bytes and address length From 53e829834379f0df241b7f3f170f92d4db7117b2 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 25 Jan 2021 13:55:06 +0100 Subject: [PATCH 23/41] Fix lint --- simapp/export.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/simapp/export.go b/simapp/export.go index bc4dd6d4fd6d..8d09e333a2e1 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -10,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" - "github.com/cosmos/cosmos-sdk/x/staking/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -158,7 +157,7 @@ func (app *SimApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [] counter := int16(0) for ; iter.Valid(); iter.Next() { - addr := sdk.ValAddress(types.AddressFromValidatorsKey(iter.Key())) + addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key())) validator, found := app.StakingKeeper.GetValidator(ctx, addr) if !found { panic("expected validator, not found") From 3e0a7ca4ae5fa5bdd7d4512226fc2a494b819d15 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 26 Jan 2021 12:23:56 +0100 Subject: [PATCH 24/41] Address review --- types/address.go | 9 +++++++++ types/address_test.go | 11 +++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/types/address.go b/types/address.go index e0db59e93900..244da4b0bd47 100644 --- a/types/address.go +++ b/types/address.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/bech32" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) const ( @@ -112,6 +113,14 @@ func VerifyAddressFormat(bz []byte) error { return verifier(bz) } + if len(bz) == 0 { + return sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty") + } + + if len(bz) > maxAddrLen { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", maxAddrLen, len(bz)) + } + return nil } diff --git a/types/address_test.go b/types/address_test.go index 6581a4bdba99..52c8a1ab5e39 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -347,15 +347,18 @@ func (s *addressTestSuite) TestVerifyAddressFormat() { addr5 := make([]byte, 5) addr20 := make([]byte, 20) addr32 := make([]byte, 32) + addr256 := make([]byte, 256) err := types.VerifyAddressFormat(addr0) - s.Require().EqualError(err, "incorrect address length 0") + s.Require().EqualError(err, "addresses cannot be empty: unknown address") err = types.VerifyAddressFormat(addr5) - s.Require().EqualError(err, "incorrect address length 5") + s.Require().NoError(err) err = types.VerifyAddressFormat(addr20) - s.Require().Nil(err) + s.Require().NoError(err) err = types.VerifyAddressFormat(addr32) - s.Require().EqualError(err, "incorrect address length 32") + s.Require().NoError(err) + err = types.VerifyAddressFormat(addr256) + s.Require().EqualError(err, "address max length is 255, got 256: unknown address") } func (s *addressTestSuite) TestCustomAddressVerifier() { From a0a851c546e10c138e24f7e497fb67cbcf2e29fc Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 26 Jan 2021 12:35:51 +0100 Subject: [PATCH 25/41] Fix x/authz --- x/authz/types/keys.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index 3be659c5aeb8..389fd29b100d 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -21,7 +21,7 @@ const ( // Keys for authz store // Items are stored with the following key: values // -// - 0x01: Grant +// - 0x01: Grant var ( // Keys for store prefixes @@ -30,12 +30,19 @@ var ( // GetAuthorizationStoreKey - return authorization store key func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { - return append(append(append(GrantKey, granter.Bytes()...), grantee.Bytes()...), []byte(msgType)...) + return append(append(append( + GrantKey, sdk.LengthPrefixAddress(granter)...), + sdk.LengthPrefixAddress(grantee)...), + []byte(msgType)..., + ) } // ExtractAddressesFromGrantKey - split granter & grantee address from the authorization key func ExtractAddressesFromGrantKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) { - granterAddr = sdk.AccAddress(key[1 : sdk.AddrLen+1]) - granteeAddr = sdk.AccAddress(key[sdk.AddrLen+1 : sdk.AddrLen*2+1]) + granterAddrLen := key[1] // remove prefix key + granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen]) + granteeAddrLen := key[2+granterAddrLen] + granteeAddr = sdk.AccAddress(key[3+granterAddrLen : 3+granterAddrLen+granteeAddrLen]) + return granterAddr, granteeAddr } From 4a789a7351d2198684a53b18cb2b24840a644b40 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 26 Jan 2021 12:46:56 +0100 Subject: [PATCH 26/41] Fix global config in test --- types/address_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/types/address_test.go b/types/address_test.go index 52c8a1ab5e39..d4e3152f2b41 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -395,6 +395,9 @@ func (s *addressTestSuite) TestCustomAddressVerifier() { s.Require().NotNil(err) _, err = types.ConsAddressFromBech32(consBech) s.Require().NotNil(err) + + // Reinitialize the global config to default address verifier (nil) + types.GetConfig().SetAddressVerifier(nil) } func (s *addressTestSuite) TestBech32ifyAddressBytes() { From 461758f7b2968d29e26face0f5cff5d01dcabfc5 Mon Sep 17 00:00:00 2001 From: Amaury Date: Tue, 26 Jan 2021 16:23:37 +0100 Subject: [PATCH 27/41] Update x/staking/keeper/val_state_change.go Co-authored-by: Robert Zaremba --- x/staking/keeper/val_state_change.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index 260f4cc91a6f..b1f10d91e7c6 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -97,7 +97,7 @@ func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { return validatorUpdates } -// ApplyAndReturnValidatorSetUpdates applies and return saccumulated updates to the bonded validator set. Also, +// ApplyAndReturnValidatorSetUpdates applies and return accumulated updates to the bonded validator set. Also, // * Updates the active valset as keyed by LastValidatorPowerKey. // * Updates the total power as keyed by LastTotalPowerKey. // * Updates validator status' according to updated powers. From 45767e4a28233be0a8fc56c36c0169457e76b278 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 26 Jan 2021 16:35:03 +0100 Subject: [PATCH 28/41] Address comments --- types/address.go | 20 +++++-- types/address_test.go | 13 +++-- types/query/filtered_pagination_test.go | 4 +- types/query/pagination_test.go | 2 +- x/authz/types/keys.go | 11 ++-- x/bank/keeper/view.go | 2 +- x/bank/types/key.go | 2 + x/bank/types/key_test.go | 2 +- x/distribution/types/keys.go | 74 ++++++++++++++++--------- x/gov/types/keys.go | 4 +- x/slashing/types/keys.go | 7 ++- x/staking/types/keys.go | 26 ++++----- 12 files changed, 104 insertions(+), 63 deletions(-) diff --git a/types/address.go b/types/address.go index 244da4b0bd47..30443699a843 100644 --- a/types/address.go +++ b/types/address.go @@ -264,19 +264,29 @@ func (aa AccAddress) Format(s fmt.State, verb rune) { } } -// LengthPrefixAddress prefixes the address bytes with its length, this is used +// LengthPrefixedAddress prefixes the address bytes with its length, this is used // for variable-length components in store keys. Note: All addresses should be // max 255 bytes, or else this function panics. -func LengthPrefixAddress(bz []byte) []byte { +func LengthPrefixedAddress(bz []byte) ([]byte, error) { if len(bz) == 0 { - return bz + return bz, nil } if len(bz) > maxAddrLen { - panic("address length should be max 255 bytes") + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address length should be max %d bytes, got %d", maxAddrLen, len(bz)) } - return append([]byte{byte(len(bz))}, bz...) + return append([]byte{byte(len(bz))}, bz...), nil +} + +// MustLengthPrefixedAddress is LengthPrefixedAddress with a panic. +func MustLengthPrefixedAddress(bz []byte) []byte { + res, err := LengthPrefixedAddress(bz) + if err != nil { + panic(err) + } + + return res } // ---------------------------------------------------------------------------- diff --git a/types/address_test.go b/types/address_test.go index d4e3152f2b41..18c2997885f4 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -367,7 +367,9 @@ func (s *addressTestSuite) TestCustomAddressVerifier() { accBech := types.AccAddress(addr).String() valBech := types.ValAddress(addr).String() consBech := types.ConsAddress(addr).String() - // Verifiy that the default logic doesn't reject this 10 byte address + // Verify that the default logic doesn't reject this 10 byte address + // The default verifier is nil, we're only checking address length is + // between 1-255 bytes. err := types.VerifyAddressFormat(addr) s.Require().Nil(err) _, err = types.AccAddressFromBech32(accBech) @@ -527,12 +529,13 @@ func (s *addressTestSuite) TestGetFromBech32() { s.Require().Equal("invalid Bech32 prefix; expected x, got cosmos", err.Error()) } -func (s *addressTestSuite) TestLengthPrefixAddress() { +func (s *addressTestSuite) TestMustLengthPrefixedAddress() { addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} addr256byte := make([]byte, 256) - s.Require().Equal(append([]byte{byte(10)}, addr10byte...), types.LengthPrefixAddress(addr10byte)) - s.Require().Equal(append([]byte{byte(20)}, addr20byte...), types.LengthPrefixAddress(addr20byte)) - s.Require().Panics(func() { types.LengthPrefixAddress(addr256byte) }) + s.Require().Equal(append([]byte{byte(10)}, addr10byte...), types.MustLengthPrefixedAddress(addr10byte)) + s.Require().Equal(append([]byte{byte(20)}, addr20byte...), types.MustLengthPrefixedAddress(addr20byte)) + // Address is too long, so panics. + s.Require().Panics(func() { types.MustLengthPrefixedAddress(addr256byte) }) } diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index dd70eede8267..cd8bbd1c3cfc 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -111,7 +111,7 @@ func ExampleFilteredPaginate() { pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr1)) + accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr1)) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { @@ -143,7 +143,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr1)) + accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr1)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index b440117ad642..bb20ca0efc86 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -193,7 +193,7 @@ func ExamplePaginate() { balResult := sdk.NewCoins() authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr1)) + accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index 389fd29b100d..bb73d61a8392 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -31,8 +31,8 @@ var ( // GetAuthorizationStoreKey - return authorization store key func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { return append(append(append( - GrantKey, sdk.LengthPrefixAddress(granter)...), - sdk.LengthPrefixAddress(grantee)...), + GrantKey, sdk.MustLengthPrefixedAddress(granter)...), + sdk.MustLengthPrefixedAddress(grantee)...), []byte(msgType)..., ) } @@ -41,8 +41,11 @@ func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, ms func ExtractAddressesFromGrantKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) { granterAddrLen := key[1] // remove prefix key granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen]) - granteeAddrLen := key[2+granterAddrLen] - granteeAddr = sdk.AccAddress(key[3+granterAddrLen : 3+granterAddrLen+granteeAddrLen]) + granteeAddrLen := int(key[2+granterAddrLen]) + granteeAddr = sdk.AccAddress(key[3+granterAddrLen:]) + if len(granteeAddr) != granteeAddrLen { + panic("error") + } return granterAddr, granteeAddr } diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index a9e19fdcbc89..85f69d8b8622 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -216,5 +216,5 @@ func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) pr store := ctx.KVStore(k.storeKey) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - return prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr)) + return prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr)) } diff --git a/x/bank/types/key.go b/x/bank/types/key.go index 5a1c56aad3b4..05cdc657086e 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -20,6 +20,8 @@ const ( // KVStore keys var ( + // BalancesPrefix is the for the account balances store. We use a byte + // (instead of say `[]]byte("balances")` to save some disk space). BalancesPrefix = []byte{0x02} SupplyKey = []byte{0x00} DenomMetadataPrefix = []byte{0x1} diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index f42e95f30060..824d8afe2583 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -22,7 +22,7 @@ func TestAddressFromBalancesStore(t *testing.T) { addrLen := len(addr) require.Equal(t, 20, addrLen) - key := cloneAppend(sdk.LengthPrefixAddress(addr), []byte("stake")) + key := cloneAppend(sdk.MustLengthPrefixedAddress(addr), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index 6d0d93908aee..c7b01672d987 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -53,8 +53,12 @@ var ( ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction ) -// GetValidatorOutstandingRewardsAddress gets an address from a validator's outstanding rewards key. +// GetValidatorOutstandingRewardsAddress creates an address from a validator's outstanding rewards key. func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) { + // key is in the format: + // 0x02 + + // Remove prefix and address length. addr := key[2:] if len(addr) != int(key[1]) { panic("unexpected key length") @@ -63,8 +67,12 @@ func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) return sdk.ValAddress(addr) } -// GetDelegatorWithdrawInfoAddress gets an address from a delegator's withdraw info key. +// GetDelegatorWithdrawInfoAddress creates an address from a delegator's withdraw info key. func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { + // key is in the format: + // 0x03 + + // Remove prefix and address length. addr := key[2:] if len(addr) != int(key[1]) { panic("unexpected key length") @@ -73,8 +81,10 @@ func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) { return sdk.AccAddress(addr) } -// GetDelegatorStartingInfoAddresses gets the addresses from a delegator starting info key. +// GetDelegatorStartingInfoAddresses creates the addresses from a delegator starting info key. func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) { + // key is in the format: + // 0x04 valAddrLen := int(key[1]) valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) delAddrLen := int(key[2+valAddrLen]) @@ -86,8 +96,10 @@ func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delA return } -// GetValidatorHistoricalRewardsAddressPeriod gets the address & period from a validator's historical rewards key. +// GetValidatorHistoricalRewardsAddressPeriod creates the address & period from a validator's historical rewards key. func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) { + // key is in the format: + // 0x05 valAddrLen := int(key[1]) valAddr = sdk.ValAddress(key[2 : 2+valAddrLen]) b := key[2+valAddrLen:] @@ -98,8 +110,12 @@ func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddr return } -// GetValidatorCurrentRewardsAddress gets the address from a validator's current rewards key. +// GetValidatorCurrentRewardsAddress creates the address from a validator's current rewards key. func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { + // key is in the format: + // 0x06: ValidatorCurrentRewards + + // Remove prefix and address length. addr := key[2:] if len(addr) != int(key[1]) { panic("unexpected key length") @@ -108,8 +124,12 @@ func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) { return sdk.ValAddress(addr) } -// GetValidatorAccumulatedCommissionAddress gets the address from a validator's accumulated commission key. +// GetValidatorAccumulatedCommissionAddress creates the address from a validator's accumulated commission key. func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) { + // key is in the format: + // 0x07: ValidatorCurrentRewards + + // Remove prefix and address length. addr := key[2:] if len(addr) != int(key[1]) { panic("unexpected key length") @@ -118,8 +138,10 @@ func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddres return sdk.ValAddress(addr) } -// GetValidatorSlashEventAddressHeight gets the height from a validator's slash event key. +// GetValidatorSlashEventAddressHeight creates the height from a validator's slash event key. func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) { + // key is in the format: + // 0x08: ValidatorSlashEvent valAddrLen := int(key[1]) valAddr = key[2 : 2+valAddrLen] startB := 2 + valAddrLen @@ -128,60 +150,60 @@ func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, he return } -// GetValidatorOutstandingRewardsKey gets the outstanding rewards key for a validator. +// GetValidatorOutstandingRewardsKey creates the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, sdk.LengthPrefixAddress(valAddr.Bytes())...) + return append(ValidatorOutstandingRewardsPrefix, sdk.MustLengthPrefixedAddress(valAddr.Bytes())...) } -// GetDelegatorWithdrawAddrKey gets the key for a delegator's withdraw addr. +// GetDelegatorWithdrawAddrKey creates the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, sdk.LengthPrefixAddress(delAddr.Bytes())...) + return append(DelegatorWithdrawAddrPrefix, sdk.MustLengthPrefixedAddress(delAddr.Bytes())...) } -// GetDelegatorStartingInfoKey gets the key for a delegator's starting info. +// GetDelegatorStartingInfoKey creates the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, sdk.LengthPrefixAddress(v.Bytes())...), sdk.LengthPrefixAddress(d.Bytes())...) + return append(append(DelegatorStartingInfoPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...), sdk.MustLengthPrefixedAddress(d.Bytes())...) } -// GetValidatorHistoricalRewardsPrefix gets the prefix key for a validator's historical rewards. +// GetValidatorHistoricalRewardsPrefix creates the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, sdk.LengthPrefixAddress(v.Bytes())...) + return append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) } -// GetValidatorHistoricalRewardsKey gets the key for a validator's historical rewards. +// GetValidatorHistoricalRewardsKey creates the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, sdk.LengthPrefixAddress(v.Bytes())...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...), b...) } -// GetValidatorCurrentRewardsKey gets the key for a validator's current rewards. +// GetValidatorCurrentRewardsKey creates the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, sdk.LengthPrefixAddress(v.Bytes())...) + return append(ValidatorCurrentRewardsPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) } -// GetValidatorAccumulatedCommissionKey gets the key for a validator's current commission. +// GetValidatorAccumulatedCommissionKey creates the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, sdk.LengthPrefixAddress(v.Bytes())...) + return append(ValidatorAccumulatedCommissionPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) } -// GetValidatorSlashEventPrefix gets the prefix key for a validator's slash fractions. +// GetValidatorSlashEventPrefix creates the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, sdk.LengthPrefixAddress(v.Bytes())...) + return append(ValidatorSlashEventPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) } -// GetValidatorSlashEventKeyPrefix gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). +// GetValidatorSlashEventKeyPrefix creates the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { heightBz := make([]byte, 8) binary.BigEndian.PutUint64(heightBz, height) return append( ValidatorSlashEventPrefix, - append(sdk.LengthPrefixAddress(v.Bytes()), heightBz...)..., + append(sdk.MustLengthPrefixedAddress(v.Bytes()), heightBz...)..., ) } -// GetValidatorSlashEventKey gets the key for a validator's slash fraction. +// GetValidatorSlashEventKey creates the key for a validator's slash fraction. func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte { periodBz := make([]byte, 8) binary.BigEndian.PutUint64(periodBz, period) diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index 06045ceccdc5..55db6a38d1c8 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -93,7 +93,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), sdk.LengthPrefixAddress(depositorAddr.Bytes())...) + return append(DepositsKey(proposalID), sdk.MustLengthPrefixedAddress(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -103,7 +103,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), sdk.LengthPrefixAddress(voterAddr.Bytes())...) + return append(VotesKey(proposalID), sdk.MustLengthPrefixedAddress(voterAddr.Bytes())...) } // Split keys function; used for iterators diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index 5811b004a50f..0b59423384a6 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -36,11 +36,12 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, sdk.LengthPrefixAddress(v.Bytes())...) + return append(ValidatorSigningInfoKeyPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { + // Remove prefix and address length. addr := key[2:] return sdk.ConsAddress(addr) @@ -48,7 +49,7 @@ func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, sdk.LengthPrefixAddress(v.Bytes())...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) @@ -61,5 +62,5 @@ func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address func AddrPubkeyRelationKey(address []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, sdk.LengthPrefixAddress(address)...) + return append(AddrPubkeyRelationKeyPrefix, sdk.MustLengthPrefixedAddress(address)...) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 0f37c3073d96..ee59db2807b5 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -51,13 +51,13 @@ var ( // GetValidatorKey gets the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, sdk.LengthPrefixAddress(operatorAddr)...) + return append(ValidatorsKey, sdk.MustLengthPrefixedAddress(operatorAddr)...) } // GetValidatorByConsAddrKey gets the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, sdk.LengthPrefixAddress(addr)...) + return append(ValidatorsByConsAddrKey, sdk.MustLengthPrefixedAddress(addr)...) } // AddressFromValidatorsKey gets the validator operator address from ValidatorsKey @@ -109,7 +109,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { // GetLastValidatorPowerKey gets the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, sdk.LengthPrefixAddress(operator)...) + return append(LastValidatorPowerKey, sdk.MustLengthPrefixedAddress(operator)...) } // ParseValidatorPowerRankKey parses the validators operator address from power rank key @@ -173,24 +173,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { // GetDelegationKey gets the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), sdk.LengthPrefixAddress(valAddr)...) + return append(GetDelegationsKey(delAddr), sdk.MustLengthPrefixedAddress(valAddr)...) } // GetDelegationsKey gets the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, sdk.LengthPrefixAddress(delAddr)...) + return append(DelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) } // GetUBDKey gets the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsKey(delAddr.Bytes()), sdk.LengthPrefixAddress(valAddr)...) + return append(GetUBDsKey(delAddr.Bytes()), sdk.MustLengthPrefixedAddress(valAddr)...) } // GetUBDByValIndexKey gets the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), sdk.LengthPrefixAddress(delAddr)...) + return append(GetUBDsByValIndexKey(valAddr), sdk.MustLengthPrefixedAddress(delAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey @@ -206,12 +206,12 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { // GetUBDsKey gets the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, sdk.LengthPrefixAddress(delAddr)...) + return append(UnbondingDelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) } // GetUBDsByValIndexKey gets the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, sdk.LengthPrefixAddress(valAddr)...) + return append(UnbondingDelegationByValIndexKey, sdk.MustLengthPrefixedAddress(valAddr)...) } // GetUnbondingDelegationTimeKey gets the prefix for all unbonding delegations from a delegator @@ -307,25 +307,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, sdk.LengthPrefixAddress(delAddr)...) + return append(RedelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, sdk.LengthPrefixAddress(valSrcAddr)...) + return append(RedelegationByValSrcIndexKey, sdk.MustLengthPrefixedAddress(valSrcAddr)...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, sdk.LengthPrefixAddress(valDstAddr)...) + return append(RedelegationByValDstIndexKey, sdk.MustLengthPrefixedAddress(valDstAddr)...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(GetREDsToValDstIndexKey(valDstAddr), sdk.LengthPrefixAddress(delAddr)...) + return append(GetREDsToValDstIndexKey(valDstAddr), sdk.MustLengthPrefixedAddress(delAddr)...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. From 29a38d0645a3db33e2c835e61a82df0061dc4e81 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 26 Jan 2021 16:41:42 +0100 Subject: [PATCH 29/41] Fix comments --- x/staking/types/keys.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index ee59db2807b5..8ee3b0cfa8f0 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -48,29 +48,29 @@ var ( HistoricalInfoKey = []byte{0x50} // prefix for the historical info ) -// GetValidatorKey gets the key for the validator with address +// GetValidatorKey creates the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { return append(ValidatorsKey, sdk.MustLengthPrefixedAddress(operatorAddr)...) } -// GetValidatorByConsAddrKey gets the key for the validator with pubkey +// GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { return append(ValidatorsByConsAddrKey, sdk.MustLengthPrefixedAddress(addr)...) } -// AddressFromValidatorsKey gets the validator operator address from ValidatorsKey +// AddressFromValidatorsKey creates the validator operator address from ValidatorsKey func AddressFromValidatorsKey(key []byte) []byte { return key[2:] // remove prefix bytes and address length } -// AddressFromLastValidatorPowerKey gets the validator operator address from LastValidatorPowerKey +// AddressFromLastValidatorPowerKey creates the validator operator address from LastValidatorPowerKey func AddressFromLastValidatorPowerKey(key []byte) []byte { return key[2:] // remove prefix bytes and address length } -// GetValidatorsByPowerIndexKey gets the validator by power index. +// GetValidatorsByPowerIndexKey creates the validator by power index. // Power index is the key used in the power-store, and represents the relative // power ranking of the validator. // VALUE: validator operator address ([]byte) @@ -107,7 +107,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { return key } -// GetLastValidatorPowerKey gets the bonded validator index key for an operator address +// GetLastValidatorPowerKey creates the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { return append(LastValidatorPowerKey, sdk.MustLengthPrefixedAddress(operator)...) } @@ -170,24 +170,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { return ts, int64(height), nil } -// GetDelegationKey gets the key for delegator bond with validator +// GetDelegationKey creates the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { return append(GetDelegationsKey(delAddr), sdk.MustLengthPrefixedAddress(valAddr)...) } -// GetDelegationsKey gets the prefix for a delegator for all validators +// GetDelegationsKey creates the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { return append(DelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) } -// GetUBDKey gets the key for an unbonding delegation by delegator and validator addr +// GetUBDKey creates the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { return append(GetUBDsKey(delAddr.Bytes()), sdk.MustLengthPrefixedAddress(valAddr)...) } -// GetUBDByValIndexKey gets the index-key for an unbonding delegation, stored by validator-index +// GetUBDByValIndexKey creates the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { return append(GetUBDsByValIndexKey(valAddr), sdk.MustLengthPrefixedAddress(delAddr)...) @@ -204,17 +204,17 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { return GetUBDKey(delAddr, valAddr) } -// GetUBDsKey gets the prefix for all unbonding delegations from a delegator +// GetUBDsKey creates the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { return append(UnbondingDelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) } -// GetUBDsByValIndexKey gets the prefix keyspace for the indexes of unbonding delegations for a validator +// GetUBDsByValIndexKey creates the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { return append(UnbondingDelegationByValIndexKey, sdk.MustLengthPrefixedAddress(valAddr)...) } -// GetUnbondingDelegationTimeKey gets the prefix for all unbonding delegations from a delegator +// GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { bz := sdk.FormatTimeBytes(timestamp) return append(UnbondingQueueKey, bz...) @@ -235,7 +235,7 @@ func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) [] return key } -// GetREDByValSrcIndexKey gets the index-key for a redelegation, stored by source-validator-index +// GetREDByValSrcIndexKey creates the index-key for a redelegation, stored by source-validator-index // VALUE: none (key rearrangement used) func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { REDSFromValsSrcKey := GetREDsFromValSrcIndexKey(valSrcAddr) @@ -252,7 +252,7 @@ func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.V return key } -// GetREDByValDstIndexKey gets the index-key for a redelegation, stored by destination-validator-index +// GetREDByValDstIndexKey creates the index-key for a redelegation, stored by destination-validator-index // VALUE: none (key rearrangement used) func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte { REDSToValsDstKey := GetREDsToValDstIndexKey(valDstAddr) From 51eaa928cdcab96eee73248cb2cb4f1ffdd036e0 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Tue, 26 Jan 2021 16:53:34 +0100 Subject: [PATCH 30/41] Address review --- x/staking/keeper/val_state_change.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x/staking/keeper/val_state_change.go b/x/staking/keeper/val_state_change.go index b1f10d91e7c6..52b739230076 100644 --- a/x/staking/keeper/val_state_change.go +++ b/x/staking/keeper/val_state_change.go @@ -386,9 +386,7 @@ func sortNoLongerBonded(last validatorsByAddr) ([][]byte, error) { if err != nil { return nil, err } - valAddr := make([]byte, len(valAddrBytes)) - copy(valAddr, valAddrBytes) - noLongerBonded[index] = valAddr + noLongerBonded[index] = valAddrBytes index++ } // sorted by address - order doesn't matter From 97376a916531182805b97c0e0a7f5d8a5e7ded97 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 27 Jan 2021 12:00:14 +0100 Subject: [PATCH 31/41] Fix authz test --- x/authz/types/keys.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index bb73d61a8392..0020d815dab7 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -39,13 +39,12 @@ func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, ms // ExtractAddressesFromGrantKey - split granter & grantee address from the authorization key func ExtractAddressesFromGrantKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) { + // key if of format: + // 0x01: Grant granterAddrLen := key[1] // remove prefix key granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen]) granteeAddrLen := int(key[2+granterAddrLen]) - granteeAddr = sdk.AccAddress(key[3+granterAddrLen:]) - if len(granteeAddr) != granteeAddrLen { - panic("error") - } + granteeAddr = sdk.AccAddress(key[3+granterAddrLen : 3+granterAddrLen+byte(granteeAddrLen)]) return granterAddr, granteeAddr } From e4c222bdbbe869553616e468e3a493adbd8aa17d Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 27 Jan 2021 12:01:36 +0100 Subject: [PATCH 32/41] Update comment --- x/authz/types/keys.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index 0020d815dab7..adb12082336e 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -40,7 +40,7 @@ func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, ms // ExtractAddressesFromGrantKey - split granter & grantee address from the authorization key func ExtractAddressesFromGrantKey(key []byte) (granterAddr, granteeAddr sdk.AccAddress) { // key if of format: - // 0x01: Grant + // 0x01 granterAddrLen := key[1] // remove prefix key granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen]) granteeAddrLen := int(key[2+granterAddrLen]) From 9769555e35455f620819f3ca0c0ccd0f13d98882 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 27 Jan 2021 13:57:03 +0100 Subject: [PATCH 33/41] Rename to LengthPrefixedAddressStoreKey --- types/address.go | 13 ++++++------ types/address_test.go | 28 ++++++++++++++++++++----- types/query/filtered_pagination_test.go | 4 ++-- types/query/pagination_test.go | 2 +- x/authz/types/keys.go | 5 +++-- x/bank/keeper/view.go | 2 +- x/bank/types/key_test.go | 2 +- x/distribution/types/keys.go | 18 ++++++++-------- x/gov/types/keys.go | 4 ++-- x/slashing/types/keys.go | 6 +++--- x/staking/types/keys.go | 26 +++++++++++------------ 11 files changed, 64 insertions(+), 46 deletions(-) diff --git a/types/address.go b/types/address.go index 30443699a843..b3ef0e4c3dca 100644 --- a/types/address.go +++ b/types/address.go @@ -264,10 +264,9 @@ func (aa AccAddress) Format(s fmt.State, verb rune) { } } -// LengthPrefixedAddress prefixes the address bytes with its length, this is used -// for variable-length components in store keys. Note: All addresses should be -// max 255 bytes, or else this function panics. -func LengthPrefixedAddress(bz []byte) ([]byte, error) { +// LengthPrefixedAddressStoreKey prefixes the address bytes with its length, this is used +// for variable-length components in store keys. +func LengthPrefixedAddressStoreKey(bz []byte) ([]byte, error) { if len(bz) == 0 { return bz, nil } @@ -279,9 +278,9 @@ func LengthPrefixedAddress(bz []byte) ([]byte, error) { return append([]byte{byte(len(bz))}, bz...), nil } -// MustLengthPrefixedAddress is LengthPrefixedAddress with a panic. -func MustLengthPrefixedAddress(bz []byte) []byte { - res, err := LengthPrefixedAddress(bz) +// MustLengthPrefixedAddressStoreKey is LengthPrefixedAddressStoreKey with a panic. +func MustLengthPrefixedAddressStoreKey(bz []byte) []byte { + res, err := LengthPrefixedAddressStoreKey(bz) if err != nil { panic(err) } diff --git a/types/address_test.go b/types/address_test.go index 18c2997885f4..e98d80708ed1 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -529,13 +529,31 @@ func (s *addressTestSuite) TestGetFromBech32() { s.Require().Equal("invalid Bech32 prefix; expected x, got cosmos", err.Error()) } -func (s *addressTestSuite) TestMustLengthPrefixedAddress() { +func (s *addressTestSuite) TestLengthPrefixedAddressStoreKey() { addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} addr256byte := make([]byte, 256) - s.Require().Equal(append([]byte{byte(10)}, addr10byte...), types.MustLengthPrefixedAddress(addr10byte)) - s.Require().Equal(append([]byte{byte(20)}, addr20byte...), types.MustLengthPrefixedAddress(addr20byte)) - // Address is too long, so panics. - s.Require().Panics(func() { types.MustLengthPrefixedAddress(addr256byte) }) + tests := []struct { + name string + addr []byte + expStoreKey []byte + expErr bool + }{ + {"10-byte address", addr10byte, append([]byte{byte(10)}, addr10byte...), false}, + {"20-byte address", addr20byte, append([]byte{byte(20)}, addr20byte...), false}, + {"256-byte address (too long)", addr256byte, nil, true}, + } + for _, tt := range tests { + tt := tt + s.T().Run(tt.name, func(t *testing.T) { + storeKey, err := types.LengthPrefixedAddressStoreKey(tt.addr) + if tt.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(tt.expStoreKey, storeKey) + } + }) + } } diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index cd8bbd1c3cfc..d3a66020b67c 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -111,7 +111,7 @@ func ExampleFilteredPaginate() { pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr1)) + accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr1)) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { @@ -143,7 +143,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr1)) + accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr1)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index bb20ca0efc86..b81e9c3bff7b 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -193,7 +193,7 @@ func ExamplePaginate() { balResult := sdk.NewCoins() authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr1)) + accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index adb12082336e..eaaf440b8ad6 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -31,8 +31,9 @@ var ( // GetAuthorizationStoreKey - return authorization store key func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { return append(append(append( - GrantKey, sdk.MustLengthPrefixedAddress(granter)...), - sdk.MustLengthPrefixedAddress(grantee)...), + GrantKey, + sdk.MustLengthPrefixedAddressStoreKey(granter)...), + sdk.MustLengthPrefixedAddressStoreKey(grantee)...), []byte(msgType)..., ) } diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 85f69d8b8622..adef0130d167 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -216,5 +216,5 @@ func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) pr store := ctx.KVStore(k.storeKey) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - return prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddress(addr)) + return prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr)) } diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index 824d8afe2583..fda81f2b1bd5 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -22,7 +22,7 @@ func TestAddressFromBalancesStore(t *testing.T) { addrLen := len(addr) require.Equal(t, 20, addrLen) - key := cloneAppend(sdk.MustLengthPrefixedAddress(addr), []byte("stake")) + key := cloneAppend(sdk.MustLengthPrefixedAddressStoreKey(addr), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index c7b01672d987..012e34f8b405 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -152,44 +152,44 @@ func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, he // GetValidatorOutstandingRewardsKey creates the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, sdk.MustLengthPrefixedAddress(valAddr.Bytes())...) + return append(ValidatorOutstandingRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(valAddr.Bytes())...) } // GetDelegatorWithdrawAddrKey creates the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, sdk.MustLengthPrefixedAddress(delAddr.Bytes())...) + return append(DelegatorWithdrawAddrPrefix, sdk.MustLengthPrefixedAddressStoreKey(delAddr.Bytes())...) } // GetDelegatorStartingInfoKey creates the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...), sdk.MustLengthPrefixedAddress(d.Bytes())...) + return append(append(DelegatorStartingInfoPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...), sdk.MustLengthPrefixedAddressStoreKey(d.Bytes())...) } // GetValidatorHistoricalRewardsPrefix creates the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) + return append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) } // GetValidatorHistoricalRewardsKey creates the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...), b...) } // GetValidatorCurrentRewardsKey creates the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) + return append(ValidatorCurrentRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) } // GetValidatorAccumulatedCommissionKey creates the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) + return append(ValidatorAccumulatedCommissionPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) } // GetValidatorSlashEventPrefix creates the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) + return append(ValidatorSlashEventPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) } // GetValidatorSlashEventKeyPrefix creates the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). @@ -199,7 +199,7 @@ func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { return append( ValidatorSlashEventPrefix, - append(sdk.MustLengthPrefixedAddress(v.Bytes()), heightBz...)..., + append(sdk.MustLengthPrefixedAddressStoreKey(v.Bytes()), heightBz...)..., ) } diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index 55db6a38d1c8..3e081453a82c 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -93,7 +93,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), sdk.MustLengthPrefixedAddress(depositorAddr.Bytes())...) + return append(DepositsKey(proposalID), sdk.MustLengthPrefixedAddressStoreKey(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -103,7 +103,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), sdk.MustLengthPrefixedAddress(voterAddr.Bytes())...) + return append(VotesKey(proposalID), sdk.MustLengthPrefixedAddressStoreKey(voterAddr.Bytes())...) } // Split keys function; used for iterators diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index 0b59423384a6..6d96b5baccd7 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -36,7 +36,7 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) + return append(ValidatorSigningInfoKeyPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key @@ -49,7 +49,7 @@ func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, sdk.MustLengthPrefixedAddress(v.Bytes())...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) @@ -62,5 +62,5 @@ func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address func AddrPubkeyRelationKey(address []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, sdk.MustLengthPrefixedAddress(address)...) + return append(AddrPubkeyRelationKeyPrefix, sdk.MustLengthPrefixedAddressStoreKey(address)...) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 8ee3b0cfa8f0..494aaa9d1bfd 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -51,13 +51,13 @@ var ( // GetValidatorKey creates the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, sdk.MustLengthPrefixedAddress(operatorAddr)...) + return append(ValidatorsKey, sdk.MustLengthPrefixedAddressStoreKey(operatorAddr)...) } // GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, sdk.MustLengthPrefixedAddress(addr)...) + return append(ValidatorsByConsAddrKey, sdk.MustLengthPrefixedAddressStoreKey(addr)...) } // AddressFromValidatorsKey creates the validator operator address from ValidatorsKey @@ -109,7 +109,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { // GetLastValidatorPowerKey creates the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, sdk.MustLengthPrefixedAddress(operator)...) + return append(LastValidatorPowerKey, sdk.MustLengthPrefixedAddressStoreKey(operator)...) } // ParseValidatorPowerRankKey parses the validators operator address from power rank key @@ -173,24 +173,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { // GetDelegationKey creates the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), sdk.MustLengthPrefixedAddress(valAddr)...) + return append(GetDelegationsKey(delAddr), sdk.MustLengthPrefixedAddressStoreKey(valAddr)...) } // GetDelegationsKey creates the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) + return append(DelegationKey, sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) } // GetUBDKey creates the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsKey(delAddr.Bytes()), sdk.MustLengthPrefixedAddress(valAddr)...) + return append(GetUBDsKey(delAddr.Bytes()), sdk.MustLengthPrefixedAddressStoreKey(valAddr)...) } // GetUBDByValIndexKey creates the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), sdk.MustLengthPrefixedAddress(delAddr)...) + return append(GetUBDsByValIndexKey(valAddr), sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey @@ -206,12 +206,12 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { // GetUBDsKey creates the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) + return append(UnbondingDelegationKey, sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) } // GetUBDsByValIndexKey creates the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, sdk.MustLengthPrefixedAddress(valAddr)...) + return append(UnbondingDelegationByValIndexKey, sdk.MustLengthPrefixedAddressStoreKey(valAddr)...) } // GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator @@ -307,25 +307,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, sdk.MustLengthPrefixedAddress(delAddr)...) + return append(RedelegationKey, sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, sdk.MustLengthPrefixedAddress(valSrcAddr)...) + return append(RedelegationByValSrcIndexKey, sdk.MustLengthPrefixedAddressStoreKey(valSrcAddr)...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, sdk.MustLengthPrefixedAddress(valDstAddr)...) + return append(RedelegationByValDstIndexKey, sdk.MustLengthPrefixedAddressStoreKey(valDstAddr)...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(GetREDsToValDstIndexKey(valDstAddr), sdk.MustLengthPrefixedAddress(delAddr)...) + return append(GetREDsToValDstIndexKey(valDstAddr), sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. From 08ea670bed6cbb7f2e7434f5cdfead34ee93bf29 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Wed, 27 Jan 2021 14:06:33 +0100 Subject: [PATCH 34/41] Use variable --- types/address.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/types/address.go b/types/address.go index b3ef0e4c3dca..80c412c84119 100644 --- a/types/address.go +++ b/types/address.go @@ -267,15 +267,16 @@ func (aa AccAddress) Format(s fmt.State, verb rune) { // LengthPrefixedAddressStoreKey prefixes the address bytes with its length, this is used // for variable-length components in store keys. func LengthPrefixedAddressStoreKey(bz []byte) ([]byte, error) { - if len(bz) == 0 { + bzLen := len(bz) + if bzLen == 0 { return bz, nil } - if len(bz) > maxAddrLen { - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address length should be max %d bytes, got %d", maxAddrLen, len(bz)) + if bzLen > maxAddrLen { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address length should be max %d bytes, got %d", maxAddrLen, bzLen) } - return append([]byte{byte(len(bz))}, bz...), nil + return append([]byte{byte(bzLen)}, bz...), nil } // MustLengthPrefixedAddressStoreKey is LengthPrefixedAddressStoreKey with a panic. From b6cdc0ae73e6c5d086c5fb87b805f62a4b853826 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Thu, 28 Jan 2021 11:58:40 +0100 Subject: [PATCH 35/41] Rename function --- types/address.go | 33 ++------------------- types/address/store_key.go | 33 +++++++++++++++++++++ types/address/store_key_test.go | 38 +++++++++++++++++++++++++ types/query/filtered_pagination_test.go | 5 ++-- types/query/pagination_test.go | 3 +- x/authz/types/keys.go | 5 ++-- x/bank/keeper/view.go | 3 +- x/bank/types/key_test.go | 3 +- x/distribution/types/keys.go | 19 +++++++------ x/gov/types/keys.go | 5 ++-- x/slashing/types/keys.go | 9 +++--- x/staking/types/keys.go | 27 +++++++++--------- 12 files changed, 118 insertions(+), 65 deletions(-) create mode 100644 types/address/store_key.go create mode 100644 types/address/store_key_test.go diff --git a/types/address.go b/types/address.go index 80c412c84119..eabff6fa97ee 100644 --- a/types/address.go +++ b/types/address.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/bech32" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -29,9 +30,6 @@ const ( // config.SetFullFundraiserPath(yourFullFundraiserPath) // config.Seal() - // Maximum allowed length (in bytes) for an address - maxAddrLen = 255 - // Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address Bech32MainPrefix = "cosmos" @@ -117,8 +115,8 @@ func VerifyAddressFormat(bz []byte) error { return sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty") } - if len(bz) > maxAddrLen { - return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", maxAddrLen, len(bz)) + if len(bz) > address.MaxAddrLen { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bz)) } return nil @@ -264,31 +262,6 @@ func (aa AccAddress) Format(s fmt.State, verb rune) { } } -// LengthPrefixedAddressStoreKey prefixes the address bytes with its length, this is used -// for variable-length components in store keys. -func LengthPrefixedAddressStoreKey(bz []byte) ([]byte, error) { - bzLen := len(bz) - if bzLen == 0 { - return bz, nil - } - - if bzLen > maxAddrLen { - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address length should be max %d bytes, got %d", maxAddrLen, bzLen) - } - - return append([]byte{byte(bzLen)}, bz...), nil -} - -// MustLengthPrefixedAddressStoreKey is LengthPrefixedAddressStoreKey with a panic. -func MustLengthPrefixedAddressStoreKey(bz []byte) []byte { - res, err := LengthPrefixedAddressStoreKey(bz) - if err != nil { - panic(err) - } - - return res -} - // ---------------------------------------------------------------------------- // validator operator // ---------------------------------------------------------------------------- diff --git a/types/address/store_key.go b/types/address/store_key.go new file mode 100644 index 000000000000..3fd08e4b7e7e --- /dev/null +++ b/types/address/store_key.go @@ -0,0 +1,33 @@ +package address + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// MaxAddrLen is the maximum allowed length (in bytes) for an address. +const MaxAddrLen = 255 + +// LengthPrefixedStoreKey prefixes the address bytes with its length, this is used +// for variable-length components in store keys. +func LengthPrefixedStoreKey(bz []byte) ([]byte, error) { + bzLen := len(bz) + if bzLen == 0 { + return bz, nil + } + + if bzLen > MaxAddrLen { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address length should be max %d bytes, got %d", MaxAddrLen, bzLen) + } + + return append([]byte{byte(bzLen)}, bz...), nil +} + +// MustLengthPrefixedStoreKey is LengthPrefixedStoreKey with panic on error. +func MustLengthPrefixedStoreKey(bz []byte) []byte { + res, err := LengthPrefixedStoreKey(bz) + if err != nil { + panic(err) + } + + return res +} diff --git a/types/address/store_key_test.go b/types/address/store_key_test.go new file mode 100644 index 000000000000..2e6cc9a42a1a --- /dev/null +++ b/types/address/store_key_test.go @@ -0,0 +1,38 @@ +package address_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/types/address" +) + +func TestLengthPrefixedAddressStoreKey(t *testing.T) { + addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} + addr256byte := make([]byte, 256) + + tests := []struct { + name string + addr []byte + expStoreKey []byte + expErr bool + }{ + {"10-byte address", addr10byte, append([]byte{byte(10)}, addr10byte...), false}, + {"20-byte address", addr20byte, append([]byte{byte(20)}, addr20byte...), false}, + {"256-byte address (too long)", addr256byte, nil, true}, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + storeKey, err := address.LengthPrefixedStoreKey(tt.addr) + if tt.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expStoreKey, storeKey) + } + }) + } +} diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index d3a66020b67c..461b0d3e823b 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/query" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -111,7 +112,7 @@ func ExampleFilteredPaginate() { pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr1)) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { @@ -143,7 +144,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr1)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index b81e9c3bff7b..b4a301a2ad3c 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/query" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -193,7 +194,7 @@ func ExamplePaginate() { balResult := sdk.NewCoins() authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index eaaf440b8ad6..2b1bc5efbc8c 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -32,8 +33,8 @@ var ( func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { return append(append(append( GrantKey, - sdk.MustLengthPrefixedAddressStoreKey(granter)...), - sdk.MustLengthPrefixedAddressStoreKey(grantee)...), + address.MustLengthPrefixedStoreKey(granter)...), + address.MustLengthPrefixedStoreKey(grantee)...), []byte(msgType)..., ) } diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index adef0130d167..aef68198e022 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -216,5 +217,5 @@ func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) pr store := ctx.KVStore(k.storeKey) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - return prefix.NewStore(balancesStore, sdk.MustLengthPrefixedAddressStoreKey(addr)) + return prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr)) } diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index fda81f2b1bd5..64a1274adf95 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/x/bank/types" ) @@ -22,7 +23,7 @@ func TestAddressFromBalancesStore(t *testing.T) { addrLen := len(addr) require.Equal(t, 20, addrLen) - key := cloneAppend(sdk.MustLengthPrefixedAddressStoreKey(addr), []byte("stake")) + key := cloneAppend(address.MustLengthPrefixedStoreKey(addr), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index 012e34f8b405..327d886f1ecd 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -4,6 +4,7 @@ import ( "encoding/binary" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -152,44 +153,44 @@ func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, he // GetValidatorOutstandingRewardsKey creates the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(valAddr.Bytes())...) + return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefixedStoreKey(valAddr.Bytes())...) } // GetDelegatorWithdrawAddrKey creates the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, sdk.MustLengthPrefixedAddressStoreKey(delAddr.Bytes())...) + return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefixedStoreKey(delAddr.Bytes())...) } // GetDelegatorStartingInfoKey creates the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...), sdk.MustLengthPrefixedAddressStoreKey(d.Bytes())...) + return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...), address.MustLengthPrefixedStoreKey(d.Bytes())...) } // GetValidatorHistoricalRewardsPrefix creates the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) + return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) } // GetValidatorHistoricalRewardsKey creates the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...), b...) } // GetValidatorCurrentRewardsKey creates the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) + return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) } // GetValidatorAccumulatedCommissionKey creates the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) + return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) } // GetValidatorSlashEventPrefix creates the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) + return append(ValidatorSlashEventPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) } // GetValidatorSlashEventKeyPrefix creates the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). @@ -199,7 +200,7 @@ func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { return append( ValidatorSlashEventPrefix, - append(sdk.MustLengthPrefixedAddressStoreKey(v.Bytes()), heightBz...)..., + append(address.MustLengthPrefixedStoreKey(v.Bytes()), heightBz...)..., ) } diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index 3e081453a82c..dbd1b9db13a4 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -6,6 +6,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -93,7 +94,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), sdk.MustLengthPrefixedAddressStoreKey(depositorAddr.Bytes())...) + return append(DepositsKey(proposalID), address.MustLengthPrefixedStoreKey(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -103,7 +104,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), sdk.MustLengthPrefixedAddressStoreKey(voterAddr.Bytes())...) + return append(VotesKey(proposalID), address.MustLengthPrefixedStoreKey(voterAddr.Bytes())...) } // Split keys function; used for iterators diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index 6d96b5baccd7..97e2b27ebd11 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -4,6 +4,7 @@ import ( "encoding/binary" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -36,7 +37,7 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) + return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key @@ -49,7 +50,7 @@ func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, sdk.MustLengthPrefixedAddressStoreKey(v.Bytes())...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) @@ -61,6 +62,6 @@ func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { } // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address -func AddrPubkeyRelationKey(address []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, sdk.MustLengthPrefixedAddressStoreKey(address)...) +func AddrPubkeyRelationKey(addr []byte) []byte { + return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefixedStoreKey(addr)...) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 494aaa9d1bfd..8672555348b3 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -8,6 +8,7 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -51,13 +52,13 @@ var ( // GetValidatorKey creates the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, sdk.MustLengthPrefixedAddressStoreKey(operatorAddr)...) + return append(ValidatorsKey, address.MustLengthPrefixedStoreKey(operatorAddr)...) } // GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, sdk.MustLengthPrefixedAddressStoreKey(addr)...) + return append(ValidatorsByConsAddrKey, address.MustLengthPrefixedStoreKey(addr)...) } // AddressFromValidatorsKey creates the validator operator address from ValidatorsKey @@ -109,7 +110,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { // GetLastValidatorPowerKey creates the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, sdk.MustLengthPrefixedAddressStoreKey(operator)...) + return append(LastValidatorPowerKey, address.MustLengthPrefixedStoreKey(operator)...) } // ParseValidatorPowerRankKey parses the validators operator address from power rank key @@ -173,24 +174,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { // GetDelegationKey creates the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), sdk.MustLengthPrefixedAddressStoreKey(valAddr)...) + return append(GetDelegationsKey(delAddr), address.MustLengthPrefixedStoreKey(valAddr)...) } // GetDelegationsKey creates the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) + return append(DelegationKey, address.MustLengthPrefixedStoreKey(delAddr)...) } // GetUBDKey creates the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsKey(delAddr.Bytes()), sdk.MustLengthPrefixedAddressStoreKey(valAddr)...) + return append(GetUBDsKey(delAddr.Bytes()), address.MustLengthPrefixedStoreKey(valAddr)...) } // GetUBDByValIndexKey creates the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) + return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefixedStoreKey(delAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey @@ -206,12 +207,12 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { // GetUBDsKey creates the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) + return append(UnbondingDelegationKey, address.MustLengthPrefixedStoreKey(delAddr)...) } // GetUBDsByValIndexKey creates the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, sdk.MustLengthPrefixedAddressStoreKey(valAddr)...) + return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefixedStoreKey(valAddr)...) } // GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator @@ -307,25 +308,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) + return append(RedelegationKey, address.MustLengthPrefixedStoreKey(delAddr)...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, sdk.MustLengthPrefixedAddressStoreKey(valSrcAddr)...) + return append(RedelegationByValSrcIndexKey, address.MustLengthPrefixedStoreKey(valSrcAddr)...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, sdk.MustLengthPrefixedAddressStoreKey(valDstAddr)...) + return append(RedelegationByValDstIndexKey, address.MustLengthPrefixedStoreKey(valDstAddr)...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(GetREDsToValDstIndexKey(valDstAddr), sdk.MustLengthPrefixedAddressStoreKey(delAddr)...) + return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefixedStoreKey(delAddr)...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. From e1ba81c1e0a274dd7ea30def291bda505868f2e1 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Thu, 28 Jan 2021 12:37:32 +0100 Subject: [PATCH 36/41] Fix test build --- types/address_test.go | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/types/address_test.go b/types/address_test.go index e98d80708ed1..b9bc0c3c5308 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -528,32 +528,3 @@ func (s *addressTestSuite) TestGetFromBech32() { s.Require().Error(err) s.Require().Equal("invalid Bech32 prefix; expected x, got cosmos", err.Error()) } - -func (s *addressTestSuite) TestLengthPrefixedAddressStoreKey() { - addr10byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} - addr20byte := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} - addr256byte := make([]byte, 256) - - tests := []struct { - name string - addr []byte - expStoreKey []byte - expErr bool - }{ - {"10-byte address", addr10byte, append([]byte{byte(10)}, addr10byte...), false}, - {"20-byte address", addr20byte, append([]byte{byte(20)}, addr20byte...), false}, - {"256-byte address (too long)", addr256byte, nil, true}, - } - for _, tt := range tests { - tt := tt - s.T().Run(tt.name, func(t *testing.T) { - storeKey, err := types.LengthPrefixedAddressStoreKey(tt.addr) - if tt.expErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - s.Require().Equal(tt.expStoreKey, storeKey) - } - }) - } -} From 55e5b923e445904c5188c711a81c78e1dfe592c7 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja <33157909+fdymylja@users.noreply.github.com> Date: Thu, 28 Jan 2021 12:40:09 +0100 Subject: [PATCH 37/41] chore: update rosetta CI (#8453) --- contrib/rosetta/configuration/bootstrap.json | 4 ++-- contrib/rosetta/configuration/data.sh | 5 +++-- contrib/rosetta/configuration/staking.ros | 4 ++-- contrib/rosetta/node/data.tar.gz | Bin 34626 -> 36558 bytes 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/contrib/rosetta/configuration/bootstrap.json b/contrib/rosetta/configuration/bootstrap.json index 15b75b550862..1793988f37e5 100644 --- a/contrib/rosetta/configuration/bootstrap.json +++ b/contrib/rosetta/configuration/bootstrap.json @@ -1,12 +1,12 @@ [ { "account_identifier": { - "address":"cosmos1hdmjfmqmf8ck4pv4evu0s3up0ucm0yjjqfl87e" + "address":"cosmos158nkd0l9tyemv2crp579rmj8dg37qty8lzff88" }, "currency":{ "symbol":"stake", "decimals":0 }, - "value": "999900000000" + "value": "999990000000" } ] \ No newline at end of file diff --git a/contrib/rosetta/configuration/data.sh b/contrib/rosetta/configuration/data.sh index dc4f2cb59a86..45297d5a21bf 100644 --- a/contrib/rosetta/configuration/data.sh +++ b/contrib/rosetta/configuration/data.sh @@ -16,12 +16,13 @@ simd init simd --chain-id testing simd keys add fd --keyring-backend=test addr=$(simd keys show fd -a --keyring-backend=test) +val_addr=$(simd keys show fd --keyring-backend=test --bech val -a) # give the accounts some money simd add-genesis-account "$addr" 1000000000000stake --keyring-backend=test # save configs for the daemon -simd gentx fd --chain-id testing --keyring-backend=test +simd gentx fd 10000000stake --chain-id testing --keyring-backend=test # input genTx to the genesis file simd collect-gentxs @@ -55,4 +56,4 @@ echo zipping data dir and saving to /tmp/data.tar.gz tar -czvf /tmp/data.tar.gz /root/.simapp -echo new address for bootstrap.json "$addr" +echo new address for bootstrap.json "$addr" "$val_addr" diff --git a/contrib/rosetta/configuration/staking.ros b/contrib/rosetta/configuration/staking.ros index 1d9de1d180fa..4f89a43b9893 100644 --- a/contrib/rosetta/configuration/staking.ros +++ b/contrib/rosetta/configuration/staking.ros @@ -94,7 +94,7 @@ staking(1){ "account": { "address": "staking_account", "sub_account": { - "address" : "cosmosvaloper1hdmjfmqmf8ck4pv4evu0s3up0ucm0yjj9atjj2" + "address" : "cosmosvaloper158nkd0l9tyemv2crp579rmj8dg37qty86kaut5" } }, "amount":{ @@ -134,7 +134,7 @@ staking(1){ "account": { "address": "staking_account", "sub_account": { - "address" : "cosmosvaloper1hdmjfmqmf8ck4pv4evu0s3up0ucm0yjj9atjj2" + "address" : "cosmosvaloper158nkd0l9tyemv2crp579rmj8dg37qty86kaut5" } }, "amount":{ diff --git a/contrib/rosetta/node/data.tar.gz b/contrib/rosetta/node/data.tar.gz index a7bed60579ea098baa390af3a29e05b08d16dcc8..ad285ac62e75198c4945859e12ccf7b563c7c29b 100644 GIT binary patch literal 36558 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 W{ds@hpZDkg{P{11*Qv_@PyztMa6X;@ literal 34626 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 O?DZF9r!))zMgjoC3=_)$ From ccb7ad1620fa2e1f0e03f04b3d98b6263936772a Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 29 Jan 2021 10:55:42 +0100 Subject: [PATCH 38/41] Rename again --- types/address/store_key.go | 10 +++++----- types/address/store_key_test.go | 2 +- types/query/filtered_pagination_test.go | 4 ++-- types/query/pagination_test.go | 2 +- x/authz/types/keys.go | 4 ++-- x/bank/keeper/view.go | 2 +- x/bank/types/key_test.go | 2 +- x/distribution/types/keys.go | 18 ++++++++--------- x/gov/types/keys.go | 4 ++-- x/slashing/types/keys.go | 6 +++--- x/staking/types/keys.go | 26 ++++++++++++------------- 11 files changed, 40 insertions(+), 40 deletions(-) diff --git a/types/address/store_key.go b/types/address/store_key.go index 3fd08e4b7e7e..5b9eb0f7cbb4 100644 --- a/types/address/store_key.go +++ b/types/address/store_key.go @@ -7,9 +7,9 @@ import ( // MaxAddrLen is the maximum allowed length (in bytes) for an address. const MaxAddrLen = 255 -// LengthPrefixedStoreKey prefixes the address bytes with its length, this is used +// LengthPrefixStoreKey prefixes the address bytes with its length, this is used // for variable-length components in store keys. -func LengthPrefixedStoreKey(bz []byte) ([]byte, error) { +func LengthPrefixStoreKey(bz []byte) ([]byte, error) { bzLen := len(bz) if bzLen == 0 { return bz, nil @@ -22,9 +22,9 @@ func LengthPrefixedStoreKey(bz []byte) ([]byte, error) { return append([]byte{byte(bzLen)}, bz...), nil } -// MustLengthPrefixedStoreKey is LengthPrefixedStoreKey with panic on error. -func MustLengthPrefixedStoreKey(bz []byte) []byte { - res, err := LengthPrefixedStoreKey(bz) +// MustLengthPrefixStoreKey is LengthPrefixStoreKey with panic on error. +func MustLengthPrefixStoreKey(bz []byte) []byte { + res, err := LengthPrefixStoreKey(bz) if err != nil { panic(err) } diff --git a/types/address/store_key_test.go b/types/address/store_key_test.go index 2e6cc9a42a1a..ef9b5b1e06f7 100644 --- a/types/address/store_key_test.go +++ b/types/address/store_key_test.go @@ -26,7 +26,7 @@ func TestLengthPrefixedAddressStoreKey(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - storeKey, err := address.LengthPrefixedStoreKey(tt.addr) + storeKey, err := address.LengthPrefixStoreKey(tt.addr) if tt.expErr { require.Error(t, err) } else { diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index 461b0d3e823b..3504514207f5 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -112,7 +112,7 @@ func ExampleFilteredPaginate() { pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr1)) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { @@ -144,7 +144,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr1)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index b4a301a2ad3c..683237351437 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -194,7 +194,7 @@ func ExamplePaginate() { balResult := sdk.NewCoins() authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index 2b1bc5efbc8c..4e67f449624a 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -33,8 +33,8 @@ var ( func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { return append(append(append( GrantKey, - address.MustLengthPrefixedStoreKey(granter)...), - address.MustLengthPrefixedStoreKey(grantee)...), + address.MustLengthPrefixStoreKey(granter)...), + address.MustLengthPrefixStoreKey(grantee)...), []byte(msgType)..., ) } diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index aef68198e022..3c20312d1474 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -217,5 +217,5 @@ func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) pr store := ctx.KVStore(k.storeKey) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - return prefix.NewStore(balancesStore, address.MustLengthPrefixedStoreKey(addr)) + return prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr)) } diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index 64a1274adf95..a7315dba2188 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -23,7 +23,7 @@ func TestAddressFromBalancesStore(t *testing.T) { addrLen := len(addr) require.Equal(t, 20, addrLen) - key := cloneAppend(address.MustLengthPrefixedStoreKey(addr), []byte("stake")) + key := cloneAppend(address.MustLengthPrefixStoreKey(addr), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index 327d886f1ecd..fce54a0fde0f 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -153,44 +153,44 @@ func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, he // GetValidatorOutstandingRewardsKey creates the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefixedStoreKey(valAddr.Bytes())...) + return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefixStoreKey(valAddr.Bytes())...) } // GetDelegatorWithdrawAddrKey creates the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefixedStoreKey(delAddr.Bytes())...) + return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefixStoreKey(delAddr.Bytes())...) } // GetDelegatorStartingInfoKey creates the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...), address.MustLengthPrefixedStoreKey(d.Bytes())...) + return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...), address.MustLengthPrefixStoreKey(d.Bytes())...) } // GetValidatorHistoricalRewardsPrefix creates the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) + return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) } // GetValidatorHistoricalRewardsKey creates the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...), b...) } // GetValidatorCurrentRewardsKey creates the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) + return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) } // GetValidatorAccumulatedCommissionKey creates the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) + return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) } // GetValidatorSlashEventPrefix creates the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) + return append(ValidatorSlashEventPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) } // GetValidatorSlashEventKeyPrefix creates the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). @@ -200,7 +200,7 @@ func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { return append( ValidatorSlashEventPrefix, - append(address.MustLengthPrefixedStoreKey(v.Bytes()), heightBz...)..., + append(address.MustLengthPrefixStoreKey(v.Bytes()), heightBz...)..., ) } diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index dbd1b9db13a4..3f1f6a0c099e 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -94,7 +94,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), address.MustLengthPrefixedStoreKey(depositorAddr.Bytes())...) + return append(DepositsKey(proposalID), address.MustLengthPrefixStoreKey(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -104,7 +104,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), address.MustLengthPrefixedStoreKey(voterAddr.Bytes())...) + return append(VotesKey(proposalID), address.MustLengthPrefixStoreKey(voterAddr.Bytes())...) } // Split keys function; used for iterators diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index 97e2b27ebd11..2da6d4cb1fcc 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -37,7 +37,7 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) + return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key @@ -50,7 +50,7 @@ func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, address.MustLengthPrefixedStoreKey(v.Bytes())...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) @@ -63,5 +63,5 @@ func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address func AddrPubkeyRelationKey(addr []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefixedStoreKey(addr)...) + return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefixStoreKey(addr)...) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 8672555348b3..06e310b9ab55 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -52,13 +52,13 @@ var ( // GetValidatorKey creates the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, address.MustLengthPrefixedStoreKey(operatorAddr)...) + return append(ValidatorsKey, address.MustLengthPrefixStoreKey(operatorAddr)...) } // GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, address.MustLengthPrefixedStoreKey(addr)...) + return append(ValidatorsByConsAddrKey, address.MustLengthPrefixStoreKey(addr)...) } // AddressFromValidatorsKey creates the validator operator address from ValidatorsKey @@ -110,7 +110,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { // GetLastValidatorPowerKey creates the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, address.MustLengthPrefixedStoreKey(operator)...) + return append(LastValidatorPowerKey, address.MustLengthPrefixStoreKey(operator)...) } // ParseValidatorPowerRankKey parses the validators operator address from power rank key @@ -174,24 +174,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { // GetDelegationKey creates the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), address.MustLengthPrefixedStoreKey(valAddr)...) + return append(GetDelegationsKey(delAddr), address.MustLengthPrefixStoreKey(valAddr)...) } // GetDelegationsKey creates the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, address.MustLengthPrefixedStoreKey(delAddr)...) + return append(DelegationKey, address.MustLengthPrefixStoreKey(delAddr)...) } // GetUBDKey creates the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsKey(delAddr.Bytes()), address.MustLengthPrefixedStoreKey(valAddr)...) + return append(GetUBDsKey(delAddr.Bytes()), address.MustLengthPrefixStoreKey(valAddr)...) } // GetUBDByValIndexKey creates the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefixedStoreKey(delAddr)...) + return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefixStoreKey(delAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey @@ -207,12 +207,12 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { // GetUBDsKey creates the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, address.MustLengthPrefixedStoreKey(delAddr)...) + return append(UnbondingDelegationKey, address.MustLengthPrefixStoreKey(delAddr)...) } // GetUBDsByValIndexKey creates the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefixedStoreKey(valAddr)...) + return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefixStoreKey(valAddr)...) } // GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator @@ -308,25 +308,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, address.MustLengthPrefixedStoreKey(delAddr)...) + return append(RedelegationKey, address.MustLengthPrefixStoreKey(delAddr)...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, address.MustLengthPrefixedStoreKey(valSrcAddr)...) + return append(RedelegationByValSrcIndexKey, address.MustLengthPrefixStoreKey(valSrcAddr)...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, address.MustLengthPrefixedStoreKey(valDstAddr)...) + return append(RedelegationByValDstIndexKey, address.MustLengthPrefixStoreKey(valDstAddr)...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefixedStoreKey(delAddr)...) + return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefixStoreKey(delAddr)...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. From 5ecfffecbe7dfd725785764d1f8837dea1bd409e Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Fri, 29 Jan 2021 16:57:05 +0100 Subject: [PATCH 39/41] Rename yet again --- types/address/store_key.go | 12 ++++++------ types/address/store_key_test.go | 2 +- types/query/filtered_pagination_test.go | 4 ++-- types/query/pagination_test.go | 2 +- x/authz/types/keys.go | 4 ++-- x/bank/keeper/view.go | 2 +- x/bank/types/key_test.go | 2 +- x/distribution/types/keys.go | 18 ++++++++--------- x/gov/types/keys.go | 4 ++-- x/slashing/types/keys.go | 6 +++--- x/staking/types/keys.go | 26 ++++++++++++------------- 11 files changed, 41 insertions(+), 41 deletions(-) diff --git a/types/address/store_key.go b/types/address/store_key.go index 5b9eb0f7cbb4..948491972936 100644 --- a/types/address/store_key.go +++ b/types/address/store_key.go @@ -7,9 +7,9 @@ import ( // MaxAddrLen is the maximum allowed length (in bytes) for an address. const MaxAddrLen = 255 -// LengthPrefixStoreKey prefixes the address bytes with its length, this is used -// for variable-length components in store keys. -func LengthPrefixStoreKey(bz []byte) ([]byte, error) { +// LengthPrefix prefixes the address bytes with its length, this is used +// for example for variable-length components in store keys. +func LengthPrefix(bz []byte) ([]byte, error) { bzLen := len(bz) if bzLen == 0 { return bz, nil @@ -22,9 +22,9 @@ func LengthPrefixStoreKey(bz []byte) ([]byte, error) { return append([]byte{byte(bzLen)}, bz...), nil } -// MustLengthPrefixStoreKey is LengthPrefixStoreKey with panic on error. -func MustLengthPrefixStoreKey(bz []byte) []byte { - res, err := LengthPrefixStoreKey(bz) +// MustLengthPrefix is LengthPrefix with panic on error. +func MustLengthPrefix(bz []byte) []byte { + res, err := LengthPrefix(bz) if err != nil { panic(err) } diff --git a/types/address/store_key_test.go b/types/address/store_key_test.go index ef9b5b1e06f7..3bb00bd022b0 100644 --- a/types/address/store_key_test.go +++ b/types/address/store_key_test.go @@ -26,7 +26,7 @@ func TestLengthPrefixedAddressStoreKey(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - storeKey, err := address.LengthPrefixStoreKey(tt.addr) + storeKey, err := address.LengthPrefix(tt.addr) if tt.expErr { require.Error(t, err) } else { diff --git a/types/query/filtered_pagination_test.go b/types/query/filtered_pagination_test.go index 3504514207f5..2622f7b8e7c8 100644 --- a/types/query/filtered_pagination_test.go +++ b/types/query/filtered_pagination_test.go @@ -112,7 +112,7 @@ func ExampleFilteredPaginate() { pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} store := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) var balResult sdk.Coins pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { @@ -144,7 +144,7 @@ func ExampleFilteredPaginate() { func execFilterPaginate(store sdk.KVStore, pageReq *query.PageRequest, appCodec codec.Marshaler) (balances sdk.Coins, res *query.PageResponse, err error) { balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) var balResult sdk.Coins res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) { diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go index 683237351437..18853e97cc69 100644 --- a/types/query/pagination_test.go +++ b/types/query/pagination_test.go @@ -194,7 +194,7 @@ func ExamplePaginate() { balResult := sdk.NewCoins() authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr1)) + accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error { var tempRes sdk.Coin err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes) diff --git a/x/authz/types/keys.go b/x/authz/types/keys.go index 4e67f449624a..7ee571b27f74 100644 --- a/x/authz/types/keys.go +++ b/x/authz/types/keys.go @@ -33,8 +33,8 @@ var ( func GetAuthorizationStoreKey(grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) []byte { return append(append(append( GrantKey, - address.MustLengthPrefixStoreKey(granter)...), - address.MustLengthPrefixStoreKey(grantee)...), + address.MustLengthPrefix(granter)...), + address.MustLengthPrefix(grantee)...), []byte(msgType)..., ) } diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 3c20312d1474..7d967eb6e919 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -217,5 +217,5 @@ func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) pr store := ctx.KVStore(k.storeKey) balancesStore := prefix.NewStore(store, types.BalancesPrefix) - return prefix.NewStore(balancesStore, address.MustLengthPrefixStoreKey(addr)) + return prefix.NewStore(balancesStore, address.MustLengthPrefix(addr)) } diff --git a/x/bank/types/key_test.go b/x/bank/types/key_test.go index a7315dba2188..206ef8335c91 100644 --- a/x/bank/types/key_test.go +++ b/x/bank/types/key_test.go @@ -23,7 +23,7 @@ func TestAddressFromBalancesStore(t *testing.T) { addrLen := len(addr) require.Equal(t, 20, addrLen) - key := cloneAppend(address.MustLengthPrefixStoreKey(addr), []byte("stake")) + key := cloneAppend(address.MustLengthPrefix(addr), []byte("stake")) res := types.AddressFromBalancesStore(key) require.Equal(t, res, addr) } diff --git a/x/distribution/types/keys.go b/x/distribution/types/keys.go index fce54a0fde0f..4f0f37f82303 100644 --- a/x/distribution/types/keys.go +++ b/x/distribution/types/keys.go @@ -153,44 +153,44 @@ func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, he // GetValidatorOutstandingRewardsKey creates the outstanding rewards key for a validator. func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte { - return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefixStoreKey(valAddr.Bytes())...) + return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefix(valAddr.Bytes())...) } // GetDelegatorWithdrawAddrKey creates the key for a delegator's withdraw addr. func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte { - return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefixStoreKey(delAddr.Bytes())...) + return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefix(delAddr.Bytes())...) } // GetDelegatorStartingInfoKey creates the key for a delegator's starting info. func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte { - return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...), address.MustLengthPrefixStoreKey(d.Bytes())...) + return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefix(v.Bytes())...), address.MustLengthPrefix(d.Bytes())...) } // GetValidatorHistoricalRewardsPrefix creates the prefix key for a validator's historical rewards. func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte { - return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) + return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefix(v.Bytes())...) } // GetValidatorHistoricalRewardsKey creates the key for a validator's historical rewards. func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte { b := make([]byte, 8) binary.LittleEndian.PutUint64(b, k) - return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...), b...) + return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefix(v.Bytes())...), b...) } // GetValidatorCurrentRewardsKey creates the key for a validator's current rewards. func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte { - return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) + return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefix(v.Bytes())...) } // GetValidatorAccumulatedCommissionKey creates the key for a validator's current commission. func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte { - return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) + return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefix(v.Bytes())...) } // GetValidatorSlashEventPrefix creates the prefix key for a validator's slash fractions. func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte { - return append(ValidatorSlashEventPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) + return append(ValidatorSlashEventPrefix, address.MustLengthPrefix(v.Bytes())...) } // GetValidatorSlashEventKeyPrefix creates the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height). @@ -200,7 +200,7 @@ func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte { return append( ValidatorSlashEventPrefix, - append(address.MustLengthPrefixStoreKey(v.Bytes()), heightBz...)..., + append(address.MustLengthPrefix(v.Bytes()), heightBz...)..., ) } diff --git a/x/gov/types/keys.go b/x/gov/types/keys.go index 3f1f6a0c099e..fe98bcbf81c4 100644 --- a/x/gov/types/keys.go +++ b/x/gov/types/keys.go @@ -94,7 +94,7 @@ func DepositsKey(proposalID uint64) []byte { // DepositKey key of a specific deposit from the store func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte { - return append(DepositsKey(proposalID), address.MustLengthPrefixStoreKey(depositorAddr.Bytes())...) + return append(DepositsKey(proposalID), address.MustLengthPrefix(depositorAddr.Bytes())...) } // VotesKey gets the first part of the votes key based on the proposalID @@ -104,7 +104,7 @@ func VotesKey(proposalID uint64) []byte { // VoteKey key of a specific vote from the store func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte { - return append(VotesKey(proposalID), address.MustLengthPrefixStoreKey(voterAddr.Bytes())...) + return append(VotesKey(proposalID), address.MustLengthPrefix(voterAddr.Bytes())...) } // Split keys function; used for iterators diff --git a/x/slashing/types/keys.go b/x/slashing/types/keys.go index 2da6d4cb1fcc..f0049760f0a0 100644 --- a/x/slashing/types/keys.go +++ b/x/slashing/types/keys.go @@ -37,7 +37,7 @@ var ( // ValidatorSigningInfoKey - stored by *Consensus* address (not operator address) func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte { - return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) + return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefix(v.Bytes())...) } // ValidatorSigningInfoAddress - extract the address from a validator signing info key @@ -50,7 +50,7 @@ func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) { // ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address) func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte { - return append(ValidatorMissedBlockBitArrayKeyPrefix, address.MustLengthPrefixStoreKey(v.Bytes())...) + return append(ValidatorMissedBlockBitArrayKeyPrefix, address.MustLengthPrefix(v.Bytes())...) } // ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address) @@ -63,5 +63,5 @@ func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte { // AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address func AddrPubkeyRelationKey(addr []byte) []byte { - return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefixStoreKey(addr)...) + return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefix(addr)...) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 06e310b9ab55..1854ddac6159 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -52,13 +52,13 @@ var ( // GetValidatorKey creates the key for the validator with address // VALUE: staking/Validator func GetValidatorKey(operatorAddr sdk.ValAddress) []byte { - return append(ValidatorsKey, address.MustLengthPrefixStoreKey(operatorAddr)...) + return append(ValidatorsKey, address.MustLengthPrefix(operatorAddr)...) } // GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { - return append(ValidatorsByConsAddrKey, address.MustLengthPrefixStoreKey(addr)...) + return append(ValidatorsByConsAddrKey, address.MustLengthPrefix(addr)...) } // AddressFromValidatorsKey creates the validator operator address from ValidatorsKey @@ -110,7 +110,7 @@ func GetValidatorsByPowerIndexKey(validator Validator) []byte { // GetLastValidatorPowerKey creates the bonded validator index key for an operator address func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte { - return append(LastValidatorPowerKey, address.MustLengthPrefixStoreKey(operator)...) + return append(LastValidatorPowerKey, address.MustLengthPrefix(operator)...) } // ParseValidatorPowerRankKey parses the validators operator address from power rank key @@ -174,24 +174,24 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { // GetDelegationKey creates the key for delegator bond with validator // VALUE: staking/Delegation func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), address.MustLengthPrefixStoreKey(valAddr)...) + return append(GetDelegationsKey(delAddr), address.MustLengthPrefix(valAddr)...) } // GetDelegationsKey creates the prefix for a delegator for all validators func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, address.MustLengthPrefixStoreKey(delAddr)...) + return append(DelegationKey, address.MustLengthPrefix(delAddr)...) } // GetUBDKey creates the key for an unbonding delegation by delegator and validator addr // VALUE: staking/UnbondingDelegation func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsKey(delAddr.Bytes()), address.MustLengthPrefixStoreKey(valAddr)...) + return append(GetUBDsKey(delAddr.Bytes()), address.MustLengthPrefix(valAddr)...) } // GetUBDByValIndexKey creates the index-key for an unbonding delegation, stored by validator-index // VALUE: none (key rearrangement used) func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefixStoreKey(delAddr)...) + return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefix(delAddr)...) } // GetUBDKeyFromValIndexKey rearranges the ValIndexKey to get the UBDKey @@ -207,12 +207,12 @@ func GetUBDKeyFromValIndexKey(indexKey []byte) []byte { // GetUBDsKey creates the prefix for all unbonding delegations from a delegator func GetUBDsKey(delAddr sdk.AccAddress) []byte { - return append(UnbondingDelegationKey, address.MustLengthPrefixStoreKey(delAddr)...) + return append(UnbondingDelegationKey, address.MustLengthPrefix(delAddr)...) } // GetUBDsByValIndexKey creates the prefix keyspace for the indexes of unbonding delegations for a validator func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { - return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefixStoreKey(valAddr)...) + return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefix(valAddr)...) } // GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator @@ -308,25 +308,25 @@ func GetRedelegationTimeKey(timestamp time.Time) []byte { // GetREDsKey returns a key prefix for indexing a redelegation from a delegator // address. func GetREDsKey(delAddr sdk.AccAddress) []byte { - return append(RedelegationKey, address.MustLengthPrefixStoreKey(delAddr)...) + return append(RedelegationKey, address.MustLengthPrefix(delAddr)...) } // GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to // a source validator. func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte { - return append(RedelegationByValSrcIndexKey, address.MustLengthPrefixStoreKey(valSrcAddr)...) + return append(RedelegationByValSrcIndexKey, address.MustLengthPrefix(valSrcAddr)...) } // GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a // destination (target) validator. func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte { - return append(RedelegationByValDstIndexKey, address.MustLengthPrefixStoreKey(valDstAddr)...) + return append(RedelegationByValDstIndexKey, address.MustLengthPrefix(valDstAddr)...) } // GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation // from an address to a source validator. func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte { - return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefixStoreKey(delAddr)...) + return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefix(delAddr)...) } // GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects. From aea577e8fe6dc51359cb9cdb9d8050015d70eea8 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 1 Feb 2021 11:45:08 +0100 Subject: [PATCH 40/41] Update feegrant keys --- x/feegrant/types/key.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x/feegrant/types/key.go b/x/feegrant/types/key.go index e30427b136b4..7cd1ce4f8c8f 100644 --- a/x/feegrant/types/key.go +++ b/x/feegrant/types/key.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -26,10 +27,10 @@ var ( // FeeAllowanceKey is the canonical key to store a grant from granter to grantee // We store by grantee first to allow searching by everyone who granted to you func FeeAllowanceKey(granter sdk.AccAddress, grantee sdk.AccAddress) []byte { - return append(append(FeeAllowanceKeyPrefix, grantee.Bytes()...), granter.Bytes()...) + return append(FeeAllowancePrefixByGrantee(grantee), address.MustLengthPrefix(granter.Bytes())...) } // FeeAllowancePrefixByGrantee returns a prefix to scan for all grants to this given address. func FeeAllowancePrefixByGrantee(grantee sdk.AccAddress) []byte { - return append(FeeAllowanceKeyPrefix, grantee.Bytes()...) + return append(FeeAllowanceKeyPrefix, address.MustLengthPrefix(grantee.Bytes())...) } From b43189ddfacbc72b69f7181153dc53bdc639e419 Mon Sep 17 00:00:00 2001 From: Amaury Martiny Date: Mon, 1 Feb 2021 12:00:57 +0100 Subject: [PATCH 41/41] Add function to create prefix --- x/bank/keeper/view.go | 4 +--- x/bank/types/key.go | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 7d967eb6e919..1b50fb81d3aa 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -8,7 +8,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" vestexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -215,7 +214,6 @@ func (k BaseViewKeeper) ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) er // getAccountStore gets the account store of the given address. func (k BaseViewKeeper) getAccountStore(ctx sdk.Context, addr sdk.AccAddress) prefix.Store { store := ctx.KVStore(k.storeKey) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - return prefix.NewStore(balancesStore, address.MustLengthPrefix(addr)) + return prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr)) } diff --git a/x/bank/types/key.go b/x/bank/types/key.go index 05cdc657086e..858fd2480ac9 100644 --- a/x/bank/types/key.go +++ b/x/bank/types/key.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" ) const ( @@ -42,3 +43,8 @@ func AddressFromBalancesStore(key []byte) sdk.AccAddress { return sdk.AccAddress(addr) } + +// CreateAccountBalancesPrefix creates the prefix for an account's balances. +func CreateAccountBalancesPrefix(addr []byte) []byte { + return append(BalancesPrefix, address.MustLengthPrefix(addr)...) +}