github.com/bencicandrej/quorum@v2.2.6-0.20190909091323-878cab86f711+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 eventSub := engine.EventMux().Subscribe(istanbul.RequestEvent{}) 199 eventLoop := func() { 200 select { 201 case ev := <-eventSub.Chan(): 202 _, ok := ev.Data.(istanbul.RequestEvent) 203 if !ok { 204 t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data)) 205 } 206 engine.Commit(otherBlock, [][]byte{}) 207 } 208 eventSub.Unsubscribe() 209 } 210 go eventLoop() 211 seal := func() { 212 engine.Seal(chain, block, nil, make(chan struct{})) 213 t.Error("seal should not be completed") 214 } 215 go seal() 216 217 const timeoutDura = 2 * time.Second 218 timeout := time.NewTimer(timeoutDura) 219 select { 220 case <-timeout.C: 221 // wait 2 seconds to ensure we cannot get any blocks from Istanbul 222 } 223 } 224 225 func TestSealCommitted(t *testing.T) { 226 chain, engine := newBlockChain(1) 227 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 228 expectedBlock, _ := engine.updateBlock(engine.chain.GetHeader(block.ParentHash(), block.NumberU64()-1), block) 229 resultCh := make(chan *types.Block, 10) 230 go func() { 231 err := engine.Seal(chain, block, resultCh, make(chan struct{})) 232 233 if err != nil { 234 t.Errorf("error mismatch: have %v, want %v", err, expectedBlock) 235 } 236 }() 237 238 finalBlock := <-resultCh 239 if finalBlock.Hash() != expectedBlock.Hash() { 240 t.Errorf("hash mismatch: have %v, want %v", finalBlock.Hash(), expectedBlock.Hash()) 241 } 242 } 243 244 func TestVerifyHeader(t *testing.T) { 245 chain, engine := newBlockChain(1) 246 247 // errEmptyCommittedSeals case 248 block := makeBlockWithoutSeal(chain, engine, chain.Genesis()) 249 block, _ = engine.updateBlock(chain.Genesis().Header(), block) 250 err := engine.VerifyHeader(chain, block.Header(), false) 251 if err != errEmptyCommittedSeals { 252 t.Errorf("error mismatch: have %v, want %v", err, errEmptyCommittedSeals) 253 } 254 255 // short extra data 256 header := block.Header() 257 header.Extra = []byte{} 258 err = engine.VerifyHeader(chain, header, false) 259 if err != errInvalidExtraDataFormat { 260 t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat) 261 } 262 // incorrect extra format 263 header.Extra = []byte("0000000000000000000000000000000012300000000000000000000000000000000000000000000000000000000000000000") 264 err = engine.VerifyHeader(chain, header, false) 265 if err != errInvalidExtraDataFormat { 266 t.Errorf("error mismatch: have %v, want %v", err, errInvalidExtraDataFormat) 267 } 268 269 // non zero MixDigest 270 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 271 header = block.Header() 272 header.MixDigest = common.StringToHash("123456789") 273 err = engine.VerifyHeader(chain, header, false) 274 if err != errInvalidMixDigest { 275 t.Errorf("error mismatch: have %v, want %v", err, errInvalidMixDigest) 276 } 277 278 // invalid uncles hash 279 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 280 header = block.Header() 281 header.UncleHash = common.StringToHash("123456789") 282 err = engine.VerifyHeader(chain, header, false) 283 if err != errInvalidUncleHash { 284 t.Errorf("error mismatch: have %v, want %v", err, errInvalidUncleHash) 285 } 286 287 // invalid difficulty 288 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 289 header = block.Header() 290 header.Difficulty = big.NewInt(2) 291 err = engine.VerifyHeader(chain, header, false) 292 if err != errInvalidDifficulty { 293 t.Errorf("error mismatch: have %v, want %v", err, errInvalidDifficulty) 294 } 295 296 // invalid timestamp 297 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 298 header = block.Header() 299 header.Time = new(big.Int).Add(chain.Genesis().Time(), new(big.Int).SetUint64(engine.config.BlockPeriod-1)) 300 err = engine.VerifyHeader(chain, header, false) 301 if err != errInvalidTimestamp { 302 t.Errorf("error mismatch: have %v, want %v", err, errInvalidTimestamp) 303 } 304 305 // future block 306 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 307 header = block.Header() 308 header.Time = new(big.Int).Add(big.NewInt(now().Unix()), new(big.Int).SetUint64(10)) 309 err = engine.VerifyHeader(chain, header, false) 310 if err != consensus.ErrFutureBlock { 311 t.Errorf("error mismatch: have %v, want %v", err, consensus.ErrFutureBlock) 312 } 313 314 // invalid nonce 315 block = makeBlockWithoutSeal(chain, engine, chain.Genesis()) 316 header = block.Header() 317 copy(header.Nonce[:], hexutil.MustDecode("0x111111111111")) 318 header.Number = big.NewInt(int64(engine.config.Epoch)) 319 err = engine.VerifyHeader(chain, header, false) 320 if err != errInvalidNonce { 321 t.Errorf("error mismatch: have %v, want %v", err, errInvalidNonce) 322 } 323 } 324 325 func TestVerifySeal(t *testing.T) { 326 chain, engine := newBlockChain(1) 327 genesis := chain.Genesis() 328 // cannot verify genesis 329 err := engine.VerifySeal(chain, genesis.Header()) 330 if err != errUnknownBlock { 331 t.Errorf("error mismatch: have %v, want %v", err, errUnknownBlock) 332 } 333 334 block := makeBlock(chain, engine, genesis) 335 // change block content 336 header := block.Header() 337 header.Number = big.NewInt(4) 338 block1 := block.WithSeal(header) 339 err = engine.VerifySeal(chain, block1.Header()) 340 if err != errUnauthorized { 341 t.Errorf("error mismatch: have %v, want %v", err, errUnauthorized) 342 } 343 344 // unauthorized users but still can get correct signer address 345 engine.privateKey, _ = crypto.GenerateKey() 346 err = engine.VerifySeal(chain, block.Header()) 347 if err != nil { 348 t.Errorf("error mismatch: have %v, want nil", err) 349 } 350 } 351 352 func TestVerifyHeaders(t *testing.T) { 353 chain, engine := newBlockChain(1) 354 genesis := chain.Genesis() 355 356 // success case 357 headers := []*types.Header{} 358 blocks := []*types.Block{} 359 size := 100 360 361 for i := 0; i < size; i++ { 362 var b *types.Block 363 if i == 0 { 364 b = makeBlockWithoutSeal(chain, engine, genesis) 365 b, _ = engine.updateBlock(genesis.Header(), b) 366 } else { 367 b = makeBlockWithoutSeal(chain, engine, blocks[i-1]) 368 b, _ = engine.updateBlock(blocks[i-1].Header(), b) 369 } 370 blocks = append(blocks, b) 371 headers = append(headers, blocks[i].Header()) 372 } 373 now = func() time.Time { 374 return time.Unix(headers[size-1].Time.Int64(), 0) 375 } 376 _, results := engine.VerifyHeaders(chain, headers, nil) 377 const timeoutDura = 2 * time.Second 378 timeout := time.NewTimer(timeoutDura) 379 index := 0 380 OUT1: 381 for { 382 select { 383 case err := <-results: 384 if err != nil { 385 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 386 t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err) 387 break OUT1 388 } 389 } 390 index++ 391 if index == size { 392 break OUT1 393 } 394 case <-timeout.C: 395 break OUT1 396 } 397 } 398 // abort cases 399 abort, results := engine.VerifyHeaders(chain, headers, nil) 400 timeout = time.NewTimer(timeoutDura) 401 index = 0 402 OUT2: 403 for { 404 select { 405 case err := <-results: 406 if err != nil { 407 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 408 t.Errorf("error mismatch: have %v, want errEmptyCommittedSeals|errInvalidCommittedSeals", err) 409 break OUT2 410 } 411 } 412 index++ 413 if index == 5 { 414 abort <- struct{}{} 415 } 416 if index >= size { 417 t.Errorf("verifyheaders should be aborted") 418 break OUT2 419 } 420 case <-timeout.C: 421 break OUT2 422 } 423 } 424 // error header cases 425 headers[2].Number = big.NewInt(100) 426 abort, results = engine.VerifyHeaders(chain, headers, nil) 427 timeout = time.NewTimer(timeoutDura) 428 index = 0 429 errors := 0 430 expectedErrors := 2 431 OUT3: 432 for { 433 select { 434 case err := <-results: 435 if err != nil { 436 if err != errEmptyCommittedSeals && err != errInvalidCommittedSeals { 437 errors++ 438 } 439 } 440 index++ 441 if index == size { 442 if errors != expectedErrors { 443 t.Errorf("error mismatch: have %v, want %v", err, expectedErrors) 444 } 445 break OUT3 446 } 447 case <-timeout.C: 448 break OUT3 449 } 450 } 451 } 452 453 func TestPrepareExtra(t *testing.T) { 454 validators := make([]common.Address, 4) 455 validators[0] = common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")) 456 validators[1] = common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")) 457 validators[2] = common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")) 458 validators[3] = common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")) 459 460 vanity := make([]byte, types.IstanbulExtraVanity) 461 expectedResult := append(vanity, hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0")...) 462 463 h := &types.Header{ 464 Extra: vanity, 465 } 466 467 payload, err := prepareExtra(h, validators) 468 if err != nil { 469 t.Errorf("error mismatch: have %v, want: nil", err) 470 } 471 if !reflect.DeepEqual(payload, expectedResult) { 472 t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult) 473 } 474 475 // append useless information to extra-data 476 h.Extra = append(vanity, make([]byte, 15)...) 477 478 payload, err = prepareExtra(h, validators) 479 if !reflect.DeepEqual(payload, expectedResult) { 480 t.Errorf("payload mismatch: have %v, want %v", payload, expectedResult) 481 } 482 } 483 484 func TestWriteSeal(t *testing.T) { 485 vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity) 486 istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0") 487 expectedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 488 expectedIstExtra := &types.IstanbulExtra{ 489 Validators: []common.Address{ 490 common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), 491 common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), 492 common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), 493 common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), 494 }, 495 Seal: expectedSeal, 496 CommittedSeal: [][]byte{}, 497 } 498 var expectedErr error 499 500 h := &types.Header{ 501 Extra: append(vanity, istRawData...), 502 } 503 504 // normal case 505 err := writeSeal(h, expectedSeal) 506 if err != expectedErr { 507 t.Errorf("error mismatch: have %v, want %v", err, expectedErr) 508 } 509 510 // verify istanbul extra-data 511 istExtra, err := types.ExtractIstanbulExtra(h) 512 if err != nil { 513 t.Errorf("error mismatch: have %v, want nil", err) 514 } 515 if !reflect.DeepEqual(istExtra, expectedIstExtra) { 516 t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra) 517 } 518 519 // invalid seal 520 unexpectedSeal := append(expectedSeal, make([]byte, 1)...) 521 err = writeSeal(h, unexpectedSeal) 522 if err != errInvalidSignature { 523 t.Errorf("error mismatch: have %v, want %v", err, errInvalidSignature) 524 } 525 } 526 527 func TestWriteCommittedSeals(t *testing.T) { 528 vanity := bytes.Repeat([]byte{0x00}, types.IstanbulExtraVanity) 529 istRawData := hexutil.MustDecode("0xf858f8549444add0ec310f115a0e603b2d7db9f067778eaf8a94294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212946beaaed781d2d2ab6350f5c4566a2c6eaac407a6948be76812f765c24641ec63dc2852b378aba2b44080c0") 530 expectedCommittedSeal := append([]byte{1, 2, 3}, bytes.Repeat([]byte{0x00}, types.IstanbulExtraSeal-3)...) 531 expectedIstExtra := &types.IstanbulExtra{ 532 Validators: []common.Address{ 533 common.BytesToAddress(hexutil.MustDecode("0x44add0ec310f115a0e603b2d7db9f067778eaf8a")), 534 common.BytesToAddress(hexutil.MustDecode("0x294fc7e8f22b3bcdcf955dd7ff3ba2ed833f8212")), 535 common.BytesToAddress(hexutil.MustDecode("0x6beaaed781d2d2ab6350f5c4566a2c6eaac407a6")), 536 common.BytesToAddress(hexutil.MustDecode("0x8be76812f765c24641ec63dc2852b378aba2b440")), 537 }, 538 Seal: []byte{}, 539 CommittedSeal: [][]byte{expectedCommittedSeal}, 540 } 541 var expectedErr error 542 543 h := &types.Header{ 544 Extra: append(vanity, istRawData...), 545 } 546 547 // normal case 548 err := writeCommittedSeals(h, [][]byte{expectedCommittedSeal}) 549 if err != expectedErr { 550 t.Errorf("error mismatch: have %v, want %v", err, expectedErr) 551 } 552 553 // verify istanbul extra-data 554 istExtra, err := types.ExtractIstanbulExtra(h) 555 if err != nil { 556 t.Errorf("error mismatch: have %v, want nil", err) 557 } 558 if !reflect.DeepEqual(istExtra, expectedIstExtra) { 559 t.Errorf("extra data mismatch: have %v, want %v", istExtra, expectedIstExtra) 560 } 561 562 // invalid seal 563 unexpectedCommittedSeal := append(expectedCommittedSeal, make([]byte, 1)...) 564 err = writeCommittedSeals(h, [][]byte{unexpectedCommittedSeal}) 565 if err != errInvalidCommittedSeals { 566 t.Errorf("error mismatch: have %v, want %v", err, errInvalidCommittedSeals) 567 } 568 }