// makeChain creates a chain of n blocks starting at and including parent. // the returned hash chain is ordered head->parent. In addition, every 3rd block // contains a transaction and every 5th an uncle to allow testing correct block // reassembly. func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { blocks, _ := core.GenerateChain(parent, testdb, n, func(i int, block *core.BlockGen) { block.SetCoinbase(common.Address{seed}) // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey) if err != nil { panic(err) } block.AddTx(tx) } // If the block number is a multiple of 5, add a bonus uncle to the block if i%5 == 0 { block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) } }) hashes := make([]common.Hash, n+1) hashes[len(hashes)-1] = parent.Hash() blockm := make(map[common.Hash]*types.Block, n+1) blockm[parent.Hash()] = parent for i, b := range blocks { hashes[len(hashes)-i-2] = b.Hash() blockm[b.Hash()] = b } return hashes, blockm }
func TestMipmapUpgrade(t *testing.T) { db, _ := ethdb.NewMemDatabase() addr := common.BytesToAddress([]byte("jeff")) genesis := core.WriteGenesisBlockForTesting(db) chain, receipts := core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) { var receipts types.Receipts switch i { case 1: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{&vm.Log{Address: addr}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 2: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{&vm.Log{Address: addr}} gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} } // store the receipts err := core.WriteReceipts(db, receipts) if err != nil { t.Fatal(err) } }) for i, block := range chain { core.WriteBlock(db, block) if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { t.Fatalf("failed to insert block number: %v", err) } if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil { t.Fatalf("failed to insert block number: %v", err) } if err := core.WriteBlockReceipts(db, block.Hash(), receipts[i]); err != nil { t.Fatal("error writing block receipts:", err) } } err := addMipmapBloomBins(db) if err != nil { t.Fatal(err) } bloom := core.GetMipmapBloom(db, 1, core.MIPMapLevels[0]) if (bloom == types.Bloom{}) { t.Error("got empty bloom filter") } data, _ := db.Get([]byte("setting-mipmap-version")) if len(data) == 0 { t.Error("setting-mipmap-version not written to database") } }
// SendTransaction implements ContractTransactor.SendTransaction, delegating the raw // transaction injection to the remote node. func (b *SimulatedBackend) SendTransaction(tx *types.Transaction) error { blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { block.AddTx(tx) } block.AddTx(tx) }) b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) return nil }
// makeChain creates a chain of n blocks starting at and including parent. // the returned hash chain is ordered head->parent. func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) { blocks := core.GenerateChain(parent, testdb, n, func(i int, gen *core.BlockGen) { gen.SetCoinbase(common.Address{seed}) }) hashes := make([]common.Hash, n+1) hashes[len(hashes)-1] = parent.Hash() blockm := make(map[common.Hash]*types.Block, n+1) blockm[parent.Hash()] = parent for i, b := range blocks { hashes[len(hashes)-i-2] = b.Hash() blockm[b.Hash()] = b } return hashes, blockm }
// Tests that feeding bad blocks will result in a peer drop. func TestBlockAttackerDropping(t *testing.T) { // Define the disconnection requirement for individual block import errors tests := []struct { failure bool drop bool }{ {true, true}, {false, false}, } // Run the tests and check disconnection status tester := newTester() for i, tt := range tests { // Register a new peer and ensure it's presence id := fmt.Sprintf("test %d", i) if err := tester.newPeer(id, eth60, []common.Hash{common.Hash{}}, nil); err != nil { t.Fatalf("test %d: failed to register new peer: %v", i, err) } if _, ok := tester.peerHashes[id]; !ok { t.Fatalf("test %d: registered peer not found", i) } // Assemble a good or bad block, depending of the test raw := core.GenerateChain(genesis, testdb, 1, nil)[0] if tt.failure { parent := types.NewBlock(&types.Header{}, nil, nil, nil) raw = core.GenerateChain(parent, testdb, 1, nil)[0] } block := &Block{OriginPeer: id, RawBlock: raw} // Simulate block processing and check the result tester.downloader.queue.blockCache[0] = block tester.downloader.process() if _, ok := tester.peerHashes[id]; !ok != tt.drop { t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.failure, !ok, tt.drop) } } }
// newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, and potential notification // channels for different events. func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) { var ( evmux = new(event.TypeMux) pow = new(core.FakePow) db, _ = ethdb.NewMemDatabase() genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{testBankAddress, testBankFunds}) blockchain, _ = core.NewBlockChain(db, pow, evmux) ) chain, _ := core.GenerateChain(genesis, db, blocks, generator) if _, err := blockchain.InsertChain(chain); err != nil { panic(err) } pm, err := NewProtocolManager(fastSync, NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db) if err != nil { return nil, err } pm.Start() return pm, nil }
// newTestProtocolManager creates a new protocol manager for testing purposes, // with the given number of blocks already known, and potential notification // channels for different events. func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) { var ( evmux = new(event.TypeMux) pow = new(core.FakePow) db, _ = ethdb.NewMemDatabase() genesis = core.WriteGenesisBlockForTesting(db, testBank) chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux) ) chain, _ := core.GenerateChain(nil, genesis, db, blocks, generator) if _, err := blockchain.InsertChain(chain); err != nil { panic(err) } pm, err := NewProtocolManager(chainConfig, fastSync, NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db) if err != nil { return nil, err } pm.Start() return pm, nil }
func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) { // Reduce the DAO handshake challenge timeout if timeout { defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout) daoChallengeTimeout = 500 * time.Millisecond } // Create a DAO aware protocol manager var ( evmux = new(event.TypeMux) pow = new(core.FakePow) db, _ = ethdb.NewMemDatabase() genesis = core.WriteGenesisBlockForTesting(db) config = &core.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} blockchain, _ = core.NewBlockChain(db, config, pow, evmux) ) pm, err := NewProtocolManager(config, false, NetworkId, evmux, new(testTxPool), pow, blockchain, db) if err != nil { t.Fatalf("failed to start test protocol manager: %v", err) } pm.Start() defer pm.Stop() // Connect a new peer and check that we receive the DAO challenge peer, _ := newTestPeer("peer", eth63, pm, true) defer peer.close() challenge := &getBlockHeadersData{ Origin: hashOrNumber{Number: config.DAOForkBlock.Uint64()}, Amount: 1, Skip: 0, Reverse: false, } if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil { t.Fatalf("challenge mismatch: %v", err) } // Create a block to reply to the challenge if no timeout is simualted if !timeout { blocks, _ := core.GenerateChain(nil, genesis, db, 1, func(i int, block *core.BlockGen) { if remoteForked { block.SetExtra(params.DAOForkBlockExtra) } }) if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil { t.Fatalf("failed to answer challenge: %v", err) } time.Sleep(100 * time.Millisecond) // Sleep to avoid the verification racing with the drops } else { // Otherwise wait until the test timeout passes time.Sleep(daoChallengeTimeout + 500*time.Millisecond) } // Verify that depending on fork side, the remote peer is maintained or dropped if localForked == remoteForked && !timeout { if peers := pm.peers.Len(); peers != 1 { t.Fatalf("peer count mismatch: have %d, want %d", peers, 1) } } else { if peers := pm.peers.Len(); peers != 0 { t.Fatalf("peer count mismatch: have %d, want %d", peers, 0) } } }
// Rollback aborts all pending transactions, reverting to the last committed state. func (b *SimulatedBackend) Rollback() { blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) }
func BenchmarkMipmaps(b *testing.B) { dir, err := ioutil.TempDir("", "mipmap") if err != nil { b.Fatal(err) } defer os.RemoveAll(dir) var ( db, _ = ethdb.NewLDBDatabase(dir, 0, 0) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = common.BytesToAddress([]byte("jeff")) addr3 = common.BytesToAddress([]byte("expanse")) addr4 = common.BytesToAddress([]byte("random addresses please")) ) defer db.Close() genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)}) chain, receipts := core.GenerateChain(nil, genesis, db, 100010, func(i int, gen *core.BlockGen) { var receipts types.Receipts switch i { case 2403: receipt := makeReceipt(addr1) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) case 1034: receipt := makeReceipt(addr2) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) case 34: receipt := makeReceipt(addr3) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) case 99999: receipt := makeReceipt(addr4) receipts = types.Receipts{receipt} gen.AddUncheckedReceipt(receipt) } // store the receipts err := core.WriteReceipts(db, receipts) if err != nil { b.Fatal(err) } core.WriteMipmapBloom(db, uint64(i+1), receipts) }) for i, block := range chain { core.WriteBlock(db, block) if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { b.Fatalf("failed to insert block number: %v", err) } if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil { b.Fatalf("failed to insert block number: %v", err) } if err := core.WriteBlockReceipts(db, block.Hash(), receipts[i]); err != nil { b.Fatal("error writing block receipts:", err) } } b.ResetTimer() filter := New(db) filter.SetAddresses([]common.Address{addr1, addr2, addr3, addr4}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) for i := 0; i < b.N; i++ { logs := filter.Find() if len(logs) != 4 { b.Fatal("expected 4 log, got", len(logs)) } } }
func TestFilters(t *testing.T) { dir, err := ioutil.TempDir("", "mipmap") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) var ( db, _ = ethdb.NewLDBDatabase(dir, 0, 0) key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr = crypto.PubkeyToAddress(key1.PublicKey) hash1 = common.BytesToHash([]byte("topic1")) hash2 = common.BytesToHash([]byte("topic2")) hash3 = common.BytesToHash([]byte("topic3")) hash4 = common.BytesToHash([]byte("topic4")) ) defer db.Close() genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)}) chain, receipts := core.GenerateChain(nil, genesis, db, 1000, func(i int, gen *core.BlockGen) { var receipts types.Receipts switch i { case 1: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash1}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 2: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash2}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 998: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash3}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} case 999: receipt := types.NewReceipt(nil, new(big.Int)) receipt.Logs = vm.Logs{ &vm.Log{ Address: addr, Topics: []common.Hash{hash4}, }, } gen.AddUncheckedReceipt(receipt) receipts = types.Receipts{receipt} } // store the receipts err := core.WriteReceipts(db, receipts) if err != nil { t.Fatal(err) } // i is used as block number for the writes but since the i // starts at 0 and block 0 (genesis) is already present increment // by one core.WriteMipmapBloom(db, uint64(i+1), receipts) }) for i, block := range chain { core.WriteBlock(db, block) if err := core.WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil { t.Fatalf("failed to insert block number: %v", err) } if err := core.WriteHeadBlockHash(db, block.Hash()); err != nil { t.Fatalf("failed to insert block number: %v", err) } if err := core.WriteBlockReceipts(db, block.Hash(), receipts[i]); err != nil { t.Fatal("error writing block receipts:", err) } } filter := New(db) filter.SetAddresses([]common.Address{addr}) filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2, hash3, hash4}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs := filter.Find() if len(logs) != 4 { t.Error("expected 4 log, got", len(logs)) } filter = New(db) filter.SetAddresses([]common.Address{addr}) filter.SetTopics([][]common.Hash{[]common.Hash{hash3}}) filter.SetBeginBlock(900) filter.SetEndBlock(999) logs = filter.Find() if len(logs) != 1 { t.Error("expected 1 log, got", len(logs)) } if len(logs) > 0 && logs[0].Topics[0] != hash3 { t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) } filter = New(db) filter.SetAddresses([]common.Address{addr}) filter.SetTopics([][]common.Hash{[]common.Hash{hash3}}) filter.SetBeginBlock(990) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 1 { t.Error("expected 1 log, got", len(logs)) } if len(logs) > 0 && logs[0].Topics[0] != hash3 { t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) } filter = New(db) filter.SetTopics([][]common.Hash{[]common.Hash{hash1, hash2}}) filter.SetBeginBlock(1) filter.SetEndBlock(10) logs = filter.Find() if len(logs) != 2 { t.Error("expected 2 log, got", len(logs)) } failHash := common.BytesToHash([]byte("fail")) filter = New(db) filter.SetTopics([][]common.Hash{[]common.Hash{failHash}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } failAddr := common.BytesToAddress([]byte("failmenow")) filter = New(db) filter.SetAddresses([]common.Address{failAddr}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } filter = New(db) filter.SetTopics([][]common.Hash{[]common.Hash{failHash}, []common.Hash{hash1}}) filter.SetBeginBlock(0) filter.SetEndBlock(-1) logs = filter.Find() if len(logs) != 0 { t.Error("expected 0 log, got", len(logs)) } }