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