github.com/nnlgsakib/mind-dpos@v0.0.0-20230606105614-f3c8ca06f808/consensus/alien/snapshot_test.go (about) 1 // Copyright 2018 The gttc Authors 2 // This file is part of the gttc library. 3 // 4 // The gttc library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The gttc library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the gttc library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package alien implements the delegated-proof-of-stake consensus engine. 18 19 package alien 20 21 import ( 22 "bytes" 23 "crypto/ecdsa" 24 "math/big" 25 "testing" 26 27 "github.com/TTCECO/gttc/common" 28 "github.com/TTCECO/gttc/core" 29 "github.com/TTCECO/gttc/core/rawdb" 30 "github.com/TTCECO/gttc/core/types" 31 "github.com/TTCECO/gttc/crypto" 32 "github.com/TTCECO/gttc/ethdb" 33 "github.com/TTCECO/gttc/params" 34 ) 35 36 type testerTransaction struct { 37 from string // name of from address 38 to string // name of to address 39 balance int // balance address in snap.voter 40 isVote bool // "ufo:1:event:vote" 41 isProposal bool // "ufo:1:event:proposal:..." 42 proposalType uint64 // proposalTypeCandidateAdd or proposalTypeCandidateRemove 43 isDeclare bool // "ufo:1:event:declare:..." 44 candidate string // name of candidate in proposal 45 txHash string // hash of tx 46 decision bool // decision of declare 47 } 48 49 type testerSingleHeader struct { 50 txs []testerTransaction 51 } 52 53 type testerSelfVoter struct { 54 voter string // name of self voter address in genesis block 55 balance int // balance 56 } 57 58 type testerVote struct { 59 voter string 60 candidate string 61 stake int 62 } 63 64 type testerSnapshot struct { 65 Signers []string 66 Votes map[string]*testerVote 67 Tally map[string]int 68 Voters map[string]int 69 } 70 71 // testerAccountPool is a pool to maintain currently active tester accounts, 72 // mapped from textual names used in the tests below to actual Ethereum private 73 // keys capable of signing transactions. 74 type testerAccountPool struct { 75 accounts map[string]*ecdsa.PrivateKey 76 } 77 78 func newTesterAccountPool() *testerAccountPool { 79 return &testerAccountPool{ 80 accounts: make(map[string]*ecdsa.PrivateKey), 81 } 82 } 83 84 func (ap *testerAccountPool) sign(header *types.Header, signer string) { 85 // Ensure we have a persistent key for the signer 86 if ap.accounts[signer] == nil { 87 ap.accounts[signer], _ = crypto.GenerateKey() 88 } 89 // Sign the header and embed the signature in extra data 90 headerSigHash, _ := sigHash(header) 91 sig, _ := crypto.Sign(headerSigHash.Bytes(), ap.accounts[signer]) 92 copy(header.Extra[len(header.Extra)-65:], sig) 93 } 94 95 func (ap *testerAccountPool) address(account string) common.Address { 96 // Ensure we have a persistent key for the account 97 if ap.accounts[account] == nil { 98 ap.accounts[account], _ = crypto.GenerateKey() 99 } 100 // Resolve and return the Ethereum address 101 return crypto.PubkeyToAddress(ap.accounts[account].PublicKey) 102 } 103 104 func (ap *testerAccountPool) name(address common.Address) string { 105 for name, v := range ap.accounts { 106 if crypto.PubkeyToAddress(v.PublicKey) == address { 107 return name 108 } 109 } 110 return "" 111 } 112 113 // testerChainReader implements consensus.ChainReader to access the genesis 114 // block. All other methods and requests will panic. 115 type testerChainReader struct { 116 db ethdb.Database 117 } 118 119 func (r *testerChainReader) Config() *params.ChainConfig { return params.AllAlienProtocolChanges } 120 func (r *testerChainReader) CurrentHeader() *types.Header { panic("not supported") } 121 func (r *testerChainReader) GetHeader(common.Hash, uint64) *types.Header { panic("not supported") } 122 func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic("not supported") } 123 func (r *testerChainReader) GetHeaderByHash(common.Hash) *types.Header { panic("not supported") } 124 func (r *testerChainReader) GetHeaderByNumber(number uint64) *types.Header { 125 if number == 0 { 126 return rawdb.ReadHeader(r.db, rawdb.ReadCanonicalHash(r.db, 0), 0) 127 } 128 panic("not supported") 129 } 130 131 // Tests that voting is evaluated correctly for various simple and complex scenarios. 132 func TestVoting(t *testing.T) { 133 // Define the various voting scenarios to test 134 tests := []struct { 135 addrNames []string // accounts used in this case 136 candidateNeedPD bool // candidate from POA 137 period uint64 // default 3 138 epoch uint64 // default 30000 139 maxSignerCount uint64 // default 5 for test 140 minVoterBalance int // default 50 141 genesisTimestamp uint64 // default time.now() - period + 1 142 lcrs uint64 // loop count to recreate signers from top tally 143 selfVoters []testerSelfVoter // 144 txHeaders []testerSingleHeader // 145 result testerSnapshot // the result of current snapshot 146 vlCnt uint64 147 }{ 148 { 149 /* Case 0: 150 * Just two self vote address A B in genesis 151 * No votes or transactions through blocks 152 */ 153 addrNames: []string{"A", "B"}, 154 period: uint64(3), 155 epoch: uint64(31), 156 maxSignerCount: uint64(5), 157 minVoterBalance: 50, 158 lcrs: 1, 159 genesisTimestamp: uint64(0), 160 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 161 txHeaders: []testerSingleHeader{ 162 {[]testerTransaction{}}, 163 {[]testerTransaction{}}, 164 {[]testerTransaction{}}, 165 {[]testerTransaction{}}, 166 {[]testerTransaction{}}, 167 {[]testerTransaction{}}, 168 }, 169 result: testerSnapshot{ 170 Signers: []string{"A", "B"}, 171 Tally: map[string]int{"A": 100, "B": 200}, 172 Voters: map[string]int{"A": 0, "B": 0}, 173 Votes: map[string]*testerVote{ 174 "A": {"A", "A", 100}, 175 "B": {"B", "B", 200}, 176 }, 177 }, 178 }, 179 { 180 /* Case 1: 181 * Two self vote address A B in genesis 182 * C vote D to be signer in block 3 183 * But current loop do not finish, so D is not signer, 184 * the vote info already in Tally, Voters and Votes 185 */ 186 addrNames: []string{"A", "B", "C", "D"}, 187 period: uint64(3), 188 epoch: uint64(31), 189 maxSignerCount: uint64(7), 190 minVoterBalance: 50, 191 lcrs: 1, 192 genesisTimestamp: uint64(0), 193 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 194 txHeaders: []testerSingleHeader{ 195 {[]testerTransaction{}}, 196 {[]testerTransaction{}}, 197 {[]testerTransaction{{from: "C", to: "D", balance: 200, isVote: true}}}, 198 {[]testerTransaction{}}, 199 }, 200 result: testerSnapshot{ 201 Signers: []string{"A", "B"}, 202 Tally: map[string]int{"A": 100, "B": 200, "D": 200}, 203 Voters: map[string]int{"A": 0, "B": 0, "C": 3}, 204 Votes: map[string]*testerVote{ 205 "A": {"A", "A", 100}, 206 "B": {"B", "B", 200}, 207 "C": {"C", "D", 200}, 208 }, 209 }, 210 }, 211 { 212 /* Case 2: 213 * Two self vote address in genesis 214 * C vote D to be signer in block 2 215 * But balance of C is lower than minVoterBalance, 216 * so this vote not processed, D is not signer 217 * the vote info is dropped . 218 */ 219 addrNames: []string{"A", "B", "C", "D"}, 220 period: uint64(3), 221 epoch: uint64(31), 222 maxSignerCount: uint64(5), 223 minVoterBalance: 50, 224 lcrs: 1, 225 genesisTimestamp: uint64(0), 226 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 227 txHeaders: []testerSingleHeader{ 228 {[]testerTransaction{}}, 229 {[]testerTransaction{{from: "C", to: "D", balance: 20, isVote: true}}}, 230 {[]testerTransaction{}}, 231 {[]testerTransaction{}}, 232 {[]testerTransaction{}}, 233 {[]testerTransaction{}}, 234 }, 235 result: testerSnapshot{ 236 Signers: []string{"A", "B"}, 237 Tally: map[string]int{"A": 100, "B": 200}, 238 Voters: map[string]int{"A": 0, "B": 0}, 239 Votes: map[string]*testerVote{ 240 "A": {"A", "A", 100}, 241 "B": {"B", "B", 200}, 242 }, 243 }, 244 }, 245 { 246 /* Case 3: 247 * Two self vote address A B in genesis 248 * C vote D to be signer in block 3 249 * balance of C is higher than minVoterBalance 250 * D is signer in next loop 251 */ 252 addrNames: []string{"A", "B", "C", "D"}, 253 period: uint64(3), 254 epoch: uint64(31), 255 maxSignerCount: uint64(5), 256 minVoterBalance: 50, 257 lcrs: 1, 258 genesisTimestamp: uint64(0), 259 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 260 txHeaders: []testerSingleHeader{ 261 {[]testerTransaction{}}, 262 {[]testerTransaction{}}, 263 {[]testerTransaction{{from: "C", to: "D", balance: 200, isVote: true}}}, 264 {[]testerTransaction{}}, 265 {[]testerTransaction{}}, 266 {[]testerTransaction{}}, 267 {[]testerTransaction{}}, 268 }, 269 result: testerSnapshot{ 270 Signers: []string{"A", "B", "D"}, 271 Tally: map[string]int{"A": 100, "B": 200, "D": 200}, 272 Voters: map[string]int{"A": 0, "B": 0, "C": 3}, 273 Votes: map[string]*testerVote{ 274 "A": {"A", "A", 100}, 275 "B": {"B", "B", 200}, 276 "C": {"C", "D", 200}, 277 }, 278 }, 279 }, 280 281 { 282 /* Case 4: 283 * Two self vote address A B in genesis 284 * C vote D to be signer in block 2 285 * C vote B to be signer in block 3 286 * balance of C is higher minVoterBalance 287 * the first vote from C is dropped 288 * the signers are still A and B 289 */ 290 addrNames: []string{"A", "B", "C", "D"}, 291 period: uint64(3), 292 epoch: uint64(31), 293 maxSignerCount: uint64(5), 294 minVoterBalance: 50, 295 lcrs: 1, 296 genesisTimestamp: uint64(0), 297 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 298 txHeaders: []testerSingleHeader{ 299 {[]testerTransaction{}}, 300 {[]testerTransaction{{from: "C", to: "D", balance: 200, isVote: true}}}, 301 {[]testerTransaction{{from: "C", to: "B", balance: 180, isVote: true}}}, 302 {[]testerTransaction{}}, 303 {[]testerTransaction{}}, 304 {[]testerTransaction{}}, 305 }, 306 result: testerSnapshot{ 307 Signers: []string{"A", "B"}, 308 Tally: map[string]int{"A": 100, "B": 380}, 309 Voters: map[string]int{"A": 0, "B": 0, "C": 3}, 310 Votes: map[string]*testerVote{ 311 "A": {"A", "A", 100}, 312 "B": {"B", "B", 200}, 313 "C": {"C", "B", 180}, 314 }, 315 }, 316 }, 317 { 318 /* Case 5: 319 * Two self vote address A B in genesis 320 * C vote D to be signer in block 2 321 * C transaction to E 20 in block 3 322 * In Voters, the vote block number of C is still 2, not 4 323 */ 324 addrNames: []string{"A", "B", "C", "D", "E"}, 325 period: uint64(3), 326 epoch: uint64(31), 327 maxSignerCount: uint64(5), 328 minVoterBalance: 50, 329 lcrs: 1, 330 genesisTimestamp: uint64(0), 331 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 332 txHeaders: []testerSingleHeader{ 333 {[]testerTransaction{}}, 334 {[]testerTransaction{{from: "C", to: "D", balance: 100, isVote: true}}}, 335 {[]testerTransaction{}}, 336 {[]testerTransaction{{from: "C", to: "E", balance: 20, isVote: false}}}, // when C transaction to E, the balance of C is 20 337 {[]testerTransaction{}}, 338 {[]testerTransaction{}}, 339 }, 340 result: testerSnapshot{ 341 Signers: []string{"A", "B", "D"}, 342 Tally: map[string]int{"A": 100, "B": 200, "D": 20}, 343 Voters: map[string]int{"A": 0, "B": 0, "C": 2}, 344 Votes: map[string]*testerVote{ 345 "A": {"A", "A", 100}, 346 "B": {"B", "B", 200}, 347 "C": {"C", "D", 20}, 348 }, 349 }, 350 }, 351 { 352 /* Case 6: 353 * Two self vote address A B in genesis 354 * C vote D , J vote K, H vote I to be signer in block 2 355 * E vote F in block 3 356 * The signers in the next loop is A,B,D,F,I but not K 357 * K is not top 5(maxsigercount) in Tally 358 */ 359 addrNames: []string{"A", "B", "C", "D", "E", "F", "H", "I", "J", "K"}, 360 period: uint64(3), 361 epoch: uint64(31), 362 maxSignerCount: uint64(5), 363 minVoterBalance: 50, 364 lcrs: 1, 365 genesisTimestamp: uint64(0), 366 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 367 txHeaders: []testerSingleHeader{ 368 {[]testerTransaction{}}, 369 {[]testerTransaction{{from: "C", to: "D", balance: 110, isVote: true}, {from: "J", to: "K", balance: 80, isVote: true}, {from: "H", to: "I", balance: 160, isVote: true}}}, 370 {[]testerTransaction{{from: "E", to: "F", balance: 130, isVote: true}}}, 371 {[]testerTransaction{}}, 372 {[]testerTransaction{}}, 373 {[]testerTransaction{}}, 374 {[]testerTransaction{}}, 375 }, 376 result: testerSnapshot{ 377 Signers: []string{"A", "B", "D", "F", "I"}, 378 Tally: map[string]int{"A": 100, "B": 200, "D": 110, "I": 160, "F": 130, "K": 80}, 379 Voters: map[string]int{"A": 0, "B": 0, "C": 2, "H": 2, "J": 2, "E": 3}, 380 Votes: map[string]*testerVote{ 381 "A": {"A", "A", 100}, 382 "B": {"B", "B", 200}, 383 "C": {"C", "D", 110}, 384 "J": {"J", "K", 80}, 385 "H": {"H", "I", 160}, 386 "E": {"E", "F", 130}, 387 }, 388 }, 389 }, 390 { 391 /* Case 7: 392 * one self vote address A in genesis 393 * C vote D , J vote K, H vote I to be signer in block 3 394 * E vote F in block 4 395 * B vote B in block 5 396 * The signers in the next loop is A, B, D,F,I,K 397 * current number - The block number of vote for A > epoch expired 398 * 399 */ 400 addrNames: []string{"A", "B", "C", "D", "E", "F", "H", "I", "J", "K"}, 401 period: uint64(3), 402 epoch: uint64(8), 403 maxSignerCount: uint64(5), 404 minVoterBalance: 50, 405 lcrs: 1, 406 genesisTimestamp: uint64(0), 407 selfVoters: []testerSelfVoter{{"A", 100}}, 408 txHeaders: []testerSingleHeader{ 409 {[]testerTransaction{}}, 410 {[]testerTransaction{}}, 411 {[]testerTransaction{}}, 412 {[]testerTransaction{}}, 413 {[]testerTransaction{}}, 414 {[]testerTransaction{}}, 415 {[]testerTransaction{}}, 416 {[]testerTransaction{}}, 417 {[]testerTransaction{}}, 418 {[]testerTransaction{}}, 419 {[]testerTransaction{}}, 420 {[]testerTransaction{{from: "C", to: "D", balance: 110, isVote: true}, {from: "J", to: "K", balance: 80, isVote: true}, {from: "H", to: "I", balance: 160, isVote: true}}}, 421 {[]testerTransaction{{from: "E", to: "F", balance: 130, isVote: true}}}, 422 {[]testerTransaction{{from: "B", to: "B", balance: 200, isVote: true}}}, 423 {[]testerTransaction{}}, 424 {[]testerTransaction{}}, 425 }, 426 result: testerSnapshot{ 427 Signers: []string{"B", "D", "F", "I", "K"}, 428 Tally: map[string]int{"B": 200, "D": 110, "I": 160, "F": 130, "K": 80}, 429 Voters: map[string]int{"B": 14, "C": 12, "H": 12, "J": 12, "E": 13}, 430 Votes: map[string]*testerVote{ 431 "B": {"B", "B", 200}, 432 "C": {"C", "D", 110}, 433 "J": {"J", "K", 80}, 434 "H": {"H", "I", 160}, 435 "E": {"E", "F", 130}, 436 }, 437 }, 438 }, 439 { 440 /* Case 8: 441 * Two self vote address A,B in genesis 442 * C vote D , D vote C to be signer in block 3 443 */ 444 addrNames: []string{"A", "B", "C", "D", "E"}, 445 period: uint64(3), 446 epoch: uint64(31), 447 maxSignerCount: uint64(5), 448 minVoterBalance: 50, 449 lcrs: 1, 450 genesisTimestamp: uint64(0), 451 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 452 txHeaders: []testerSingleHeader{ 453 {[]testerTransaction{}}, 454 {[]testerTransaction{}}, 455 {[]testerTransaction{{from: "C", to: "D", balance: 110, isVote: true}, {from: "D", to: "C", balance: 80, isVote: true}, {from: "C", to: "E", balance: 110, isVote: false}}}, 456 {[]testerTransaction{}}, 457 {[]testerTransaction{}}, 458 {[]testerTransaction{}}, 459 }, 460 result: testerSnapshot{ 461 Signers: []string{"B", "A", "C", "D"}, 462 Tally: map[string]int{"B": 200, "D": 110, "A": 100, "C": 80}, 463 Voters: map[string]int{"B": 0, "C": 3, "D": 3, "A": 0}, 464 Votes: map[string]*testerVote{ 465 "B": {"B", "B", 200}, 466 "A": {"A", "A", 100}, 467 "C": {"C", "D", 110}, 468 "D": {"D", "C", 80}, 469 }, 470 }, 471 }, 472 { 473 /* Case 9: 474 * Two self vote address A B in genesis 475 * C vote D to be signer in block 3 476 * lcrs is 2, so the signers will recalculate after 5 *2 block 477 * D is still not signer 478 */ 479 addrNames: []string{"A", "B", "C", "D"}, 480 period: uint64(3), 481 epoch: uint64(31), 482 maxSignerCount: uint64(5), 483 minVoterBalance: 50, 484 lcrs: 2, 485 genesisTimestamp: uint64(0), 486 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 487 txHeaders: []testerSingleHeader{ 488 {[]testerTransaction{}}, 489 {[]testerTransaction{}}, 490 {[]testerTransaction{{from: "C", to: "D", balance: 200, isVote: true}}}, 491 {[]testerTransaction{}}, 492 {[]testerTransaction{}}, 493 {[]testerTransaction{}}, 494 {[]testerTransaction{}}, 495 }, 496 result: testerSnapshot{ 497 Signers: []string{"A", "B"}, 498 Tally: map[string]int{"A": 100, "B": 200, "D": 200}, 499 Voters: map[string]int{"A": 0, "B": 0, "C": 3}, 500 Votes: map[string]*testerVote{ 501 "A": {"A", "A", 100}, 502 "B": {"B", "B", 200}, 503 "C": {"C", "D", 200}, 504 }, 505 }, 506 }, 507 { 508 /* Case 10: 509 * Two self vote address A B in genesis 510 * C vote D to be signer in block 3 511 * lcrs is 2, so the signers will recalculate after 5 *2 block 512 * D is signer 513 */ 514 addrNames: []string{"A", "B", "C", "D"}, 515 period: uint64(3), 516 epoch: uint64(31), 517 maxSignerCount: uint64(5), 518 minVoterBalance: 50, 519 lcrs: 2, 520 genesisTimestamp: uint64(0), 521 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 522 txHeaders: []testerSingleHeader{ 523 {[]testerTransaction{}}, 524 {[]testerTransaction{}}, 525 {[]testerTransaction{{from: "C", to: "D", balance: 200, isVote: true}}}, 526 {[]testerTransaction{}}, 527 {[]testerTransaction{}}, 528 {[]testerTransaction{}}, 529 {[]testerTransaction{}}, 530 {[]testerTransaction{}}, 531 {[]testerTransaction{}}, 532 {[]testerTransaction{}}, 533 {[]testerTransaction{}}, 534 {[]testerTransaction{}}, 535 }, 536 result: testerSnapshot{ 537 Signers: []string{"A", "B", "D"}, 538 Tally: map[string]int{"A": 100, "B": 200, "D": 200}, 539 Voters: map[string]int{"A": 0, "B": 0, "C": 3}, 540 Votes: map[string]*testerVote{ 541 "A": {"A", "A", 100}, 542 "B": {"B", "B", 200}, 543 "C": {"C", "D", 200}, 544 }, 545 }, 546 }, 547 { 548 /* Case 11: 549 * All self vote in genesis 550 * lcrs is 1, so the signers will recalculate after 5 block 551 * official 21 node test case 552 */ 553 addrNames: []string{"A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", 554 "A11", "A12", "A13", "A14", "A15", "A16", "A17", "A18", "A19", "A20", 555 "A21", "A22", "A23", "A24", "A25", "A26", "A27", "A28", "A29", "A30", 556 "A31", "A32", "A33", "A34", "A35", "A36", "A37", "A38", "A39", "A40"}, 557 period: uint64(3), 558 epoch: uint64(300), 559 maxSignerCount: uint64(21), 560 minVoterBalance: 50, 561 lcrs: 1, 562 genesisTimestamp: uint64(0), 563 selfVoters: []testerSelfVoter{{"A1", 5000}, {"A2", 5000}, {"A3", 5000}, {"A4", 5000}, {"A5", 5000}, 564 {"A6", 5000}, {"A7", 5000}, {"A8", 5000}, {"A9", 5000}, {"A10", 5000}, 565 {"A11", 4000}, {"A12", 4000}, {"A13", 4000}, {"A14", 4000}, {"A15", 4000}, 566 {"A16", 4000}, {"A17", 4000}, {"A18", 4000}, {"A19", 4000}, {"A20", 4000}, 567 {"A21", 3000}, {"A22", 3000}, {"A23", 3000}, {"A24", 3000}, {"A25", 3000}, 568 {"A26", 3000}, {"A27", 3000}, {"A28", 3000}, {"A29", 3000}, {"A30", 3000}, 569 {"A31", 2000}, {"A32", 2000}, {"A33", 2000}, {"A34", 2000}, {"A35", 2000}, 570 {"A36", 2000}, {"A37", 2000}, {"A38", 2000}, {"A39", 2000}, {"A40", 2000}}, 571 txHeaders: []testerSingleHeader{ 572 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 573 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 574 {[]testerTransaction{}}, {[]testerTransaction{}}, 575 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 576 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 577 {[]testerTransaction{}}, {[]testerTransaction{}}, 578 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 579 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 580 {[]testerTransaction{}}, {[]testerTransaction{}}, 581 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 582 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 583 {[]testerTransaction{}}, {[]testerTransaction{}}, 584 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 585 {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, {[]testerTransaction{}}, 586 {[]testerTransaction{}}, {[]testerTransaction{}}, 587 }, 588 result: testerSnapshot{ 589 Signers: []string{}, 590 Tally: map[string]int{"A1": 5000, "A2": 5000, "A3": 5000, "A4": 5000, "A5": 5000, "A6": 5000, "A7": 5000, "A8": 5000, "A9": 5000, "A10": 5000, 591 "A11": 4000, "A12": 4000, "A13": 4000, "A14": 4000, "A15": 4000, "A16": 4000, "A17": 4000, "A18": 4000, "A19": 4000, "A20": 4000, 592 "A21": 3000, "A22": 3000, "A23": 3000, "A24": 3000, "A25": 3000, "A26": 3000, "A27": 3000, "A28": 3000, "A29": 3000, "A30": 3000, 593 "A31": 2000, "A32": 2000, "A33": 2000, "A34": 2000, "A35": 2000, "A36": 2000, "A37": 2000, "A38": 2000, "A39": 2000, "A40": 2000}, 594 Voters: map[string]int{"A1": 0, "A2": 0, "A3": 0, "A4": 0, "A5": 0, "A6": 0, "A7": 0, "A8": 0, "A9": 0, "A10": 0, 595 "A11": 0, "A12": 0, "A13": 0, "A14": 0, "A15": 0, "A16": 0, "A17": 0, "A18": 0, "A19": 0, "A20": 0, 596 "A21": 0, "A22": 0, "A23": 0, "A24": 0, "A25": 0, "A26": 0, "A27": 0, "A28": 0, "A29": 0, "A30": 0, 597 "A31": 0, "A32": 0, "A33": 0, "A34": 0, "A35": 0, "A36": 0, "A37": 0, "A38": 0, "A39": 0, "A40": 0}, 598 Votes: map[string]*testerVote{ 599 "A1": {"A1", "A1", 5000}, 600 "A2": {"A2", "A2", 5000}, 601 "A3": {"A3", "A3", 5000}, 602 "A4": {"A4", "A4", 5000}, 603 "A5": {"A5", "A5", 5000}, 604 "A6": {"A6", "A6", 5000}, 605 "A7": {"A7", "A7", 5000}, 606 "A8": {"A8", "A8", 5000}, 607 "A9": {"A9", "A9", 5000}, 608 "A10": {"A10", "A10", 5000}, 609 "A11": {"A11", "A11", 4000}, 610 "A12": {"A12", "A12", 4000}, 611 "A13": {"A13", "A13", 4000}, 612 "A14": {"A14", "A14", 4000}, 613 "A15": {"A15", "A15", 4000}, 614 "A16": {"A16", "A16", 4000}, 615 "A17": {"A17", "A17", 4000}, 616 "A18": {"A18", "A18", 4000}, 617 "A19": {"A19", "A19", 4000}, 618 "A20": {"A20", "A20", 4000}, 619 "A21": {"A21", "A21", 3000}, 620 "A22": {"A22", "A22", 3000}, 621 "A23": {"A23", "A23", 3000}, 622 "A24": {"A24", "A24", 3000}, 623 "A25": {"A25", "A25", 3000}, 624 "A26": {"A26", "A26", 3000}, 625 "A27": {"A27", "A27", 3000}, 626 "A28": {"A28", "A28", 3000}, 627 "A29": {"A29", "A29", 3000}, 628 "A30": {"A30", "A30", 3000}, 629 "A31": {"A31", "A31", 2000}, 630 "A32": {"A32", "A32", 2000}, 631 "A33": {"A33", "A33", 2000}, 632 "A34": {"A34", "A34", 2000}, 633 "A35": {"A35", "A35", 2000}, 634 "A36": {"A36", "A36", 2000}, 635 "A37": {"A37", "A37", 2000}, 636 "A38": {"A38", "A38", 2000}, 637 "A39": {"A39", "A39", 2000}, 638 "A40": {"A40", "A40", 2000}, 639 }, 640 }, 641 }, 642 { 643 /* Case 12: 644 * Candidate from Poa is enable 645 * Two self vote address A B in genesis 646 * C vote D to be signer in block 3, but D is not in candidates ,so this vote not valid 647 */ 648 addrNames: []string{"A", "B", "C", "D"}, 649 candidateNeedPD: true, 650 period: uint64(3), 651 epoch: uint64(31), 652 maxSignerCount: uint64(5), 653 minVoterBalance: 50, 654 lcrs: 1, 655 genesisTimestamp: uint64(0), 656 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 657 txHeaders: []testerSingleHeader{ 658 {[]testerTransaction{}}, 659 {[]testerTransaction{}}, 660 {[]testerTransaction{{from: "C", to: "D", balance: 200, isVote: true}}}, 661 {[]testerTransaction{}}, 662 {[]testerTransaction{}}, 663 {[]testerTransaction{}}, 664 {[]testerTransaction{}}, 665 }, 666 result: testerSnapshot{ 667 Signers: []string{"A", "B"}, 668 Tally: map[string]int{"A": 100, "B": 200}, 669 Voters: map[string]int{"A": 0, "B": 0}, 670 Votes: map[string]*testerVote{ 671 "A": {"A", "A", 100}, 672 "B": {"B", "B", 200}, 673 }, 674 }, 675 }, 676 { 677 /* Case 13: 678 * Candidate from Poa is enable 679 * Two self vote address A B in genesis 680 * A proposal D to candidates, B declare agree to this proposal ,but not pass 2/3 * all stake, so fail 681 * C vote D to be signer in block 3, but D is not in candidates ,so this vote not valid 682 */ 683 addrNames: []string{"A", "B", "C", "D"}, 684 candidateNeedPD: true, 685 period: uint64(3), 686 epoch: uint64(31), 687 maxSignerCount: uint64(5), 688 minVoterBalance: 50, 689 lcrs: 1, 690 genesisTimestamp: uint64(0), 691 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 692 txHeaders: []testerSingleHeader{ 693 {[]testerTransaction{}}, 694 {[]testerTransaction{{from: "A", to: "A", isProposal: true, candidate: "D", txHash: "a", proposalType: proposalTypeCandidateAdd}}}, 695 {[]testerTransaction{{from: "B", to: "B", isDeclare: true, txHash: "a", decision: true}}}, 696 {[]testerTransaction{}}, 697 {[]testerTransaction{{from: "C", to: "D", balance: 250, isVote: true}}}, 698 {[]testerTransaction{}}, 699 {[]testerTransaction{}}, 700 {[]testerTransaction{}}, 701 {[]testerTransaction{}}, 702 {[]testerTransaction{}}, 703 {[]testerTransaction{}}, 704 }, 705 result: testerSnapshot{ 706 Signers: []string{"A", "B"}, 707 Tally: map[string]int{"A": 100, "B": 200}, 708 Voters: map[string]int{"A": 0, "B": 0}, 709 Votes: map[string]*testerVote{ 710 "A": {"A", "A", 100}, 711 "B": {"B", "B", 200}, 712 }, 713 }, 714 }, 715 { 716 /* Case 14: 717 * Candidate from Poa is enable 718 * Two self vote address A B in genesis 719 * A proposal D to candidates, and A,B declare agree to this proposal, so D is in candidates 720 * C vote D to be signer in block 5 721 */ 722 addrNames: []string{"A", "B", "C", "D"}, 723 candidateNeedPD: true, 724 period: uint64(3), 725 epoch: uint64(31), 726 maxSignerCount: uint64(5), 727 minVoterBalance: 50, 728 lcrs: 1, 729 genesisTimestamp: uint64(0), 730 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}}, 731 txHeaders: []testerSingleHeader{ 732 {[]testerTransaction{}}, 733 {[]testerTransaction{{from: "A", to: "A", isProposal: true, candidate: "D", txHash: "a", proposalType: proposalTypeCandidateAdd}}}, 734 {[]testerTransaction{{from: "A", to: "A", isDeclare: true, txHash: "a", decision: true}, {from: "B", to: "B", isDeclare: true, txHash: "a", decision: true}}}, 735 {[]testerTransaction{}}, 736 {[]testerTransaction{}}, 737 {[]testerTransaction{}}, 738 {[]testerTransaction{}}, 739 {[]testerTransaction{}}, 740 {[]testerTransaction{}}, 741 {[]testerTransaction{}}, 742 {[]testerTransaction{{from: "C", to: "D", balance: 250, isVote: true}}}, 743 {[]testerTransaction{}}, 744 {[]testerTransaction{}}, 745 {[]testerTransaction{}}, 746 {[]testerTransaction{}}, 747 {[]testerTransaction{}}, 748 {[]testerTransaction{}}, 749 }, 750 result: testerSnapshot{ 751 Signers: []string{"A", "B", "D"}, 752 Tally: map[string]int{"A": 100, "B": 200, "D": 250}, 753 Voters: map[string]int{"A": 0, "B": 0, "C": 11}, 754 Votes: map[string]*testerVote{ 755 "A": {"A", "A", 100}, 756 "B": {"B", "B", 200}, 757 "C": {"C", "D", 250}, 758 }, 759 }, 760 }, 761 { 762 /* Case 15: 763 * Candidate from Poa is enable 764 * Two self vote address A B E F in genesis 765 * A proposal D to candidates, and A,B,F declare agree to this proposal, 766 * but the sum stake of A B F is less than 2/3 of all stake, so D is not in candidates 767 * C vote D to be signer in block 5 768 */ 769 addrNames: []string{"A", "B", "C", "D", "E", "F"}, 770 candidateNeedPD: true, 771 period: uint64(3), 772 epoch: uint64(31), 773 maxSignerCount: uint64(5), 774 minVoterBalance: 50, 775 lcrs: 1, 776 genesisTimestamp: uint64(0), 777 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}, {"E", 2000}, {"F", 200}}, 778 txHeaders: []testerSingleHeader{ 779 {[]testerTransaction{}}, 780 {[]testerTransaction{{from: "A", to: "A", isProposal: true, candidate: "D", txHash: "a", proposalType: proposalTypeCandidateAdd}}}, 781 {[]testerTransaction{{from: "A", to: "A", isDeclare: true, txHash: "a", decision: true}, {from: "B", to: "B", isDeclare: true, txHash: "a", decision: true}, {from: "F", to: "F", isDeclare: true, txHash: "a", decision: true}}}, 782 {[]testerTransaction{}}, 783 {[]testerTransaction{{from: "C", to: "D", balance: 250, isVote: true}}}, 784 {[]testerTransaction{}}, 785 {[]testerTransaction{}}, 786 {[]testerTransaction{}}, 787 {[]testerTransaction{}}, 788 {[]testerTransaction{}}, 789 {[]testerTransaction{}}, 790 }, 791 result: testerSnapshot{ 792 Signers: []string{"A", "B", "E", "F"}, 793 Tally: map[string]int{"A": 100, "B": 200, "E": 2000, "F": 200}, 794 Voters: map[string]int{"A": 0, "B": 0, "E": 0, "F": 0}, 795 Votes: map[string]*testerVote{ 796 "A": {"A", "A", 100}, 797 "B": {"B", "B", 200}, 798 "E": {"E", "E", 2000}, 799 "F": {"F", "F", 200}, 800 }, 801 }, 802 }, 803 { 804 /* Case 16: 805 * Candidate from Poa is enable 806 * Two self vote address A B E F in genesis 807 * A proposal B remove from candidates, and A, E ,F declare agree to this proposal, 808 * the sum stake of A E F is more than 2/3 of all stake, so B is not in candidates 809 * Now do not change the vote automatically, 810 */ 811 addrNames: []string{"A", "B", "C", "D", "E", "F"}, 812 candidateNeedPD: true, 813 period: uint64(3), 814 epoch: uint64(31), 815 maxSignerCount: uint64(5), 816 minVoterBalance: 50, 817 lcrs: 1, 818 genesisTimestamp: uint64(0), 819 selfVoters: []testerSelfVoter{{"A", 100}, {"B", 200}, {"E", 2000}, {"F", 200}}, 820 txHeaders: []testerSingleHeader{ 821 {[]testerTransaction{}}, 822 {[]testerTransaction{{from: "A", to: "A", isProposal: true, candidate: "B", txHash: "a", proposalType: proposalTypeCandidateRemove}}}, 823 {[]testerTransaction{{from: "A", to: "A", isDeclare: true, txHash: "a", decision: true}, {from: "E", to: "E", isDeclare: true, txHash: "a", decision: true}, {from: "F", to: "F", isDeclare: true, txHash: "a", decision: true}}}, 824 {[]testerTransaction{}}, 825 {[]testerTransaction{}}, 826 {[]testerTransaction{}}, 827 {[]testerTransaction{}}, 828 {[]testerTransaction{}}, 829 {[]testerTransaction{}}, 830 {[]testerTransaction{}}, 831 }, 832 result: testerSnapshot{ 833 Signers: []string{"A", "E", "F"}, 834 Tally: map[string]int{"A": 100, "B": 200, "E": 2000, "F": 200}, 835 Voters: map[string]int{"A": 0, "B": 0, "E": 0, "F": 0}, 836 Votes: map[string]*testerVote{ 837 "A": {"A", "A", 100}, 838 "B": {"B", "B", 200}, 839 "E": {"E", "E", 2000}, 840 "F": {"F", "F", 200}, 841 }, 842 }, 843 }, 844 } 845 846 // Run through the scenarios and test them 847 for i, tt := range tests { 848 candidateNeedPD = tt.candidateNeedPD 849 if tt.vlCnt == 0 { 850 tt.vlCnt = 1 851 } 852 // Create the account pool and generate the initial set of all address in addrNames 853 accounts := newTesterAccountPool() 854 addrNames := make([]common.Address, len(tt.addrNames)) 855 for j, signer := range tt.addrNames { 856 addrNames[j] = accounts.address(signer) 857 } 858 for j := 0; j < len(addrNames); j++ { 859 for k := j + 1; k < len(addrNames); k++ { 860 if bytes.Compare(addrNames[j][:], addrNames[k][:]) > 0 { 861 addrNames[j], addrNames[k] = addrNames[k], addrNames[j] 862 } 863 } 864 } 865 866 var snap *Snapshot 867 // Prepare data for the genesis block 868 var genesisVotes []*Vote // for create the new snapshot of genesis block 869 var selfVoteSigners []common.UnprefixedAddress // for header extra 870 alreadyVote := make(map[common.Address]struct{}) 871 for _, voter := range tt.selfVoters { 872 if _, ok := alreadyVote[accounts.address(voter.voter)]; !ok { 873 genesisVotes = append(genesisVotes, &Vote{ 874 Voter: accounts.address(voter.voter), 875 Candidate: accounts.address(voter.voter), 876 Stake: big.NewInt(int64(voter.balance)), 877 }) 878 selfVoteSigners = append(selfVoteSigners, common.UnprefixedAddress(accounts.address(voter.voter))) 879 alreadyVote[accounts.address(voter.voter)] = struct{}{} 880 } 881 } 882 883 // extend length of extra, so address of CoinBase can keep signature . 884 genesis := &core.Genesis{ 885 ExtraData: make([]byte, extraVanity+extraSeal), 886 } 887 888 // Create a pristine blockchain with the genesis injected 889 db := ethdb.NewMemDatabase() 890 genesis.Commit(db) 891 892 // Create new alien 893 alien := New(¶ms.AlienConfig{ 894 Period: tt.period, 895 Epoch: tt.epoch, 896 MinVoterBalance: big.NewInt(int64(tt.minVoterBalance)), 897 MaxSignerCount: tt.maxSignerCount, 898 SelfVoteSigners: selfVoteSigners, 899 }, db) 900 901 // Assemble a chain of headers from the cast votes 902 headers := make([]*types.Header, len(tt.txHeaders)) 903 for j, header := range tt.txHeaders { 904 905 var currentBlockVotes []Vote 906 var currentBlockProposals []Proposal 907 var currentBlockDeclares []Declare 908 var modifyPredecessorVotes []Vote 909 for _, trans := range header.txs { 910 if trans.isVote { 911 if trans.balance >= tt.minVoterBalance && (!candidateNeedPD || snap.isCandidate(accounts.address(trans.to))) { 912 // vote event 913 currentBlockVotes = append(currentBlockVotes, Vote{ 914 Voter: accounts.address(trans.from), 915 Candidate: accounts.address(trans.to), 916 Stake: big.NewInt(int64(trans.balance)), 917 }) 918 } 919 } else if trans.isProposal { 920 if snap.isCandidate(accounts.address(trans.from)) { 921 currentBlockProposals = append(currentBlockProposals, Proposal{ 922 Hash: common.HexToHash(trans.txHash), 923 ReceivedNumber: big.NewInt(int64(j)), 924 CurrentDeposit: proposalDeposit, 925 ValidationLoopCnt: tt.vlCnt, 926 ProposalType: trans.proposalType, 927 Proposer: accounts.address(trans.from), 928 TargetAddress: accounts.address(trans.candidate), 929 MinerRewardPerThousand: minerRewardPerThousand, 930 SCHash: common.Hash{}, 931 SCBlockCountPerPeriod: 1, 932 SCBlockRewardPerPeriod: 0, 933 Declares: []*Declare{}, 934 MinVoterBalance: new(big.Int).Div(minVoterBalance, big.NewInt(1e+18)).Uint64(), 935 ProposalDeposit: new(big.Int).Div(proposalDeposit, big.NewInt(1e+18)).Uint64(), 936 SCRentFee: 0, 937 SCRentRate: 1, 938 SCRentLength: defaultSCRentLength, 939 }) 940 } 941 } else if trans.isDeclare { 942 if snap.isCandidate(accounts.address(trans.from)) { 943 944 currentBlockDeclares = append(currentBlockDeclares, Declare{ 945 ProposalHash: common.HexToHash(trans.txHash), 946 Declarer: accounts.address(trans.from), 947 Decision: trans.decision, 948 }) 949 950 } 951 } else { 952 // modify balance 953 // modifyPredecessorVotes 954 // only consider the voter 955 modifyPredecessorVotes = append(modifyPredecessorVotes, Vote{ 956 Voter: accounts.address(trans.from), 957 Stake: big.NewInt(int64(trans.balance)), 958 }) 959 } 960 } 961 currentHeaderExtra := HeaderExtra{} 962 signer := common.Address{} 963 964 // (j==0) means (header.Number==1) 965 if j == 0 { 966 for k := 0; k < int(tt.maxSignerCount); k++ { 967 currentHeaderExtra.SignerQueue = append(currentHeaderExtra.SignerQueue, common.Address(selfVoteSigners[k%len(selfVoteSigners)])) 968 } 969 currentHeaderExtra.LoopStartTime = tt.genesisTimestamp // here should be parent genesisTimestamp 970 signer = common.Address(selfVoteSigners[0]) 971 972 } else { 973 // decode parent header.extra 974 //rlp.DecodeBytes(headers[j-1].Extra[extraVanity:len(headers[j-1].Extra)-extraSeal], ¤tHeaderExtra) 975 976 decodeHeaderExtra(alien.config, headers[j-1].Number, headers[j-1].Extra[extraVanity:len(headers[j-1].Extra)-extraSeal], ¤tHeaderExtra) 977 signer = currentHeaderExtra.SignerQueue[uint64(j)%tt.maxSignerCount] 978 // means header.Number % tt.maxSignerCount == 0 979 if (j+1)%int(tt.maxSignerCount) == 0 { 980 snap, err := alien.snapshot(&testerChainReader{db: db}, headers[j-1].Number.Uint64(), headers[j-1].Hash(), headers, nil, uint64(tt.lcrs)) 981 if err != nil { 982 t.Errorf("test %d: failed to create voting snapshot: %v", i, err) 983 continue 984 } 985 currentHeaderExtra.SignerQueue = []common.Address{} 986 newSignerQueue, err := snap.createSignerQueue() 987 if err != nil { 988 t.Errorf("test %d: failed to create signer queue: %v", i, err) 989 } 990 991 currentHeaderExtra.SignerQueue = newSignerQueue 992 993 currentHeaderExtra.LoopStartTime = currentHeaderExtra.LoopStartTime + tt.period*tt.maxSignerCount 994 } else { 995 } 996 } 997 998 currentHeaderExtra.CurrentBlockVotes = currentBlockVotes 999 currentHeaderExtra.ModifyPredecessorVotes = modifyPredecessorVotes 1000 currentHeaderExtra.CurrentBlockProposals = currentBlockProposals 1001 currentHeaderExtra.CurrentBlockDeclares = currentBlockDeclares 1002 //currentHeaderExtraEnc, err := rlp.EncodeToBytes(currentHeaderExtra) 1003 currentHeaderExtraEnc, err := encodeHeaderExtra(alien.config, big.NewInt(int64(j)+1), currentHeaderExtra) 1004 1005 if err != nil { 1006 t.Errorf("test %d: failed to rlp encode to bytes: %v", i, err) 1007 continue 1008 } 1009 // Create the genesis block with the initial set of signers 1010 ExtraData := make([]byte, extraVanity+len(currentHeaderExtraEnc)+extraSeal) 1011 copy(ExtraData[extraVanity:], currentHeaderExtraEnc) 1012 1013 headers[j] = &types.Header{ 1014 Number: big.NewInt(int64(j) + 1), 1015 Time: big.NewInt((int64(j)+1)*int64(defaultBlockPeriod) - 1), 1016 Coinbase: signer, 1017 Extra: ExtraData, 1018 } 1019 if j > 0 { 1020 headers[j].ParentHash = headers[j-1].Hash() 1021 } 1022 accounts.sign(headers[j], accounts.name(signer)) 1023 1024 // Pass all the headers through alien and ensure tallying succeeds 1025 snap, err = alien.snapshot(&testerChainReader{db: db}, headers[j].Number.Uint64(), headers[j].Hash(), headers[:j+1], genesisVotes, uint64(tt.lcrs)) 1026 genesisVotes = []*Vote{} 1027 if err != nil { 1028 t.Errorf("test %d: failed to create voting snapshot: %v", i, err) 1029 continue 1030 } 1031 } 1032 1033 // verify the result in test case 1034 head := headers[len(headers)-1] 1035 snap, err := alien.snapshot(&testerChainReader{db: db}, head.Number.Uint64(), head.Hash(), headers, nil, uint64(tt.lcrs)) 1036 // 1037 if err != nil { 1038 t.Errorf("test %d: failed to create voting snapshot: %v", i, err) 1039 continue 1040 } 1041 // check signers 1042 if len(tt.result.Signers) > 0 { 1043 1044 signers := map[common.Address]int{} 1045 for _, signer := range snap.Signers { 1046 signers[*signer] = 1 1047 1048 } 1049 for _, signer := range tt.result.Signers { 1050 signers[accounts.address(signer)] += 2 1051 } 1052 1053 for address, cnt := range signers { 1054 if cnt != 3 { 1055 t.Errorf("test %d: signer %v address: %v not in result signers %d", i, accounts.name(address), address, cnt) 1056 continue 1057 } 1058 } 1059 } else { 1060 // check signers official 21 node 1061 firstLevel := map[common.Address]int{} 1062 secondLevel := map[common.Address]int{} 1063 thirdLevel := map[common.Address]int{} 1064 otherLevel := map[common.Address]int{} 1065 1066 for signer, tally := range tt.result.Tally { 1067 switch tally { 1068 case 5000: 1069 firstLevel[accounts.address(signer)] = 0 1070 case 4000: 1071 secondLevel[accounts.address(signer)] = 0 1072 case 3000: 1073 thirdLevel[accounts.address(signer)] = 0 1074 case 2000: 1075 otherLevel[accounts.address(signer)] = 0 1076 1077 } 1078 1079 } 1080 var l1, l2, l3, l4 int 1081 for _, signer := range snap.Signers { 1082 if _, ok := firstLevel[*signer]; ok { 1083 l1 += 1 1084 continue 1085 } 1086 if _, ok := secondLevel[*signer]; ok { 1087 l2 += 1 1088 continue 1089 } 1090 if _, ok := thirdLevel[*signer]; ok { 1091 l3 += 1 1092 continue 1093 } 1094 if _, ok := otherLevel[*signer]; ok { 1095 l4 += 1 1096 } 1097 } 1098 if l1 != 10 || l2 != 6 || l3 != 4 || l4 != 1 { 1099 t.Errorf("test %d: signer not select right count from different level l1 = %d, l2 = %d, l3 = %d, l4 = %d", i, l1, l2, l3, l4) 1100 } 1101 1102 } 1103 1104 // check tally 1105 if len(tt.result.Tally) != len(snap.Tally) { 1106 t.Errorf("test %d: tally length result %d, snap %d dismatch", i, len(tt.result.Tally), len(snap.Tally)) 1107 } 1108 for name, tally := range tt.result.Tally { 1109 if big.NewInt(int64(tally)).Cmp(snap.Tally[accounts.address(name)]) != 0 { 1110 t.Errorf("test %d: tally %v address: %v, tally:%v ,result: %v", i, name, accounts.address(name), snap.Tally[accounts.address(name)], big.NewInt(int64(tally))) 1111 continue 1112 } 1113 } 1114 // check voters 1115 if len(tt.result.Voters) != len(snap.Voters) { 1116 t.Errorf("test %d: voter length result %d, snap %d dismatch", i, len(tt.result.Voters), len(snap.Voters)) 1117 } 1118 for name, number := range tt.result.Voters { 1119 if snap.Voters[accounts.address(name)].Cmp(big.NewInt(int64(number))) != 0 { 1120 t.Errorf("test %d: voter %v address: %v, number:%v ,result: %v", i, name, accounts.address(name), snap.Voters[accounts.address(name)], big.NewInt(int64(number))) 1121 continue 1122 } 1123 } 1124 // check votes 1125 1126 if len(tt.result.Votes) != len(snap.Votes) { 1127 t.Errorf("test %d: votes length result %d, snap %d dismatch", i, len(tt.result.Votes), len(snap.Votes)) 1128 } 1129 for name, vote := range tt.result.Votes { 1130 snapVote, ok := snap.Votes[accounts.address(name)] 1131 if !ok { 1132 t.Errorf("test %d: votes %v address: %v can not found", i, name, accounts.address(name)) 1133 1134 } 1135 if snapVote.Voter != accounts.address(vote.voter) { 1136 t.Errorf("test %d: votes voter dismatch %v address: %v , show in snap is %v address: %v", i, vote.voter, accounts.address(vote.voter), accounts.name(snapVote.Voter), snapVote.Voter) 1137 } 1138 if snapVote.Candidate != accounts.address(vote.candidate) { 1139 t.Errorf("test %d: votes candidate dismatch %v address: %v , show in snap is %v address: %v ", i, vote.candidate, accounts.address(vote.candidate), accounts.name(snapVote.Candidate), snapVote.Candidate) 1140 } 1141 if snapVote.Stake.Cmp(big.NewInt(int64(vote.stake))) != 0 { 1142 t.Errorf("test %d: votes stake dismatch %v ,show in snap is %v ", i, vote.stake, snapVote.Stake) 1143 } 1144 } 1145 1146 } 1147 }