diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 0621e81c2b..26849d2ff0 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -58,7 +58,7 @@ type SimulatedBackend struct { // NewSimulatedBackend creates a new binding backend using a simulated blockchain // for testing purposes. func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend { - database, _ := ethdb.NewMemDatabase() + database := ethdb.NewMemDatabase() genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc} genesis.MustCommit(database) blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), vm.Config{}) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 96de0c76ac..375dab3153 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -99,7 +99,7 @@ func runCmd(ctx *cli.Context) error { _, statedb = gen.ToBlock() chainConfig = gen.Config } else { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) } if ctx.GlobalString(SenderFlag.Name) != "" { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index a1717d799f..148f866b76 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -351,7 +351,7 @@ func TestVoting(t *testing.T) { copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:]) } // Create a pristine blockchain with the genesis injected - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() genesis.Commit(db) // Assemble a chain of headers from the cast votes diff --git a/core/bench_test.go b/core/bench_test.go index ab25c27d39..c0e7ab853f 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -149,7 +149,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Create the database in memory or in a temporary directory. var db ethdb.Database if !disk { - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() } else { dir, err := ioutil.TempDir("", "eth-core-bench") if err != nil { diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 6d54c2b932..e6e62806f0 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -32,7 +32,7 @@ import ( func TestHeaderVerification(t *testing.T) { // Create a simple chain to verify var ( - testdb, _ = ethdb.NewMemDatabase() + testdb = ethdb.NewMemDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil) @@ -84,7 +84,7 @@ func TestHeaderConcurrentVerification32(t *testing.T) { testHeaderConcurrentVeri func testHeaderConcurrentVerification(t *testing.T, threads int) { // Create a simple chain to verify var ( - testdb, _ = ethdb.NewMemDatabase() + testdb = ethdb.NewMemDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil) @@ -156,7 +156,7 @@ func TestHeaderConcurrentAbortion32(t *testing.T) { testHeaderConcurrentAbortion func testHeaderConcurrentAbortion(t *testing.T, threads int) { // Create a simple chain to verify var ( - testdb, _ = ethdb.NewMemDatabase() + testdb = ethdb.NewMemDatabase() gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index cb1df8d4b0..765cd30d87 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -36,7 +36,7 @@ import ( // newTestBlockChain creates a blockchain without validation. func newTestBlockChain(fake bool) *BlockChain { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() gspec := &Genesis{ Config: params.TestChainConfig, Difficulty: big.NewInt(1), @@ -577,11 +577,11 @@ func testInsertNonceError(t *testing.T, full bool) { func TestFastVsFullChains(t *testing.T) { // Configure and generate a sample block chain var ( - gendb, _ = ethdb.NewMemDatabase() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) - gspec = &Genesis{ + gendb = ethdb.NewMemDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + gspec = &Genesis{ Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}, } @@ -607,7 +607,7 @@ func TestFastVsFullChains(t *testing.T) { } }) // Import the chain as an archive node for the comparison baseline - archiveDb, _ := ethdb.NewMemDatabase() + archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), vm.Config{}) defer archive.Stop() @@ -616,7 +616,7 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to process block %d: %v", n, err) } // Fast import the chain as a non-archive node to test - fastDb, _ := ethdb.NewMemDatabase() + fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), vm.Config{}) defer fast.Stop() @@ -665,12 +665,12 @@ func TestFastVsFullChains(t *testing.T) { func TestLightVsFastVsFullChainHeads(t *testing.T) { // Configure and generate a sample block chain var ( - gendb, _ = ethdb.NewMemDatabase() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) - gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} - genesis = gspec.MustCommit(gendb) + gendb = ethdb.NewMemDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} + genesis = gspec.MustCommit(gendb) ) height := uint64(1024) blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil) @@ -693,7 +693,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { } } // Import the chain as an archive node and ensure all pointers are updated - archiveDb, _ := ethdb.NewMemDatabase() + archiveDb := ethdb.NewMemDatabase() gspec.MustCommit(archiveDb) archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), vm.Config{}) @@ -707,7 +707,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { assert(t, "archive", archive, height/2, height/2, height/2) // Import the chain as a non-archive node and ensure all pointers are updated - fastDb, _ := ethdb.NewMemDatabase() + fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), vm.Config{}) defer fast.Stop() @@ -727,7 +727,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { assert(t, "fast", fast, height/2, height/2, 0) // Import the chain as a light node and ensure all pointers are updated - lightDb, _ := ethdb.NewMemDatabase() + lightDb := ethdb.NewMemDatabase() gspec.MustCommit(lightDb) light, _ := NewBlockChain(lightDb, gspec.Config, ethash.NewFaker(), vm.Config{}) @@ -750,7 +750,7 @@ func TestChainTxReorgs(t *testing.T) { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() gspec = &Genesis{ Config: params.TestChainConfig, GasLimit: 3141592, @@ -862,7 +862,7 @@ func TestLogReorgs(t *testing.T) { var ( key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() // this code generates a log code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}} @@ -906,7 +906,7 @@ func TestLogReorgs(t *testing.T) { func TestReorgSideEvent(t *testing.T) { var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr1 = crypto.PubkeyToAddress(key1.PublicKey) gspec = &Genesis{ @@ -1031,7 +1031,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) { func TestEIP155Transition(t *testing.T) { // Configure and generate a sample block chain var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) @@ -1135,7 +1135,7 @@ func TestEIP155Transition(t *testing.T) { func TestEIP161AccountRemoval(t *testing.T) { // Configure and generate a sample block chain var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) funds = big.NewInt(1000000000) diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go index b761e8a5b2..be40307bc3 100644 --- a/core/chain_indexer_test.go +++ b/core/chain_indexer_test.go @@ -46,7 +46,7 @@ func TestChainIndexerWithChildren(t *testing.T) { // multiple backends. The section size and required confirmation count parameters // are randomized. func testChainIndexer(t *testing.T, count int) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() defer db.Close() // Create a chain of indexers and ensure they all report empty diff --git a/core/chain_makers.go b/core/chain_makers.go index dd3e2fb192..81b4d2f117 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -232,7 +232,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { // Initialize a fresh chain with only a genesis block gspec := new(Genesis) - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() genesis := gspec.MustCommit(db) blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, ethash.NewFaker(), vm.Config{}) diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 2260c62fbd..455155abd1 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -36,7 +36,7 @@ func ExampleGenerateChain() { addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey) - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() ) // Ensure that key1 has some funds in the genesis block. diff --git a/core/dao_test.go b/core/dao_test.go index b9898ff7c8..a3f3dd865f 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -32,13 +32,13 @@ func TestDAOForkRangeExtradata(t *testing.T) { forkBlock := big.NewInt(32) // Generate a common prefix for both pro-forkers and non-forkers - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() gspec := new(Genesis) genesis := gspec.MustCommit(db) prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) // Create the concurrent, conflicting two nodes - proDb, _ := ethdb.NewMemDatabase() + proDb := ethdb.NewMemDatabase() gspec.MustCommit(proDb) proConf := *params.TestChainConfig @@ -48,7 +48,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { proBc, _ := NewBlockChain(proDb, &proConf, ethash.NewFaker(), vm.Config{}) defer proBc.Stop() - conDb, _ := ethdb.NewMemDatabase() + conDb := ethdb.NewMemDatabase() gspec.MustCommit(conDb) conConf := *params.TestChainConfig @@ -67,7 +67,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { // Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() gspec.MustCommit(db) bc, _ := NewBlockChain(db, &conConf, ethash.NewFaker(), vm.Config{}) defer bc.Stop() @@ -89,7 +89,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err) } // Create a no-fork block, and try to feed into the pro-fork chain - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() gspec.MustCommit(db) bc, _ = NewBlockChain(db, &proConf, ethash.NewFaker(), vm.Config{}) defer bc.Stop() @@ -112,7 +112,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { } } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() gspec.MustCommit(db) bc, _ := NewBlockChain(db, &conConf, ethash.NewFaker(), vm.Config{}) defer bc.Stop() @@ -129,7 +129,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err) } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() gspec.MustCommit(db) bc, _ = NewBlockChain(db, &proConf, ethash.NewFaker(), vm.Config{}) defer bc.Stop() diff --git a/core/database_util_test.go b/core/database_util_test.go index 36f43cf50a..9a69a7f748 100644 --- a/core/database_util_test.go +++ b/core/database_util_test.go @@ -30,7 +30,7 @@ import ( // Tests block header storage and retrieval operations. func TestHeaderStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test header to move around the database and make sure it's really new header := &types.Header{Number: big.NewInt(42), Extra: []byte("test header")} @@ -65,7 +65,7 @@ func TestHeaderStorage(t *testing.T) { // Tests block body storage and retrieval operations. func TestBodyStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test body to move around the database and make sure it's really new body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}} @@ -105,7 +105,7 @@ func TestBodyStorage(t *testing.T) { // Tests block storage and retrieval operations. func TestBlockStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test block to move around the database and make sure it's really new block := types.NewBlockWithHeader(&types.Header{ @@ -157,7 +157,7 @@ func TestBlockStorage(t *testing.T) { // Tests that partial block contents don't get reassembled into full blocks. func TestPartialBlockStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() block := types.NewBlockWithHeader(&types.Header{ Extra: []byte("test block"), UncleHash: types.EmptyUncleHash, @@ -198,7 +198,7 @@ func TestPartialBlockStorage(t *testing.T) { // Tests block total difficulty storage and retrieval operations. func TestTdStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test TD to move around the database and make sure it's really new hash, td := common.Hash{}, big.NewInt(314) @@ -223,7 +223,7 @@ func TestTdStorage(t *testing.T) { // Tests that canonical numbers can be mapped to hashes and retrieved. func TestCanonicalMappingStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() // Create a test canonical number and assinged hash to move around hash, number := common.Hash{0: 0xff}, uint64(314) @@ -248,7 +248,7 @@ func TestCanonicalMappingStorage(t *testing.T) { // Tests that head headers and head blocks can be assigned, individually. func TestHeadStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")}) blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")}) @@ -288,7 +288,7 @@ func TestHeadStorage(t *testing.T) { // Tests that positional lookup metadata can be stored and retrieved. func TestLookupStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), big.NewInt(1111), big.NewInt(11111), []byte{0x11, 0x11, 0x11}) tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), big.NewInt(2222), big.NewInt(22222), []byte{0x22, 0x22, 0x22}) @@ -333,7 +333,7 @@ func TestLookupStorage(t *testing.T) { // Tests that receipts associated with a single block can be stored and retrieved. func TestBlockReceiptStorage(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() receipt1 := &types.Receipt{ Status: types.ReceiptStatusFailed, diff --git a/core/genesis.go b/core/genesis.go index fd6ed61159..e9a1ec36bb 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -222,7 +222,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { // ToBlock creates the block and state of a genesis specification. func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) for addr, account := range g.Alloc { statedb.AddBalance(addr, account.Balance) diff --git a/core/genesis_test.go b/core/genesis_test.go index 482f861904..fd8764ca41 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -138,7 +138,7 @@ func TestSetupGenesis(t *testing.T) { } for _, test := range tests { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() config, hash, err := test.fn(db) // Check the return values. if !reflect.DeepEqual(err, test.wantErr) { diff --git a/core/helper_test.go b/core/helper_test.go index 698a2924cb..edb8cc0c52 100644 --- a/core/helper_test.go +++ b/core/helper_test.go @@ -18,7 +18,6 @@ package core import ( "container/list" - "fmt" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" @@ -77,15 +76,9 @@ func (tm *TestManager) Db() ethdb.Database { } func NewTestManager() *TestManager { - db, err := ethdb.NewMemDatabase() - if err != nil { - fmt.Println("Could not create mem-db, failing") - return nil - } - testManager := &TestManager{} testManager.eventMux = new(event.TypeMux) - testManager.db = db + testManager.db = ethdb.NewMemDatabase() // testManager.txPool = NewTxPool(testManager) // testManager.blockChain = NewBlockChain(testManager) // testManager.stateManager = NewStateManager(testManager) diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go index 1cfdd3a890..ebe796bc01 100644 --- a/core/state/managed_state_test.go +++ b/core/state/managed_state_test.go @@ -26,7 +26,7 @@ import ( var addr = common.BytesToAddress([]byte("test")) func create() (*ManagedState, *account) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := New(common.Hash{}, NewDatabase(db)) ms := ManageState(statedb) ms.StateDB.SetNonce(addr, 100) diff --git a/core/state/state_test.go b/core/state/state_test.go index bbae3685bb..c363b34fc3 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -87,7 +87,7 @@ func (s *StateSuite) TestDump(c *checker.C) { } func (s *StateSuite) SetUpTest(c *checker.C) { - s.db, _ = ethdb.NewMemDatabase() + s.db = ethdb.NewMemDatabase() s.state, _ = New(common.Hash{}, NewDatabase(s.db)) } @@ -133,7 +133,7 @@ func (s *StateSuite) TestSnapshotEmpty(c *checker.C) { // use testing instead of checker because checker does not support // printing/logging in tests (-check.vv does not work) func TestSnapshot2(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() state, _ := New(common.Hash{}, NewDatabase(db)) stateobjaddr0 := toAddr([]byte("so0")) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index b2bd18e65e..1bd4d587e4 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -39,7 +39,7 @@ import ( // actually committing the state. func TestUpdateLeaks(t *testing.T) { // Create an empty state database - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() state, _ := New(common.Hash{}, NewDatabase(db)) // Update it with some accounts @@ -66,8 +66,8 @@ func TestUpdateLeaks(t *testing.T) { // only the one right before the commit. func TestIntermediateLeaks(t *testing.T) { // Create two state databases, one transitioning to the final state, the other final from the beginning - transDb, _ := ethdb.NewMemDatabase() - finalDb, _ := ethdb.NewMemDatabase() + transDb := ethdb.NewMemDatabase() + finalDb := ethdb.NewMemDatabase() transState, _ := New(common.Hash{}, NewDatabase(transDb)) finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) @@ -283,7 +283,7 @@ func (test *snapshotTest) String() string { func (test *snapshotTest) run() bool { // Run all actions and create snapshots. var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() state, _ = New(common.Hash{}, NewDatabase(db)) snapshotRevs = make([]int, len(test.snapshots)) sindex = 0 diff --git a/core/state/sync_test.go b/core/state/sync_test.go index 06c572ea62..3be8384a08 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -38,7 +38,7 @@ type testAccount struct { // makeTestState create a sample test state to test node-wise reconstruction. func makeTestState() (Database, *ethdb.MemDatabase, common.Hash, []*testAccount) { // Create an empty state - mem, _ := ethdb.NewMemDatabase() + mem := ethdb.NewMemDatabase() db := NewDatabase(mem) state, _ := New(common.Hash{}, db) @@ -125,7 +125,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error { // Tests that an empty state is not scheduled for syncing. func TestEmptyStateSync(t *testing.T) { empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() if req := NewStateSync(empty, db).Missing(1); len(req) != 0 { t.Errorf("content requested for empty state: %v", req) } @@ -141,7 +141,7 @@ func testIterativeStateSync(t *testing.T, batch int) { _, srcMem, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := append([]common.Hash{}, sched.Missing(batch)...) @@ -173,7 +173,7 @@ func TestIterativeDelayedStateSync(t *testing.T) { _, srcMem, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := append([]common.Hash{}, sched.Missing(0)...) @@ -210,7 +210,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) { _, srcMem, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := make(map[common.Hash]struct{}) @@ -250,7 +250,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) { _, srcMem, srcRoot, srcAccounts := makeTestState() // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) queue := make(map[common.Hash]struct{}) @@ -297,7 +297,7 @@ func TestIncompleteStateSync(t *testing.T) { checkTrieConsistency(srcMem, srcRoot) // Create a destination state and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewStateSync(srcRoot, dstDb) added := []common.Hash{} diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 17d7368774..4674cefe9a 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -78,7 +78,7 @@ func pricedTransaction(nonce uint64, gaslimit, gasprice *big.Int, key *ecdsa.Pri } func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -136,7 +136,7 @@ func (c *testChain) State() (*state.StateDB, error) { // a state change between those fetches. stdb := c.statedb if *c.trigger { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) // simulate that the new head block included tx0 and tx1 c.statedb.SetNonce(c.address, 2) @@ -151,7 +151,7 @@ func (c *testChain) State() (*state.StateDB, error) { // block head event that initiated the resetState(). func TestStateChangeDuringPoolReset(t *testing.T) { var ( - db, _ = ethdb.NewMemDatabase() + db = ethdb.NewMemDatabase() key, _ = crypto.GenerateKey() address = crypto.PubkeyToAddress(key.PublicKey) statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) @@ -305,7 +305,7 @@ func TestTransactionChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) statedb.AddBalance(addr, big.NewInt(100000000000000)) @@ -333,7 +333,7 @@ func TestTransactionDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) statedb.AddBalance(addr, big.NewInt(100000000000000)) @@ -633,7 +633,7 @@ func TestTransactionQueueGlobalLimitingNoLocals(t *testing.T) { func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -722,7 +722,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { evictionInterval = time.Second // Create the pool to test the non-expiration enforcement - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -860,7 +860,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { // attacks. func TestTransactionPendingGlobalLimiting(t *testing.T) { // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -905,7 +905,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { // Tests that if transactions start being capped, transactions are also removed from 'all' func TestTransactionCapClearsFromAll(t *testing.T) { // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -938,7 +938,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { // the transactions are still kept. func TestTransactionPendingMinimumAllowance(t *testing.T) { // Create the pool to test the limit enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -985,7 +985,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { // Note, local transactions are never allowed to be dropped. func TestTransactionPoolRepricing(t *testing.T) { // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -1065,7 +1065,7 @@ func TestTransactionPoolRepricing(t *testing.T) { // remove local transactions. func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -1126,7 +1126,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // Note, local transactions are never allowed to be dropped. func TestTransactionPoolUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -1212,7 +1212,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { // price bump required. func TestTransactionReplacement(t *testing.T) { // Create the pool to test the pricing enforcement with - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} @@ -1290,7 +1290,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { os.Remove(journal) // Create the original pool to inject transaction into the journal - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index edbf541766..9bf2f2e0bb 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -101,7 +101,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { setDefaults(cfg) if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) } var ( @@ -132,7 +132,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { setDefaults(cfg) if cfg.State == nil { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(db)) } var ( diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 2c4dc50265..c061dc2ec5 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -94,7 +94,7 @@ func TestExecute(t *testing.T) { } func TestCall(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() state, _ := state.New(common.Hash{}, state.NewDatabase(db)) address := common.HexToAddress("0x0a") state.SetCode(address, []byte{ diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index 58f6e9a624..a656e1a1eb 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -75,12 +75,13 @@ type downloadTester struct { // newTester creates a new downloader test mocker. func newTester() *downloadTester { - testdb, _ := ethdb.NewMemDatabase() + testdb := ethdb.NewMemDatabase() genesis := core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000)) tester := &downloadTester{ genesis: genesis, peerDb: testdb, + stateDb: ethdb.NewMemDatabase(), ownHashes: []common.Hash{genesis.Hash()}, ownHeaders: map[common.Hash]*types.Header{genesis.Hash(): genesis.Header()}, ownBlocks: map[common.Hash]*types.Block{genesis.Hash(): genesis}, @@ -93,7 +94,6 @@ func newTester() *downloadTester { peerChainTds: make(map[string]map[common.Hash]*big.Int), peerMissingStates: make(map[string]map[common.Hash]bool), } - tester.stateDb, _ = ethdb.NewMemDatabase() tester.stateDb.Put(genesis.Root().Bytes(), []byte{0x00}) tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer) diff --git a/eth/downloader/statesync.go b/eth/downloader/statesync.go index a0b05c9be6..e0f7ed0cd7 100644 --- a/eth/downloader/statesync.go +++ b/eth/downloader/statesync.go @@ -18,14 +18,12 @@ package downloader import ( "fmt" - "hash" "sync" "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/crypto/sha3" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" @@ -211,9 +209,8 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync { type stateSync struct { d *Downloader // Downloader instance to access and manage current peerset - sched *trie.TrieSync // State trie sync scheduler defining the tasks - keccak hash.Hash // Keccak256 hasher to verify deliveries with - tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval + sched *trie.TrieSync // State trie sync scheduler defining the tasks + tasks map[common.Hash]*stateTask // Set of tasks currently queued for retrieval numUncommitted int bytesUncommitted int @@ -237,7 +234,6 @@ func newStateSync(d *Downloader, root common.Hash) *stateSync { return &stateSync{ d: d, sched: state.NewStateSync(root, d.stateDB), - keccak: sha3.NewKeccak256(), tasks: make(map[common.Hash]*stateTask), deliver: make(chan *stateReq), cancel: make(chan struct{}), @@ -401,7 +397,7 @@ func (s *stateSync) process(req *stateReq) (bool, error) { progress, stale := false, len(req.response) > 0 for _, blob := range req.response { - prog, hash, err := s.processNodeData(blob) + prog, hash, err := s.sched.Process(&trie.SyncResult{Data: blob}) switch err { case nil: s.numUncommitted++ @@ -446,18 +442,6 @@ func (s *stateSync) process(req *stateReq) (bool, error) { return stale, nil } -// processNodeData tries to inject a trie node data blob delivered from a remote -// peer into the state trie, returning whether anything useful was written or any -// error occurred. -func (s *stateSync) processNodeData(blob []byte) (bool, common.Hash, error) { - res := trie.SyncResult{Data: blob} - s.keccak.Reset() - s.keccak.Write(blob) - s.keccak.Sum(res.Hash[:0]) - committed, _, err := s.sched.Process([]trie.SyncResult{res}) - return committed, res.Hash, err -} - // updateStats bumps the various state sync progress counters and displays a log // message for the user to see. func (s *stateSync) updateStats(written, duplicate, unexpected int, duration time.Duration) { diff --git a/eth/handler_test.go b/eth/handler_test.go index 6752cd2a84..88028a0514 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -368,7 +368,7 @@ func testGetNodeData(t *testing.T, protocol int) { t.Errorf("data hash mismatch: have %x, want %x", hash, want) } } - statedb, _ := ethdb.NewMemDatabase() + statedb := ethdb.NewMemDatabase() for i := 0; i < len(data); i++ { statedb.Put(hashes[i].Bytes(), data[i]) } diff --git a/ethdb/database_test.go b/ethdb/database_test.go index 5e4a3ca34a..2deb50988c 100644 --- a/ethdb/database_test.go +++ b/ethdb/database_test.go @@ -53,8 +53,7 @@ func TestLDB_PutGet(t *testing.T) { } func TestMemoryDB_PutGet(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - testPutGet(db, t) + testPutGet(ethdb.NewMemDatabase(), t) } func testPutGet(db ethdb.Database, t *testing.T) { @@ -131,8 +130,7 @@ func TestLDB_ParallelPutGet(t *testing.T) { } func TestMemoryDB_ParallelPutGet(t *testing.T) { - db, _ := ethdb.NewMemDatabase() - testParallelPutGet(db, t) + testParallelPutGet(ethdb.NewMemDatabase(), t) } func testParallelPutGet(db ethdb.Database, t *testing.T) { diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go index 699bd0c9fd..8c52b89855 100644 --- a/ethdb/memory_database.go +++ b/ethdb/memory_database.go @@ -23,18 +23,15 @@ import ( "github.com/ethereum/go-ethereum/common" ) -/* - * This is a test memory database. Do not use for any production it does not get persisted - */ type MemDatabase struct { db map[string][]byte lock sync.RWMutex } -func NewMemDatabase() (*MemDatabase, error) { +func NewMemDatabase() *MemDatabase { return &MemDatabase{ db: make(map[string][]byte), - }, nil + } } func (db *MemDatabase) Put(key []byte, value []byte) error { diff --git a/les/handler_test.go b/les/handler_test.go index 93e2763026..680373f860 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -42,7 +42,7 @@ func expectResponse(r p2p.MsgReader, msgcode, reqID, bv uint64, data interface{} func TestGetBlockHeadersLes1(t *testing.T) { testGetBlockHeaders(t, 1) } func testGetBlockHeaders(t *testing.T, protocol int) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, downloader.MaxHashFetch+15, nil, nil, nil, db) bc := pm.blockchain.(*core.BlockChain) peer, _ := newTestPeer(t, "peer", protocol, pm, true) @@ -171,7 +171,7 @@ func testGetBlockHeaders(t *testing.T, protocol int) { func TestGetBlockBodiesLes1(t *testing.T) { testGetBlockBodies(t, 1) } func testGetBlockBodies(t *testing.T, protocol int) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, downloader.MaxBlockFetch+15, nil, nil, nil, db) bc := pm.blockchain.(*core.BlockChain) peer, _ := newTestPeer(t, "peer", protocol, pm, true) @@ -248,7 +248,7 @@ func TestGetCodeLes1(t *testing.T) { testGetCode(t, 1) } func testGetCode(t *testing.T, protocol int) { // Assemble the test environment - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) bc := pm.blockchain.(*core.BlockChain) peer, _ := newTestPeer(t, "peer", protocol, pm, true) @@ -281,7 +281,7 @@ func TestGetReceiptLes1(t *testing.T) { testGetReceipt(t, 1) } func testGetReceipt(t *testing.T, protocol int) { // Assemble the test environment - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) bc := pm.blockchain.(*core.BlockChain) peer, _ := newTestPeer(t, "peer", protocol, pm, true) @@ -308,7 +308,7 @@ func TestGetProofsLes1(t *testing.T) { testGetProofs(t, 1) } func testGetProofs(t *testing.T, protocol int) { // Assemble the test environment - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) bc := pm.blockchain.(*core.BlockChain) peer, _ := newTestPeer(t, "peer", protocol, pm, true) diff --git a/les/odr_test.go b/les/odr_test.go index f56c4036d4..62270f46cd 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -152,8 +152,8 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { peers := newPeerSet() dist := newRequestDistributor(peers, make(chan struct{})) rm := newRetrieveManager(peers, dist, nil) - db, _ := ethdb.NewMemDatabase() - ldb, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() + ldb := ethdb.NewMemDatabase() odr := NewLesOdr(ldb, rm) pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) lpm := newTestProtocolManagerMust(t, true, 0, nil, peers, odr, ldb) diff --git a/les/request_test.go b/les/request_test.go index 6b594462dc..8c660ccb7b 100644 --- a/les/request_test.go +++ b/les/request_test.go @@ -71,8 +71,8 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) { peers := newPeerSet() dist := newRequestDistributor(peers, make(chan struct{})) rm := newRetrieveManager(peers, dist, nil) - db, _ := ethdb.NewMemDatabase() - ldb, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() + ldb := ethdb.NewMemDatabase() odr := NewLesOdr(ldb, rm) pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db) diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 40a4d396a8..8f9769efc8 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -51,7 +51,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [ // chain. Depending on the full flag, if creates either a full block chain or a // header only chain. func newCanonical(n int) (ethdb.Database, *LightChain, error) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker()) @@ -68,7 +68,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { // newTestLightChain creates a LightChain that doesn't validate anything. func newTestLightChain() *LightChain { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() gspec := &core.Genesis{ Difficulty: big.NewInt(1), Config: params.TestChainConfig, diff --git a/node/node.go b/node/node.go index 6f189d8fe5..b957cc8267 100644 --- a/node/node.go +++ b/node/node.go @@ -637,7 +637,7 @@ func (n *Node) EventMux() *event.TypeMux { // ephemeral, a memory database is returned. func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { if n.config.DataDir == "" { - return ethdb.NewMemDatabase() + return ethdb.NewMemDatabase(), nil } return ethdb.NewLDBDatabase(n.config.resolvePath(name), cache, handles) } diff --git a/node/service.go b/node/service.go index 55062a5004..afc43e8486 100644 --- a/node/service.go +++ b/node/service.go @@ -41,7 +41,7 @@ type ServiceContext struct { // node is an ephemeral one, a memory database is returned. func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (ethdb.Database, error) { if ctx.config.DataDir == "" { - return ethdb.NewMemDatabase() + return ethdb.NewMemDatabase(), nil } db, err := ethdb.NewLDBDatabase(ctx.config.resolvePath(name), cache, handles) if err != nil { diff --git a/tests/block_test_util.go b/tests/block_test_util.go index a789e6d887..6fdb2d84fd 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -98,7 +98,7 @@ func (t *BlockTest) Run() error { } // import pre accounts & construct test genesis block & state root - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() gblock, err := t.genesis(config).Commit(db) if err != nil { return err diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 64bf09cb42..c2ac9a79ff 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -126,7 +126,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD return nil, UnsupportedForkError{subtest.Fork} } block, _ := t.genesis(config).ToBlock() - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb := makePreState(db, t.json.Pre) post := t.json.Post[subtest.Fork][subtest.Index] diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 0aa37955ce..928405aaf2 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -79,7 +79,7 @@ type vmExecMarshaling struct { } func (t *VMTest) Run(vmconfig vm.Config) error { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() statedb := makePreState(db, t.json.Pre) ret, gasRemaining, err := t.exec(statedb, vmconfig) diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 4808d8b0c6..3ec4230952 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -279,7 +279,7 @@ func TestIteratorNoDups(t *testing.T) { // This test checks that nodeIterator.Next can be retried after inserting missing trie nodes. func TestIteratorContinueAfterError(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() tr, _ := New(common.Hash{}, db) for _, val := range testdata1 { tr.Update([]byte(val.k), []byte(val.v)) @@ -330,7 +330,7 @@ func TestIteratorContinueAfterError(t *testing.T) { // should retry seeking before returning true for the first time. func TestIteratorContinueAfterSeekError(t *testing.T) { // Commit test trie to db, then remove the node containing "bars". - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() ctr, _ := New(common.Hash{}, db) for _, val := range testdata1 { ctr.Update([]byte(val.k), []byte(val.v)) diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index d74102e2a2..62b7d4c55e 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -28,7 +28,7 @@ import ( ) func newEmptySecure() *SecureTrie { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() trie, _ := NewSecure(common.Hash{}, db, 0) return trie } @@ -36,7 +36,7 @@ func newEmptySecure() *SecureTrie { // makeTestSecureTrie creates a large enough secure trie for testing. func makeTestSecureTrie() (ethdb.Database, *SecureTrie, map[string][]byte) { // Create an empty trie - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() trie, _ := NewSecure(common.Hash{}, db, 0) // Fill it with some arbitrary data diff --git a/trie/sync.go b/trie/sync.go index 1130b062db..c9fd650681 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -17,10 +17,14 @@ package trie import ( + "bytes" "errors" "fmt" + "hash" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/ethdb" "gopkg.in/karalabe/cookiejar.v2/collections/prque" ) @@ -50,10 +54,10 @@ type request struct { // be a batch of trie leaves (with associated merkle proofs) if returning batched // results. type SyncResult struct { - Hash common.Hash // Hash of the originally unknown trie node - Data []byte // Data content of the retrieved node, in node-sync mode - Leaves [][]byte // Trie leaves rooted under the specified hash, in leaf-sync mode - Proofs [][]byte // Proofs to validate the leaves, in leaf-sync mode, if leaves are partial + Data []byte // Data content of the retrieved node, in node-sync mode + Keys [][]byte // Trie keys rooted under the specified hash, in leaf-sync mode + Values [][]byte // Trie values rooted under the specified hash, in leaf-sync mode + Proof [][]byte // Proofs to validate the leaves, in leaf-sync mode, if leaves are partial } // syncMemBatch is an in-memory buffer of successfully downloaded but not yet @@ -84,6 +88,7 @@ type TrieSync struct { membatch *syncMemBatch // Memory buffer to avoid frequest database writes requests map[common.Hash]*request // Pending requests pertaining to a key hash queue *prque.Prque // Priority queue with the pending requests + keccak hash.Hash // Keccak256 hasher to verify deliveries with } // NewTrieSync creates a new trie data download scheduler. @@ -93,6 +98,7 @@ func NewTrieSync(root common.Hash, database DatabaseReader, callback TrieSyncLea membatch: newSyncMemBatch(), requests: make(map[common.Hash]*request), queue: prque.New(), + keccak: sha3.NewKeccak256(), } ts.AddSubTrie(root, 0, common.Hash{}, callback) return ts @@ -167,7 +173,10 @@ func (s *TrieSync) AddRawEntry(hash common.Hash, depth int, parent common.Hash) func (s *TrieSync) Missing(max int) []common.Hash { requests := []common.Hash{} for !s.queue.Empty() && (max == 0 || len(requests) < max) { - requests = append(requests, s.queue.PopItem().(common.Hash)) + hash := s.queue.PopItem().(common.Hash) + if s.requests[hash] != nil { + requests = append(requests, hash) + } } return requests } @@ -175,48 +184,187 @@ func (s *TrieSync) Missing(max int) []common.Hash { // Process injects a batch of retrieved trie nodes data, returning if something // was committed to the database and also the index of an entry if processing of // it failed. -func (s *TrieSync) Process(results []SyncResult) (bool, int, error) { - committed := false +func (s *TrieSync) Process(result *SyncResult) (bool, common.Hash, error) { + // If it's a plain or full sub-trie delivery, inject and return + if len(result.Keys) == 0 && len(result.Proof) == 0 { + return s.processNode(result.Data) + } + if len(result.Proof) == 0 { + return s.processLeaves(result.Keys, result.Values) + } + // For partial depliveries, expand the keys and iteratively fulfil the sub-trie + for i, key := range result.Keys { + result.Keys[i] = keybytesToHex(key) + } + return s.processPartialLeaves(result.Keys, result.Values, result.Proof) +} - for i, item := range results { - // If the item was not requested, bail out - request := s.requests[item.Hash] - if request == nil { - return committed, i, ErrNotRequested - } - if request.data != nil { - return committed, i, ErrAlreadyProcessed - } - // If the item is a raw entry request, commit directly - if request.raw { - request.data = item.Data - s.commit(request) - committed = true - continue - } - // Decode the node data content and update the request - node, err := decodeNode(item.Hash[:], item.Data, 0) - if err != nil { - return committed, i, err - } - request.data = item.Data +// processNode verifies and processes a trie node, returning if anything was +// committed and the hash of the node injected. +func (s *TrieSync) processNode(blob []byte) (bool, common.Hash, error) { + // Derive the hash of the result based on its content + var hash common.Hash - // Create and schedule a request for all the children nodes - requests, err := s.children(request, node) - if err != nil { - return committed, i, err - } - if len(requests) == 0 && request.deps == 0 { - s.commit(request) - committed = true - continue - } - request.deps += len(requests) - for _, child := range requests { - s.schedule(child) + s.keccak.Reset() + s.keccak.Write(blob) + s.keccak.Sum(hash[:0]) + + // If the item was not requested, bail out + request := s.requests[hash] + if request == nil { + return false, hash, ErrNotRequested + } + if request.data != nil { + return false, hash, nil // TODO(karalabe): Why not ErrAlreadyProcessed + } + // If the item is a raw entry request, commit directly + if request.raw { + request.data = blob + s.commit(request) + return true, hash, nil + } + // Decode and inject into the trie + node, err := decodeNode(hash[:], blob, 0) + if err != nil { + return false, hash, err + } + request.data = blob + + // Create and schedule a request for all the children nodes + requests, err := s.children(request, node) + if err != nil { + return false, hash, err + } + if len(requests) == 0 && request.deps == 0 { + s.commit(request) + return true, hash, nil + } + request.deps += len(requests) + for _, child := range requests { + s.schedule(child) + } + return false, hash, nil +} + +// processLeaves reconstructs a sub-trie from the given key-value pairs, returning +// the root of the sub-trie or an error on failure. +func (s *TrieSync) processLeaves(keys [][]byte, values [][]byte) (bool, common.Hash, error) { + // Inject all the leaves into a fresh trie and derive it's root hash + db := ethdb.NewMemDatabase() + trie, err := New(common.Hash{}, db) + if err != nil { + return false, common.Hash{}, err + } + for j := 0; j < len(keys); j++ { + trie.Update(keys[j], values[j]) + } + root, err := trie.Commit() + if err != nil { + return false, common.Hash{}, err + } + // If the item was not requested, bail out + request := s.requests[root] + if request == nil { + return false, root, ErrNotRequested + } + if request.data != nil { + return false, root, ErrAlreadyProcessed + } + // Inject all key-values as is and complete the root + for _, key := range db.Keys() { + value, _ := db.Get(key) + if hash := common.BytesToHash(key); hash != root { + s.commitEntry(hash, value) + } else { + request.data = value } } - return committed, 0, nil + s.commit(request) + + return true, root, nil +} + +// processPartialLeaves reconstructs a sub-trie from the Merkle proof and the +// available key-value pairs, commiting the available parts and scheduling the +// missing items for future retrival. +func (s *TrieSync) processPartialLeaves(keys [][]byte, values [][]byte, proof [][]byte) (bool, common.Hash, error) { + // Derive the hash of the topmost proof + var root common.Hash + + s.keccak.Reset() + s.keccak.Write(proof[0]) + s.keccak.Sum(root[:0]) + + // If the item was not requested, bail out + request := s.requests[root] + if request == nil { + return false, root, ErrNotRequested + } + if request.data != nil { + return false, root, ErrAlreadyProcessed + } + // Decode the root node and schedule missing children + node, err := decodeNode(root[:], proof[0], 0) + if err != nil { + return false, root, err + } + request.data = proof[0] + + requests, err := s.children(request, node) + if err != nil { + return false, root, err + } + if len(requests) == 0 && request.deps == 0 { + s.commit(request) + return true, root, nil + } + request.deps += len(requests) + for _, child := range requests { + s.schedule(child) + } + // Fulfill any children satisfied by the key-value pairs + switch node := (node).(type) { + case *shortNode: + // All keys must have the short node's path as a prefix + for i, key := range keys { + if !bytes.HasPrefix(key, node.Key) { + return false, root, fmt.Errorf("key mismatch at proof %x", proof[0]) + } + keys[i] = key[len(node.Key):] + } + // Recurse into the subtrie of the short node + commit, _, err := s.processPartialLeaves(keys, values, proof[1:]) + return commit, root, err + + case *fullNode: + // Split up the keyspace between the full node's children + for i := 0; i < 17; i++ { + if node.Children[i] != nil { + // Split off the keyspace for this child + var split int + for split < len(keys) && keys[split][0] == byte(i) { + keys[split] = keys[split][1:] + split++ + } + // Only process this child if it's not fully embedded + if _, ok := node.Children[i].(hashNode); !ok { + // If we're at the last node, process it as a partial trie + if split == len(keys) && len(proof) != 1 { + commit, _, err := s.processPartialLeaves(keys[:split], values[:split], proof[1:]) + return commit, root, err + } + // Otherwise we have a full sub-trie, parse in its entirety (if not already contained within the full node) + commit, _, err := s.processLeaves(keys[:split], values[:split]) + if err != nil { + return commit, root, err + } + } + keys = keys[split:] + values = values[split:] + } + } + } + return false, root, nil } // Commit flushes the data stored in the internal membatch out to persistent @@ -320,9 +468,7 @@ func (s *TrieSync) children(req *request, object node) ([]*request, error) { // committed themselves. func (s *TrieSync) commit(req *request) (err error) { // Write the node content to the membatch - s.membatch.batch[req.hash] = req.data - s.membatch.order = append(s.membatch.order, req.hash) - + s.commitEntry(req.hash, req.data) delete(s.requests, req.hash) // Check all parents for completion @@ -336,3 +482,10 @@ func (s *TrieSync) commit(req *request) (err error) { } return nil } + +// commitEntry injects a raw database entry into the memory batch to be flushed +// out at a later point into the real database. +func (s *TrieSync) commitEntry(key common.Hash, blob []byte) { + s.membatch.batch[key] = blob + s.membatch.order = append(s.membatch.order, key) +} diff --git a/trie/sync_test.go b/trie/sync_test.go index 7048c08cae..18146ee3fa 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -18,6 +18,7 @@ package trie import ( "bytes" + "math/rand" "testing" "github.com/ethereum/go-ethereum/common" @@ -27,7 +28,7 @@ import ( // makeTestTrie create a sample test trie to test node-wise reconstruction. func makeTestTrie() (ethdb.Database, *Trie, map[string][]byte) { // Create an empty trie - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() trie, _ := New(common.Hash{}, db) // Fill it with some arbitrary data @@ -92,7 +93,7 @@ func TestEmptyTrieSync(t *testing.T) { emptyB, _ := New(emptyRoot, nil) for i, trie := range []*Trie{emptyA, emptyB} { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() if req := NewTrieSync(common.BytesToHash(trie.Root()), db, nil).Missing(1); len(req) != 0 { t.Errorf("test %d: content requested for empty trie: %v", i, req) } @@ -109,21 +110,27 @@ func testIterativeTrieSync(t *testing.T, batch int) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) queue := append([]common.Hash{}, sched.Missing(batch)...) for len(queue) > 0 { - results := make([]SyncResult, len(queue)) + results := make([]*SyncResult, len(queue)) for i, hash := range queue { - data, err := srcDb.Get(hash.Bytes()) - if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + if rand.Int()%2 == 0 { + data, err := srcDb.Get(hash.Bytes()) + if err != nil { + t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + } + results[i] = &SyncResult{Data: data} + } else { + results[i], _ = srcTrie.FetchData(hash, 8192) } - results[i] = SyncResult{Hash: hash, Data: data} } - if _, index, err := sched.Process(results); err != nil { - t.Fatalf("failed to process result #%d: %v", index, err) + for index, result := range results { + if _, _, err := sched.Process(result); err != nil { + t.Fatalf("failed to process result #%d: %v", index, err) + } } if index, err := sched.Commit(dstDb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) @@ -141,22 +148,28 @@ func TestIterativeDelayedTrieSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) queue := append([]common.Hash{}, sched.Missing(10000)...) for len(queue) > 0 { // Sync only half of the scheduled nodes - results := make([]SyncResult, len(queue)/2+1) + results := make([]*SyncResult, len(queue)/2+1) for i, hash := range queue[:len(results)] { - data, err := srcDb.Get(hash.Bytes()) - if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + if rand.Int()%2 == 0 { + data, err := srcDb.Get(hash.Bytes()) + if err != nil { + t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + } + results[i] = &SyncResult{Data: data} + } else { + results[i], _ = srcTrie.FetchData(hash, 8192) } - results[i] = SyncResult{Hash: hash, Data: data} } - if _, index, err := sched.Process(results); err != nil { - t.Fatalf("failed to process result #%d: %v", index, err) + for index, result := range results { + if _, _, err := sched.Process(result); err != nil { + t.Fatalf("failed to process result #%d: %v", index, err) + } } if index, err := sched.Commit(dstDb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) @@ -178,7 +191,7 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) queue := make(map[common.Hash]struct{}) @@ -187,17 +200,24 @@ func testIterativeRandomTrieSync(t *testing.T, batch int) { } for len(queue) > 0 { // Fetch all the queued nodes in a random order - results := make([]SyncResult, 0, len(queue)) + results := make([]*SyncResult, 0, len(queue)) for hash := range queue { - data, err := srcDb.Get(hash.Bytes()) - if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + if rand.Int()%2 == 0 { + data, err := srcDb.Get(hash.Bytes()) + if err != nil { + t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + } + results = append(results, &SyncResult{Data: data}) + } else { + request, _ := srcTrie.FetchData(hash, 8192) + results = append(results, request) } - results = append(results, SyncResult{Hash: hash, Data: data}) } // Feed the retrieved results back and queue new tasks - if _, index, err := sched.Process(results); err != nil { - t.Fatalf("failed to process result #%d: %v", index, err) + for index, result := range results { + if _, _, err := sched.Process(result); err != nil { + t.Fatalf("failed to process result #%d: %v", index, err) + } } if index, err := sched.Commit(dstDb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) @@ -218,7 +238,7 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) queue := make(map[common.Hash]struct{}) @@ -227,28 +247,33 @@ func TestIterativeRandomDelayedTrieSync(t *testing.T) { } for len(queue) > 0 { // Sync only half of the scheduled nodes, even those in random order - results := make([]SyncResult, 0, len(queue)/2+1) + results := make([]*SyncResult, 0, len(queue)/2+1) for hash := range queue { - data, err := srcDb.Get(hash.Bytes()) - if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + if rand.Int()%2 == 0 { + data, err := srcDb.Get(hash.Bytes()) + if err != nil { + t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + } + results = append(results, &SyncResult{Data: data}) + } else { + request, _ := srcTrie.FetchData(hash, 8192) + results = append(results, request) } - results = append(results, SyncResult{Hash: hash, Data: data}) - if len(results) >= cap(results) { break } } // Feed the retrieved results back and queue new tasks - if _, index, err := sched.Process(results); err != nil { - t.Fatalf("failed to process result #%d: %v", index, err) + for index, result := range results { + _, hash, err := sched.Process(result) + if err != nil { + t.Fatalf("failed to process result #%d: %v", index, err) + } + delete(queue, hash) } if index, err := sched.Commit(dstDb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } - for _, result := range results { - delete(queue, result.Hash) - } for _, hash := range sched.Missing(10000) { queue[hash] = struct{}{} } @@ -264,28 +289,34 @@ func TestDuplicateAvoidanceTrieSync(t *testing.T) { srcDb, srcTrie, srcData := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) queue := append([]common.Hash{}, sched.Missing(0)...) requested := make(map[common.Hash]struct{}) for len(queue) > 0 { - results := make([]SyncResult, len(queue)) + results := make([]*SyncResult, len(queue)) for i, hash := range queue { - data, err := srcDb.Get(hash.Bytes()) - if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) - } if _, ok := requested[hash]; ok { t.Errorf("hash %x already requested once", hash) } requested[hash] = struct{}{} - results[i] = SyncResult{Hash: hash, Data: data} + if rand.Int()%2 == 0 { + data, err := srcDb.Get(hash.Bytes()) + if err != nil { + t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + } + results[i] = &SyncResult{Data: data} + } else { + results[i], _ = srcTrie.FetchData(hash, 8192) + } } - if _, index, err := sched.Process(results); err != nil { - t.Fatalf("failed to process result #%d: %v", index, err) + for index, result := range results { + if _, _, err := sched.Process(result); err != nil { + t.Fatalf("failed to process result #%d: %v", index, err) + } } if index, err := sched.Commit(dstDb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) @@ -303,31 +334,36 @@ func TestIncompleteTrieSync(t *testing.T) { srcDb, srcTrie, _ := makeTestTrie() // Create a destination trie and sync with the scheduler - dstDb, _ := ethdb.NewMemDatabase() + dstDb := ethdb.NewMemDatabase() sched := NewTrieSync(common.BytesToHash(srcTrie.Root()), dstDb, nil) added := []common.Hash{} queue := append([]common.Hash{}, sched.Missing(1)...) for len(queue) > 0 { // Fetch a batch of trie nodes - results := make([]SyncResult, len(queue)) + results := make([]*SyncResult, len(queue)) for i, hash := range queue { - data, err := srcDb.Get(hash.Bytes()) - if err != nil { - t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + if rand.Int()%2 == 0 { + data, err := srcDb.Get(hash.Bytes()) + if err != nil { + t.Fatalf("failed to retrieve node data for %x: %v", hash, err) + } + results[i] = &SyncResult{Data: data} + } else { + results[i], _ = srcTrie.FetchData(hash, 8192) } - results[i] = SyncResult{Hash: hash, Data: data} } // Process each of the trie nodes - if _, index, err := sched.Process(results); err != nil { - t.Fatalf("failed to process result #%d: %v", index, err) + for index, result := range results { + _, hash, err := sched.Process(result) + if err != nil { + t.Fatalf("failed to process result #%d: %v", index, err) + } + added = append(added, hash) } if index, err := sched.Commit(dstDb); err != nil { t.Fatalf("failed to commit data #%d: %v", index, err) } - for _, result := range results { - added = append(added, result.Hash) - } // Check that all known sub-tries in the synced trie are complete for _, root := range added { if err := checkTrieConsistency(dstDb, root); err != nil { diff --git a/trie/trie.go b/trie/trie.go index 7f69a3d1de..d19aad272c 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -504,3 +504,40 @@ func (t *Trie) hashRoot(db DatabaseWriter) (node, node, error) { defer returnHasherToPool(h) return h.hash(t.root, db, true) } + +// FetchData retrieves synchronization data from the trie to send to remote +// nodes. +func (t *Trie) FetchData(hash common.Hash, limit common.StorageSize) (res *SyncResult, fail error) { + // If this method panics, hash points to a non-iterable trie; return individual node + defer func() { + if r := recover(); r != nil { + blob, err := t.db.Get(hash[:]) + if err != nil { + fail = err + } else { + res = &SyncResult{Data: blob} + } + } + }() + // Try to gather the necessary data as key-value pairs + result := new(SyncResult) + + trie, _ := New(hash, t.db) + it := NewIterator(trie.NodeIterator(nil)) + + size := common.StorageSize(0) + for size < limit && it.Next() { + result.Keys = append(result.Keys, common.CopyBytes(it.Key)) + result.Values = append(result.Values, common.CopyBytes(it.Value)) + + size += common.StorageSize(len(it.Key) + len(it.Value)) + } + // If we've went past our data allowance, prove the partial data + if size >= limit { + result.Proof = it.Prove() + if !it.Next() { + result.Proof = nil // Overflowing item was the last after all + } + } + return result, nil +} diff --git a/trie/trie_test.go b/trie/trie_test.go index 1c90950703..b55f2ae1c1 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -40,7 +40,7 @@ func init() { // Used for testing func newEmpty() *Trie { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() trie, _ := New(common.Hash{}, db) return trie } @@ -65,7 +65,7 @@ func TestNull(t *testing.T) { } func TestMissingRoot(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), db) if trie != nil { t.Error("New returned non-nil trie for invalid root") @@ -76,7 +76,7 @@ func TestMissingRoot(t *testing.T) { } func TestMissingNode(t *testing.T) { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() trie, _ := New(common.Hash{}, db) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") @@ -404,7 +404,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value { } func runRandTest(rt randTest) bool { - db, _ := ethdb.NewMemDatabase() + db := ethdb.NewMemDatabase() tr, _ := New(common.Hash{}, db) values := make(map[string]string) // tracks content of the trie