core, eth, les, trie: expand trie sync with leaf mode

This commit is contained in:
Péter Szilágyi 2017-10-10 14:57:15 +03:00
parent 486e795d1b
commit 458e760066
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
41 changed files with 447 additions and 249 deletions

View file

@ -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{})

View file

@ -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) != "" {

View file

@ -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

View file

@ -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 {

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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{})

View file

@ -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.

View file

@ -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()

View file

@ -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,

View file

@ -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)

View file

@ -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) {

View file

@ -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)

View file

@ -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)

View file

@ -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"))

View file

@ -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

View file

@ -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{}

View file

@ -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)}

View file

@ -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 (

View file

@ -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{

View file

@ -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)

View file

@ -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) {

View file

@ -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])
}

View file

@ -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) {

View file

@ -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 {

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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,

View file

@ -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)
}

View file

@ -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 {

View file

@ -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

View file

@ -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]

View file

@ -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)

View file

@ -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))

View file

@ -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

View file

@ -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)
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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