mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
core, eth, les, trie: expand trie sync with leaf mode
This commit is contained in:
parent
486e795d1b
commit
458e760066
41 changed files with 447 additions and 249 deletions
|
|
@ -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{})
|
||||
|
|
|
|||
|
|
@ -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) != "" {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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{})
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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{}
|
||||
|
|
|
|||
|
|
@ -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)}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
245
trie/sync.go
245
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
37
trie/trie.go
37
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue