github.com/cosmos/cosmos-sdk@v0.50.10/x/staking/keeper/historical_info_test.go (about) 1 package keeper_test 2 3 import ( 4 cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" 5 6 "cosmossdk.io/math" 7 8 "github.com/cosmos/cosmos-sdk/x/staking/testutil" 9 stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" 10 ) 11 12 // IsValSetSorted reports whether valset is sorted. 13 func IsValSetSorted(data []stakingtypes.Validator, powerReduction math.Int) bool { 14 n := len(data) 15 for i := n - 1; i > 0; i-- { 16 if stakingtypes.ValidatorsByVotingPower(data).Less(i, i-1, powerReduction) { 17 return false 18 } 19 } 20 return true 21 } 22 23 func (s *KeeperTestSuite) TestHistoricalInfo() { 24 ctx, keeper := s.ctx, s.stakingKeeper 25 require := s.Require() 26 27 _, addrVals := createValAddrs(50) 28 29 validators := make([]stakingtypes.Validator, len(addrVals)) 30 31 for i, valAddr := range addrVals { 32 validators[i] = testutil.NewValidator(s.T(), valAddr, PKs[i]) 33 } 34 35 hi := stakingtypes.NewHistoricalInfo(ctx.BlockHeader(), stakingtypes.Validators{Validators: validators}, keeper.PowerReduction(ctx)) 36 require.NoError(keeper.SetHistoricalInfo(ctx, 2, &hi)) 37 38 recv, err := keeper.GetHistoricalInfo(ctx, 2) 39 require.NoError(err, "HistoricalInfo not found after set") 40 require.Equal(hi, recv, "HistoricalInfo not equal") 41 require.True(IsValSetSorted(recv.Valset, keeper.PowerReduction(ctx)), "HistoricalInfo validators is not sorted") 42 43 require.NoError(keeper.DeleteHistoricalInfo(ctx, 2)) 44 45 recv, err = keeper.GetHistoricalInfo(ctx, 2) 46 require.ErrorIs(err, stakingtypes.ErrNoHistoricalInfo, "HistoricalInfo found after delete") 47 require.Equal(stakingtypes.HistoricalInfo{}, recv, "HistoricalInfo is not empty") 48 } 49 50 func (s *KeeperTestSuite) TestTrackHistoricalInfo() { 51 ctx, keeper := s.ctx, s.stakingKeeper 52 require := s.Require() 53 54 _, addrVals := createValAddrs(50) 55 56 // set historical entries in params to 5 57 params := stakingtypes.DefaultParams() 58 params.HistoricalEntries = 5 59 require.NoError(keeper.SetParams(ctx, params)) 60 61 // set historical info at 5, 4 which should be pruned 62 // and check that it has been stored 63 h4 := cmtproto.Header{ 64 ChainID: "HelloChain", 65 Height: 4, 66 } 67 h5 := cmtproto.Header{ 68 ChainID: "HelloChain", 69 Height: 5, 70 } 71 valSet := []stakingtypes.Validator{ 72 testutil.NewValidator(s.T(), addrVals[0], PKs[0]), 73 testutil.NewValidator(s.T(), addrVals[1], PKs[1]), 74 } 75 hi4 := stakingtypes.NewHistoricalInfo(h4, stakingtypes.Validators{Validators: valSet}, keeper.PowerReduction(ctx)) 76 hi5 := stakingtypes.NewHistoricalInfo(h5, stakingtypes.Validators{Validators: valSet}, keeper.PowerReduction(ctx)) 77 require.NoError(keeper.SetHistoricalInfo(ctx, 4, &hi4)) 78 require.NoError(keeper.SetHistoricalInfo(ctx, 5, &hi5)) 79 recv, err := keeper.GetHistoricalInfo(ctx, 4) 80 require.NoError(err) 81 require.Equal(hi4, recv) 82 recv, err = keeper.GetHistoricalInfo(ctx, 5) 83 require.NoError(err) 84 require.Equal(hi5, recv) 85 86 // Set bonded validators in keeper 87 val1 := testutil.NewValidator(s.T(), addrVals[2], PKs[2]) 88 val1.Status = stakingtypes.Bonded // when not bonded, consensus power is Zero 89 val1.Tokens = keeper.TokensFromConsensusPower(ctx, 10) 90 require.NoError(keeper.SetValidator(ctx, val1)) 91 valbz, err := keeper.ValidatorAddressCodec().StringToBytes(val1.GetOperator()) 92 require.NoError(err) 93 require.NoError(keeper.SetLastValidatorPower(ctx, valbz, 10)) 94 val2 := testutil.NewValidator(s.T(), addrVals[3], PKs[3]) 95 val1.Status = stakingtypes.Bonded 96 val2.Tokens = keeper.TokensFromConsensusPower(ctx, 80) 97 require.NoError(keeper.SetValidator(ctx, val2)) 98 valbz, err = keeper.ValidatorAddressCodec().StringToBytes(val2.GetOperator()) 99 require.NoError(err) 100 require.NoError(keeper.SetLastValidatorPower(ctx, valbz, 80)) 101 102 vals := []stakingtypes.Validator{val1, val2} 103 require.True(IsValSetSorted(vals, keeper.PowerReduction(ctx))) 104 105 // Set Header for BeginBlock context 106 header := cmtproto.Header{ 107 ChainID: "HelloChain", 108 Height: 10, 109 } 110 ctx = ctx.WithBlockHeader(header) 111 112 require.NoError(keeper.TrackHistoricalInfo(ctx)) 113 114 // Check HistoricalInfo at height 10 is persisted 115 expected := stakingtypes.HistoricalInfo{ 116 Header: header, 117 Valset: vals, 118 } 119 recv, err = keeper.GetHistoricalInfo(ctx, 10) 120 require.NoError(err, "GetHistoricalInfo failed after BeginBlock") 121 require.Equal(expected, recv, "GetHistoricalInfo returned unexpected result") 122 123 // Check HistoricalInfo at height 5, 4 is pruned 124 recv, err = keeper.GetHistoricalInfo(ctx, 4) 125 require.ErrorIs(err, stakingtypes.ErrNoHistoricalInfo, "GetHistoricalInfo did not prune earlier height") 126 require.Equal(stakingtypes.HistoricalInfo{}, recv, "GetHistoricalInfo at height 4 is not empty after prune") 127 recv, err = keeper.GetHistoricalInfo(ctx, 5) 128 require.ErrorIs(err, stakingtypes.ErrNoHistoricalInfo, "GetHistoricalInfo did not prune first prune height") 129 require.Equal(stakingtypes.HistoricalInfo{}, recv, "GetHistoricalInfo at height 5 is not empty after prune") 130 } 131 132 func (s *KeeperTestSuite) TestGetAllHistoricalInfo() { 133 ctx, keeper := s.ctx, s.stakingKeeper 134 require := s.Require() 135 136 _, addrVals := createValAddrs(50) 137 138 valSet := []stakingtypes.Validator{ 139 testutil.NewValidator(s.T(), addrVals[0], PKs[0]), 140 testutil.NewValidator(s.T(), addrVals[1], PKs[1]), 141 } 142 143 header1 := cmtproto.Header{ChainID: "HelloChain", Height: 9} 144 header2 := cmtproto.Header{ChainID: "HelloChain", Height: 10} 145 header3 := cmtproto.Header{ChainID: "HelloChain", Height: 11} 146 147 hist1 := stakingtypes.HistoricalInfo{Header: header1, Valset: valSet} 148 hist2 := stakingtypes.HistoricalInfo{Header: header2, Valset: valSet} 149 hist3 := stakingtypes.HistoricalInfo{Header: header3, Valset: valSet} 150 151 expHistInfos := []stakingtypes.HistoricalInfo{hist1, hist2, hist3} 152 153 for i, hi := range expHistInfos { 154 require.NoError(keeper.SetHistoricalInfo(ctx, int64(9+i), &hi)) //nolint:gosec // G601: Implicit memory aliasing in for loop. 155 } 156 157 infos, err := keeper.GetAllHistoricalInfo(ctx) 158 require.NoError(err) 159 require.Equal(expHistInfos, infos) 160 }