github.com/klaytn/klaytn@v1.10.2/consensus/istanbul/backend/engine_test.go (about) 1 // Modifications Copyright 2020 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from quorum/consensus/istanbul/backend/engine_test.go (2020/04/16). 19 // Modified and improved for the klaytn development. 20 21 package backend 22 23 import ( 24 "bytes" 25 "crypto/ecdsa" 26 "math/big" 27 "reflect" 28 "sort" 29 "strings" 30 "testing" 31 "time" 32 33 "github.com/klaytn/klaytn/blockchain" 34 "github.com/klaytn/klaytn/blockchain/types" 35 "github.com/klaytn/klaytn/blockchain/vm" 36 "github.com/klaytn/klaytn/common" 37 "github.com/klaytn/klaytn/common/hexutil" 38 "github.com/klaytn/klaytn/consensus" 39 "github.com/klaytn/klaytn/consensus/istanbul" 40 "github.com/klaytn/klaytn/consensus/istanbul/core" 41 "github.com/klaytn/klaytn/crypto" 42 "github.com/klaytn/klaytn/params" 43 "github.com/klaytn/klaytn/reward" 44 "github.com/klaytn/klaytn/rlp" 45 "github.com/stretchr/testify/assert" 46 ) 47 48 // These variables are the global variables of the test blockchain. 49 var ( 50 nodeKeys []*ecdsa.PrivateKey 51 addrs []common.Address 52 ) 53 54 // These are the types in order to add a custom configuration of the test chain. 55 // You may need to create a configuration type if necessary. 56 type ( 57 istanbulCompatibleBlock *big.Int 58 LondonCompatibleBlock *big.Int 59 EthTxTypeCompatibleBlock *big.Int 60 magmaCompatibleBlock *big.Int 61 koreCompatibleBlock *big.Int 62 ) 63 64 type ( 65 minimumStake *big.Int 66 mintingAmount *big.Int 67 stakingUpdateInterval uint64 68 proposerUpdateInterval uint64 69 proposerPolicy uint64 70 governanceMode string 71 epoch uint64 72 subGroupSize uint64 73 blockPeriod uint64 74 ) 75 76 // makeCommittedSeals returns a list of committed seals for the global variable nodeKeys. 77 func makeCommittedSeals(hash common.Hash) [][]byte { 78 committedSeals := make([][]byte, len(nodeKeys)) 79 hashData := crypto.Keccak256(core.PrepareCommittedSeal(hash)) 80 for i, key := range nodeKeys { 81 sig, _ := crypto.Sign(hashData, key) 82 committedSeals[i] = make([]byte, types.IstanbulExtraSeal) 83 copy(committedSeals[i][:], sig) 84 } 85 return committedSeals 86 } 87 88 // Include a node from the global nodeKeys and addrs 89 func includeNode(addr common.Address, key *ecdsa.PrivateKey) { 90 for _, a := range addrs { 91 if a.String() == addr.String() { 92 // already exists 93 return 94 } 95 } 96 nodeKeys = append(nodeKeys, key) 97 addrs = append(addrs, addr) 98 } 99 100 // Exclude a node from the global nodeKeys and addrs 101 func excludeNodeByAddr(target common.Address) { 102 for i, a := range addrs { 103 if a.String() == target.String() { 104 nodeKeys = append(nodeKeys[:i], nodeKeys[i+1:]...) 105 addrs = append(addrs[:i], addrs[i+1:]...) 106 break 107 } 108 } 109 } 110 111 // in this test, we can set n to 1, and it means we can process Istanbul and commit a 112 // block by one node. Otherwise, if n is larger than 1, we have to generate 113 // other fake events to process Istanbul. 114 func newBlockChain(n int, items ...interface{}) (*blockchain.BlockChain, *backend) { 115 // generate a genesis block 116 genesis := blockchain.DefaultGenesisBlock() 117 genesis.Config = params.TestChainConfig.Copy() 118 genesis.Timestamp = uint64(time.Now().Unix()) 119 120 var ( 121 key *ecdsa.PrivateKey 122 period = istanbul.DefaultConfig.BlockPeriod 123 ) 124 // force enable Istanbul engine and governance 125 genesis.Config.Istanbul = params.GetDefaultIstanbulConfig() 126 genesis.Config.Governance = params.GetDefaultGovernanceConfig() 127 for _, item := range items { 128 switch v := item.(type) { 129 case istanbulCompatibleBlock: 130 genesis.Config.IstanbulCompatibleBlock = v 131 case LondonCompatibleBlock: 132 genesis.Config.LondonCompatibleBlock = v 133 case EthTxTypeCompatibleBlock: 134 genesis.Config.EthTxTypeCompatibleBlock = v 135 case magmaCompatibleBlock: 136 genesis.Config.MagmaCompatibleBlock = v 137 case koreCompatibleBlock: 138 genesis.Config.KoreCompatibleBlock = v 139 case proposerPolicy: 140 genesis.Config.Istanbul.ProposerPolicy = uint64(v) 141 case epoch: 142 genesis.Config.Istanbul.Epoch = uint64(v) 143 case subGroupSize: 144 genesis.Config.Istanbul.SubGroupSize = uint64(v) 145 case minimumStake: 146 genesis.Config.Governance.Reward.MinimumStake = v 147 case stakingUpdateInterval: 148 genesis.Config.Governance.Reward.StakingUpdateInterval = uint64(v) 149 case proposerUpdateInterval: 150 genesis.Config.Governance.Reward.ProposerUpdateInterval = uint64(v) 151 case mintingAmount: 152 genesis.Config.Governance.Reward.MintingAmount = v 153 case governanceMode: 154 genesis.Config.Governance.GovernanceMode = string(v) 155 case *ecdsa.PrivateKey: 156 key = v 157 case blockPeriod: 158 period = uint64(v) 159 } 160 } 161 nodeKeys = make([]*ecdsa.PrivateKey, n) 162 addrs = make([]common.Address, n) 163 164 var b *backend 165 if len(items) != 0 { 166 b = newTestBackendWithConfig(genesis.Config, period, key) 167 } else { 168 b = newTestBackend() 169 } 170 171 nodeKeys[0] = b.privateKey 172 addrs[0] = b.address // if governance mode is single, this address is the governing node address 173 for i := 1; i < n; i++ { 174 nodeKeys[i], _ = crypto.GenerateKey() 175 addrs[i] = crypto.PubkeyToAddress(nodeKeys[i].PublicKey) 176 } 177 178 appendValidators(genesis, addrs) 179 180 genesis.MustCommit(b.db) 181 182 bc, err := blockchain.NewBlockChain(b.db, nil, genesis.Config, b, vm.Config{}) 183 if err != nil { 184 panic(err) 185 } 186 b.governance.SetBlockchain(bc) 187 188 if b.Start(bc, bc.CurrentBlock, bc.HasBadBlock) != nil { 189 panic(err) 190 } 191 192 return bc, b 193 } 194 195 func appendValidators(genesis *blockchain.Genesis, addrs []common.Address) { 196 if len(genesis.ExtraData) < types.IstanbulExtraVanity { 197 genesis.ExtraData = append(genesis.ExtraData, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity)...) 198 } 199 genesis.ExtraData = genesis.ExtraData[:types.IstanbulExtraVanity] 200 201 ist := &types.IstanbulExtra{ 202 Validators: addrs, 203 Seal: []byte{}, 204 CommittedSeal: [][]byte{}, 205 } 206 207 istPayload, err := rlp.EncodeToBytes(&ist) 208 if err != nil { 209 panic("failed to encode istanbul extra") 210 } 211 genesis.ExtraData = append(genesis.ExtraData, istPayload...) 212 } 213 214 func makeHeader(parent *types.Block, config *istanbul.Config) *types.Header { 215 header := &types.Header{ 216 ParentHash: parent.Hash(), 217 Number: parent.Number().Add(parent.Number(), common.Big1), 218 GasUsed: 0, 219 Extra: parent.Extra(), 220 Time: new(big.Int).Add(parent.Time(), new(big.Int).SetUint64(config.BlockPeriod)), 221 BlockScore: defaultBlockScore, 222 } 223 if parent.Header().BaseFee != nil { 224 // We don't have chainConfig so the BaseFee of the current block is set by parent's for test 225 header.BaseFee = parent.Header().BaseFee 226 } 227 return header 228 } 229 230 func makeBlock(chain *blockchain.BlockChain, engine *backend, parent *types.Block) *types.Block { 231 block := makeBlockWithoutSeal(chain, engine, parent) 232 stopCh := make(chan struct{}) 233 result, err := engine.Seal(chain, block, stopCh) 234 if err != nil { 235 panic(err) 236 } 237 return result 238 } 239 240 // makeBlockWithSeal creates a block with the proposer seal as well as all committed seals of validators. 241 func makeBlockWithSeal(chain *blockchain.BlockChain, engine *backend, parent *types.Block) *types.Block { 242 blockWithoutSeal := makeBlockWithoutSeal(chain, engine, parent) 243 244 // add proposer seal for the block 245 block, err := engine.updateBlock(nil, blockWithoutSeal) 246 if err != nil { 247 panic(err) 248 } 249 250 // write validators committed seals to the block 251 header := block.Header() 252 committedSeals := makeCommittedSeals(block.Hash()) 253 err = writeCommittedSeals(header, committedSeals) 254 if err != nil { 255 panic(err) 256 } 257 block = block.WithSeal(header) 258 259 return block 260 } 261 262 func makeBlockWithoutSeal(chain *blockchain.BlockChain, engine *backend, parent *types.Block) *types.Block { 263 header := makeHeader(parent, engine.config) 264 if err := engine.Prepare(chain, header); err != nil { 265 panic(err) 266 } 267 state, _ := chain.StateAt(parent.Root()) 268 block, _ := engine.Finalize(chain, header, state, nil, nil) 269 return block 270 } 271 272 func TestPrepare(t *testing.T) { 273 chain, engine := newBlockChain(1) 274 defer engine.Stop() 275 276 header := makeHeader(chain.Genesis(), engine.config) 277 err := engine.Prepare(chain, header) 278 if err != nil { 279 t.Errorf("error mismatch: have %v, want nil", err) 280 } 281 282 header.ParentHash = common.HexToHash("0x1234567890") 283 err = engine.Prepare(chain, header) 284 if err != consensus.ErrUnknownAncestor { 285 t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrUnknownAncestor) 286 } 287 } 288 289 func TestSealStopChannel(t *testing.T) { 290 chain, engine := newBlockChain(4) 291 defer engine.Stop() 292 293 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 294 stop := make(chan struct{}, 1) 295 eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{}) 296 eventLoop := func() { 297 select { 298 case ev := <-eventSub.Chan(): 299 _, ok := ev.Data.(istanbul.RequestEvent) 300 if !ok { 301 t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) 302 } 303 stop <- struct{}{} 304 } 305 eventSub.Unsubscribe() 306 } 307 go eventLoop() 308 309 finalBlock, err := engine.Seal(chain, block, stop) 310 if err != nil { 311 t.Errorf("error mismatch: have %v, want nil", err) 312 } 313 314 if finalBlock != nil { 315 t.Errorf("block mismatch: have %v, want nil", finalBlock) 316 } 317 } 318 319 func TestSealCommitted(t *testing.T) { 320 chain, engine := newBlockChain(1) 321 defer engine.Stop() 322 323 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 324 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 325 326 actualBlock, err := engine.Seal(chain, block, make(chan struct{})) 327 if err != nil { 328 t.Errorf("error mismatch: have %v, want %v", err, expectedBlock) 329 } 330 331 if actualBlock.Hash() != expectedBlock.Hash() { 332 t.Errorf("hash mismatch: have %v, want %v", actualBlock.Hash(), expectedBlock.Hash()) 333 } 334 } 335 336 func TestVerifyHeader(t *testing.T) { 337 var configItems []interface{} 338 configItems = append(configItems, istanbulCompatibleBlock(new(big.Int).SetUint64(0))) 339 configItems = append(configItems, LondonCompatibleBlock(new(big.Int).SetUint64(0))) 340 configItems = append(configItems, EthTxTypeCompatibleBlock(new(big.Int).SetUint64(0))) 341 configItems = append(configItems, magmaCompatibleBlock(new(big.Int).SetUint64(0))) 342 configItems = append(configItems, koreCompatibleBlock(new(big.Int).SetUint64(0))) 343 chain, engine := newBlockChain(1, configItems...) 344 defer engine.Stop() 345 346 // errEmptyCommittedSeals case 347 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 348 block, _ = engine.updateBlock(chain.Genesis().Header(), block) 349 err := engine.VerifyHeader(chain, block.Header(), false) 350 if err != errEmptyCommittedSeals { 351 t.Errorf("error mismatch: have %v, want %v", err, errEmptyCommittedSeals) 352 } 353 354 // short extra data 355 header := block.Header() 356 header.Extra = []byte{} 357 err = engine.VerifyHeader(chain, header, false) 358 if err != errInvalidExtraDataFormat { 359 t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat) 360 } 361 // incorrect extra format 362 header.Extra = []byte("0000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000000") 363 err = engine.VerifyHeader(chain, header, false) 364 if err != errInvalidExtraDataFormat { 365 t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat) 366 } 367 368 // invalid difficulty 369 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 370 header = block.Header() 371 header.BlockScore = big.NewInt(2) 372 err = engine.VerifyHeader(chain, header, false) 373 if err != errInvalidBlockScore { 374 t.Errorf("error mismatch: have %v, want %v", err, errInvalidBlockScore) 375 } 376 377 // invalid timestamp 378 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 379 header = block.Header() 380 header.Time = new(big.Int).Add(chain.Genesis().Time(), new(big.Int).SetUint64(engine.config.BlockPeriod-1)) 381 err = engine.VerifyHeader(chain, header, false) 382 if err != errInvalidTimestamp { 383 t.Errorf("error mismatch: have %v, want %v", err, errInvalidTimestamp) 384 } 385 386 // future block 387 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 388 header = block.Header() 389 header.Time = new(big.Int).Add(big.NewInt(now().Unix()), new(big.Int).SetUint64(10)) 390 err = engine.VerifyHeader(chain, header, false) 391 if err != consensus.ErrFutureBlock { 392 t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrFutureBlock) 393 } 394 395 // TODO-Klaytn: add more tests for header.Governance, header.Rewardbase, header.Vote 396 } 397 398 func TestVerifySeal(t *testing.T) { 399 chain, engine := newBlockChain(1) 400 defer engine.Stop() 401 402 genesis := chain.Genesis() 403 404 // cannot verify genesis 405 err := engine.VerifySeal(chain, genesis.Header()) 406 if err != errUnknownBlock { 407 t.Errorf("error mismatch: have %v, want %v", err, errUnknownBlock) 408 } 409 block := makeBlock(chain, engine, genesis) 410 411 // clean cache before testing 412 signatureAddresses.Purge() 413 414 // change block content 415 header := block.Header() 416 header.Number = big.NewInt(4) 417 block1 := block.WithSeal(header) 418 err = engine.VerifySeal(chain, block1.Header()) 419 if err != errUnauthorized { 420 t.Errorf("error mismatch: have %v, want %v", err, errUnauthorized) 421 } 422 423 // clean cache before testing 424 signatureAddresses.Purge() 425 426 // unauthorized users but still can get correct signer address 427 engine.privateKey, _ = crypto.GenerateKey() 428 err = engine.VerifySeal(chain, block.Header()) 429 if err != nil { 430 t.Errorf("error mismatch: have %v, want nil", err) 431 } 432 } 433 434 func TestVerifyHeaders(t *testing.T) { 435 chain, engine := newBlockChain(1) 436 defer engine.Stop() 437 438 genesis := chain.Genesis() 439 440 // success case 441 headers := []*types.Header{} 442 blocks := []*types.Block{} 443 size := 100 444 445 for i := 0; i < size; i++ { 446 var b *types.Block 447 if i == 0 { 448 b = makeBlockWithoutSeal(chain, engine, genesis) 449 b, _ = engine.updateBlock(genesis.Header(), b) 450 engine.db.WriteHeader(b.Header()) 451 } else { 452 b = makeBlockWithoutSeal(chain, engine, blocks[i-1]) 453 b, _ = engine.updateBlock(blocks[i-1].Header(), b) 454 engine.db.WriteHeader(b.Header()) 455 } 456 blocks = append(blocks, b) 457 headers = append(headers, blocks[i].Header()) 458 } 459 460 // proceed time to avoid future block errors 461 now = func() time.Time { 462 return time.Unix(headers[size-1].Time.Int64(), 0) 463 } 464 defer func() { 465 now = time.Now 466 }() 467 468 _, results := engine.VerifyHeaders(chain, headers, nil) 469 const timeoutDura = 2 * time.Second 470 timeout := time.NewTimer(timeoutDura) 471 index := 0 472 OUT1: 473 for { 474 select { 475 case err := <-results: 476 if err != nil { 477 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 478 t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err) 479 break OUT1 480 } 481 } 482 index++ 483 if index == size { 484 break OUT1 485 } 486 case <-timeout.C: 487 break OUT1 488 } 489 } 490 // abort cases 491 abort, results := engine.VerifyHeaders(chain, headers, nil) 492 timeout = time.NewTimer(timeoutDura) 493 index = 0 494 OUT2: 495 for { 496 select { 497 case err := <-results: 498 if err != nil { 499 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 500 t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err) 501 break OUT2 502 } 503 } 504 index++ 505 if index == 5 { 506 abort <- struct{}{} 507 } 508 if index >= size { 509 t.Errorf("verifyheaders should be aborted") 510 break OUT2 511 } 512 case <-timeout.C: 513 break OUT2 514 } 515 } 516 // error header cases 517 headers[2].Number = big.NewInt(100) 518 abort, results = engine.VerifyHeaders(chain, headers, nil) 519 timeout = time.NewTimer(timeoutDura) 520 index = 0 521 errors := 0 522 expectedErrors := 2 523 OUT3: 524 for { 525 select { 526 case err := <-results: 527 if err != nil { 528 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 529 errors++ 530 } 531 } 532 index++ 533 if index == size { 534 if errors != expectedErrors { 535 t.Errorf("error mismatch: have %v, want %v", err, expectedErrors) 536 } 537 break OUT3 538 } 539 case <-timeout.C: 540 break OUT3 541 } 542 } 543 } 544 545 func TestPrepareExtra(t *testing.T) { 546 validators := make([]common.Address, 4) 547 validators[0] = common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")) 548 validators[1] = common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")) 549 validators[2] = common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")) 550 validators[3] = common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")) 551 552 vanity := make([]byte, types.IstanbulExtraVanity) 553 expectedResult := append(vanity, hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")...) 554 555 h := &types.Header{ 556 Extra: vanity, 557 } 558 559 payload, err := prepareExtra(h, validators) 560 if err != nil { 561 t.Errorf("error mismatch: have %v, want: nil", err) 562 } 563 if !reflect.DeepEqual(payload, expectedResult) { 564 t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult) 565 } 566 567 // append useless information to extra-data 568 h.Extra = append(vanity, make([]byte, 15)...) 569 570 payload, err = prepareExtra(h, validators) 571 if !reflect.DeepEqual(payload, expectedResult) { 572 t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult) 573 } 574 } 575 576 func TestWriteSeal(t *testing.T) { 577 vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity) 578 istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0") 579 expectedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 580 expectedIstExtra := &types.IstanbulExtra{ 581 Validators: []common.Address{ 582 common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), 583 common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), 584 common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), 585 common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), 586 }, 587 Seal: expectedSeal, 588 CommittedSeal: [][]byte{}, 589 } 590 var expectedErr error 591 592 h := &types.Header{ 593 Extra: append(vanity, istRawData...), 594 } 595 596 // normal case 597 err := writeSeal(h, expectedSeal) 598 if err != expectedErr { 599 t.Errorf("error mismatch: have %v, want %v", err, expectedErr) 600 } 601 602 // verify istanbul extra-data 603 istExtra, err := types.ExtractIstanbulExtra(h) 604 if err != nil { 605 t.Errorf("error mismatch: have %v, want nil", err) 606 } 607 if !reflect.DeepEqual(istExtra, expectedIstExtra) { 608 t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra) 609 } 610 611 // invalid seal 612 unexpectedSeal := append(expectedSeal, make([]byte, 1)...) 613 err = writeSeal(h, unexpectedSeal) 614 if err != errInvalidSignature { 615 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 616 } 617 } 618 619 func TestWriteCommittedSeals(t *testing.T) { 620 vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity) 621 istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0") 622 expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 623 expectedIstExtra := &types.IstanbulExtra{ 624 Validators: []common.Address{ 625 common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), 626 common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), 627 common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), 628 common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), 629 }, 630 Seal: []byte{}, 631 CommittedSeal: [][]byte{expectedCommittedSeal}, 632 } 633 var expectedErr error 634 635 h := &types.Header{ 636 Extra: append(vanity, istRawData...), 637 } 638 639 // normal case 640 err := writeCommittedSeals(h, [][]byte{expectedCommittedSeal}) 641 if err != expectedErr { 642 t.Errorf("error mismatch: have %v, want %v", err, expectedErr) 643 } 644 645 // verify istanbul extra-data 646 istExtra, err := types.ExtractIstanbulExtra(h) 647 if err != nil { 648 t.Errorf("error mismatch: have %v, want nil", err) 649 } 650 if !reflect.DeepEqual(istExtra, expectedIstExtra) { 651 t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra) 652 } 653 654 // invalid seal 655 unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...) 656 err = writeCommittedSeals(h, [][]byte{unexpectedCommittedSeal}) 657 if err != errInvalidCommittedSeals { 658 t.Errorf("error mismatch: have %v, want %v", err, errInvalidCommittedSeals) 659 } 660 } 661 662 func TestRewardDistribution(t *testing.T) { 663 type vote = map[string]interface{} 664 type expected = map[int]uint64 665 type testcase struct { 666 length int // total number of blocks to simulate 667 votes map[int]vote 668 expected expected 669 } 670 671 mintAmount := uint64(1) 672 koreBlock := uint64(9) 673 testEpoch := 3 674 675 testcases := []testcase{ 676 { 677 12, 678 map[int]vote{ 679 1: {"reward.mintingamount": "2"}, // activated at block 7 (activation is before-Kore) 680 4: {"reward.mintingamount": "3"}, // activated at block 9 (activation is after-Kore) 681 }, 682 map[int]uint64{ 683 1: 1, 684 2: 2, 685 3: 3, 686 4: 4, 687 5: 5, 688 6: 6, 689 7: 8, // 2 is minted from now 690 8: 10, 691 9: 13, // 3 is minted from now 692 10: 16, 693 11: 19, 694 12: 22, 695 13: 25, 696 }, 697 }, 698 } 699 700 var configItems []interface{} 701 configItems = append(configItems, epoch(testEpoch)) 702 configItems = append(configItems, mintingAmount(new(big.Int).SetUint64(mintAmount))) 703 configItems = append(configItems, istanbulCompatibleBlock(new(big.Int).SetUint64(0))) 704 configItems = append(configItems, LondonCompatibleBlock(new(big.Int).SetUint64(0))) 705 configItems = append(configItems, EthTxTypeCompatibleBlock(new(big.Int).SetUint64(0))) 706 configItems = append(configItems, magmaCompatibleBlock(new(big.Int).SetUint64(0))) 707 configItems = append(configItems, koreCompatibleBlock(new(big.Int).SetUint64(koreBlock))) 708 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 709 710 chain, engine := newBlockChain(1, configItems...) 711 assert.Equal(t, uint64(testEpoch), engine.governance.CurrentParams().Epoch()) 712 assert.Equal(t, mintAmount, engine.governance.CurrentParams().MintingAmountBig().Uint64()) 713 714 var previousBlock, currentBlock *types.Block = nil, chain.Genesis() 715 716 for _, tc := range testcases { 717 // Place a vote if a vote is scheduled in upcoming block 718 // Note that we're building (head+1)'th block here. 719 for num := 0; num <= tc.length; num++ { 720 for k, v := range tc.votes[num+1] { 721 ok := engine.governance.AddVote(k, v) 722 assert.True(t, ok) 723 } 724 725 // Create a block 726 previousBlock = currentBlock 727 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 728 _, err := chain.InsertChain(types.Blocks{currentBlock}) 729 assert.NoError(t, err) 730 731 // check balance 732 addr := currentBlock.Rewardbase() 733 state, err := chain.State() 734 assert.NoError(t, err) 735 bal := state.GetBalance(addr) 736 737 assert.Equal(t, tc.expected[num+1], bal.Uint64(), "wrong at block %d", num+1) 738 } 739 } 740 } 741 742 func makeSnapshotTestConfigItems() []interface{} { 743 return []interface{}{ 744 stakingUpdateInterval(1), 745 proposerUpdateInterval(1), 746 proposerPolicy(params.WeightedRandom), 747 } 748 } 749 750 func makeFakeStakingInfo(blockNumber uint64, keys []*ecdsa.PrivateKey, amounts []uint64) *reward.StakingInfo { 751 stakingInfo := &reward.StakingInfo{ 752 BlockNum: blockNumber, 753 } 754 for idx, key := range keys { 755 addr := crypto.PubkeyToAddress(key.PublicKey) 756 757 pk, _ := crypto.GenerateKey() 758 rewardAddr := crypto.PubkeyToAddress(pk.PublicKey) 759 760 stakingInfo.CouncilNodeAddrs = append(stakingInfo.CouncilNodeAddrs, addr) 761 stakingInfo.CouncilStakingAddrs = append(stakingInfo.CouncilStakingAddrs, addr) 762 stakingInfo.CouncilStakingAmounts = append(stakingInfo.CouncilStakingAmounts, amounts[idx]) 763 stakingInfo.CouncilRewardAddrs = append(stakingInfo.CouncilRewardAddrs, rewardAddr) 764 } 765 return stakingInfo 766 } 767 768 func toAddressList(validators []istanbul.Validator) []common.Address { 769 addresses := make([]common.Address, len(validators)) 770 for idx, val := range validators { 771 addresses[idx] = val.Address() 772 } 773 return addresses 774 } 775 776 func copyAndSortAddrs(addrs []common.Address) []common.Address { 777 copied := make([]common.Address, len(addrs)) 778 copy(copied, addrs) 779 780 sort.Slice(copied, func(i, j int) bool { 781 return strings.Compare(copied[i].String(), copied[j].String()) < 0 782 }) 783 784 return copied 785 } 786 787 func makeExpectedResult(indices []int, candidate []common.Address) []common.Address { 788 expected := make([]common.Address, len(indices)) 789 for eIdx, cIdx := range indices { 790 expected[eIdx] = candidate[cIdx] 791 } 792 return copyAndSortAddrs(expected) 793 } 794 795 // Asserts taht if all (key,value) pairs of `subset` exists in `set` 796 func assertMapSubset(t *testing.T, subset, set map[string]interface{}) { 797 for k, v := range subset { 798 assert.Equal(t, set[k], v) 799 } 800 } 801 802 func TestSnapshot_Validators_AfterMinimumStakingVotes(t *testing.T) { 803 type vote struct { 804 key string 805 value interface{} 806 } 807 type expected struct { 808 blocks []uint64 809 validators []int 810 demoted []int 811 } 812 type testcase struct { 813 stakingInfo []uint64 814 votes []vote 815 expected []expected 816 } 817 818 testcases := []testcase{ 819 { 820 // test the validators are updated properly when minimum staking is changed in none mode 821 []uint64{8000000, 7000000, 6000000, 5000000}, 822 []vote{ 823 {"governance.governancemode", "none"}, // voted on epoch 1, applied from 6-8 824 {"reward.minimumstake", "5500000"}, // voted on epoch 2, applied from 9-11 825 {"reward.minimumstake", "6500000"}, // voted on epoch 3, applied from 12-14 826 {"reward.minimumstake", "7500000"}, // voted on epoch 4, applied from 15-17 827 {"reward.minimumstake", "8500000"}, // voted on epoch 5, applied from 18-20 828 {"reward.minimumstake", "7500000"}, // voted on epoch 6, applied from 21-23 829 {"reward.minimumstake", "6500000"}, // voted on epoch 7, applied from 24-26 830 {"reward.minimumstake", "5500000"}, // voted on epoch 8, applied from 27-29 831 {"reward.minimumstake", "4500000"}, // voted on epoch 9, applied from 30-32 832 }, 833 []expected{ 834 {[]uint64{0, 1, 2, 3, 4, 5, 6, 7, 8}, []int{0, 1, 2, 3}, []int{}}, 835 {[]uint64{9, 10, 11}, []int{0, 1, 2}, []int{3}}, 836 {[]uint64{12, 13, 14}, []int{0, 1}, []int{2, 3}}, 837 {[]uint64{15, 16, 17}, []int{0}, []int{1, 2, 3}}, 838 {[]uint64{18, 19, 20}, []int{0, 1, 2, 3}, []int{}}, 839 {[]uint64{21, 22, 23}, []int{0}, []int{1, 2, 3}}, 840 {[]uint64{24, 25, 26}, []int{0, 1}, []int{2, 3}}, 841 {[]uint64{27, 28, 29}, []int{0, 1, 2}, []int{3}}, 842 {[]uint64{30, 31, 32}, []int{0, 1, 2, 3}, []int{}}, 843 }, 844 }, 845 { 846 // test the validators (including governing node) are updated properly when minimum staking is changed in single mode 847 []uint64{5000000, 6000000, 7000000, 8000000}, 848 []vote{ 849 {"reward.minimumstake", "8500000"}, // voted on epoch 1, applied from 6-8 850 {"reward.minimumstake", "7500000"}, // voted on epoch 2, applied from 9-11 851 {"reward.minimumstake", "6500000"}, // voted on epoch 3, applied from 12-14 852 {"reward.minimumstake", "5500000"}, // voted on epoch 4, applied from 15-17 853 {"reward.minimumstake", "4500000"}, // voted on epoch 5, applied from 18-20 854 {"reward.minimumstake", "5500000"}, // voted on epoch 6, applied from 21-23 855 {"reward.minimumstake", "6500000"}, // voted on epoch 7, applied from 24-26 856 {"reward.minimumstake", "7500000"}, // voted on epoch 8, applied from 27-29 857 {"reward.minimumstake", "8500000"}, // voted on epoch 9, applied from 30-32 858 }, 859 []expected{ 860 // 0 is governing node, so it is included in the validators all the time 861 {[]uint64{0, 1, 2, 3, 4, 5, 6, 7, 8}, []int{0, 1, 2, 3}, []int{}}, 862 {[]uint64{9, 10, 11}, []int{0, 3}, []int{1, 2}}, 863 {[]uint64{12, 13, 14}, []int{0, 2, 3}, []int{1}}, 864 {[]uint64{15, 16, 17, 18, 19, 20, 21, 22, 23}, []int{0, 1, 2, 3}, []int{}}, 865 {[]uint64{24, 25, 26}, []int{0, 2, 3}, []int{1}}, 866 {[]uint64{27, 28, 29}, []int{0, 3}, []int{1, 2}}, 867 {[]uint64{30, 31, 32}, []int{0, 1, 2, 3}, []int{}}, 868 }, 869 }, 870 { 871 // test the validators are updated properly if governing node is changed 872 []uint64{6000000, 6000000, 5000000, 5000000}, 873 []vote{ 874 {"reward.minimumstake", "5500000"}, // voted on epoch 1, applied from 6-8 875 {"governance.governingnode", 2}, // voted on epoch 2, applied from 9-11 876 }, 877 []expected{ 878 // 0 is governing node, so it is included in the validators all the time 879 {[]uint64{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3}, []int{}}, 880 {[]uint64{6, 7, 8}, []int{0, 1}, []int{2, 3}}, 881 {[]uint64{9, 10, 11}, []int{0, 1, 2}, []int{3}}, 882 }, 883 }, 884 } 885 886 testEpoch := 3 887 888 var configItems []interface{} 889 configItems = append(configItems, proposerPolicy(params.WeightedRandom)) 890 configItems = append(configItems, proposerUpdateInterval(1)) 891 configItems = append(configItems, epoch(testEpoch)) 892 configItems = append(configItems, governanceMode("single")) 893 configItems = append(configItems, minimumStake(new(big.Int).SetUint64(4000000))) 894 configItems = append(configItems, istanbulCompatibleBlock(new(big.Int).SetUint64(0))) 895 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 896 897 for _, tc := range testcases { 898 chain, engine := newBlockChain(4, configItems...) 899 900 // set old staking manager after finishing this test. 901 oldStakingManager := reward.GetStakingManager() 902 903 // set new staking manager with the given staking information. 904 stakingInfo := makeFakeStakingInfo(0, nodeKeys, tc.stakingInfo) 905 reward.SetTestStakingManagerWithStakingInfoCache(stakingInfo) 906 907 var previousBlock, currentBlock *types.Block = nil, chain.Genesis() 908 909 for _, v := range tc.votes { 910 // vote a vote in each epoch 911 if v.key == "governance.governingnode" { 912 idx := v.value.(int) 913 v.value = addrs[idx].String() 914 } 915 engine.governance.AddVote(v.key, v.value) 916 917 for i := 0; i < testEpoch; i++ { 918 previousBlock = currentBlock 919 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 920 _, err := chain.InsertChain(types.Blocks{currentBlock}) 921 assert.NoError(t, err) 922 } 923 } 924 925 // insert blocks on extra epoch 926 for i := 0; i < 2*testEpoch; i++ { 927 previousBlock = currentBlock 928 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 929 _, err := chain.InsertChain(types.Blocks{currentBlock}) 930 assert.NoError(t, err) 931 } 932 933 for _, e := range tc.expected { 934 for _, num := range e.blocks { 935 block := chain.GetBlockByNumber(num) 936 snap, err := engine.snapshot(chain, block.NumberU64(), block.Hash(), nil, true) 937 assert.NoError(t, err) 938 939 validators := toAddressList(snap.ValSet.List()) 940 demoted := toAddressList(snap.ValSet.DemotedList()) 941 942 expectedValidators := makeExpectedResult(e.validators, addrs) 943 expectedDemoted := makeExpectedResult(e.demoted, addrs) 944 945 assert.Equal(t, expectedValidators, validators) 946 assert.Equal(t, expectedDemoted, demoted) 947 } 948 } 949 950 reward.SetTestStakingManager(oldStakingManager) 951 engine.Stop() 952 } 953 } 954 955 func TestSnapshot_Validators_BasedOnStaking(t *testing.T) { 956 type testcase struct { 957 stakingAmounts []uint64 // test staking amounts of each validator 958 isIstanbulCompatible bool // whether or not if the inserted block is istanbul compatible 959 isSingleMode bool // whether or not if the governance mode is single 960 expectedValidators []int // the indices of expected validators 961 expectedDemoted []int // the indices of expected demoted validators 962 } 963 964 testcases := []testcase{ 965 // The following testcases are the ones before istanbul incompatible change 966 { 967 []uint64{5000000, 5000000, 5000000, 5000000}, 968 false, 969 false, 970 []int{0, 1, 2, 3}, 971 []int{}, 972 }, 973 { 974 []uint64{5000000, 5000000, 5000000, 6000000}, 975 false, 976 false, 977 []int{0, 1, 2, 3}, 978 []int{}, 979 }, 980 { 981 []uint64{5000000, 5000000, 6000000, 6000000}, 982 false, 983 false, 984 []int{0, 1, 2, 3}, 985 []int{}, 986 }, 987 { 988 []uint64{5000000, 6000000, 6000000, 6000000}, 989 false, 990 false, 991 []int{0, 1, 2, 3}, 992 []int{}, 993 }, 994 { 995 []uint64{6000000, 6000000, 6000000, 6000000}, 996 false, 997 false, 998 []int{0, 1, 2, 3}, 999 []int{}, 1000 }, 1001 // The following testcases are the ones after istanbul incompatible change 1002 { 1003 []uint64{5000000, 5000000, 5000000, 5000000}, 1004 true, 1005 false, 1006 []int{0, 1, 2, 3}, 1007 []int{}, 1008 }, 1009 { 1010 []uint64{5000000, 5000000, 5000000, 6000000}, 1011 true, 1012 false, 1013 []int{3}, 1014 []int{0, 1, 2}, 1015 }, 1016 { 1017 []uint64{5000000, 5000000, 6000000, 6000000}, 1018 true, 1019 false, 1020 []int{2, 3}, 1021 []int{0, 1}, 1022 }, 1023 { 1024 []uint64{5000000, 6000000, 6000000, 6000000}, 1025 true, 1026 false, 1027 []int{1, 2, 3}, 1028 []int{0}, 1029 }, 1030 { 1031 []uint64{6000000, 6000000, 6000000, 6000000}, 1032 true, 1033 false, 1034 []int{0, 1, 2, 3}, 1035 []int{}, 1036 }, 1037 { 1038 []uint64{5500001, 5500000, 5499999, 0}, 1039 true, 1040 false, 1041 []int{0, 1}, 1042 []int{2, 3}, 1043 }, 1044 // The following testcases are the ones for testing governing node in single mode 1045 // The first staking amount is of the governing node 1046 { 1047 []uint64{6000000, 6000000, 6000000, 6000000}, 1048 true, 1049 true, 1050 []int{0, 1, 2, 3}, 1051 []int{}, 1052 }, 1053 { 1054 []uint64{5000000, 6000000, 6000000, 6000000}, 1055 true, 1056 true, 1057 []int{0, 1, 2, 3}, 1058 []int{}, 1059 }, 1060 { 1061 []uint64{5000000, 5000000, 6000000, 6000000}, 1062 true, 1063 true, 1064 []int{0, 2, 3}, 1065 []int{1}, 1066 }, 1067 { 1068 []uint64{5000000, 5000000, 5000000, 6000000}, 1069 true, 1070 true, 1071 []int{0, 3}, 1072 []int{1, 2}, 1073 }, 1074 { 1075 []uint64{5000000, 5000000, 5000000, 5000000}, 1076 true, 1077 true, 1078 []int{0, 1, 2, 3}, 1079 []int{}, 1080 }, 1081 } 1082 1083 testNum := 4 1084 ms := uint64(5500000) 1085 configItems := makeSnapshotTestConfigItems() 1086 configItems = append(configItems, minimumStake(new(big.Int).SetUint64(ms))) 1087 for _, tc := range testcases { 1088 if tc.isIstanbulCompatible { 1089 configItems = append(configItems, istanbulCompatibleBlock(new(big.Int).SetUint64(0))) 1090 } 1091 if tc.isSingleMode { 1092 configItems = append(configItems, governanceMode("single")) 1093 } 1094 chain, engine := newBlockChain(testNum, configItems...) 1095 1096 // set old staking manager after finishing this test. 1097 oldStakingManager := reward.GetStakingManager() 1098 1099 // set new staking manager with the given staking information. 1100 stakingInfo := makeFakeStakingInfo(0, nodeKeys, tc.stakingAmounts) 1101 reward.SetTestStakingManagerWithStakingInfoCache(stakingInfo) 1102 1103 block := makeBlockWithSeal(chain, engine, chain.Genesis()) 1104 _, err := chain.InsertChain(types.Blocks{block}) 1105 assert.NoError(t, err) 1106 1107 snap, err := engine.snapshot(chain, block.NumberU64(), block.Hash(), nil, true) 1108 assert.NoError(t, err) 1109 1110 validators := toAddressList(snap.ValSet.List()) 1111 demoted := toAddressList(snap.ValSet.DemotedList()) 1112 1113 expectedValidators := makeExpectedResult(tc.expectedValidators, addrs) 1114 expectedDemoted := makeExpectedResult(tc.expectedDemoted, addrs) 1115 1116 assert.Equal(t, expectedValidators, validators) 1117 assert.Equal(t, expectedDemoted, demoted) 1118 1119 reward.SetTestStakingManager(oldStakingManager) 1120 engine.Stop() 1121 } 1122 } 1123 1124 func TestSnapshot_Validators_AddRemove(t *testing.T) { 1125 type vote struct { 1126 key string 1127 value interface{} 1128 } 1129 type expected struct { 1130 validators []int // expected validator indexes at given block 1131 } 1132 type testcase struct { 1133 length int // total number of blocks to simulate 1134 votes map[int]vote 1135 expected map[int]expected 1136 } 1137 1138 testcases := []testcase{ 1139 { // Singular change 1140 5, 1141 map[int]vote{ 1142 1: {"governance.removevalidator", 3}, 1143 3: {"governance.addvalidator", 3}, 1144 }, 1145 map[int]expected{ 1146 0: {[]int{0, 1, 2, 3}}, 1147 1: {[]int{0, 1, 2, 3}}, 1148 2: {[]int{0, 1, 2}}, 1149 3: {[]int{0, 1, 2}}, 1150 4: {[]int{0, 1, 2, 3}}, 1151 }, 1152 }, 1153 { // Plural change 1154 5, 1155 map[int]vote{ 1156 1: {"governance.removevalidator", []int{1, 2, 3}}, 1157 3: {"governance.addvalidator", []int{1, 2}}, 1158 }, 1159 map[int]expected{ 1160 0: {[]int{0, 1, 2, 3}}, 1161 1: {[]int{0, 1, 2, 3}}, 1162 2: {[]int{0}}, 1163 3: {[]int{0}}, 1164 4: {[]int{0, 1, 2}}, 1165 }, 1166 }, 1167 { // Around checkpoint interval (i.e. every 1024 block) 1168 checkpointInterval + 10, 1169 map[int]vote{ 1170 checkpointInterval - 5: {"governance.removevalidator", 3}, 1171 checkpointInterval - 1: {"governance.removevalidator", 2}, 1172 checkpointInterval + 0: {"governance.removevalidator", 1}, 1173 checkpointInterval + 1: {"governance.addvalidator", 1}, 1174 checkpointInterval + 2: {"governance.addvalidator", 2}, 1175 checkpointInterval + 3: {"governance.addvalidator", 3}, 1176 }, 1177 map[int]expected{ 1178 0: {[]int{0, 1, 2, 3}}, 1179 1: {[]int{0, 1, 2, 3}}, 1180 checkpointInterval - 4: {[]int{0, 1, 2}}, 1181 checkpointInterval + 0: {[]int{0, 1}}, 1182 checkpointInterval + 1: {[]int{0}}, 1183 checkpointInterval + 2: {[]int{0, 1}}, 1184 checkpointInterval + 3: {[]int{0, 1, 2}}, 1185 checkpointInterval + 4: {[]int{0, 1, 2, 3}}, 1186 checkpointInterval + 9: {[]int{0, 1, 2, 3}}, 1187 }, 1188 }, 1189 { // multiple addvalidator & removevalidator 1190 10, 1191 map[int]vote{ 1192 0: {"governance.removevalidator", 3}, 1193 2: {"governance.addvalidator", 3}, 1194 4: {"governance.addvalidator", 3}, 1195 6: {"governance.removevalidator", 3}, 1196 8: {"governance.removevalidator", 3}, 1197 }, 1198 map[int]expected{ 1199 1: {[]int{0, 1, 2}}, 1200 3: {[]int{0, 1, 2, 3}}, 1201 5: {[]int{0, 1, 2, 3}}, 1202 7: {[]int{0, 1, 2}}, 1203 9: {[]int{0, 1, 2}}, 1204 }, 1205 }, 1206 { // multiple removevalidator & addvalidator 1207 10, 1208 map[int]vote{ 1209 0: {"governance.removevalidator", 3}, 1210 2: {"governance.removevalidator", 3}, 1211 4: {"governance.addvalidator", 3}, 1212 6: {"governance.addvalidator", 3}, 1213 }, 1214 map[int]expected{ 1215 1: {[]int{0, 1, 2}}, 1216 3: {[]int{0, 1, 2}}, 1217 5: {[]int{0, 1, 2, 3}}, 1218 7: {[]int{0, 1, 2, 3}}, 1219 }, 1220 }, 1221 { // multiple addvalidators & removevalidators 1222 10, 1223 map[int]vote{ 1224 0: {"governance.removevalidator", []int{2, 3}}, 1225 2: {"governance.addvalidator", []int{2, 3}}, 1226 4: {"governance.addvalidator", []int{2, 3}}, 1227 6: {"governance.removevalidator", []int{2, 3}}, 1228 8: {"governance.removevalidator", []int{2, 3}}, 1229 }, 1230 map[int]expected{ 1231 1: {[]int{0, 1}}, 1232 3: {[]int{0, 1, 2, 3}}, 1233 5: {[]int{0, 1, 2, 3}}, 1234 7: {[]int{0, 1}}, 1235 9: {[]int{0, 1}}, 1236 }, 1237 }, 1238 { // multiple removevalidators & addvalidators 1239 10, 1240 map[int]vote{ 1241 0: {"governance.removevalidator", []int{2, 3}}, 1242 2: {"governance.removevalidator", []int{2, 3}}, 1243 4: {"governance.addvalidator", []int{2, 3}}, 1244 6: {"governance.addvalidator", []int{2, 3}}, 1245 }, 1246 map[int]expected{ 1247 1: {[]int{0, 1}}, 1248 3: {[]int{0, 1}}, 1249 5: {[]int{0, 1, 2, 3}}, 1250 7: {[]int{0, 1, 2, 3}}, 1251 }, 1252 }, 1253 } 1254 1255 var configItems []interface{} 1256 configItems = append(configItems, proposerPolicy(params.WeightedRandom)) 1257 configItems = append(configItems, proposerUpdateInterval(1)) 1258 configItems = append(configItems, epoch(3)) 1259 configItems = append(configItems, subGroupSize(4)) 1260 configItems = append(configItems, governanceMode("single")) 1261 configItems = append(configItems, minimumStake(new(big.Int).SetUint64(4000000))) 1262 configItems = append(configItems, istanbulCompatibleBlock(new(big.Int).SetUint64(0))) 1263 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 1264 stakes := []uint64{4000000, 4000000, 4000000, 4000000} 1265 1266 for _, tc := range testcases { 1267 // Create test blockchain 1268 chain, engine := newBlockChain(4, configItems...) 1269 1270 oldStakingManager := reward.GetStakingManager() 1271 stakingInfo := makeFakeStakingInfo(0, nodeKeys, stakes) 1272 reward.SetTestStakingManagerWithStakingInfoCache(stakingInfo) 1273 1274 // Backup the globals. The globals `nodeKeys` and `addrs` will be 1275 // modified according to validator change votes. 1276 allNodeKeys := make([]*ecdsa.PrivateKey, len(nodeKeys)) 1277 allAddrs := make([]common.Address, len(addrs)) 1278 copy(allNodeKeys, nodeKeys) 1279 copy(allAddrs, addrs) 1280 1281 var previousBlock, currentBlock *types.Block = nil, chain.Genesis() 1282 1283 // Create blocks with votes 1284 for i := 0; i < tc.length; i++ { 1285 if v, ok := tc.votes[i]; ok { // If a vote is scheduled in this block, 1286 if idx, ok := v.value.(int); ok { 1287 addr := allAddrs[idx] 1288 engine.governance.AddVote(v.key, addr) 1289 } else { 1290 addrList := makeExpectedResult(v.value.([]int), allAddrs) 1291 engine.governance.AddVote(v.key, addrList) 1292 } 1293 // t.Logf("Voting at block #%d for %s, %v", i, v.key, v.value) 1294 } 1295 1296 previousBlock = currentBlock 1297 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1298 _, err := chain.InsertChain(types.Blocks{currentBlock}) 1299 assert.NoError(t, err) 1300 1301 // After a voting, reflect the validator change to the globals 1302 if v, ok := tc.votes[i]; ok { 1303 var indices []int 1304 if idx, ok := v.value.(int); ok { 1305 indices = []int{idx} 1306 } else { 1307 indices = v.value.([]int) 1308 } 1309 if v.key == "governance.addvalidator" { 1310 for _, i := range indices { 1311 includeNode(allAddrs[i], allNodeKeys[i]) 1312 } 1313 } 1314 if v.key == "governance.removevalidator" { 1315 for _, i := range indices { 1316 excludeNodeByAddr(allAddrs[i]) 1317 } 1318 } 1319 } 1320 } 1321 1322 // Calculate historical validators using the snapshot. 1323 for i := 0; i < tc.length; i++ { 1324 if _, ok := tc.expected[i]; !ok { 1325 continue 1326 } 1327 block := chain.GetBlockByNumber(uint64(i)) 1328 snap, err := engine.snapshot(chain, block.NumberU64(), block.Hash(), nil, true) 1329 assert.NoError(t, err) 1330 validators := copyAndSortAddrs(toAddressList(snap.ValSet.List())) 1331 1332 expectedValidators := makeExpectedResult(tc.expected[i].validators, allAddrs) 1333 assert.Equal(t, expectedValidators, validators) 1334 // t.Logf("snap at block #%d: size %d", i, snap.ValSet.Size()) 1335 } 1336 1337 reward.SetTestStakingManager(oldStakingManager) 1338 engine.Stop() 1339 } 1340 } 1341 1342 func TestSnapshot_Writable(t *testing.T) { 1343 var configItems []interface{} 1344 configItems = append(configItems, proposerPolicy(params.WeightedRandom)) 1345 configItems = append(configItems, epoch(3)) 1346 configItems = append(configItems, governanceMode("single")) 1347 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 1348 chain, engine := newBlockChain(1, configItems...) 1349 1350 // add votes and insert voted blocks 1351 var ( 1352 previousBlock, currentBlock *types.Block = nil, chain.Genesis() 1353 err error 1354 ) 1355 1356 // voteData is inserted at block 4, and current block is block 5. 1357 for i := 0; i < 5; i++ { 1358 if i == 4 { 1359 engine.governance.AddVote("governance.unitprice", uint64(2000000)) 1360 } 1361 previousBlock = currentBlock 1362 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1363 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1364 assert.NoError(t, err) 1365 } 1366 1367 // save current gov.changeSet's length for the expected value. 1368 currentChangeSetLength := len(engine.governance.GetGovernanceChange()) 1369 assert.Equal(t, 1, currentChangeSetLength) 1370 1371 // block 3 is the start block of an epoch. In this test, the cache of this block's snapshot is cleared. 1372 // If cache is not removed, it will just read the cache rather than making the snapshot itself. 1373 block := chain.GetBlockByNumber(uint64(3)) 1374 1375 // case [writable == false] 1376 // expected result: gov.changeSet should not be modified. 1377 engine.recents.Remove(block.Hash()) // assume node is restarted 1378 _, err = engine.snapshot(chain, block.NumberU64(), block.Hash(), nil, false) 1379 assert.Equal(t, currentChangeSetLength, len(engine.governance.GetGovernanceChange())) 1380 1381 // case [writable == true] 1382 // expected result: gov.changeSet is modified. 1383 engine.recents.Remove(block.Hash()) // assume node is restarted 1384 _, err = engine.snapshot(chain, block.NumberU64(), block.Hash(), nil, true) 1385 assert.Equal(t, 0, len(engine.governance.GetGovernanceChange())) 1386 } 1387 1388 func TestGovernance_Votes(t *testing.T) { 1389 type vote struct { 1390 key string 1391 value interface{} 1392 } 1393 type governanceItem struct { 1394 vote 1395 appliedBlockNumber uint64 // if applied block number is 0, then it checks the item on current block 1396 } 1397 type testcase struct { 1398 votes []vote 1399 expected []governanceItem 1400 } 1401 1402 testcases := []testcase{ 1403 { 1404 votes: []vote{ 1405 {"governance.governancemode", "none"}, // voted on block 1 1406 {"istanbul.committeesize", uint64(4)}, // voted on block 2 1407 {"governance.unitprice", uint64(2000000)}, // voted on block 3 1408 {"reward.mintingamount", "96000000000"}, // voted on block 4 1409 {"reward.ratio", "34/33/33"}, // voted on block 5 1410 {"reward.useginicoeff", true}, // voted on block 6 1411 {"reward.minimumstake", "5000000"}, // voted on block 7 1412 {"reward.kip82ratio", "50/50"}, // voted on block 8 1413 {"governance.deriveshaimpl", uint64(2)}, // voted on block 9 1414 }, 1415 expected: []governanceItem{ 1416 {vote{"governance.governancemode", "none"}, 6}, 1417 {vote{"istanbul.committeesize", uint64(4)}, 6}, 1418 {vote{"governance.unitprice", uint64(2000000)}, 9}, 1419 {vote{"reward.mintingamount", "96000000000"}, 9}, 1420 {vote{"reward.ratio", "34/33/33"}, 9}, 1421 {vote{"reward.useginicoeff", true}, 12}, 1422 {vote{"reward.minimumstake", "5000000"}, 12}, 1423 {vote{"reward.kip82ratio", "50/50"}, 12}, 1424 {vote{"governance.deriveshaimpl", uint64(2)}, 15}, 1425 // check governance items on current block 1426 {vote{"governance.governancemode", "none"}, 0}, 1427 {vote{"istanbul.committeesize", uint64(4)}, 0}, 1428 {vote{"governance.unitprice", uint64(2000000)}, 0}, 1429 {vote{"reward.mintingamount", "96000000000"}, 0}, 1430 {vote{"reward.ratio", "34/33/33"}, 0}, 1431 {vote{"reward.useginicoeff", true}, 0}, 1432 {vote{"reward.minimumstake", "5000000"}, 0}, 1433 {vote{"reward.kip82ratio", "50/50"}, 0}, 1434 {vote{"governance.deriveshaimpl", uint64(2)}, 0}, 1435 }, 1436 }, 1437 { 1438 votes: []vote{ 1439 {"governance.governancemode", "none"}, // voted on block 1 1440 {"governance.governancemode", "single"}, // voted on block 2 1441 {"governance.governancemode", "none"}, // voted on block 3 1442 {"governance.governancemode", "single"}, // voted on block 4 1443 {"governance.governancemode", "none"}, // voted on block 5 1444 {"governance.governancemode", "single"}, // voted on block 6 1445 {"governance.governancemode", "none"}, // voted on block 7 1446 {"governance.governancemode", "single"}, // voted on block 8 1447 {"governance.governancemode", "none"}, // voted on block 9 1448 }, 1449 expected: []governanceItem{ 1450 {vote{"governance.governancemode", "single"}, 6}, 1451 {vote{"governance.governancemode", "none"}, 9}, 1452 {vote{"governance.governancemode", "single"}, 12}, 1453 {vote{"governance.governancemode", "none"}, 15}, 1454 }, 1455 }, 1456 { 1457 votes: []vote{ 1458 {"governance.governancemode", "none"}, // voted on block 1 1459 {"istanbul.committeesize", uint64(4)}, // voted on block 2 1460 {"governance.unitprice", uint64(2000000)}, // voted on block 3 1461 {"governance.governancemode", "single"}, // voted on block 4 1462 {"istanbul.committeesize", uint64(22)}, // voted on block 5 1463 {"governance.unitprice", uint64(2)}, // voted on block 6 1464 {"governance.governancemode", "none"}, // voted on block 7 1465 }, 1466 expected: []governanceItem{ 1467 // governance mode for all blocks 1468 {vote{"governance.governancemode", "single"}, 1}, 1469 {vote{"governance.governancemode", "single"}, 2}, 1470 {vote{"governance.governancemode", "single"}, 3}, 1471 {vote{"governance.governancemode", "single"}, 4}, 1472 {vote{"governance.governancemode", "single"}, 5}, 1473 {vote{"governance.governancemode", "none"}, 6}, 1474 {vote{"governance.governancemode", "none"}, 7}, 1475 {vote{"governance.governancemode", "none"}, 8}, 1476 {vote{"governance.governancemode", "single"}, 9}, 1477 {vote{"governance.governancemode", "single"}, 10}, 1478 {vote{"governance.governancemode", "single"}, 11}, 1479 {vote{"governance.governancemode", "none"}, 12}, 1480 {vote{"governance.governancemode", "none"}, 13}, 1481 {vote{"governance.governancemode", "none"}, 14}, 1482 {vote{"governance.governancemode", "none"}, 0}, // check on current 1483 1484 // committee size for all blocks 1485 {vote{"istanbul.committeesize", uint64(21)}, 1}, 1486 {vote{"istanbul.committeesize", uint64(21)}, 2}, 1487 {vote{"istanbul.committeesize", uint64(21)}, 3}, 1488 {vote{"istanbul.committeesize", uint64(21)}, 4}, 1489 {vote{"istanbul.committeesize", uint64(21)}, 5}, 1490 {vote{"istanbul.committeesize", uint64(4)}, 6}, 1491 {vote{"istanbul.committeesize", uint64(4)}, 7}, 1492 {vote{"istanbul.committeesize", uint64(4)}, 8}, 1493 {vote{"istanbul.committeesize", uint64(22)}, 9}, 1494 {vote{"istanbul.committeesize", uint64(22)}, 10}, 1495 {vote{"istanbul.committeesize", uint64(22)}, 11}, 1496 {vote{"istanbul.committeesize", uint64(22)}, 12}, 1497 {vote{"istanbul.committeesize", uint64(22)}, 13}, 1498 {vote{"istanbul.committeesize", uint64(22)}, 14}, 1499 {vote{"istanbul.committeesize", uint64(22)}, 0}, // check on current 1500 1501 // unitprice for all blocks 1502 {vote{"governance.unitprice", uint64(1)}, 1}, 1503 {vote{"governance.unitprice", uint64(1)}, 2}, 1504 {vote{"governance.unitprice", uint64(1)}, 3}, 1505 {vote{"governance.unitprice", uint64(1)}, 4}, 1506 {vote{"governance.unitprice", uint64(1)}, 5}, 1507 {vote{"governance.unitprice", uint64(1)}, 6}, 1508 {vote{"governance.unitprice", uint64(1)}, 7}, 1509 {vote{"governance.unitprice", uint64(1)}, 8}, 1510 {vote{"governance.unitprice", uint64(2000000)}, 9}, 1511 {vote{"governance.unitprice", uint64(2000000)}, 10}, 1512 {vote{"governance.unitprice", uint64(2000000)}, 11}, 1513 {vote{"governance.unitprice", uint64(2)}, 12}, 1514 {vote{"governance.unitprice", uint64(2)}, 13}, 1515 {vote{"governance.unitprice", uint64(2)}, 14}, 1516 {vote{"governance.unitprice", uint64(2)}, 0}, // check on current 1517 }, 1518 }, 1519 { 1520 votes: []vote{ 1521 {}, // voted on block 1 1522 {"kip71.lowerboundbasefee", uint64(750000000000)}, // voted on block 2 1523 {}, // voted on block 3 1524 {}, // voted on block 4 1525 {"kip71.lowerboundbasefee", uint64(25000000000)}, // voted on block 5 1526 }, 1527 expected: []governanceItem{ 1528 {vote{"kip71.lowerboundbasefee", uint64(750000000000)}, 6}, 1529 {vote{"kip71.lowerboundbasefee", uint64(25000000000)}, 9}, 1530 }, 1531 }, 1532 { 1533 votes: []vote{ 1534 {}, // voted on block 1 1535 {"kip71.upperboundbasefee", uint64(750000000000)}, // voted on block 2 1536 {}, // voted on block 3 1537 {}, // voted on block 4 1538 {"kip71.upperboundbasefee", uint64(25000000000)}, // voted on block 5 1539 }, 1540 expected: []governanceItem{ 1541 {vote{"kip71.upperboundbasefee", uint64(750000000000)}, 6}, 1542 {vote{"kip71.upperboundbasefee", uint64(25000000000)}, 9}, 1543 }, 1544 }, 1545 { 1546 votes: []vote{ 1547 {}, // voted on block 1 1548 {"kip71.maxblockgasusedforbasefee", uint64(840000000)}, // voted on block 2 1549 {}, // voted on block 3 1550 {}, // voted on block 4 1551 {"kip71.maxblockgasusedforbasefee", uint64(84000000)}, // voted on block 5 1552 }, 1553 expected: []governanceItem{ 1554 {vote{"kip71.maxblockgasusedforbasefee", uint64(840000000)}, 6}, 1555 {vote{"kip71.maxblockgasusedforbasefee", uint64(84000000)}, 9}, 1556 }, 1557 }, 1558 { 1559 votes: []vote{ 1560 {}, // voted on block 1 1561 {"kip71.gastarget", uint64(50000000)}, // voted on block 2 1562 {}, // voted on block 3 1563 {}, // voted on block 4 1564 {"kip71.gastarget", uint64(30000000)}, // voted on block 5 1565 }, 1566 expected: []governanceItem{ 1567 {vote{"kip71.gastarget", uint64(50000000)}, 6}, 1568 {vote{"kip71.gastarget", uint64(30000000)}, 9}, 1569 }, 1570 }, 1571 { 1572 votes: []vote{ 1573 {}, // voted on block 1 1574 {"kip71.basefeedenominator", uint64(32)}, // voted on block 2 1575 {}, // voted on block 3 1576 {}, // voted on block 4 1577 {"kip71.basefeedenominator", uint64(64)}, // voted on block 5 1578 }, 1579 expected: []governanceItem{ 1580 {vote{"kip71.basefeedenominator", uint64(32)}, 6}, 1581 {vote{"kip71.basefeedenominator", uint64(64)}, 9}, 1582 }, 1583 }, 1584 { 1585 votes: []vote{ 1586 {}, // voted on block 1 1587 {"governance.govparamcontract", common.HexToAddress("0x0000000000000000000000000000000000000000")}, // voted on block 2 1588 {}, // voted on block 3 1589 {}, // voted on block 4 1590 {"governance.govparamcontract", common.HexToAddress("0x0000000000000000000000000000000000000400")}, // voted on block 5 1591 }, 1592 expected: []governanceItem{ 1593 {vote{"governance.govparamcontract", common.HexToAddress("0x0000000000000000000000000000000000000000")}, 6}, 1594 {vote{"governance.govparamcontract", common.HexToAddress("0x0000000000000000000000000000000000000400")}, 9}, 1595 }, 1596 }, 1597 } 1598 1599 var configItems []interface{} 1600 configItems = append(configItems, proposerPolicy(params.WeightedRandom)) 1601 configItems = append(configItems, epoch(3)) 1602 configItems = append(configItems, governanceMode("single")) 1603 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 1604 for _, tc := range testcases { 1605 chain, engine := newBlockChain(1, configItems...) 1606 1607 // test initial governance items 1608 assert.Equal(t, uint64(3), engine.governance.CurrentParams().Epoch()) 1609 assert.Equal(t, "single", engine.governance.CurrentParams().GovernanceModeStr()) 1610 assert.Equal(t, uint64(21), engine.governance.CurrentParams().CommitteeSize()) 1611 assert.Equal(t, uint64(1), engine.governance.CurrentParams().UnitPrice()) 1612 assert.Equal(t, "0", engine.governance.CurrentParams().MintingAmountStr()) 1613 assert.Equal(t, "100/0/0", engine.governance.CurrentParams().Ratio()) 1614 assert.Equal(t, false, engine.governance.CurrentParams().UseGiniCoeff()) 1615 assert.Equal(t, "2000000", engine.governance.CurrentParams().MinimumStakeStr()) 1616 1617 // add votes and insert voted blocks 1618 var ( 1619 previousBlock, currentBlock *types.Block = nil, chain.Genesis() 1620 err error 1621 ) 1622 1623 for _, v := range tc.votes { 1624 engine.governance.AddVote(v.key, v.value) 1625 previousBlock = currentBlock 1626 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1627 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1628 assert.NoError(t, err) 1629 } 1630 1631 // insert blocks until the vote is applied 1632 for i := 0; i < 6; i++ { 1633 previousBlock = currentBlock 1634 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1635 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1636 assert.NoError(t, err) 1637 } 1638 1639 for _, item := range tc.expected { 1640 blockNumber := item.appliedBlockNumber 1641 if blockNumber == 0 { 1642 blockNumber = chain.CurrentBlock().NumberU64() 1643 } 1644 _, items, err := engine.governance.ReadGovernance(blockNumber) 1645 assert.NoError(t, err) 1646 assert.Equal(t, item.value, items[item.key]) 1647 } 1648 1649 engine.Stop() 1650 } 1651 } 1652 1653 func TestGovernance_ReaderEngine(t *testing.T) { 1654 // Test that ReaderEngine (CurrentParams(), EffectiveParams(), UpdateParams()) works. 1655 type vote = map[string]interface{} 1656 type expected = map[string]interface{} // expected (subset of) governance items 1657 type testcase struct { 1658 length int // total number of blocks to simulate 1659 votes map[int]vote 1660 expected map[int]expected 1661 } 1662 1663 testcases := []testcase{ 1664 { 1665 8, 1666 map[int]vote{ 1667 1: {"governance.unitprice": uint64(17)}, 1668 }, 1669 map[int]expected{ 1670 0: {"governance.unitprice": uint64(1)}, 1671 1: {"governance.unitprice": uint64(1)}, 1672 2: {"governance.unitprice": uint64(1)}, 1673 3: {"governance.unitprice": uint64(1)}, 1674 4: {"governance.unitprice": uint64(1)}, 1675 5: {"governance.unitprice": uint64(1)}, 1676 6: {"governance.unitprice": uint64(1)}, 1677 7: {"governance.unitprice": uint64(17)}, 1678 8: {"governance.unitprice": uint64(17)}, 1679 }, 1680 }, 1681 } 1682 1683 var configItems []interface{} 1684 configItems = append(configItems, proposerPolicy(params.WeightedRandom)) 1685 configItems = append(configItems, proposerUpdateInterval(1)) 1686 configItems = append(configItems, epoch(3)) 1687 configItems = append(configItems, governanceMode("single")) 1688 configItems = append(configItems, minimumStake(new(big.Int).SetUint64(4000000))) 1689 configItems = append(configItems, istanbulCompatibleBlock(new(big.Int).SetUint64(0))) 1690 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 1691 stakes := []uint64{4000000, 4000000, 4000000, 4000000} 1692 1693 for _, tc := range testcases { 1694 // Create test blockchain 1695 chain, engine := newBlockChain(4, configItems...) 1696 1697 oldStakingManager := reward.GetStakingManager() 1698 stakingInfo := makeFakeStakingInfo(0, nodeKeys, stakes) 1699 reward.SetTestStakingManagerWithStakingInfoCache(stakingInfo) 1700 1701 var previousBlock, currentBlock *types.Block = nil, chain.Genesis() 1702 1703 // Create blocks with votes 1704 for num := 0; num <= tc.length; num++ { 1705 // Validate current params with CurrentParams() and CurrentSetCopy(). 1706 // Check that both returns the expected result. 1707 assertMapSubset(t, tc.expected[num+1], engine.governance.CurrentParams().StrMap()) 1708 assertMapSubset(t, tc.expected[num+1], engine.governance.CurrentSetCopy()) 1709 1710 // Place a vote if a vote is scheduled in upcoming block 1711 // Note that we're building (head+1)'th block here. 1712 for k, v := range tc.votes[num+1] { 1713 ok := engine.governance.AddVote(k, v) 1714 assert.True(t, ok) 1715 } 1716 1717 // Create a block 1718 previousBlock = currentBlock 1719 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1720 _, err := chain.InsertChain(types.Blocks{currentBlock}) 1721 assert.NoError(t, err) 1722 1723 // Load parameters for the next block 1724 err = engine.governance.UpdateParams(currentBlock.NumberU64()) 1725 assert.NoError(t, err) 1726 } 1727 1728 // Validate historic parameters with EffectiveParams() and ReadGovernance(). 1729 // Check that both returns the expected result. 1730 for num := 0; num <= tc.length; num++ { 1731 pset, err := engine.governance.EffectiveParams(uint64(num)) 1732 assert.NoError(t, err) 1733 assertMapSubset(t, tc.expected[num], pset.StrMap()) 1734 1735 _, items, err := engine.governance.ReadGovernance(uint64(num)) 1736 assert.NoError(t, err) 1737 assertMapSubset(t, tc.expected[num+1], items) 1738 } 1739 1740 reward.SetTestStakingManager(oldStakingManager) 1741 engine.Stop() 1742 } 1743 } 1744 1745 func TestChainConfig_UpdateAfterVotes(t *testing.T) { 1746 type vote struct { 1747 key string 1748 value interface{} 1749 } 1750 type testcase struct { 1751 voting vote 1752 expected vote 1753 } 1754 1755 testcases := []testcase{ 1756 { 1757 voting: vote{"kip71.lowerboundbasefee", uint64(20000000000)}, // voted on block 1 1758 expected: vote{"kip71.lowerboundbasefee", uint64(20000000000)}, 1759 }, 1760 { 1761 voting: vote{"kip71.upperboundbasefee", uint64(500000000000)}, // voted on block 1 1762 expected: vote{"kip71.upperboundbasefee", uint64(500000000000)}, 1763 }, 1764 { 1765 voting: vote{"kip71.maxblockgasusedforbasefee", uint64(100000000)}, // voted on block 1 1766 expected: vote{"kip71.maxblockgasusedforbasefee", uint64(100000000)}, 1767 }, 1768 { 1769 voting: vote{"kip71.gastarget", uint64(50000000)}, // voted on block 1 1770 expected: vote{"kip71.gastarget", uint64(50000000)}, 1771 }, 1772 { 1773 voting: vote{"kip71.basefeedenominator", uint64(32)}, // voted on block 1 1774 expected: vote{"kip71.basefeedenominator", uint64(32)}, 1775 }, 1776 } 1777 1778 var configItems []interface{} 1779 configItems = append(configItems, epoch(3)) 1780 configItems = append(configItems, governanceMode("single")) 1781 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 1782 for _, tc := range testcases { 1783 chain, engine := newBlockChain(1, configItems...) 1784 1785 // test initial governance items 1786 assert.Equal(t, uint64(25000000000), chain.Config().Governance.KIP71.LowerBoundBaseFee) 1787 assert.Equal(t, uint64(750000000000), chain.Config().Governance.KIP71.UpperBoundBaseFee) 1788 assert.Equal(t, uint64(20), chain.Config().Governance.KIP71.BaseFeeDenominator) 1789 assert.Equal(t, uint64(60000000), chain.Config().Governance.KIP71.MaxBlockGasUsedForBaseFee) 1790 assert.Equal(t, uint64(30000000), chain.Config().Governance.KIP71.GasTarget) 1791 1792 // add votes and insert voted blocks 1793 var ( 1794 previousBlock, currentBlock *types.Block = nil, chain.Genesis() 1795 err error 1796 ) 1797 1798 engine.governance.SetBlockchain(chain) 1799 engine.governance.AddVote(tc.voting.key, tc.voting.value) 1800 previousBlock = currentBlock 1801 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1802 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1803 assert.NoError(t, err) 1804 1805 // insert blocks until the vote is applied 1806 for i := 0; i < 6; i++ { 1807 previousBlock = currentBlock 1808 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1809 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1810 assert.NoError(t, err) 1811 } 1812 1813 govConfig := chain.Config().Governance 1814 switch tc.expected.key { 1815 case "kip71.lowerboundbasefee": 1816 assert.Equal(t, tc.expected.value, govConfig.KIP71.LowerBoundBaseFee) 1817 case "kip71.upperboundbasefee": 1818 assert.Equal(t, tc.expected.value, govConfig.KIP71.UpperBoundBaseFee) 1819 case "kip71.gastarget": 1820 assert.Equal(t, tc.expected.value, govConfig.KIP71.GasTarget) 1821 case "kip71.maxblockgasusedforbasefee": 1822 assert.Equal(t, tc.expected.value, govConfig.KIP71.MaxBlockGasUsedForBaseFee) 1823 case "kip71.basefeedenominator": 1824 assert.Equal(t, tc.expected.value, govConfig.KIP71.BaseFeeDenominator) 1825 default: 1826 assert.Error(t, nil) 1827 } 1828 } 1829 } 1830 1831 func TestChainConfig_ReadFromDBAfterVotes(t *testing.T) { 1832 type vote struct { 1833 key string 1834 value interface{} 1835 } 1836 type testcase struct { 1837 voting vote 1838 expected vote 1839 } 1840 1841 testcases := []testcase{ 1842 { 1843 voting: vote{"kip71.lowerboundbasefee", uint64(20000000000)}, // voted on block 1 1844 expected: vote{"kip71.lowerboundbasefee", uint64(20000000000)}, 1845 }, 1846 { 1847 voting: vote{"kip71.upperboundbasefee", uint64(500000000000)}, // voted on block 1 1848 expected: vote{"kip71.upperboundbasefee", uint64(500000000000)}, 1849 }, 1850 { 1851 voting: vote{"kip71.maxblockgasusedforbasefee", uint64(100000000)}, // voted on block 1 1852 expected: vote{"kip71.maxblockgasusedforbasefee", uint64(100000000)}, 1853 }, 1854 { 1855 voting: vote{"kip71.gastarget", uint64(50000000)}, // voted on block 1 1856 expected: vote{"kip71.gastarget", uint64(50000000)}, 1857 }, 1858 { 1859 voting: vote{"kip71.basefeedenominator", uint64(32)}, // voted on block 1 1860 expected: vote{"kip71.basefeedenominator", uint64(32)}, 1861 }, 1862 } 1863 1864 var configItems []interface{} 1865 configItems = append(configItems, proposerPolicy(params.WeightedRandom)) 1866 configItems = append(configItems, epoch(3)) 1867 configItems = append(configItems, governanceMode("single")) 1868 configItems = append(configItems, blockPeriod(0)) // set block period to 0 to prevent creating future block 1869 for _, tc := range testcases { 1870 chain, engine := newBlockChain(1, configItems...) 1871 1872 // test initial governance items 1873 assert.Equal(t, uint64(25000000000), chain.Config().Governance.KIP71.LowerBoundBaseFee) 1874 assert.Equal(t, uint64(750000000000), chain.Config().Governance.KIP71.UpperBoundBaseFee) 1875 assert.Equal(t, uint64(20), chain.Config().Governance.KIP71.BaseFeeDenominator) 1876 assert.Equal(t, uint64(60000000), chain.Config().Governance.KIP71.MaxBlockGasUsedForBaseFee) 1877 assert.Equal(t, uint64(30000000), chain.Config().Governance.KIP71.GasTarget) 1878 1879 // add votes and insert voted blocks 1880 var ( 1881 previousBlock, currentBlock *types.Block = nil, chain.Genesis() 1882 err error 1883 ) 1884 1885 engine.governance.SetBlockchain(chain) 1886 engine.governance.AddVote(tc.voting.key, tc.voting.value) 1887 previousBlock = currentBlock 1888 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1889 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1890 assert.NoError(t, err) 1891 1892 // insert blocks until the vote is applied 1893 for i := 0; i < checkpointInterval; i++ { 1894 previousBlock = currentBlock 1895 currentBlock = makeBlockWithSeal(chain, engine, previousBlock) 1896 _, err = chain.InsertChain(types.Blocks{currentBlock}) 1897 assert.NoError(t, err) 1898 } 1899 1900 switch tc.expected.key { 1901 case "kip71.lowerboundbasefee": 1902 assert.Equal(t, tc.expected.value, chain.Config().Governance.KIP71.LowerBoundBaseFee) 1903 case "kip71.upperboundbasefee": 1904 assert.Equal(t, tc.expected.value, chain.Config().Governance.KIP71.UpperBoundBaseFee) 1905 case "kip71.gastarget": 1906 assert.Equal(t, tc.expected.value, chain.Config().Governance.KIP71.GasTarget) 1907 case "kip71.maxblockgasusedforbasefee": 1908 assert.Equal(t, tc.expected.value, chain.Config().Governance.KIP71.MaxBlockGasUsedForBaseFee) 1909 case "kip71.basefeedenominator": 1910 assert.Equal(t, tc.expected.value, chain.Config().Governance.KIP71.BaseFeeDenominator) 1911 default: 1912 assert.Error(t, nil) 1913 } 1914 1915 engine.Stop() 1916 } 1917 }