github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/staking/candidate_test.go (about) 1 // Copyright (c) 2020 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package staking 7 8 import ( 9 "math/big" 10 "testing" 11 12 "github.com/golang/mock/gomock" 13 "github.com/pkg/errors" 14 "github.com/stretchr/testify/require" 15 16 "github.com/iotexproject/iotex-core/action" 17 "github.com/iotexproject/iotex-core/pkg/unit" 18 "github.com/iotexproject/iotex-core/state" 19 "github.com/iotexproject/iotex-core/test/identityset" 20 "github.com/iotexproject/iotex-core/testutil/testdb" 21 ) 22 23 func TestSer(t *testing.T) { 24 r := require.New(t) 25 26 l := &CandidateList{ 27 &Candidate{ 28 Owner: identityset.Address(1), 29 Operator: identityset.Address(2), 30 Reward: identityset.Address(3), 31 Name: "testname1", 32 Votes: big.NewInt(100), 33 SelfStakeBucketIdx: 0, 34 SelfStake: big.NewInt(1100000000), 35 }, 36 &Candidate{ 37 Owner: identityset.Address(4), 38 Operator: identityset.Address(5), 39 Reward: identityset.Address(6), 40 Name: "testname2", 41 Votes: big.NewInt(20), 42 SelfStakeBucketIdx: 1, 43 SelfStake: big.NewInt(2100000000), 44 }, 45 &Candidate{ 46 Owner: identityset.Address(7), 47 Operator: identityset.Address(8), 48 Reward: identityset.Address(9), 49 Name: "testname3", 50 Votes: big.NewInt(3000), 51 SelfStakeBucketIdx: 2, 52 SelfStake: big.NewInt(3100000000), 53 }, 54 } 55 56 ser, err := l.Serialize() 57 r.NoError(err) 58 l1 := &CandidateList{} 59 r.NoError(l1.Deserialize(ser)) 60 r.Equal(l, l1) 61 62 // empty CandidateList can successfully Serialize/Deserialize 63 var m CandidateList 64 ser, err = m.Serialize() 65 r.NoError(err) 66 r.Equal([]byte{}, ser) 67 var m1 CandidateList 68 r.NoError(m1.Deserialize(ser)) 69 r.Nil(m1) 70 } 71 72 func TestClone(t *testing.T) { 73 r := require.New(t) 74 75 d := &Candidate{ 76 Owner: identityset.Address(1), 77 Operator: identityset.Address(2), 78 Reward: identityset.Address(3), 79 Name: "testname1234", 80 Votes: big.NewInt(0), 81 SelfStakeBucketIdx: 0, 82 SelfStake: big.NewInt(2100000000), 83 } 84 r.NoError(d.Validate()) 85 86 d2 := d.Clone() 87 r.True(d.Equal(d2)) 88 d.AddVote(big.NewInt(100)) 89 r.False(d.Equal(d2)) 90 r.NoError(d.Collision(d2)) 91 d.Owner = identityset.Address(0) 92 r.Equal(action.ErrInvalidCanName, d.Collision(d2)) 93 d.Name = "noconflict" 94 r.Equal(ErrInvalidOperator, d.Collision(d2)) 95 d.Operator = identityset.Address(0) 96 r.Equal(ErrInvalidSelfStkIndex, d.Collision(d2)) 97 d.SelfStakeBucketIdx++ 98 r.NoError(d.Collision(d2)) 99 100 c := d.toStateCandidate() 101 r.Equal(d.Owner.String(), c.Address) 102 r.Equal(d.Reward.String(), c.RewardAddress) 103 r.Equal(d.Votes, c.Votes) 104 r.Equal(d.Name, string(c.CanName)) 105 } 106 107 var ( 108 testCandidates = []struct { 109 d *Candidate 110 index int 111 }{ 112 { 113 &Candidate{ 114 Owner: identityset.Address(1), 115 Operator: identityset.Address(7), 116 Reward: identityset.Address(1), 117 Name: "test1", 118 Votes: big.NewInt(2), 119 SelfStakeBucketIdx: 1, 120 SelfStake: unit.ConvertIotxToRau(1200000), 121 }, 122 2, 123 }, 124 { 125 &Candidate{ 126 Owner: identityset.Address(2), 127 Operator: identityset.Address(8), 128 Reward: identityset.Address(1), 129 Name: "test2", 130 Votes: big.NewInt(3), 131 SelfStakeBucketIdx: 2, 132 SelfStake: unit.ConvertIotxToRau(1200000), 133 }, 134 1, 135 }, 136 { 137 &Candidate{ 138 Owner: identityset.Address(3), 139 Operator: identityset.Address(9), 140 Reward: identityset.Address(1), 141 Name: "test3", 142 Votes: big.NewInt(3), 143 SelfStakeBucketIdx: 3, 144 SelfStake: unit.ConvertIotxToRau(1200000), 145 }, 146 0, 147 }, 148 { 149 &Candidate{ 150 Owner: identityset.Address(4), 151 Operator: identityset.Address(10), 152 Reward: identityset.Address(1), 153 Name: "test4", 154 Votes: big.NewInt(1), 155 SelfStakeBucketIdx: 4, 156 SelfStake: unit.ConvertIotxToRau(1200000), 157 }, 158 3, 159 }, 160 // the below 2 will be filtered out in ActiveCandidates() due to insufficient self-stake 161 { 162 &Candidate{ 163 Owner: identityset.Address(5), 164 Operator: identityset.Address(11), 165 Reward: identityset.Address(2), 166 Name: "test5", 167 Votes: big.NewInt(1), 168 SelfStakeBucketIdx: 5, 169 SelfStake: unit.ConvertIotxToRau(1199999), 170 }, 171 5, 172 }, 173 { 174 &Candidate{ 175 Owner: identityset.Address(6), 176 Operator: identityset.Address(12), 177 Reward: identityset.Address(2), 178 Name: "test6", 179 Votes: big.NewInt(1), 180 SelfStakeBucketIdx: 0, 181 SelfStake: unit.ConvertIotxToRau(1100000), 182 }, 183 6, 184 }, 185 } 186 ) 187 188 func TestGetPutCandidate(t *testing.T) { 189 require := require.New(t) 190 191 ctrl := gomock.NewController(t) 192 sm := testdb.NewMockStateManager(ctrl) 193 csm := newCandidateStateManager(sm) 194 csr := newCandidateStateReader(sm) 195 196 // put candidates and get 197 for _, e := range testCandidates { 198 _, _, err := csr.getCandidate(e.d.Owner) 199 require.Equal(state.ErrStateNotExist, errors.Cause(err)) 200 require.NoError(csm.putCandidate(e.d)) 201 d1, _, err := csr.getCandidate(e.d.Owner) 202 require.NoError(err) 203 require.Equal(e.d, d1) 204 } 205 206 // get all candidates 207 all, _, err := csr.getAllCandidates() 208 require.NoError(err) 209 require.Equal(len(testCandidates), len(all)) 210 for _, e := range testCandidates { 211 for i := range all { 212 if all[i].Name == e.d.Name { 213 require.Equal(e.d, all[i]) 214 break 215 } 216 } 217 } 218 219 // delete buckets and get 220 for _, e := range testCandidates { 221 require.NoError(csm.delCandidate(e.d.Owner)) 222 _, _, err := csr.getCandidate(e.d.Owner) 223 require.Equal(state.ErrStateNotExist, errors.Cause(err)) 224 } 225 } 226 227 func TestLess(t *testing.T) { 228 r := require.New(t) 229 pairs := []CandidateList{ 230 { 231 &Candidate{ 232 Owner: identityset.Address(6), 233 Operator: identityset.Address(12), 234 Reward: identityset.Address(2), 235 Name: "test6", 236 Votes: big.NewInt(2), 237 SelfStakeBucketIdx: 0, 238 SelfStake: unit.ConvertIotxToRau(1100000), 239 }, 240 &Candidate{ 241 Owner: identityset.Address(6), 242 Operator: identityset.Address(12), 243 Reward: identityset.Address(2), 244 Name: "test6", 245 Votes: big.NewInt(1), 246 SelfStakeBucketIdx: 0, 247 SelfStake: unit.ConvertIotxToRau(1100000), 248 }, 249 }, 250 { 251 &Candidate{ 252 Owner: identityset.Address(6), 253 Operator: identityset.Address(12), 254 Reward: identityset.Address(2), 255 Name: "test6", 256 Votes: big.NewInt(1), 257 SelfStakeBucketIdx: 0, 258 SelfStake: unit.ConvertIotxToRau(1100000), 259 }, 260 &Candidate{ 261 Owner: identityset.Address(5), 262 Operator: identityset.Address(12), 263 Reward: identityset.Address(2), 264 Name: "test6", 265 Votes: big.NewInt(1), 266 SelfStakeBucketIdx: 0, 267 SelfStake: unit.ConvertIotxToRau(1100000), 268 }, 269 }, 270 { 271 &Candidate{ 272 Owner: identityset.Address(6), 273 Operator: identityset.Address(6), 274 Reward: identityset.Address(2), 275 Name: "test6", 276 Votes: big.NewInt(1), 277 SelfStakeBucketIdx: 0, 278 SelfStake: unit.ConvertIotxToRau(1100000), 279 }, 280 &Candidate{ 281 Owner: identityset.Address(6), 282 Operator: identityset.Address(5), 283 Reward: identityset.Address(2), 284 Name: "test6", 285 Votes: big.NewInt(1), 286 SelfStakeBucketIdx: 0, 287 SelfStake: unit.ConvertIotxToRau(1100000), 288 }, 289 }, 290 { 291 &Candidate{ 292 Owner: identityset.Address(6), 293 Operator: identityset.Address(12), 294 Reward: identityset.Address(6), 295 Name: "test6", 296 Votes: big.NewInt(1), 297 SelfStakeBucketIdx: 0, 298 SelfStake: unit.ConvertIotxToRau(1100000), 299 }, 300 &Candidate{ 301 Owner: identityset.Address(6), 302 Operator: identityset.Address(12), 303 Reward: identityset.Address(5), 304 Name: "test6", 305 Votes: big.NewInt(1), 306 SelfStakeBucketIdx: 0, 307 SelfStake: unit.ConvertIotxToRau(1100000), 308 }, 309 }, 310 { 311 &Candidate{ 312 Owner: identityset.Address(6), 313 Operator: identityset.Address(12), 314 Reward: identityset.Address(6), 315 Name: "test6", 316 Votes: big.NewInt(1), 317 SelfStakeBucketIdx: 0, 318 SelfStake: unit.ConvertIotxToRau(1100000), 319 }, 320 &Candidate{ 321 Owner: identityset.Address(6), 322 Operator: identityset.Address(12), 323 Reward: identityset.Address(6), 324 Name: "test5", 325 Votes: big.NewInt(1), 326 SelfStakeBucketIdx: 0, 327 SelfStake: unit.ConvertIotxToRau(1100000), 328 }, 329 }, 330 { 331 &Candidate{ 332 Owner: identityset.Address(6), 333 Operator: identityset.Address(12), 334 Reward: identityset.Address(6), 335 Name: "test6", 336 Votes: big.NewInt(1), 337 SelfStakeBucketIdx: 1, 338 SelfStake: unit.ConvertIotxToRau(1100000), 339 }, 340 &Candidate{ 341 Owner: identityset.Address(6), 342 Operator: identityset.Address(12), 343 Reward: identityset.Address(6), 344 Name: "test6", 345 Votes: big.NewInt(1), 346 SelfStakeBucketIdx: 0, 347 SelfStake: unit.ConvertIotxToRau(1100000), 348 }, 349 }, 350 { 351 &Candidate{ 352 Owner: identityset.Address(6), 353 Operator: identityset.Address(12), 354 Reward: identityset.Address(6), 355 Name: "test6", 356 Votes: big.NewInt(1), 357 SelfStakeBucketIdx: 0, 358 SelfStake: unit.ConvertIotxToRau(1100001), 359 }, 360 &Candidate{ 361 Owner: identityset.Address(6), 362 Operator: identityset.Address(12), 363 Reward: identityset.Address(6), 364 Name: "test6", 365 Votes: big.NewInt(1), 366 SelfStakeBucketIdx: 0, 367 SelfStake: unit.ConvertIotxToRau(1100000), 368 }, 369 }, 370 } 371 for _, pair := range pairs { 372 r.True(pair.Less(0, 1)) 373 } 374 }