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