github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/chain_manager_test.go (about) 1 // Copyright 2014 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 core 18 19 import ( 20 "fmt" 21 "math/big" 22 "math/rand" 23 "os" 24 "path/filepath" 25 "runtime" 26 "strconv" 27 "testing" 28 29 "github.com/ethereum/ethash" 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/core/state" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/ethdb" 34 "github.com/ethereum/go-ethereum/event" 35 "github.com/ethereum/go-ethereum/pow" 36 "github.com/ethereum/go-ethereum/rlp" 37 "github.com/hashicorp/golang-lru" 38 ) 39 40 func init() { 41 runtime.GOMAXPROCS(runtime.NumCPU()) 42 } 43 44 func thePow() pow.PoW { 45 pow, _ := ethash.NewForTesting() 46 return pow 47 } 48 49 func theChainManager(db common.Database, t *testing.T) *ChainManager { 50 var eventMux event.TypeMux 51 WriteTestNetGenesisBlock(db, 0) 52 chainMan, err := NewChainManager(db, thePow(), &eventMux) 53 if err != nil { 54 t.Error("failed creating chainmanager:", err) 55 t.FailNow() 56 return nil 57 } 58 blockMan := NewBlockProcessor(db, nil, chainMan, &eventMux) 59 chainMan.SetProcessor(blockMan) 60 61 return chainMan 62 } 63 64 // Test fork of length N starting from block i 65 func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) { 66 // switch databases to process the new chain 67 db, err := ethdb.NewMemDatabase() 68 if err != nil { 69 t.Fatal("Failed to create db:", err) 70 } 71 // copy old chain up to i into new db with deterministic canonical 72 bman2, err := newCanonical(i, db) 73 if err != nil { 74 t.Fatal("could not make new canonical in testFork", err) 75 } 76 // asert the bmans have the same block at i 77 bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash() 78 bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash() 79 if bi1 != bi2 { 80 t.Fatal("chains do not have the same hash at height", i) 81 } 82 bman2.bc.SetProcessor(bman2) 83 84 // extend the fork 85 parent := bman2.bc.CurrentBlock() 86 chainB := makeChain(parent, N, db, forkSeed) 87 _, err = bman2.bc.InsertChain(chainB) 88 if err != nil { 89 t.Fatal("Insert chain error for fork:", err) 90 } 91 92 tdpre := bman.bc.Td() 93 // Test the fork's blocks on the original chain 94 td, err := testChain(chainB, bman) 95 if err != nil { 96 t.Fatal("expected chainB not to give errors:", err) 97 } 98 // Compare difficulties 99 f(tdpre, td) 100 101 // Loop over parents making sure reconstruction is done properly 102 } 103 104 func printChain(bc *ChainManager) { 105 for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- { 106 b := bc.GetBlockByNumber(uint64(i)) 107 fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty()) 108 } 109 } 110 111 // process blocks against a chain 112 func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) { 113 td := new(big.Int) 114 for _, block := range chainB { 115 _, _, err := bman.bc.processor.Process(block) 116 if err != nil { 117 if IsKnownBlockErr(err) { 118 continue 119 } 120 return nil, err 121 } 122 parent := bman.bc.GetBlock(block.ParentHash()) 123 block.Td = CalcTD(block, parent) 124 td = block.Td 125 126 bman.bc.mu.Lock() 127 { 128 WriteBlock(bman.bc.chainDb, block) 129 } 130 bman.bc.mu.Unlock() 131 } 132 return td, nil 133 } 134 135 func loadChain(fn string, t *testing.T) (types.Blocks, error) { 136 fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm) 137 if err != nil { 138 return nil, err 139 } 140 defer fh.Close() 141 142 var chain types.Blocks 143 if err := rlp.Decode(fh, &chain); err != nil { 144 return nil, err 145 } 146 147 return chain, nil 148 } 149 150 func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) { 151 _, err := chainMan.InsertChain(chain) 152 if err != nil { 153 fmt.Println(err) 154 t.FailNow() 155 } 156 done <- true 157 } 158 159 func TestExtendCanonical(t *testing.T) { 160 CanonicalLength := 5 161 db, err := ethdb.NewMemDatabase() 162 if err != nil { 163 t.Fatal("Failed to create db:", err) 164 } 165 // make first chain starting from genesis 166 bman, err := newCanonical(CanonicalLength, db) 167 if err != nil { 168 t.Fatal("Could not make new canonical chain:", err) 169 } 170 f := func(td1, td2 *big.Int) { 171 if td2.Cmp(td1) <= 0 { 172 t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1) 173 } 174 } 175 // Start fork from current height (CanonicalLength) 176 testFork(t, bman, CanonicalLength, 1, f) 177 testFork(t, bman, CanonicalLength, 2, f) 178 testFork(t, bman, CanonicalLength, 5, f) 179 testFork(t, bman, CanonicalLength, 10, f) 180 } 181 182 func TestShorterFork(t *testing.T) { 183 db, err := ethdb.NewMemDatabase() 184 if err != nil { 185 t.Fatal("Failed to create db:", err) 186 } 187 // make first chain starting from genesis 188 bman, err := newCanonical(10, db) 189 if err != nil { 190 t.Fatal("Could not make new canonical chain:", err) 191 } 192 f := func(td1, td2 *big.Int) { 193 if td2.Cmp(td1) >= 0 { 194 t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1) 195 } 196 } 197 // Sum of numbers must be less than 10 198 // for this to be a shorter fork 199 testFork(t, bman, 0, 3, f) 200 testFork(t, bman, 0, 7, f) 201 testFork(t, bman, 1, 1, f) 202 testFork(t, bman, 1, 7, f) 203 testFork(t, bman, 5, 3, f) 204 testFork(t, bman, 5, 4, f) 205 } 206 207 func TestLongerFork(t *testing.T) { 208 db, err := ethdb.NewMemDatabase() 209 if err != nil { 210 t.Fatal("Failed to create db:", err) 211 } 212 // make first chain starting from genesis 213 bman, err := newCanonical(10, db) 214 if err != nil { 215 t.Fatal("Could not make new canonical chain:", err) 216 } 217 f := func(td1, td2 *big.Int) { 218 if td2.Cmp(td1) <= 0 { 219 t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1) 220 } 221 } 222 // Sum of numbers must be greater than 10 223 // for this to be a longer fork 224 testFork(t, bman, 0, 11, f) 225 testFork(t, bman, 0, 15, f) 226 testFork(t, bman, 1, 10, f) 227 testFork(t, bman, 1, 12, f) 228 testFork(t, bman, 5, 6, f) 229 testFork(t, bman, 5, 8, f) 230 } 231 232 func TestEqualFork(t *testing.T) { 233 db, err := ethdb.NewMemDatabase() 234 if err != nil { 235 t.Fatal("Failed to create db:", err) 236 } 237 bman, err := newCanonical(10, db) 238 if err != nil { 239 t.Fatal("Could not make new canonical chain:", err) 240 } 241 f := func(td1, td2 *big.Int) { 242 if td2.Cmp(td1) != 0 { 243 t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1) 244 } 245 } 246 // Sum of numbers must be equal to 10 247 // for this to be an equal fork 248 testFork(t, bman, 0, 10, f) 249 testFork(t, bman, 1, 9, f) 250 testFork(t, bman, 2, 8, f) 251 testFork(t, bman, 5, 5, f) 252 testFork(t, bman, 6, 4, f) 253 testFork(t, bman, 9, 1, f) 254 } 255 256 func TestBrokenChain(t *testing.T) { 257 db, err := ethdb.NewMemDatabase() 258 if err != nil { 259 t.Fatal("Failed to create db:", err) 260 } 261 bman, err := newCanonical(10, db) 262 if err != nil { 263 t.Fatal("Could not make new canonical chain:", err) 264 } 265 db2, err := ethdb.NewMemDatabase() 266 if err != nil { 267 t.Fatal("Failed to create db:", err) 268 } 269 bman2, err := newCanonical(10, db2) 270 if err != nil { 271 t.Fatal("Could not make new canonical chain:", err) 272 } 273 bman2.bc.SetProcessor(bman2) 274 parent := bman2.bc.CurrentBlock() 275 chainB := makeChain(parent, 5, db2, forkSeed) 276 chainB = chainB[1:] 277 _, err = testChain(chainB, bman) 278 if err == nil { 279 t.Error("expected broken chain to return error") 280 } 281 } 282 283 func TestChainInsertions(t *testing.T) { 284 t.Skip("Skipped: outdated test files") 285 286 db, _ := ethdb.NewMemDatabase() 287 288 chain1, err := loadChain("valid1", t) 289 if err != nil { 290 fmt.Println(err) 291 t.FailNow() 292 } 293 294 chain2, err := loadChain("valid2", t) 295 if err != nil { 296 fmt.Println(err) 297 t.FailNow() 298 } 299 300 chainMan := theChainManager(db, t) 301 302 const max = 2 303 done := make(chan bool, max) 304 305 go insertChain(done, chainMan, chain1, t) 306 go insertChain(done, chainMan, chain2, t) 307 308 for i := 0; i < max; i++ { 309 <-done 310 } 311 312 if chain2[len(chain2)-1].Hash() != chainMan.CurrentBlock().Hash() { 313 t.Error("chain2 is canonical and shouldn't be") 314 } 315 316 if chain1[len(chain1)-1].Hash() != chainMan.CurrentBlock().Hash() { 317 t.Error("chain1 isn't canonical and should be") 318 } 319 } 320 321 func TestChainMultipleInsertions(t *testing.T) { 322 t.Skip("Skipped: outdated test files") 323 324 db, _ := ethdb.NewMemDatabase() 325 326 const max = 4 327 chains := make([]types.Blocks, max) 328 var longest int 329 for i := 0; i < max; i++ { 330 var err error 331 name := "valid" + strconv.Itoa(i+1) 332 chains[i], err = loadChain(name, t) 333 if len(chains[i]) >= len(chains[longest]) { 334 longest = i 335 } 336 fmt.Println("loaded", name, "with a length of", len(chains[i])) 337 if err != nil { 338 fmt.Println(err) 339 t.FailNow() 340 } 341 } 342 343 chainMan := theChainManager(db, t) 344 345 done := make(chan bool, max) 346 for i, chain := range chains { 347 // XXX the go routine would otherwise reference the same (chain[3]) variable and fail 348 i := i 349 chain := chain 350 go func() { 351 insertChain(done, chainMan, chain, t) 352 fmt.Println(i, "done") 353 }() 354 } 355 356 for i := 0; i < max; i++ { 357 <-done 358 } 359 360 if chains[longest][len(chains[longest])-1].Hash() != chainMan.CurrentBlock().Hash() { 361 t.Error("Invalid canonical chain") 362 } 363 } 364 365 type bproc struct{} 366 367 func (bproc) Process(*types.Block) (state.Logs, types.Receipts, error) { return nil, nil, nil } 368 369 func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { 370 var chain []*types.Block 371 for i, difficulty := range d { 372 header := &types.Header{ 373 Coinbase: common.Address{seed}, 374 Number: big.NewInt(int64(i + 1)), 375 Difficulty: big.NewInt(int64(difficulty)), 376 } 377 if i == 0 { 378 header.ParentHash = genesis.Hash() 379 } else { 380 header.ParentHash = chain[i-1].Hash() 381 } 382 block := types.NewBlockWithHeader(header) 383 chain = append(chain, block) 384 } 385 return chain 386 } 387 388 func chm(genesis *types.Block, db common.Database) *ChainManager { 389 var eventMux event.TypeMux 390 bc := &ChainManager{chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}} 391 bc.cache, _ = lru.New(100) 392 bc.futureBlocks, _ = lru.New(100) 393 bc.processor = bproc{} 394 bc.ResetWithGenesisBlock(genesis) 395 396 return bc 397 } 398 399 func TestReorgLongest(t *testing.T) { 400 db, _ := ethdb.NewMemDatabase() 401 402 genesis, err := WriteTestNetGenesisBlock(db, 0) 403 if err != nil { 404 t.Error(err) 405 t.FailNow() 406 } 407 bc := chm(genesis, db) 408 409 chain1 := makeChainWithDiff(genesis, []int{1, 2, 4}, 10) 410 chain2 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 11) 411 412 bc.InsertChain(chain1) 413 bc.InsertChain(chain2) 414 415 prev := bc.CurrentBlock() 416 for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) { 417 if prev.ParentHash() != block.Hash() { 418 t.Errorf("parent hash mismatch %x - %x", prev.ParentHash(), block.Hash()) 419 } 420 } 421 } 422 423 func TestReorgShortest(t *testing.T) { 424 db, _ := ethdb.NewMemDatabase() 425 genesis, err := WriteTestNetGenesisBlock(db, 0) 426 if err != nil { 427 t.Error(err) 428 t.FailNow() 429 } 430 bc := chm(genesis, db) 431 432 chain1 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 10) 433 chain2 := makeChainWithDiff(genesis, []int{1, 10}, 11) 434 435 bc.InsertChain(chain1) 436 bc.InsertChain(chain2) 437 438 prev := bc.CurrentBlock() 439 for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) { 440 if prev.ParentHash() != block.Hash() { 441 t.Errorf("parent hash mismatch %x - %x", prev.ParentHash(), block.Hash()) 442 } 443 } 444 } 445 446 func TestInsertNonceError(t *testing.T) { 447 for i := 1; i < 25 && !t.Failed(); i++ { 448 db, _ := ethdb.NewMemDatabase() 449 genesis, err := WriteTestNetGenesisBlock(db, 0) 450 if err != nil { 451 t.Error(err) 452 t.FailNow() 453 } 454 bc := chm(genesis, db) 455 bc.processor = NewBlockProcessor(db, bc.pow, bc, bc.eventMux) 456 blocks := makeChain(bc.currentBlock, i, db, 0) 457 458 fail := rand.Int() % len(blocks) 459 failblock := blocks[fail] 460 bc.pow = failpow{failblock.NumberU64()} 461 n, err := bc.InsertChain(blocks) 462 463 // Check that the returned error indicates the nonce failure. 464 if n != fail { 465 t.Errorf("(i=%d) wrong failed block index: got %d, want %d", i, n, fail) 466 } 467 if !IsBlockNonceErr(err) { 468 t.Fatalf("(i=%d) got %q, want a nonce error", i, err) 469 } 470 nerr := err.(*BlockNonceErr) 471 if nerr.Number.Cmp(failblock.Number()) != 0 { 472 t.Errorf("(i=%d) wrong block number in error, got %v, want %v", i, nerr.Number, failblock.Number()) 473 } 474 if nerr.Hash != failblock.Hash() { 475 t.Errorf("(i=%d) wrong block hash in error, got %v, want %v", i, nerr.Hash, failblock.Hash()) 476 } 477 478 // Check that all no blocks after the failing block have been inserted. 479 for _, block := range blocks[fail:] { 480 if bc.HasBlock(block.Hash()) { 481 t.Errorf("(i=%d) invalid block %d present in chain", i, block.NumberU64()) 482 } 483 } 484 } 485 } 486 487 /* 488 func TestGenesisMismatch(t *testing.T) { 489 db, _ := ethdb.NewMemDatabase() 490 var mux event.TypeMux 491 genesis := GenesisBlock(0, db) 492 _, err := NewChainManager(genesis, db, db, db, thePow(), &mux) 493 if err != nil { 494 t.Error(err) 495 } 496 genesis = GenesisBlock(1, db) 497 _, err = NewChainManager(genesis, db, db, db, thePow(), &mux) 498 if err == nil { 499 t.Error("expected genesis mismatch error") 500 } 501 } 502 */ 503 504 // failpow returns false from Verify for a certain block number. 505 type failpow struct{ num uint64 } 506 507 func (pow failpow) Search(pow.Block, <-chan struct{}) (nonce uint64, mixHash []byte) { 508 return 0, nil 509 } 510 func (pow failpow) Verify(b pow.Block) bool { 511 return b.NumberU64() != pow.num 512 } 513 func (pow failpow) GetHashrate() int64 { 514 return 0 515 } 516 func (pow failpow) Turbo(bool) { 517 }