github.com/cosmos/cosmos-sdk@v0.50.10/x/slashing/migrations/v4/migrate.go (about) 1 package v4 2 3 import ( 4 "github.com/bits-and-blooms/bitset" 5 gogotypes "github.com/cosmos/gogoproto/types" 6 7 "cosmossdk.io/errors" 8 storetypes "cosmossdk.io/store/types" 9 10 "github.com/cosmos/cosmos-sdk/codec" 11 sdk "github.com/cosmos/cosmos-sdk/types" 12 "github.com/cosmos/cosmos-sdk/x/slashing/types" 13 ) 14 15 // Migrate migrates state to consensus version 4. Specifically, the migration 16 // deletes all existing validator bitmap entries and replaces them with a real 17 // "chunked" bitmap. 18 func Migrate(ctx sdk.Context, cdc codec.BinaryCodec, store storetypes.KVStore, params types.Params) error { 19 // Get all the missed blocks for each validator, based on the existing signing 20 // info. 21 var missedBlocks []types.ValidatorMissedBlocks 22 iterateValidatorSigningInfos(ctx, cdc, store, func(addr sdk.ConsAddress, info types.ValidatorSigningInfo) (stop bool) { 23 bechAddr := addr.String() 24 localMissedBlocks := GetValidatorMissedBlocks(ctx, cdc, store, addr, params) 25 26 missedBlocks = append(missedBlocks, types.ValidatorMissedBlocks{ 27 Address: bechAddr, 28 MissedBlocks: localMissedBlocks, 29 }) 30 31 return false 32 }) 33 34 // For each missed blocks entry, of which there should only be one per validator, 35 // we clear all the old entries and insert the new chunked entry. 36 for _, mb := range missedBlocks { 37 addr, err := sdk.ConsAddressFromBech32(mb.Address) 38 if err != nil { 39 return err 40 } 41 42 deleteValidatorMissedBlockBitArray(ctx, store, addr) 43 44 for _, b := range mb.MissedBlocks { 45 // Note: It is not necessary to store entries with missed=false, i.e. where 46 // the bit is zero, since when the bitmap is initialized, all non-set bits 47 // are already zero. 48 if b.Missed { 49 if err := setMissedBlockBitmapValue(ctx, store, addr, b.Index, true); err != nil { 50 return err 51 } 52 } 53 } 54 } 55 56 return nil 57 } 58 59 func iterateValidatorSigningInfos( 60 ctx sdk.Context, 61 cdc codec.BinaryCodec, 62 store storetypes.KVStore, 63 cb func(address sdk.ConsAddress, info types.ValidatorSigningInfo) (stop bool), 64 ) { 65 iter := storetypes.KVStorePrefixIterator(store, ValidatorSigningInfoKeyPrefix) 66 defer iter.Close() 67 68 for ; iter.Valid(); iter.Next() { 69 address := ValidatorSigningInfoAddress(iter.Key()) 70 var info types.ValidatorSigningInfo 71 cdc.MustUnmarshal(iter.Value(), &info) 72 73 if cb(address, info) { 74 break 75 } 76 } 77 } 78 79 func iterateValidatorMissedBlockBitArray( 80 ctx sdk.Context, 81 cdc codec.BinaryCodec, 82 store storetypes.KVStore, 83 addr sdk.ConsAddress, 84 params types.Params, 85 cb func(index int64, missed bool) (stop bool), 86 ) { 87 for i := int64(0); i < params.SignedBlocksWindow; i++ { 88 var missed gogotypes.BoolValue 89 bz := store.Get(ValidatorMissedBlockBitArrayKey(addr, i)) 90 if bz == nil { 91 continue 92 } 93 94 cdc.MustUnmarshal(bz, &missed) 95 if cb(i, missed.Value) { 96 break 97 } 98 } 99 } 100 101 func GetValidatorMissedBlocks( 102 ctx sdk.Context, 103 cdc codec.BinaryCodec, 104 store storetypes.KVStore, 105 addr sdk.ConsAddress, 106 params types.Params, 107 ) []types.MissedBlock { 108 var missedBlocks []types.MissedBlock 109 iterateValidatorMissedBlockBitArray(ctx, cdc, store, addr, params, func(index int64, missed bool) (stop bool) { 110 missedBlocks = append(missedBlocks, types.NewMissedBlock(index, missed)) 111 return false 112 }) 113 114 return missedBlocks 115 } 116 117 func deleteValidatorMissedBlockBitArray(ctx sdk.Context, store storetypes.KVStore, addr sdk.ConsAddress) { 118 iter := storetypes.KVStorePrefixIterator(store, validatorMissedBlockBitArrayPrefixKey(addr)) 119 defer iter.Close() 120 121 for ; iter.Valid(); iter.Next() { 122 store.Delete(iter.Key()) 123 } 124 } 125 126 func setMissedBlockBitmapValue(ctx sdk.Context, store storetypes.KVStore, addr sdk.ConsAddress, index int64, missed bool) error { 127 // get the chunk or "word" in the logical bitmap 128 chunkIndex := index / MissedBlockBitmapChunkSize 129 key := ValidatorMissedBlockBitmapKey(addr, chunkIndex) 130 131 bs := bitset.New(uint(MissedBlockBitmapChunkSize)) 132 chunk := store.Get(key) 133 if chunk != nil { 134 if err := bs.UnmarshalBinary(chunk); err != nil { 135 return errors.Wrapf(err, "failed to decode bitmap chunk; index: %d", index) 136 } 137 } 138 139 // get the bit position in the chunk of the logical bitmap 140 bitIndex := uint(index % MissedBlockBitmapChunkSize) 141 if missed { 142 bs.Set(bitIndex) 143 } else { 144 bs.Clear(bitIndex) 145 } 146 147 updatedChunk, err := bs.MarshalBinary() 148 if err != nil { 149 return errors.Wrapf(err, "failed to encode bitmap chunk; index: %d", index) 150 } 151 152 store.Set(key, updatedChunk) 153 return nil 154 }