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