Refactor store keys for variable-length addresses (#8363)

* Change account store key in x/bank

* Fix pagination test

* Fix merge master

* Fix staking keys.go

* Use bech32 in val state change map

* Fix sortNoLongerBonded

* Use length-prefix function

* Use length prefix function

* Fix test accountStore

* Fix ExamplePaginate

* Fix staking keys

* Use shorter balances prefix

* Do slashing keys

* Fix gov keys

* Fix x/gov tests

* Fix x/distrib

* Address reviews

* add change log entry

* Add changelog

* Fix failing tests

* Fix sim tests

* fix after-export sim

* Fix lint

* Address review

* Fix x/authz

* Fix global config in test

* Update x/staking/keeper/val_state_change.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Address comments

* Fix comments

* Address review

* Fix authz test

* Update comment

* Rename to LengthPrefixedAddressStoreKey

* Use variable

* Rename function

* Fix test build

* chore: update rosetta CI (#8453)

* Rename again

* Rename yet again

* Update feegrant keys

* Add function to create prefix

Co-authored-by: Robert Zaremba <robert@zaremba.ch>
Co-authored-by: Frojdi Dymylja <33157909+fdymylja@users.noreply.github.com>
Co-authored-by: Aaron Craelius <aaron@regen.network>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Amaury
2021-02-01 13:17:44 +00:00
committed by GitHub
co-authored by Robert Zaremba Frojdi Dymylja Aaron Craelius mergify[bot]
parent 17d7e9a8d5
commit c1b567f44c
28 changed files with 411 additions and 271 deletions
+5
View File
@@ -36,8 +36,13 @@ 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.
* (x/ibc) [\#8266](https://github.com/cosmos/cosmos-sdk/issues/8266) Add amino JSON for IBC messages in order to support Ledger text signing.
### Improvements
+2 -2
View File
@@ -1,12 +1,12 @@
[
{
"account_identifier": {
"address":"cosmos1hdmjfmqmf8ck4pv4evu0s3up0ucm0yjjqfl87e"
"address":"cosmos158nkd0l9tyemv2crp579rmj8dg37qty8lzff88"
},
"currency":{
"symbol":"stake",
"decimals":0
},
"value": "999900000000"
"value": "999990000000"
}
]
+3 -2
View File
@@ -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"
+2 -2
View File
@@ -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":{
Binary file not shown.
+1 -1
View File
@@ -157,7 +157,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(stakingtypes.AddressFromValidatorsKey(iter.Key()))
validator, found := app.StakingKeeper.GetValidator(ctx, addr)
if !found {
panic("expected validator, not found")
+10 -4
View File
@@ -12,7 +12,9 @@ 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"
)
const (
@@ -28,8 +30,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 +110,15 @@ 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))
if len(bz) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, "addresses cannot be empty")
}
if len(bz) > address.MaxAddrLen {
return sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "address max length is %d, got %d", address.MaxAddrLen, len(bz))
}
return nil
}
+33
View File
@@ -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
// 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
}
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
}
// MustLengthPrefix is LengthPrefix with panic on error.
func MustLengthPrefix(bz []byte) []byte {
res, err := LengthPrefix(bz)
if err != nil {
panic(err)
}
return res
}
+38
View File
@@ -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.LengthPrefix(tt.addr)
if tt.expErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expStoreKey, storeKey)
}
})
}
}
+24 -16
View File
@@ -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() {
@@ -364,34 +367,39 @@ 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
// 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().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)
// Reinitialize the global config to default address verifier (nil)
types.GetConfig().SetAddressVerifier(nil)
}
func (s *addressTestSuite) TestBech32ifyAddressBytes() {
+3 -2
View File
@@ -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, addr1.Bytes())
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) {
@@ -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, addr1.Bytes())
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) {
+2 -1
View File
@@ -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, addr1.Bytes())
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)
+15 -4
View File
@@ -2,6 +2,7 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
@@ -21,7 +22,7 @@ const (
// Keys for authz store
// Items are stored with the following key: values
//
// - 0x01<granterAddress_Bytes><granteeAddress_Bytes><msgType_Bytes>: Grant
// - 0x01<granterAddressLen (1 Byte)><granterAddress_Bytes><granteeAddressLen (1 Byte)><granteeAddress_Bytes><msgType_Bytes>: Grant
var (
// Keys for store prefixes
@@ -30,12 +31,22 @@ 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,
address.MustLengthPrefix(granter)...),
address.MustLengthPrefix(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])
// key if of format:
// 0x01<granterAddressLen (1 Byte)><granterAddress_Bytes><granteeAddressLen (1 Byte)><granteeAddress_Bytes><msgType_Bytes>
granterAddrLen := key[1] // remove prefix key
granterAddr = sdk.AccAddress(key[2 : 2+granterAddrLen])
granteeAddrLen := int(key[2+granterAddrLen])
granteeAddr = sdk.AccAddress(key[3+granterAddrLen : 3+granterAddrLen+byte(granteeAddrLen)])
return granterAddr, granteeAddr
}
+1 -3
View File
@@ -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
+2 -7
View File
@@ -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)
+9 -6
View File
@@ -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,10 @@ 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)
return prefix.NewStore(store, types.CreateAccountBalancesPrefix(addr))
}
+11 -7
View File
@@ -1,9 +1,8 @@
package types
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
@@ -22,7 +21,9 @@ const (
// KVStore keys
var (
BalancesPrefix = []byte("balances")
// 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}
)
@@ -37,10 +38,13 @@ 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)
}
// CreateAccountBalancesPrefix creates the prefix for an account's balances.
func CreateAccountBalancesPrefix(addr []byte) []byte {
return append(BalancesPrefix, address.MustLengthPrefix(addr)...)
}
+4 -1
View File
@@ -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"
)
@@ -19,8 +20,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(address.MustLengthPrefix(addr), []byte("stake"))
res := types.AddressFromBalancesStore(key)
require.Equal(t, res, addr)
}
+9 -12
View File
@@ -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())
}
*/
+82 -61
View File
@@ -4,6 +4,7 @@ import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
@@ -27,19 +28,19 @@ const (
//
// - 0x01: sdk.ConsAddress
//
// - 0x02<valAddr_Bytes>: ValidatorOutstandingRewards
// - 0x02<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorOutstandingRewards
//
// - 0x03<accAddr_Bytes>: sdk.AccAddress
// - 0x03<accAddrLen (1 Byte)><accAddr_Bytes>: sdk.AccAddress
//
// - 0x04<valAddr_Bytes><accAddr_Bytes>: DelegatorStartingInfo
// - 0x04<valAddrLen (1 Byte)><valAddr_Bytes><accAddrLen (1 Byte)><accAddr_Bytes>: DelegatorStartingInfo
//
// - 0x05<valAddr_Bytes><period_Bytes>: ValidatorHistoricalRewards
// - 0x05<valAddrLen (1 Byte)><valAddr_Bytes><period_Bytes>: ValidatorHistoricalRewards
//
// - 0x06<valAddr_Bytes>: ValidatorCurrentRewards
// - 0x06<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorCurrentRewards
//
// - 0x07<valAddr_Bytes>: ValidatorCurrentRewards
// - 0x07<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorCurrentRewards
//
// - 0x08<valAddr_Bytes><height>: ValidatorSlashEvent
// - 0x08<valAddrLen (1 Byte)><valAddr_Bytes><height>: ValidatorSlashEvent
var (
FeePoolKey = []byte{0x00} // key for global distribution state
ProposerKey = []byte{0x01} // key for the proposer operator address
@@ -53,47 +54,56 @@ var (
ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction
)
// 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) {
addr := key[1:]
if len(addr) != sdk.AddrLen {
// key is in the format:
// 0x02<valAddrLen (1 Byte)><valAddr_Bytes>
// Remove prefix and address length.
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 creates an address from a delegator's withdraw info key.
func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
addr := key[1:]
if len(addr) != sdk.AddrLen {
// key is in the format:
// 0x03<accAddrLen (1 Byte)><accAddr_Bytes>
// Remove prefix and address length.
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 creates 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 {
// key is in the format:
// 0x04<valAddrLen (1 Byte)><valAddr_Bytes><accAddrLen (1 Byte)><accAddr_Bytes>
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")
}
valAddr = sdk.ValAddress(addr)
addr = key[1+sdk.AddrLen:]
if len(addr) != sdk.AddrLen {
panic("unexpected key length")
}
delAddr = sdk.AccAddress(addr)
return
}
// 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) {
addr := key[1 : 1+sdk.AddrLen]
if len(addr) != sdk.AddrLen {
panic("unexpected key length")
}
valAddr = sdk.ValAddress(addr)
b := key[1+sdk.AddrLen:]
// key is in the format:
// 0x05<valAddrLen (1 Byte)><valAddr_Bytes><period_Bytes>
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 +111,104 @@ func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddr
return
}
// 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) {
addr := key[1:]
if len(addr) != sdk.AddrLen {
// key is in the format:
// 0x06<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorCurrentRewards
// Remove prefix and address length.
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 creates the address from a validator's accumulated commission key.
func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) {
addr := key[1:]
if len(addr) != sdk.AddrLen {
// key is in the format:
// 0x07<valAddrLen (1 Byte)><valAddr_Bytes>: ValidatorCurrentRewards
// Remove prefix and address length.
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 creates 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
// key is in the format:
// 0x08<valAddrLen (1 Byte)><valAddr_Bytes><height>: ValidatorSlashEvent
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 creates the outstanding rewards key for a validator.
func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte {
return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...)
return append(ValidatorOutstandingRewardsPrefix, address.MustLengthPrefix(valAddr.Bytes())...)
}
// 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, delAddr.Bytes()...)
return append(DelegatorWithdrawAddrPrefix, address.MustLengthPrefix(delAddr.Bytes())...)
}
// 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, v.Bytes()...), d.Bytes()...)
return append(append(DelegatorStartingInfoPrefix, address.MustLengthPrefix(v.Bytes())...), address.MustLengthPrefix(d.Bytes())...)
}
// 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, v.Bytes()...)
return append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefix(v.Bytes())...)
}
// 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, v.Bytes()...), b...)
return append(append(ValidatorHistoricalRewardsPrefix, address.MustLengthPrefix(v.Bytes())...), b...)
}
// 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, v.Bytes()...)
return append(ValidatorCurrentRewardsPrefix, address.MustLengthPrefix(v.Bytes())...)
}
// 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, v.Bytes()...)
return append(ValidatorAccumulatedCommissionPrefix, address.MustLengthPrefix(v.Bytes())...)
}
// 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, v.Bytes()...)
return append(ValidatorSlashEventPrefix, address.MustLengthPrefix(v.Bytes())...)
}
// 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(v.Bytes(), heightBz...)...,
append(address.MustLengthPrefix(v.Bytes()), heightBz...)...,
)
}
// 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)
prefix := GetValidatorSlashEventKeyPrefix(v, height)
return append(prefix, periodBz...)
}
+3 -2
View File
@@ -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())...)
}
+8 -9
View File
@@ -6,6 +6,7 @@ import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
@@ -33,9 +34,9 @@ const (
//
// - 0x03: nextProposalID
//
// - 0x10<proposalID_Bytes><depositorAddr_Bytes>: Deposit
// - 0x10<proposalID_Bytes><depositorAddrLen (1 Byte)><depositorAddr_Bytes>: Deposit
//
// - 0x20<proposalID_Bytes><voterAddr_Bytes>: Voter
// - 0x20<proposalID_Bytes><voterAddrLen (1 Byte)><voterAddr_Bytes>: Voter
var (
ProposalsKeyPrefix = []byte{0x00}
ActiveProposalQueuePrefix = []byte{0x01}
@@ -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), depositorAddr.Bytes()...)
return append(DepositsKey(proposalID), address.MustLengthPrefix(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), voterAddr.Bytes()...)
return append(VotesKey(proposalID), address.MustLengthPrefix(voterAddr.Bytes())...)
}
// Split keys function; used for iterators
@@ -154,11 +155,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:
// <prefix (1 Byte)><proposalID (8 bytes)><addrLen (1 Byte)><addr_Bytes>
proposalID = GetProposalIDFromBytes(key[1:9])
addr = sdk.AccAddress(key[9:])
addr = sdk.AccAddress(key[10:])
return
}
-10
View File
@@ -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) })
}
+12 -11
View File
@@ -4,6 +4,7 @@ import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
@@ -23,11 +24,11 @@ const (
// Keys for slashing store
// Items are stored with the following key: values
//
// - 0x01<consAddress_Bytes>: ValidatorSigningInfo
// - 0x01<consAddrLen (1 Byte)><consAddress_Bytes>: ValidatorSigningInfo
//
// - 0x02<consAddress_Bytes><period_Bytes>: bool
// - 0x02<consAddrLen (1 Byte)><consAddress_Bytes><period_Bytes>: bool
//
// - 0x03<accAddr_Bytes>: crypto.PubKey
// - 0x03<accAddrLen (1 Byte)><accAddr_Bytes>: cryptotypes.PubKey
var (
ValidatorSigningInfoKeyPrefix = []byte{0x01} // Prefix for signing info
ValidatorMissedBlockBitArrayKeyPrefix = []byte{0x02} // Prefix for missed block bit array
@@ -36,31 +37,31 @@ var (
// ValidatorSigningInfoKey - stored by *Consensus* address (not operator address)
func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte {
return append(ValidatorSigningInfoKeyPrefix, v.Bytes()...)
return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefix(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")
}
// Remove prefix and address 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, address.MustLengthPrefix(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...)
func AddrPubkeyRelationKey(addr []byte) []byte {
return append(AddrPubkeyRelationKeyPrefix, address.MustLengthPrefix(addr)...)
}
+39 -24
View File
@@ -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 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.
@@ -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,13 +178,17 @@ 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
}
for _, valAddrBytes := range noLongerBonded {
validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes))
validator, err = k.bondedToUnbonding(ctx, validator)
@@ -339,39 +347,46 @@ 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
// 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 := types.AddressFromLastValidatorPowerKey(iterator.Key())
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[:])
noLongerBonded[index] = valAddr
for valAddrStr := range last {
valAddrBytes, err := sdk.ValAddressFromBech32(valAddrStr)
if err != nil {
return nil, err
}
noLongerBonded[index] = valAddrBytes
index++
}
// sorted by address - order doesn't matter
@@ -380,5 +395,5 @@ func sortNoLongerBonded(last validatorsByAddr) [][]byte {
return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1
})
return noLongerBonded
return noLongerBonded, nil
}
+1 -1
View File
@@ -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)
+82 -73
View File
@@ -8,6 +8,7 @@ import (
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
@@ -48,24 +49,29 @@ var (
HistoricalInfoKey = []byte{0x50} // prefix for the historical info
)
// 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, operatorAddr.Bytes()...)
return append(ValidatorsKey, address.MustLengthPrefix(operatorAddr)...)
}
// 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, addr.Bytes()...)
return append(ValidatorsByConsAddrKey, address.MustLengthPrefix(addr)...)
}
// Get the validator operator address from LastValidatorPowerKey
// AddressFromValidatorsKey creates the validator operator address from ValidatorsKey
func AddressFromValidatorsKey(key []byte) []byte {
return key[2:] // remove prefix bytes and address length
}
// AddressFromLastValidatorPowerKey creates 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 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)
@@ -80,39 +86,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 creates the bonded validator index key for an operator address
func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte {
return append(LastValidatorPowerKey, operator...)
return append(LastValidatorPowerKey, address.MustLengthPrefix(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 +171,51 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) {
return ts, int64(height), nil
}
// 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), valAddr.Bytes()...)
return append(GetDelegationsKey(delAddr), address.MustLengthPrefix(valAddr)...)
}
// 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, delAddr.Bytes()...)
return append(DelegationKey, address.MustLengthPrefix(delAddr)...)
}
// 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()),
valAddr.Bytes()...)
return append(GetUBDsKey(delAddr.Bytes()), address.MustLengthPrefix(valAddr)...)
}
// 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), delAddr.Bytes()...)
return append(GetUBDsByValIndexKey(valAddr), address.MustLengthPrefix(delAddr)...)
}
// 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 creates the prefix for all unbonding delegations from a delegator
func GetUBDsKey(delAddr sdk.AccAddress) []byte {
return append(UnbondingDelegationKey, delAddr.Bytes()...)
return append(UnbondingDelegationKey, address.MustLengthPrefix(delAddr)...)
}
// 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, valAddr.Bytes()...)
return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefix(valAddr)...)
}
// 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...)
@@ -222,69 +224,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 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)
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 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)
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 +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, delAddr.Bytes()...)
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, valSrcAddr.Bytes()...)
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, valDstAddr.Bytes()...)
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), delAddr.Bytes()...)
return append(GetREDsToValDstIndexKey(valDstAddr), address.MustLengthPrefix(delAddr)...)
}
// GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects.
+10 -10
View File
@@ -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))