refactor(x/slashing): migrate ValidatorMissedBlockBitmap to collections (#17568)

This commit is contained in:
Likhita Polavarapu 2023-08-30 14:27:28 +05:30 committed by GitHub
parent 356097a6ab
commit a24d7071c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 59 deletions

View File

@ -59,6 +59,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking Changes
* (x/slashing) [#17568](https://github.com/cosmos/cosmos-sdk/pull/17568) Use collections for `ValidatorMissedBlockBitmap`:
* remove from `types`: `ValidatorMissedBlockBitmapPrefixKey`, `ValidatorMissedBlockBitmapKey`
* (x/staking) [#17481](https://github.com/cosmos/cosmos-sdk/pull/17481) Use collections for `UnbondingQueue`:
* remove from `Keeper`: `UBDQueueIterator`
* remove from `types`: `GetUnbondingDelegationTimeKey`

View File

@ -25,11 +25,12 @@ type Keeper struct {
// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string
Schema collections.Schema
Params collections.Item[types.Params]
ValidatorSigningInfo collections.Map[sdk.ConsAddress, types.ValidatorSigningInfo]
AddrPubkeyRelation collections.Map[[]byte, cryptotypes.PubKey]
authority string
Schema collections.Schema
Params collections.Item[types.Params]
ValidatorSigningInfo collections.Map[sdk.ConsAddress, types.ValidatorSigningInfo]
AddrPubkeyRelation collections.Map[[]byte, cryptotypes.PubKey]
ValidatorMissedBlockBitmap collections.Map[collections.Pair[[]byte, uint64], []byte]
}
// NewKeeper creates a slashing keeper
@ -56,6 +57,13 @@ func NewKeeper(cdc codec.BinaryCodec, legacyAmino *codec.LegacyAmino, storeServi
sdk.LengthPrefixedBytesKey, // sdk.LengthPrefixedBytesKey is needed to retain state compatibility
codec.CollInterfaceValue[cryptotypes.PubKey](cdc),
),
ValidatorMissedBlockBitmap: collections.NewMap(
sb,
types.ValidatorMissedBlockBitmapKeyPrefix,
"validator_missed_block_bitmap",
collections.PairKeyCodec(sdk.LengthPrefixedBytesKey, collections.Uint64Key),
collections.BytesValue,
),
}
schema, err := sb.Build()

View File

@ -1,6 +1,7 @@
package keeper_test
import (
"encoding/binary"
"testing"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
@ -18,6 +19,7 @@ import (
sdktestutil "github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
addresstypes "github.com/cosmos/cosmos-sdk/types/address"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
@ -36,10 +38,12 @@ type KeeperTestSuite struct {
slashingKeeper slashingkeeper.Keeper
queryClient slashingtypes.QueryClient
msgServer slashingtypes.MsgServer
key *storetypes.KVStoreKey
}
func (s *KeeperTestSuite) SetupTest() {
key := storetypes.NewKVStoreKey(slashingtypes.StoreKey)
s.key = key
storeService := runtime.NewKVStoreService(key)
testCtx := sdktestutil.DefaultContextWithDB(s.T(), key, storetypes.NewTransientStoreKey("transient_test"))
ctx := testCtx.Ctx.WithBlockHeader(cmtproto.Header{Time: cmttime.Now()})
@ -131,6 +135,45 @@ func (s *KeeperTestSuite) TestJailAndSlashWithInfractionReason() {
s.Require().NoError(s.slashingKeeper.Jail(s.ctx, consAddr))
}
// ValidatorMissedBlockBitmapKey returns the key for a validator's missed block
// bitmap chunk.
func validatorMissedBlockBitmapKey(v sdk.ConsAddress, chunkIndex int64) []byte {
bz := make([]byte, 8)
binary.LittleEndian.PutUint64(bz, uint64(chunkIndex))
validatorMissedBlockBitmapKeyPrefix := []byte{0x02} // Prefix for missed block bitmap
return append(append(validatorMissedBlockBitmapKeyPrefix, addresstypes.MustLengthPrefix(v.Bytes())...), bz...)
}
func (s *KeeperTestSuite) TestValidatorMissedBlockBMMigrationToColls() {
s.SetupTest()
consAddr := sdk.ConsAddress(sdk.AccAddress([]byte("addr1_______________")))
index := int64(0)
err := sdktestutil.DiffCollectionsMigration(
s.ctx,
s.key,
100,
func(i int64) {
s.ctx.KVStore(s.key).Set(validatorMissedBlockBitmapKey(consAddr, index), []byte{})
},
"7ad1f994d45ec9495ae5f990a3fba100c2cc70167a154c33fb43882dc004eafd",
)
s.Require().NoError(err)
err = sdktestutil.DiffCollectionsMigration(
s.ctx,
s.key,
100,
func(i int64) {
err := s.slashingKeeper.SetMissedBlockBitmapChunk(s.ctx, consAddr, index, []byte{})
s.Require().NoError(err)
},
"7ad1f994d45ec9495ae5f990a3fba100c2cc70167a154c33fb43882dc004eafd",
)
s.Require().NoError(err)
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -2,12 +2,13 @@ package keeper
import (
"context"
"errors"
"time"
"github.com/bits-and-blooms/bitset"
"cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/collections"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/slashing/types"
@ -25,7 +26,7 @@ func (k Keeper) HasValidatorSigningInfo(ctx context.Context, consAddr sdk.ConsAd
func (k Keeper) JailUntil(ctx context.Context, consAddr sdk.ConsAddress, jailTime time.Time) error {
signInfo, err := k.ValidatorSigningInfo.Get(ctx, consAddr)
if err != nil {
return errors.Wrap(err, "cannot jail validator that does not have any signing information")
return errorsmod.Wrap(err, "cannot jail validator that does not have any signing information")
}
signInfo.JailedUntil = jailTime
@ -61,17 +62,25 @@ func (k Keeper) IsTombstoned(ctx context.Context, consAddr sdk.ConsAddress) bool
// getMissedBlockBitmapChunk gets the bitmap chunk at the given chunk index for
// a validator's missed block signing window.
func (k Keeper) getMissedBlockBitmapChunk(ctx context.Context, addr sdk.ConsAddress, chunkIndex int64) ([]byte, error) {
store := k.storeService.OpenKVStore(ctx)
chunk, err := store.Get(types.ValidatorMissedBlockBitmapKey(addr, chunkIndex))
return chunk, err
consAddr, err := k.sk.ConsensusAddressCodec().StringToBytes(addr.String())
if err != nil {
return nil, err
}
chunk, err := k.ValidatorMissedBlockBitmap.Get(ctx, collections.Join(consAddr, uint64(chunkIndex)))
if err != nil && !errors.Is(err, collections.ErrNotFound) {
return nil, err
}
return chunk, nil
}
// setMissedBlockBitmapChunk sets the bitmap chunk at the given chunk index for
// SetMissedBlockBitmapChunk sets the bitmap chunk at the given chunk index for
// a validator's missed block signing window.
func (k Keeper) setMissedBlockBitmapChunk(ctx context.Context, addr sdk.ConsAddress, chunkIndex int64, chunk []byte) error {
store := k.storeService.OpenKVStore(ctx)
key := types.ValidatorMissedBlockBitmapKey(addr, chunkIndex)
return store.Set(key, chunk)
func (k Keeper) SetMissedBlockBitmapChunk(ctx context.Context, addr sdk.ConsAddress, chunkIndex int64, chunk []byte) error {
consAddr, err := k.sk.ConsensusAddressCodec().StringToBytes(addr.String())
if err != nil {
return err
}
return k.ValidatorMissedBlockBitmap.Set(ctx, collections.Join(consAddr, uint64(chunkIndex)), chunk)
}
// GetMissedBlockBitmapValue returns true if a validator missed signing a block
@ -87,12 +96,12 @@ func (k Keeper) GetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddr
bs := bitset.New(uint(types.MissedBlockBitmapChunkSize))
chunk, err := k.getMissedBlockBitmapChunk(ctx, addr, chunkIndex)
if err != nil {
return false, errors.Wrapf(err, "failed to get bitmap chunk; index: %d", index)
return false, errorsmod.Wrapf(err, "failed to get bitmap chunk; index: %d", index)
}
if chunk != nil {
if err := bs.UnmarshalBinary(chunk); err != nil {
return false, errors.Wrapf(err, "failed to decode bitmap chunk; index: %d", index)
return false, errorsmod.Wrapf(err, "failed to decode bitmap chunk; index: %d", index)
}
}
@ -116,12 +125,12 @@ func (k Keeper) SetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddr
bs := bitset.New(uint(types.MissedBlockBitmapChunkSize))
chunk, err := k.getMissedBlockBitmapChunk(ctx, addr, chunkIndex)
if err != nil {
return errors.Wrapf(err, "failed to get bitmap chunk; index: %d", index)
return errorsmod.Wrapf(err, "failed to get bitmap chunk; index: %d", index)
}
if chunk != nil {
if err := bs.UnmarshalBinary(chunk); err != nil {
return errors.Wrapf(err, "failed to decode bitmap chunk; index: %d", index)
return errorsmod.Wrapf(err, "failed to decode bitmap chunk; index: %d", index)
}
}
@ -135,28 +144,30 @@ func (k Keeper) SetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddr
updatedChunk, err := bs.MarshalBinary()
if err != nil {
return errors.Wrapf(err, "failed to encode bitmap chunk; index: %d", index)
return errorsmod.Wrapf(err, "failed to encode bitmap chunk; index: %d", index)
}
return k.setMissedBlockBitmapChunk(ctx, addr, chunkIndex, updatedChunk)
return k.SetMissedBlockBitmapChunk(ctx, addr, chunkIndex, updatedChunk)
}
// DeleteMissedBlockBitmap removes a validator's missed block bitmap from state.
func (k Keeper) DeleteMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddress) error {
store := k.storeService.OpenKVStore(ctx)
prefix := types.ValidatorMissedBlockBitmapPrefixKey(addr)
iter, err := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix))
consAddr, err := k.sk.ConsensusAddressCodec().StringToBytes(addr.String())
if err != nil {
return err
}
defer iter.Close()
for ; iter.Valid(); iter.Next() {
err = store.Delete(iter.Key())
rng := collections.NewPrefixedPairRange[[]byte, uint64](consAddr)
err = k.ValidatorMissedBlockBitmap.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], value []byte) (bool, error) {
err := k.ValidatorMissedBlockBitmap.Remove(ctx, key)
if err != nil {
return err
return true, err
}
return false, nil
})
if err != nil {
return err
}
return nil
}
@ -167,20 +178,17 @@ func (k Keeper) DeleteMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddres
// Note: A callback will only be executed over all bitmap chunks that exist in
// state.
func (k Keeper) IterateMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddress, cb func(index int64, missed bool) (stop bool)) error {
store := k.storeService.OpenKVStore(ctx)
prefix := types.ValidatorMissedBlockBitmapPrefixKey(addr)
iter, err := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix))
consAddr, err := k.sk.ConsensusAddressCodec().StringToBytes(addr.String())
if err != nil {
return err
}
defer iter.Close()
var index int64
for ; iter.Valid(); iter.Next() {
rng := collections.NewPrefixedPairRange[[]byte, uint64](consAddr)
err = k.ValidatorMissedBlockBitmap.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], value []byte) (bool, error) {
bs := bitset.New(uint(types.MissedBlockBitmapChunkSize))
if err := bs.UnmarshalBinary(iter.Value()); err != nil {
return errors.Wrapf(err, "failed to decode bitmap chunk; index: %v", string(iter.Key()))
if err := bs.UnmarshalBinary(value); err != nil {
return true, errorsmod.Wrapf(err, "failed to decode bitmap chunk; index: %v", key)
}
for i := uint(0); i < types.MissedBlockBitmapChunkSize; i++ {
@ -191,6 +199,10 @@ func (k Keeper) IterateMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddre
index++
}
return false, nil
})
if err != nil {
return err
}
return nil
}

View File

@ -27,12 +27,10 @@ func TestDecodeStore(t *testing.T) {
dec := simulation.NewDecodeStore(cdc)
info := types.NewValidatorSigningInfo(consAddr1, 0, 1, time.Now().UTC(), false, 0)
missed := []byte{1} // we want to display the bytes for simulation diffs
kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{Key: types.ValidatorSigningInfoKey(consAddr1), Value: cdc.MustMarshal(&info)},
{Key: types.ValidatorMissedBlockBitmapKey(consAddr1, 6), Value: missed},
{Key: []byte{0x99}, Value: []byte{0x99}}, // This test should panic
},
}
@ -43,7 +41,6 @@ func TestDecodeStore(t *testing.T) {
panics bool
}{
{"ValidatorSigningInfo", fmt.Sprintf("%v\n%v", info, info), false},
{"ValidatorMissedBlockBitArray", fmt.Sprintf("missedA: %v\nmissedB: %v\n", missed, missed), false},
{"other", "", true},
}
for i, tt := range tests {

View File

@ -1,8 +1,6 @@
package types
import (
"encoding/binary"
"cosmossdk.io/collections"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -51,7 +49,7 @@ const (
var (
ParamsKey = collections.NewPrefix(0) // Prefix for params key
ValidatorSigningInfoKeyPrefix = collections.NewPrefix(1) // Prefix for signing info
ValidatorMissedBlockBitmapKeyPrefix = []byte{0x02} // Prefix for missed block bitmap
ValidatorMissedBlockBitmapKeyPrefix = collections.NewPrefix(2) // Prefix for missed block bitmap
AddrPubkeyRelationKeyPrefix = collections.NewPrefix(3) // Prefix for address-pubkey relation
)
@ -59,18 +57,3 @@ var (
func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte {
return append(ValidatorSigningInfoKeyPrefix, address.MustLengthPrefix(v.Bytes())...)
}
// ValidatorMissedBlockBitmapPrefixKey returns the key prefix for a validator's
// missed block bitmap.
func ValidatorMissedBlockBitmapPrefixKey(v sdk.ConsAddress) []byte {
return append(ValidatorMissedBlockBitmapKeyPrefix, address.MustLengthPrefix(v.Bytes())...)
}
// ValidatorMissedBlockBitmapKey returns the key for a validator's missed block
// bitmap chunk.
func ValidatorMissedBlockBitmapKey(v sdk.ConsAddress, chunkIndex int64) []byte {
bz := make([]byte, 8)
binary.LittleEndian.PutUint64(bz, uint64(chunkIndex))
return append(ValidatorMissedBlockBitmapPrefixKey(v), bz...)
}