github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/consensus/istanbul/backend/engine_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package backend 18 19 import ( 20 "bytes" 21 "crypto/ecdsa" 22 "math/big" 23 "reflect" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/istanbul" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/core/vm" 34 "github.com/ethereum/go-ethereum/crypto" 35 "github.com/ethereum/go-ethereum/ethdb" 36 "github.com/ethereum/go-ethereum/params" 37 "github.com/ethereum/go-ethereum/rlp" 38 ) 39 40 // in this test, we can set n to 1, and it means we can process Istanbul and commit a 41 // block by one node. Otherwise, if n is larger than 1, we have to generate 42 // other fake events to process Istanbul. 43 func newBlockChain(n int) (*core.BlockChain, *backend) { 44 genesis, nodeKeys := getGenesisAndKeys(n) 45 memDB := ethdb.NewMemDatabase() 46 config := istanbul.DefaultConfig 47 // Use the first key as private key 48 b, _ := New(config, nodeKeys[0], memDB).(*backend) 49 genesis.MustCommit(memDB) 50 blockchain, err := core.NewBlockChain(memDB, nil, genesis.Config, b, vm.Config{}, nil) 51 if err != nil { 52 panic(err) 53 } 54 b.Start(blockchain, blockchain.CurrentBlock, blockchain.HasBadBlock) 55 snap, err := b.snapshot(blockchain, 0, common.Hash{}, nil) 56 if err != nil { 57 panic(err) 58 } 59 if snap == nil { 60 panic("failed to get snapshot") 61 } 62 proposerAddr := snap.ValSet.GetProposer().Address() 63 64 // find proposer key 65 for _, key := range nodeKeys { 66 addr := crypto.PubkeyToAddress(key.PublicKey) 67 if addr.String() == proposerAddr.String() { 68 b.privateKey = key 69 b.address = addr 70 } 71 } 72 73 return blockchain, b 74 } 75 76 func getGenesisAndKeys(n int) (*core.Genesis, []*ecdsa.PrivateKey) { 77 // Setup validators 78 var nodeKeys = make([]*ecdsa.PrivateKey, n) 79 var addrs = make([]common.Address, n) 80 for i := 0; i < n; i++ { 81 nodeKeys[i], _ = crypto.GenerateKey() 82 addrs[i] = crypto.PubkeyToAddress(nodeKeys[i].PublicKey) 83 } 84 85 // generate genesis block 86 genesis := core.DefaultGenesisBlock() 87 genesis.Config = params.TestChainConfig 88 // force enable Istanbul engine 89 genesis.Config.Istanbul = ¶ms.IstanbulConfig{} 90 genesis.Config.Ethash = nil 91 genesis.Difficulty = defaultDifficulty 92 genesis.Nonce = emptyNonce.Uint64() 93 genesis.Mixhash = types.IstanbulDigest 94 95 appendValidators(genesis, addrs) 96 return genesis, nodeKeys 97 } 98 99 func appendValidators(genesis *core.Genesis, addrs []common.Address) { 100 101 if len(genesis.ExtraData) < types.IstanbulExtraVanity { 102 genesis.ExtraData = append(genesis.ExtraData, bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity)...) 103 } 104 genesis.ExtraData = genesis.ExtraData[:types.IstanbulExtraVanity] 105 106 ist := &types.IstanbulExtra{ 107 Validators: addrs, 108 Seal: []byte{}, 109 CommittedSeal: [][]byte{}, 110 } 111 112 istPayload, err := rlp.EncodeToBytes(&ist) 113 if err != nil { 114 panic("failed to encode istanbul extra") 115 } 116 genesis.ExtraData = append(genesis.ExtraData, istPayload...) 117 } 118 119 func makeHeader(parent *types.Block, config *istanbul.Config) *types.Header { 120 header := &types.Header{ 121 ParentHash: parent.Hash(), 122 Number: parent.Number().Add(parent.Number(), common.Big1), 123 GasLimit: core.CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()), 124 GasUsed: 0, 125 Extra: parent.Extra(), 126 Time: new(big.Int).Add(parent.Time(), new(big.Int).SetUint64(config.BlockPeriod)), 127 Difficulty: defaultDifficulty, 128 } 129 return header 130 } 131 132 func makeBlock(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block { 133 block := makeBlockWithoutSeal(chain, engine, parent) 134 stopCh := make(chan struct{}) 135 resultCh := make(chan *types.Block, 10) 136 go engine.Seal(chain, block, resultCh, stopCh) 137 blk := <-resultCh 138 return blk 139 } 140 141 func makeBlockWithoutSeal(chain *core.BlockChain, engine *backend, parent *types.Block) *types.Block { 142 header := makeHeader(parent, engine.config) 143 engine.Prepare(chain, header) 144 state, _, _ := chain.StateAt(parent.Root()) 145 block, _ := engine.Finalize(chain, header, state, nil, nil, nil) 146 return block 147 } 148 149 func TestPrepare(t *testing.T) { 150 chain, engine := newBlockChain(1) 151 header := makeHeader(chain.Genesis(), engine.config) 152 err := engine.Prepare(chain, header) 153 if err != nil { 154 t.Errorf("error mismatch: have %v, want nil", err) 155 } 156 header.ParentHash = common.StringToHash("1234567890") 157 err = engine.Prepare(chain, header) 158 if err != consensus.ErrUnknownAncestor { 159 t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrUnknownAncestor) 160 } 161 } 162 163 func TestSealStopChannel(t *testing.T) { 164 chain, engine := newBlockChain(4) 165 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 166 stop := make(chan struct{}, 1) 167 eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{}) 168 eventLoop := func() { 169 select { 170 case ev := <-eventSub.Chan(): 171 _, ok := ev.Data.(istanbul.RequestEvent) 172 if !ok { 173 t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) 174 } 175 stop <- struct{}{} 176 } 177 eventSub.Unsubscribe() 178 } 179 go eventLoop() 180 resultCh := make(chan *types.Block, 10) 181 go func() { 182 err := engine.Seal(chain, block, resultCh, stop) 183 if err != nil { 184 t.Errorf("error mismatch: have %v, want nil", err) 185 } 186 }() 187 188 finalBlock := <-resultCh 189 if finalBlock != nil { 190 t.Errorf("block mismatch: have %v, want nil", finalBlock) 191 } 192 } 193 194 func TestSealCommittedOtherHash(t *testing.T) { 195 chain, engine := newBlockChain(4) 196 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 197 otherBlock := makeBlockWithoutSeal(chain, engine, block) 198 expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 199 200 eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{}) 201 blockOutputChannel := make(chan *types.Block) 202 stopChannel := make(chan struct{}) 203 204 go func() { 205 select { 206 case ev := <-eventSub.Chan(): 207 if _, ok := ev.Data.(istanbul.RequestEvent); !ok { 208 t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) 209 } 210 if err := engine.Commit(otherBlock, [][]byte{expectedCommittedSeal}); err != nil { 211 t.Error(err.Error()) 212 } 213 } 214 eventSub.Unsubscribe() 215 }() 216 217 go func() { 218 if err := engine.Seal(chain, block, blockOutputChannel, stopChannel); err != nil { 219 t.Error(err.Error()) 220 } 221 }() 222 223 select { 224 case <-blockOutputChannel: 225 t.Error("Wrong block found!") 226 default: 227 //no block found, stop the sealing 228 close(stopChannel) 229 } 230 231 select { 232 case output := <-blockOutputChannel: 233 if output != nil { 234 t.Error("Block not nil!") 235 } 236 } 237 } 238 239 func TestSealCommitted(t *testing.T) { 240 chain, engine := newBlockChain(1) 241 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 242 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 243 resultCh := make(chan *types.Block, 10) 244 go func() { 245 err := engine.Seal(chain, block, resultCh, make(chan struct{})) 246 247 if err != nil { 248 t.Errorf("error mismatch: have %v, want %v", err, expectedBlock) 249 } 250 }() 251 252 finalBlock := <-resultCh 253 if finalBlock.Hash() != expectedBlock.Hash() { 254 t.Errorf("hash mismatch: have %v, want %v", finalBlock.Hash(), expectedBlock.Hash()) 255 } 256 } 257 258 func TestVerifyHeader(t *testing.T) { 259 chain, engine := newBlockChain(1) 260 261 // errEmptyCommittedSeals case 262 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 263 block, _ = engine.updateBlock(chain.Genesis().Header(), block) 264 err := engine.VerifyHeader(chain, block.Header(), false) 265 if err != errEmptyCommittedSeals { 266 t.Errorf("error mismatch: have %v, want %v", err, errEmptyCommittedSeals) 267 } 268 269 // short extra data 270 header := block.Header() 271 header.Extra = []byte{} 272 err = engine.VerifyHeader(chain, header, false) 273 if err != errInvalidExtraDataFormat { 274 t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat) 275 } 276 // incorrect extra format 277 header.Extra = []byte("0000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000000") 278 err = engine.VerifyHeader(chain, header, false) 279 if err != errInvalidExtraDataFormat { 280 t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat) 281 } 282 283 // non zero MixDigest 284 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 285 header = block.Header() 286 header.MixDigest = common.StringToHash("123456789") 287 err = engine.VerifyHeader(chain, header, false) 288 if err != errInvalidMixDigest { 289 t.Errorf("error mismatch: have %v, want %v", err, errInvalidMixDigest) 290 } 291 292 // invalid uncles hash 293 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 294 header = block.Header() 295 header.UncleHash = common.StringToHash("123456789") 296 err = engine.VerifyHeader(chain, header, false) 297 if err != errInvalidUncleHash { 298 t.Errorf("error mismatch: have %v, want %v", err, errInvalidUncleHash) 299 } 300 301 // invalid difficulty 302 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 303 header = block.Header() 304 header.Difficulty = big.NewInt(2) 305 err = engine.VerifyHeader(chain, header, false) 306 if err != errInvalidDifficulty { 307 t.Errorf("error mismatch: have %v, want %v", err, errInvalidDifficulty) 308 } 309 310 // invalid timestamp 311 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 312 header = block.Header() 313 header.Time = new(big.Int).Add(chain.Genesis().Time(), new(big.Int).SetUint64(engine.config.BlockPeriod-1)) 314 err = engine.VerifyHeader(chain, header, false) 315 if err != errInvalidTimestamp { 316 t.Errorf("error mismatch: have %v, want %v", err, errInvalidTimestamp) 317 } 318 319 // future block 320 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 321 header = block.Header() 322 header.Time = new(big.Int).Add(big.NewInt(now().Unix()), new(big.Int).SetUint64(10)) 323 err = engine.VerifyHeader(chain, header, false) 324 if err != consensus.ErrFutureBlock { 325 t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrFutureBlock) 326 } 327 328 // invalid nonce 329 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 330 header = block.Header() 331 copy(header.Nonce[:], hexutil.MustDecode("0x111111111111")) 332 header.Number = big.NewInt(int64(engine.config.Epoch)) 333 err = engine.VerifyHeader(chain, header, false) 334 if err != errInvalidNonce { 335 t.Errorf("error mismatch: have %v, want %v", err, errInvalidNonce) 336 } 337 } 338 339 func TestVerifySeal(t *testing.T) { 340 chain, engine := newBlockChain(1) 341 genesis := chain.Genesis() 342 // cannot verify genesis 343 err := engine.VerifySeal(chain, genesis.Header()) 344 if err != errUnknownBlock { 345 t.Errorf("error mismatch: have %v, want %v", err, errUnknownBlock) 346 } 347 348 block := makeBlock(chain, engine, genesis) 349 // change block content 350 header := block.Header() 351 header.Number = big.NewInt(4) 352 block1 := block.WithSeal(header) 353 err = engine.VerifySeal(chain, block1.Header()) 354 if err != errUnauthorized { 355 t.Errorf("error mismatch: have %v, want %v", err, errUnauthorized) 356 } 357 358 // unauthorized users but still can get correct signer address 359 engine.privateKey, _ = crypto.GenerateKey() 360 err = engine.VerifySeal(chain, block.Header()) 361 if err != nil { 362 t.Errorf("error mismatch: have %v, want nil", err) 363 } 364 } 365 366 func TestVerifyHeaders(t *testing.T) { 367 chain, engine := newBlockChain(1) 368 genesis := chain.Genesis() 369 370 // success case 371 headers := []*types.Header{} 372 blocks := []*types.Block{} 373 size := 100 374 375 for i := 0; i < size; i++ { 376 var b *types.Block 377 if i == 0 { 378 b = makeBlockWithoutSeal(chain, engine, genesis) 379 b, _ = engine.updateBlock(genesis.Header(), b) 380 } else { 381 b = makeBlockWithoutSeal(chain, engine, blocks[i-1]) 382 b, _ = engine.updateBlock(blocks[i-1].Header(), b) 383 } 384 blocks = append(blocks, b) 385 headers = append(headers, blocks[i].Header()) 386 } 387 now = func() time.Time { 388 return time.Unix(headers[size-1].Time.Int64(), 0) 389 } 390 _, results := engine.VerifyHeaders(chain, headers, nil) 391 const timeoutDura = 2 * time.Second 392 timeout := time.NewTimer(timeoutDura) 393 index := 0 394 OUT1: 395 for { 396 select { 397 case err := <-results: 398 if err != nil { 399 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 400 t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err) 401 break OUT1 402 } 403 } 404 index++ 405 if index == size { 406 break OUT1 407 } 408 case <-timeout.C: 409 break OUT1 410 } 411 } 412 // abort cases 413 abort, results := engine.VerifyHeaders(chain, headers, nil) 414 timeout = time.NewTimer(timeoutDura) 415 index = 0 416 OUT2: 417 for { 418 select { 419 case err := <-results: 420 if err != nil { 421 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 422 t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err) 423 break OUT2 424 } 425 } 426 index++ 427 if index == 5 { 428 abort <- struct{}{} 429 } 430 if index >= size { 431 t.Errorf("verifyheaders should be aborted") 432 break OUT2 433 } 434 case <-timeout.C: 435 break OUT2 436 } 437 } 438 // error header cases 439 headers[2].Number = big.NewInt(100) 440 abort, results = engine.VerifyHeaders(chain, headers, nil) 441 timeout = time.NewTimer(timeoutDura) 442 index = 0 443 errors := 0 444 expectedErrors := 2 445 OUT3: 446 for { 447 select { 448 case err := <-results: 449 if err != nil { 450 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 451 errors++ 452 } 453 } 454 index++ 455 if index == size { 456 if errors != expectedErrors { 457 t.Errorf("error mismatch: have %v, want %v", err, expectedErrors) 458 } 459 break OUT3 460 } 461 case <-timeout.C: 462 break OUT3 463 } 464 } 465 } 466 467 func TestPrepareExtra(t *testing.T) { 468 validators := make([]common.Address, 4) 469 validators[0] = common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")) 470 validators[1] = common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")) 471 validators[2] = common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")) 472 validators[3] = common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")) 473 474 vanity := make([]byte, types.IstanbulExtraVanity) 475 expectedResult := append(vanity, hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")...) 476 477 h := &types.Header{ 478 Extra: vanity, 479 } 480 481 payload, err := prepareExtra(h, validators) 482 if err != nil { 483 t.Errorf("error mismatch: have %v, want: nil", err) 484 } 485 if !reflect.DeepEqual(payload, expectedResult) { 486 t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult) 487 } 488 489 // append useless information to extra-data 490 h.Extra = append(vanity, make([]byte, 15)...) 491 492 payload, err = prepareExtra(h, validators) 493 if !reflect.DeepEqual(payload, expectedResult) { 494 t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult) 495 } 496 } 497 498 func TestWriteSeal(t *testing.T) { 499 vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity) 500 istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0") 501 expectedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 502 expectedIstExtra := &types.IstanbulExtra{ 503 Validators: []common.Address{ 504 common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), 505 common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), 506 common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), 507 common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), 508 }, 509 Seal: expectedSeal, 510 CommittedSeal: [][]byte{}, 511 } 512 var expectedErr error 513 514 h := &types.Header{ 515 Extra: append(vanity, istRawData...), 516 } 517 518 // normal case 519 err := writeSeal(h, expectedSeal) 520 if err != expectedErr { 521 t.Errorf("error mismatch: have %v, want %v", err, expectedErr) 522 } 523 524 // verify istanbul extra-data 525 istExtra, err := types.ExtractIstanbulExtra(h) 526 if err != nil { 527 t.Errorf("error mismatch: have %v, want nil", err) 528 } 529 if !reflect.DeepEqual(istExtra, expectedIstExtra) { 530 t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra) 531 } 532 533 // invalid seal 534 unexpectedSeal := append(expectedSeal, make([]byte, 1)...) 535 err = writeSeal(h, unexpectedSeal) 536 if err != errInvalidSignature { 537 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 538 } 539 } 540 541 func TestWriteCommittedSeals(t *testing.T) { 542 vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity) 543 istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0") 544 expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 545 expectedIstExtra := &types.IstanbulExtra{ 546 Validators: []common.Address{ 547 common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), 548 common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), 549 common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), 550 common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), 551 }, 552 Seal: []byte{}, 553 CommittedSeal: [][]byte{expectedCommittedSeal}, 554 } 555 var expectedErr error 556 557 h := &types.Header{ 558 Extra: append(vanity, istRawData...), 559 } 560 561 // normal case 562 err := writeCommittedSeals(h, [][]byte{expectedCommittedSeal}) 563 if err != expectedErr { 564 t.Errorf("error mismatch: have %v, want %v", err, expectedErr) 565 } 566 567 // verify istanbul extra-data 568 istExtra, err := types.ExtractIstanbulExtra(h) 569 if err != nil { 570 t.Errorf("error mismatch: have %v, want nil", err) 571 } 572 if !reflect.DeepEqual(istExtra, expectedIstExtra) { 573 t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra) 574 } 575 576 // invalid seal 577 unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...) 578 err = writeCommittedSeals(h, [][]byte{unexpectedCommittedSeal}) 579 if err != errInvalidCommittedSeals { 580 t.Errorf("error mismatch: have %v, want %v", err, errInvalidCommittedSeals) 581 } 582 }