github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/rolldpos/epoch_test.go (about) 1 package rolldpos 2 3 import ( 4 "context" 5 "strconv" 6 "testing" 7 8 "github.com/golang/mock/gomock" 9 "github.com/pkg/errors" 10 "github.com/stretchr/testify/require" 11 12 "github.com/iotexproject/iotex-core/test/mock/mock_chainmanager" 13 ) 14 15 func TestEnableDardanellesSubEpoch(t *testing.T) { 16 require := require.New(t) 17 numSubEpochs := 1 18 options := EnableDardanellesSubEpoch(uint64(0), uint64(numSubEpochs)) 19 p := NewProtocol(23, 4, 3) 20 require.Nil(options(p)) 21 require.NotNil(options) 22 } 23 24 func TestNewProtocol(t *testing.T) { 25 require := require.New(t) 26 numCandidateDelegates := uint64(23) 27 numDelegates := uint64(24) 28 numSubEpochs := uint64(3) 29 height := 0 30 options := EnableDardanellesSubEpoch(uint64(height), numSubEpochs) 31 require.NotNil(NewProtocol(numCandidateDelegates, numDelegates, numSubEpochs, options)) 32 } 33 34 func TestProtocol_Handle(t *testing.T) { 35 require := require.New(t) 36 p := NewProtocol(23, 4, 3) 37 ctx := context.Background() 38 receipt, error := p.Handle(ctx, nil, nil) 39 require.Nil(receipt) 40 require.NoError(error) 41 } 42 43 func TestProtocol_NumCandidateDelegates(t *testing.T) { 44 require := require.New(t) 45 p := NewProtocol(23, 4, 3) 46 require.Equal(uint64(23), p.NumCandidateDelegates()) 47 } 48 49 func TestProtocol_NumDelegates(t *testing.T) { 50 require := require.New(t) 51 p := NewProtocol(23, 4, 3) 52 require.Equal(uint64(4), p.NumDelegates()) 53 } 54 55 func TestProtocol_ReadState(t *testing.T) { 56 require := require.New(t) 57 p := NewProtocol(23, 4, 3) 58 ctx := context.Background() 59 methods := [8]string{ 60 "NumCandidateDelegates", 61 "NumDelegates", 62 "NumSubEpochs", 63 "EpochNumber", 64 "EpochHeight", 65 "EpochLastHeight", 66 "SubEpochNumber", 67 "trick", 68 } 69 70 arg1 := []byte("10") 71 arg2 := []byte("20") 72 73 ctrl := gomock.NewController(t) 74 sm := mock_chainmanager.NewMockStateManager(ctrl) 75 sm.EXPECT().Height().Return(uint64(1), nil).AnyTimes() 76 77 arg1Num, err := strconv.ParseUint(string(arg1), 10, 64) 78 require.NoError(err) 79 80 for i, method := range methods { 81 82 if i != 0 && i != 1 { 83 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1, arg2) 84 require.Nil(result) 85 require.Error(err) 86 } 87 88 switch method { 89 90 case "NumCandidateDelegates": 91 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 92 require.Equal(strconv.FormatUint(p.numCandidateDelegates, 10), string(result)) 93 require.NoError(err) 94 95 case "NumDelegates": 96 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 97 require.Equal(strconv.FormatUint(p.numDelegates, 10), string(result)) 98 require.NoError(err) 99 100 case "NumSubEpochs": 101 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 102 require.Equal(strconv.FormatUint(p.NumSubEpochs(arg1Num), 10), string(result)) 103 require.NoError(err) 104 105 case "EpochNumber": 106 107 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 108 require.Equal(strconv.FormatUint(p.GetEpochNum(arg1Num), 10), string(result)) 109 require.NoError(err) 110 111 case "EpochHeight": 112 113 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 114 require.Equal(strconv.FormatUint(p.GetEpochHeight(arg1Num), 10), string(result)) 115 require.NoError(err) 116 117 case "EpochLastHeight": 118 119 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 120 require.Equal(strconv.FormatUint(p.GetEpochLastBlockHeight(arg1Num), 10), string(result)) 121 require.NoError(err) 122 123 case "SubEpochNumber": 124 125 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 126 require.Equal(strconv.FormatUint(p.GetSubEpochNum(arg1Num), 10), string(result)) 127 require.NoError(err) 128 129 default: 130 result, _, err := p.ReadState(ctx, sm, []byte(method), arg1) 131 require.Nil(result) 132 require.Error(err) 133 134 } 135 136 } 137 138 } 139 140 func TestProtocol_NumSubEpochs(t *testing.T) { 141 142 require := require.New(t) 143 144 height := []uint64{0, 1, 12, 25, 38, 53, 59, 80, 90, 93, 120} 145 146 expectedP := []uint64{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3} 147 148 for i := 0; i < len(height); i++ { 149 p1 := NewProtocol(23, 4, 3) 150 p2 := NewProtocol(23, 4, 3) 151 p2.numSubEpochsDardanelles = p2.numSubEpochs 152 p2.dardanellesHeight = height[i] 153 p2.dardanellesOn = true 154 numSubEpochs := p1.NumSubEpochs(height[i]) 155 require.Equal(expectedP[i], numSubEpochs) 156 numSubEpochs = p2.NumSubEpochs(height[i]) 157 require.Equal(expectedP[i], numSubEpochs) 158 } 159 160 } 161 162 func TestGetEpochNum(t *testing.T) { 163 require := require.New(t) 164 165 height := []uint64{0, 1, 12, 25, 38, 53, 59, 80, 90, 93, 120} 166 167 expectedP1 := []uint64{0, 1, 1, 3, 4, 5, 5, 7, 8, 8, 10} 168 expectedP2 := []uint64{0, 1, 1, 3, 4, 5, 5, 7, 8, 8, 10} 169 expectedP3 := []uint64{0, 0, 1, 2, 3, 4, 4, 6, 7, 7, 10} 170 171 //If only the modification of function EnableDardanellesSubEpoch to Protocol, 172 //then function GetEpochNum won't jump out of the second if block 173 //If dardanellesOn =true, and height <= p3.dardanellesHeight, 174 //then p3.numSubEpochsDardanelles can't be 0. 175 //Assume that in addition of function EnableDardanellesSubEpoch, 176 //there are other function that can assign values to numSubEpochsDardanelles 177 for i := 0; i < len(height); i++ { 178 p1 := NewProtocol(23, 4, 3) 179 180 p2 := NewProtocol(23, 4, 3) 181 p2.numSubEpochsDardanelles = p2.numSubEpochs 182 p2.dardanellesHeight = height[i] 183 p2.dardanellesOn = true 184 185 p3 := NewProtocol(23, 4, 3) 186 p3.dardanellesOn = true 187 p3.numSubEpochsDardanelles = 3 188 189 epochNum := p1.GetEpochNum(height[i]) 190 require.Equal(expectedP1[i], epochNum) 191 192 epochNum = p2.GetEpochNum(height[i]) 193 require.Equal(expectedP2[i], epochNum) 194 195 epochNum = p3.GetEpochNum(height[i]) 196 require.Equal(expectedP3[i], epochNum) 197 } 198 199 } 200 201 func TestGetEpochHeight(t *testing.T) { 202 203 require := require.New(t) 204 epochNum := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 205 206 expectedP1 := []uint64{0, 1, 13, 25, 37, 49, 61, 73, 85, 97, 109} 207 expectedP2 := []uint64{0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120} 208 209 for i := 0; i < len(epochNum); i++ { 210 211 p1 := NewProtocol(23, 4, 3) 212 213 p2 := NewProtocol(23, 4, 3) 214 p2.dardanellesOn = true 215 p2.numSubEpochsDardanelles = p2.numSubEpochs 216 p2.dardanellesHeight = 0 //Consider tha p2 doesn't meet the condition fo the second if block, ie height = 0 217 218 epochHeight := p1.GetEpochHeight(epochNum[i]) 219 require.Equal(expectedP1[i], epochHeight) 220 221 epochHeight = p2.GetEpochHeight(epochNum[i]) 222 require.Equal(expectedP2[i], epochHeight) 223 } 224 225 } 226 227 func TestGetEpochLastBlockHeight(t *testing.T) { 228 require := require.New(t) 229 p := NewProtocol(23, 4, 3) 230 231 epochNums := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 232 expectedHeights := []uint64{0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120} 233 for i, epochNum := range epochNums { 234 height := p.GetEpochLastBlockHeight(epochNum) 235 require.Equal(expectedHeights[i], height) 236 } 237 } 238 239 func TestGetSubEpochNum(t *testing.T) { 240 require := require.New(t) 241 p := NewProtocol(23, 4, 3) 242 epochHeights := []uint64{0, 1, 12, 25, 38, 53, 59, 80, 90, 93, 120} 243 expectedSubEpochNums := []uint64{0, 0, 2, 0, 0, 1, 2, 1, 1, 2, 2} 244 for i, epochHeight := range epochHeights { 245 subEpochNum := p.GetSubEpochNum(epochHeight) 246 require.Equal(expectedSubEpochNums[i], subEpochNum) 247 } 248 } 249 250 func productivity(epochStartHeight uint64, epochEndHeight uint64) (map[string]uint64, error) { 251 if epochStartHeight == 0 || epochEndHeight == 0 { 252 return nil, errors.New("productivity error") 253 } 254 return map[string]uint64{"ret": 0}, nil 255 } 256 257 func TestProductivityByEpoch(t *testing.T) { 258 require := require.New(t) 259 p := NewProtocol(23, 4, 3) 260 261 t.Run("normal call", func(t *testing.T) { 262 epochNum := uint64(1) 263 tipHeight := uint64(1) 264 expectedHeights := uint64(1) 265 expectedProduces := map[string]uint64{"ret": 0} 266 retHeight, retProduce, retError := p.ProductivityByEpoch(epochNum, tipHeight, productivity) 267 require.Equal(retHeight, expectedHeights) 268 require.Equal(retProduce, expectedProduces) 269 require.NoError(retError) 270 }) 271 272 t.Run("tipHeight param error", func(t *testing.T) { 273 epochNum := uint64(0) 274 tipHeight := uint64(0) 275 expectedHeights := uint64(0) 276 expectedProduces := map[string]uint64{} 277 retHeight, retProduce, retError := p.ProductivityByEpoch(epochNum, tipHeight, productivity) 278 require.Equal(retHeight, expectedHeights) 279 require.Equal(retProduce, expectedProduces) 280 require.NoError(retError) 281 }) 282 283 t.Run("epochNum param error", func(t *testing.T) { 284 epochNum := uint64(2) 285 tipHeight := uint64(12) 286 expectedHeights := uint64(0) 287 var expectedProduces = map[string]uint64{} 288 expectedProduces = nil 289 expectedErrors := errors.New("epoch number 2 is larger than current epoch number 1") 290 retHeight, retProduce, retError := p.ProductivityByEpoch(epochNum, tipHeight, productivity) 291 require.Equal(retHeight, expectedHeights) 292 require.Equal(retProduce, expectedProduces) 293 require.EqualError(retError, expectedErrors.Error()) 294 }) 295 296 t.Run("productivity param error", func(t *testing.T) { 297 epochNum := uint64(0) 298 tipHeight := uint64(1) 299 expectedHeights := uint64(1) 300 var expectedProduces = map[string]uint64{} 301 expectedProduces = nil 302 expectedErrors := errors.New("productivity error") 303 retHeight, retProduce, retError := p.ProductivityByEpoch(epochNum, tipHeight, productivity) 304 require.Equal(retHeight, expectedHeights) 305 require.Equal(retProduce, expectedProduces) 306 require.EqualError(retError, expectedErrors.Error()) 307 }) 308 }