Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor store keys for variable-length addresses #8363

Merged
merged 54 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
105ea4b
Change account store key in x/bank
amaury1093 Jan 18, 2021
54ddbce
Merge branch 'master' of ssh://github.com/cosmos/cosmos-sdk into am-8…
amaury1093 Jan 18, 2021
ade4a94
Fix pagination test
amaury1093 Jan 20, 2021
bb0cdaf
Merge branch 'master' of ssh://github.com/cosmos/cosmos-sdk into am-8…
amaury1093 Jan 20, 2021
64cfb46
Fix merge master
amaury1093 Jan 20, 2021
f7c4a00
Fix staking keys.go
amaury1093 Jan 22, 2021
47abd5a
Use bech32 in val state change map
amaury1093 Jan 22, 2021
d67029d
Fix sortNoLongerBonded
amaury1093 Jan 22, 2021
ba75256
Use length-prefix function
amaury1093 Jan 22, 2021
129680f
Use length prefix function
amaury1093 Jan 22, 2021
e627da3
Fix test accountStore
amaury1093 Jan 22, 2021
17d2678
Fix ExamplePaginate
amaury1093 Jan 22, 2021
bf16313
Fix staking keys
amaury1093 Jan 22, 2021
98d67f5
Use shorter balances prefix
amaury1093 Jan 22, 2021
045905d
Do slashing keys
amaury1093 Jan 25, 2021
18a2eb1
Fix gov keys
amaury1093 Jan 25, 2021
f0803fc
Fix x/gov tests
amaury1093 Jan 25, 2021
06780ae
Fix x/distrib
amaury1093 Jan 25, 2021
8c0c5b5
Address reviews
amaury1093 Jan 25, 2021
e0f7532
add change log entry
amaury1093 Jan 25, 2021
42cf5c8
Add changelog
amaury1093 Jan 25, 2021
b07a79b
Fix failing tests
amaury1093 Jan 25, 2021
dd432de
Fix sim tests
amaury1093 Jan 25, 2021
b6f001c
fix after-export sim
amaury1093 Jan 25, 2021
4e4408c
Merge branch 'master' into am-8345-store-keys
amaury1093 Jan 25, 2021
53e8298
Fix lint
amaury1093 Jan 25, 2021
3e0a7ca
Address review
amaury1093 Jan 26, 2021
9a1a68a
Merge branch 'master' into am-8345-store-keys
amaury1093 Jan 26, 2021
a0a851c
Fix x/authz
amaury1093 Jan 26, 2021
4a789a7
Fix global config in test
amaury1093 Jan 26, 2021
461758f
Update x/staking/keeper/val_state_change.go
amaury1093 Jan 26, 2021
45767e4
Address comments
amaury1093 Jan 26, 2021
85742b3
merge master
amaury1093 Jan 26, 2021
22cc126
Merge branch 'am-8345-store-keys' of ssh://github.com/cosmos/cosmos-s…
amaury1093 Jan 26, 2021
29a38d0
Fix comments
amaury1093 Jan 26, 2021
51eaa92
Address review
amaury1093 Jan 26, 2021
97376a9
Fix authz test
amaury1093 Jan 27, 2021
e4c222b
Update comment
amaury1093 Jan 27, 2021
9769555
Rename to LengthPrefixedAddressStoreKey
amaury1093 Jan 27, 2021
08ea670
Use variable
amaury1093 Jan 27, 2021
0fbde65
Merge branch 'master' of ssh://github.com/cosmos/cosmos-sdk into am-8…
amaury1093 Jan 28, 2021
b6cdc0a
Rename function
amaury1093 Jan 28, 2021
e1ba81c
Fix test build
amaury1093 Jan 28, 2021
55e5b92
chore: update rosetta CI (#8453)
fdymylja Jan 28, 2021
f27735a
Merge branch 'master' of ssh://github.com/cosmos/cosmos-sdk into am-8…
amaury1093 Jan 29, 2021
ccb7ad1
Rename again
amaury1093 Jan 29, 2021
9463f89
Merge branch 'am-8345-store-keys' of ssh://github.com/cosmos/cosmos-s…
amaury1093 Jan 29, 2021
5ecfffe
Rename yet again
amaury1093 Jan 29, 2021
d1a76cb
Merge branch 'master' into am-8345-store-keys
aaronc Jan 29, 2021
73c6b6b
Merge branch 'master' into am-8345-store-keys
amaury1093 Feb 1, 2021
aea577e
Update feegrant keys
amaury1093 Feb 1, 2021
b43189d
Add function to create prefix
amaury1093 Feb 1, 2021
d928b39
Merge branch 'master' into am-8345-store-keys
amaury1093 Feb 1, 2021
8be9c09
Merge branch 'master' into am-8345-store-keys
mergify[bot] Feb 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions types/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
func LengthPrefixAddress(bz []byte) []byte {
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
if len(bz) == 0 {
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
return bz
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
}

if len(bz) > 255 {
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
panic("address length should be max 255 bytes")
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
}

return append([]byte{byte(len(bz))}, bz...)
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
}

// ----------------------------------------------------------------------------
// validator operator
// ----------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions types/query/filtered_pagination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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, sdk.LengthPrefixAddress(addr1))

var balResult sdk.Coins
res, err = query.FilteredPaginate(accountStore, pageReq, func(key []byte, value []byte, accumulate bool) (bool, error) {
Expand Down
2 changes: 1 addition & 1 deletion types/query/pagination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions x/bank/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,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(_, value []byte) error {
var result sdk.Coin
Expand Down
9 changes: 2 additions & 7 deletions x/bank/keeper/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
16 changes: 10 additions & 6 deletions x/bank/keeper/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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()
Expand Down Expand Up @@ -214,3 +210,11 @@ 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)

return prefix.NewStore(balancesStore, sdk.LengthPrefixAddress(addr))
}
10 changes: 3 additions & 7 deletions x/bank/types/key.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package types

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand All @@ -22,7 +20,7 @@ const (

// KVStore keys
var (
BalancesPrefix = []byte("balances")
BalancesPrefix = []byte{0x02}
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
SupplyKey = []byte{0x00}
DenomMetadataPrefix = []byte{0x1}
)
Expand All @@ -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]
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved

return sdk.AccAddress(addr)
}
4 changes: 3 additions & 1 deletion x/bank/types/key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(sdk.LengthPrefixAddress(addr), []byte("stake"))
res := types.AddressFromBalancesStore(key)
require.Equal(t, res, addr)
}
62 changes: 39 additions & 23 deletions x/staking/keeper/val_state_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
// Called in each EndBlock
func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate {
// Calculate validator set changes.
Expand Down Expand Up @@ -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,
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
// * Updates the active valset as keyed by LastValidatorPowerKey.
// * Updates the total power as keyed by LastTotalPowerKey.
// * Updates validator status' according to updated powers.
Expand All @@ -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)
Expand Down Expand Up @@ -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})

Expand All @@ -174,13 +178,16 @@ 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))
}

noLongerBonded := sortNoLongerBonded(last)
noLongerBonded, err := sortNoLongerBonded(last)
if err != nil {
return nil, err
}
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
for _, valAddrBytes := range noLongerBonded {
validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes))
validator, err = k.bondedToUnbonding(ctx, validator)
Expand Down Expand Up @@ -339,38 +346,47 @@ 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
// We use bech32 strings here, because we can't have slices as keys: map[[]byte][]byte
type validatorsByAddr map[string][]byte
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most changes in this file are related to this change: since we use variable-length addresses, we cannot have map[[]byte][]byte. I'm using the bech32-string as map key here.


// 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
// 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)
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved
noLongerBonded[index] = valAddr
index++
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
}
Expand All @@ -380,5 +396,5 @@ func sortNoLongerBonded(last validatorsByAddr) [][]byte {
return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1
})

return noLongerBonded
return noLongerBonded, nil
}
Loading