diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 6f46fc1495..406ac5917b 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -35,8 +35,8 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/filters"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
@@ -51,8 +51,8 @@ var errGasEstimationFailed = errors.New("gas required exceeds allowance or alway
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
// the background. Its main purpose is to allow easily testing contract bindings.
type SimulatedBackend struct {
- database ethdb.Database // In memory database to store our testing data
- blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
+ database database.Database // In memory database to store our testing data
+ blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
mu sync.Mutex
pendingBlock *types.Block // Currently pending block that will be imported on request
@@ -66,7 +66,7 @@ type SimulatedBackend struct {
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
// for testing purposes.
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
- database := ethdb.NewMemDatabase()
+ database := rawdb.NewMemoryDatabase()
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
genesis.MustCommit(database)
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil)
@@ -422,12 +422,12 @@ func (m callmsg) Data() []byte { return m.CallMsg.Data }
// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
type filterBackend struct {
- db ethdb.Database
+ db database.Database
bc *core.BlockChain
}
-func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db }
-func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
+func (fb *filterBackend) ChainDb() database.Database { return fb.db }
+func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
if block == rpc.LatestBlockNumber {
diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go
index c732c8b574..bc5d00cfbe 100644
--- a/cmd/evm/runner.go
+++ b/cmd/evm/runner.go
@@ -31,10 +31,10 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/vm/runtime"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
cli "gopkg.in/urfave/cli.v1"
@@ -99,12 +99,12 @@ func runCmd(ctx *cli.Context) error {
if ctx.GlobalString(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
genesisConfig = gen
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := gen.ToBlock(db)
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
chainConfig = gen.Config
} else {
- statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
genesisConfig = new(core.Genesis)
}
if ctx.GlobalString(SenderFlag.Name) != "" {
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 6d41261f80..545250378c 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -29,14 +29,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
- "github.com/syndtr/goleveldb/leveldb/util"
"gopkg.in/urfave/cli.v1"
)
@@ -193,7 +192,7 @@ func initGenesis(ctx *cli.Context) error {
defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} {
- chaindb, err := stack.OpenDatabase(name, 0, 0)
+ chaindb, err := stack.OpenDatabase(name, 0, 0, "")
if err != nil {
utils.Fatalf("Failed to open database: %v", err)
}
@@ -201,6 +200,7 @@ func initGenesis(ctx *cli.Context) error {
if err != nil {
utils.Fatalf("Failed to write genesis block: %v", err)
}
+ chaindb.Close()
log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
}
return nil
@@ -213,8 +213,8 @@ func importChain(ctx *cli.Context) error {
stack := makeFullNode(ctx)
defer stack.Close()
- chain, chainDb := utils.MakeChain(ctx, stack)
- defer chainDb.Close()
+ chain, db := utils.MakeChain(ctx, stack)
+ defer db.Close()
// Start periodically gathering memory profiles
var peakMemAlloc, peakMemSys uint64
@@ -249,15 +249,13 @@ func importChain(ctx *cli.Context) error {
fmt.Printf("Import done in %v.\n\n", time.Since(start))
// Output pre-compaction stats mostly to see the import trashing
- db := chainDb.(*ethdb.LDBDatabase)
-
- stats, err := db.LDB().GetProperty("leveldb.stats")
+ stats, err := db.Stat("leveldb.stats")
if err != nil {
utils.Fatalf("Failed to read database stats: %v", err)
}
fmt.Println(stats)
- ioStats, err := db.LDB().GetProperty("leveldb.iostats")
+ ioStats, err := db.Stat("leveldb.iostats")
if err != nil {
utils.Fatalf("Failed to read database iostats: %v", err)
}
@@ -280,24 +278,24 @@ func importChain(ctx *cli.Context) error {
}
// Compact the entire database to more accurately measure disk io and print the stats
- start = time.Now()
+ /*start = time.Now()
fmt.Println("Compacting entire database...")
if err = db.LDB().CompactRange(util.Range{}); err != nil {
utils.Fatalf("Compaction failed: %v", err)
}
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
- stats, err = db.LDB().GetProperty("leveldb.stats")
+ stats, err = db.Stat("leveldb.stats")
if err != nil {
utils.Fatalf("Failed to read database stats: %v", err)
}
fmt.Println(stats)
- ioStats, err = db.LDB().GetProperty("leveldb.iostats")
+ ioStats, err = db.Stat("leveldb.iostats")
if err != nil {
utils.Fatalf("Failed to read database iostats: %v", err)
}
- fmt.Println(ioStats)
+ fmt.Println(ioStats)*/
return nil
}
@@ -344,10 +342,10 @@ func importPreimages(ctx *cli.Context) error {
stack := makeFullNode(ctx)
defer stack.Close()
- diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
+ db := utils.MakeChainDatabase(ctx, stack)
start := time.Now()
- if err := utils.ImportPreimages(diskdb, ctx.Args().First()); err != nil {
+ if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil {
utils.Fatalf("Import error: %v\n", err)
}
fmt.Printf("Import done in %v\n", time.Since(start))
@@ -362,10 +360,10 @@ func exportPreimages(ctx *cli.Context) error {
stack := makeFullNode(ctx)
defer stack.Close()
- diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
+ db := utils.MakeChainDatabase(ctx, stack)
start := time.Now()
- if err := utils.ExportPreimages(diskdb, ctx.Args().First()); err != nil {
+ if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v\n", time.Since(start))
@@ -374,9 +372,12 @@ func exportPreimages(ctx *cli.Context) error {
func copyDb(ctx *cli.Context) error {
// Ensure we have a source chain directory to copy
- if len(ctx.Args()) != 1 {
+ if len(ctx.Args()) < 1 {
utils.Fatalf("Source chaindata directory path argument missing")
}
+ if len(ctx.Args()) < 2 {
+ utils.Fatalf("Source ancient chain directory path argument missing")
+ }
// Initialize a new chain for the running node to sync into
stack := makeFullNode(ctx)
defer stack.Close()
@@ -386,7 +387,7 @@ func copyDb(ctx *cli.Context) error {
dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil)
// Create a source peer to satisfy downloader requests from
- db, err := ethdb.NewLDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256)
+ db, err := rawdb.NewLeveldbDatabaseWithFreezer(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name), 256, ctx.Args().Get(1), "")
if err != nil {
return err
}
@@ -411,12 +412,12 @@ func copyDb(ctx *cli.Context) error {
fmt.Printf("Database copy done in %v\n", time.Since(start))
// Compact the entire database to remove any sync overhead
- start = time.Now()
+ /*start = time.Now()
fmt.Println("Compacting entire database...")
if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil {
utils.Fatalf("Compaction failed: %v", err)
}
- fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
+ fmt.Printf("Compaction done in %v.\n\n", time.Since(start))*/
return nil
}
diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go
index 52983ff2af..dc75732806 100644
--- a/cmd/geth/dao_test.go
+++ b/cmd/geth/dao_test.go
@@ -25,7 +25,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -121,7 +120,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
}
// Retrieve the DAO config flag from the database
path := filepath.Join(datadir, "geth", "chaindata")
- db, err := ethdb.NewLDBDatabase(path, 0, 0)
+ db, err := rawdb.NewLeveldbDatabase(path, 0, 0, "")
if err != nil {
t.Fatalf("test %d: failed to open test database: %v", test, err)
}
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 17bf438e2a..2cee8cbc4e 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -61,6 +61,7 @@ var (
utils.BootnodesV4Flag,
utils.BootnodesV5Flag,
utils.DataDirFlag,
+ utils.AncientFlag,
utils.KeyStoreDirFlag,
utils.ExternalSignerFlag,
utils.NoUSBFlag,
diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go
index 0b5c6fd905..b003ebd2c5 100644
--- a/cmd/geth/usage.go
+++ b/cmd/geth/usage.go
@@ -69,6 +69,7 @@ var AppHelpFlagGroups = []flagGroup{
Flags: []cli.Flag{
configFileFlag,
utils.DataDirFlag,
+ utils.AncientFlag,
utils.KeyStoreDirFlag,
utils.NoUSBFlag,
utils.NetworkIdFlag,
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index f23aa5775b..f0383a275d 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -32,7 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
@@ -238,7 +238,7 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
}
// ImportPreimages imports a batch of exported hash preimages into the database.
-func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
+func ImportPreimages(db database.Database, fn string) error {
log.Info("Importing preimages", "file", fn)
// Open the file handle and potentially unwrap the gzip stream
@@ -285,7 +285,7 @@ func ImportPreimages(db *ethdb.LDBDatabase, fn string) error {
// ExportPreimages exports all known hash preimages into the specified file,
// truncating any data already present in the file.
-func ExportPreimages(db *ethdb.LDBDatabase, fn string) error {
+func ExportPreimages(db database.Database, fn string) error {
log.Info("Exporting preimages", "file", fn)
// Open the file handle and potentially wrap with a gzip stream
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 66f533102e..482d3dcfe3 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -41,10 +41,10 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/dashboard"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
@@ -120,6 +120,10 @@ var (
Usage: "Data directory for the databases and keystore",
Value: DirectoryString{node.DefaultDataDir()},
}
+ AncientFlag = DirectoryFlag{
+ Name: "datadir.ancient",
+ Usage: "Data directory for ancient chain segments (default = inside chaindata)",
+ }
KeyStoreDirFlag = DirectoryFlag{
Name: "keystore",
Usage: "Directory for the keystore (default = inside the datadir)",
@@ -1317,6 +1321,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
}
cfg.DatabaseHandles = makeDatabaseHandles()
+ if ctx.GlobalIsSet(AncientFlag.Name) {
+ cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name)
+ }
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
@@ -1526,7 +1533,7 @@ func SplitTagsFlag(tagsFlag string) map[string]string {
}
// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
-func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
+func MakeChainDatabase(ctx *cli.Context, stack *node.Node) database.Database {
var (
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
handles = makeDatabaseHandles()
@@ -1535,7 +1542,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
if ctx.GlobalString(SyncModeFlag.Name) == "light" {
name = "lightchaindata"
}
- chainDb, err := stack.OpenDatabase(name, cache, handles)
+ chainDb, err := stack.OpenDatabase(name, cache, handles, "")
if err != nil {
Fatalf("Could not open database: %v", err)
}
@@ -1558,7 +1565,7 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
}
// MakeChain creates a chain manager from set command line flags.
-func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
+func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb database.Database) {
var err error
chainDb = MakeChainDatabase(ctx, stack)
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go
index 967a843dec..2c60ff3107 100644
--- a/consensus/clique/clique.go
+++ b/consensus/clique/clique.go
@@ -34,7 +34,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
@@ -170,7 +170,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er
// Ethereum testnet following the Ropsten attacks.
type Clique struct {
config *params.CliqueConfig // Consensus engine configuration parameters
- db ethdb.Database // Database to store and retrieve snapshot checkpoints
+ db database.Database // Database to store and retrieve snapshot checkpoints
recents *lru.ARCCache // Snapshots for recent block to speed up reorgs
signatures *lru.ARCCache // Signatures of recent blocks to speed up mining
@@ -187,7 +187,7 @@ type Clique struct {
// New creates a Clique proof-of-authority consensus engine with the initial
// signers set to the ones provided by the user.
-func New(config *params.CliqueConfig, db ethdb.Database) *Clique {
+func New(config *params.CliqueConfig, db database.Database) *Clique {
// Set any missing consensus parameters to their defaults
conf := *config
if conf.Epoch == 0 {
diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go
index 54d4555f3b..5270f8e390 100644
--- a/consensus/clique/snapshot.go
+++ b/consensus/clique/snapshot.go
@@ -23,7 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
lru "github.com/hashicorp/golang-lru"
)
@@ -84,7 +84,7 @@ func newSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, number uin
}
// loadSnapshot loads an existing snapshot from the database.
-func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
+func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db database.Database, hash common.Hash) (*Snapshot, error) {
blob, err := db.Get(append([]byte("clique-"), hash[:]...))
if err != nil {
return nil, err
@@ -100,7 +100,7 @@ func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.
}
// store inserts the snapshot into the database.
-func (s *Snapshot) store(db ethdb.Database) error {
+func (s *Snapshot) store(db database.Database) error {
blob, err := json.Marshal(s)
if err != nil {
return err
diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go
index b920312a89..47c25aa040 100644
--- a/consensus/clique/snapshot_test.go
+++ b/consensus/clique/snapshot_test.go
@@ -24,10 +24,10 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -400,7 +400,7 @@ func TestClique(t *testing.T) {
copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:])
}
// Create a pristine blockchain with the genesis injected
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis.Commit(db)
// Assemble a chain of headers from the cast votes
diff --git a/core/bench_test.go b/core/bench_test.go
index 53cba05170..6defa98efc 100644
--- a/core/bench_test.go
+++ b/core/bench_test.go
@@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
)
@@ -148,16 +148,16 @@ func genUncles(i int, gen *BlockGen) {
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
+ var db database.Database
if !disk {
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
} else {
dir, err := ioutil.TempDir("", "eth-core-bench")
if err != nil {
b.Fatalf("cannot create temporary directory: %v", err)
}
defer os.RemoveAll(dir)
- db, err = ethdb.NewLDBDatabase(dir, 128, 128)
+ db, err = rawdb.NewLeveldbDatabase(dir, 128, 128, "")
if err != nil {
b.Fatalf("cannot create temporary database: %v", err)
}
@@ -223,7 +223,7 @@ func BenchmarkChainWrite_full_500k(b *testing.B) {
// makeChainForBench writes a given number of headers or empty blocks/receipts
// into a database.
-func makeChainForBench(db ethdb.Database, full bool, count uint64) {
+func makeChainForBench(db database.Database, full bool, count uint64) {
var hash common.Hash
for n := uint64(0); n < count; n++ {
header := &types.Header{
@@ -255,7 +255,7 @@ func benchWriteChain(b *testing.B, full bool, count uint64) {
if err != nil {
b.Fatalf("cannot create temporary directory: %v", err)
}
- db, err := ethdb.NewLDBDatabase(dir, 128, 1024)
+ db, err := rawdb.NewLeveldbDatabase(dir, 128, 1024, "")
if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err)
}
@@ -272,7 +272,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
}
defer os.RemoveAll(dir)
- db, err := ethdb.NewLDBDatabase(dir, 128, 1024)
+ db, err := rawdb.NewLeveldbDatabase(dir, 128, 1024, "")
if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err)
}
@@ -283,7 +283,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
- db, err := ethdb.NewLDBDatabase(dir, 128, 1024)
+ db, err := rawdb.NewLeveldbDatabase(dir, 128, 1024, "")
if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err)
}
diff --git a/core/block_validator_test.go b/core/block_validator_test.go
index 9319a7835d..06e2ba1a4f 100644
--- a/core/block_validator_test.go
+++ b/core/block_validator_test.go
@@ -22,9 +22,9 @@ import (
"time"
"github.com/ethereum/go-ethereum/consensus/ethash"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -32,7 +32,7 @@ import (
func TestHeaderVerification(t *testing.T) {
// Create a simple chain to verify
var (
- testdb = ethdb.NewMemDatabase()
+ testdb = rawdb.NewMemoryDatabase()
gspec = &Genesis{Config: params.TestChainConfig}
genesis = gspec.MustCommit(testdb)
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), 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 = rawdb.NewMemoryDatabase()
gspec = &Genesis{Config: params.TestChainConfig}
genesis = gspec.MustCommit(testdb)
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), 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 = rawdb.NewMemoryDatabase()
gspec = &Genesis{Config: params.TestChainConfig}
genesis = gspec.MustCommit(testdb)
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil)
diff --git a/core/blockchain.go b/core/blockchain.go
index feb9fb9426..bf1c8dd182 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -36,7 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@@ -95,9 +95,9 @@ type BlockChain struct {
chainConfig *params.ChainConfig // Chain & network configuration
cacheConfig *CacheConfig // Cache configuration for pruning
- db ethdb.Database // Low level persistent database to store final content in
- triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
- gcproc time.Duration // Accumulates canonical block processing for trie dumping
+ db database.Database // Low level persistent database to store final content in
+ triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
+ gcproc time.Duration // Accumulates canonical block processing for trie dumping
hc *HeaderChain
rmLogsFeed event.Feed
@@ -140,7 +140,7 @@ type BlockChain struct {
// NewBlockChain returns a fully initialised block chain using information
// available in the database. It initialises the default Ethereum Validator and
// Processor.
-func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) {
+func NewBlockChain(db database.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) {
if cacheConfig == nil {
cacheConfig = &CacheConfig{
TrieCleanLimit: 256,
@@ -284,7 +284,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
defer bc.chainmu.Unlock()
// Rewind the header chain, deleting all block bodies until then
- delFn := func(db rawdb.DatabaseDeleter, hash common.Hash, num uint64) {
+ delFn := func(db database.Deleter, hash common.Hash, num uint64) {
rawdb.DeleteBody(db, hash, num)
}
bc.hc.SetHead(head, delFn)
@@ -866,7 +866,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
stats.processed++
- if batch.ValueSize() >= ethdb.IdealBatchSize {
+ if batch.ValueSize() >= database.IdealBatchSize {
if err := batch.Write(); err != nil {
return 0, err
}
@@ -976,7 +976,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
)
if nodes > limit || imgs > 4*1024*1024 {
- triedb.Cap(limit - ethdb.IdealBatchSize)
+ triedb.Cap(limit - database.IdealBatchSize)
}
// Find the next state trie we need to commit
chosen := current - triesInMemory
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index fa68c2894a..9fc7c344da 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -32,7 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
)
@@ -45,9 +45,9 @@ var (
// newCanonical creates a chain database, and injects a deterministic canonical
// chain. Depending on the full flag, if creates either a full block chain or a
// header only chain.
-func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) {
+func newCanonical(engine consensus.Engine, n int, full bool) (database.Database, *BlockChain, error) {
var (
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
genesis = new(Genesis).MustCommit(db)
)
@@ -603,7 +603,7 @@ func testInsertNonceError(t *testing.T, full bool) {
func TestFastVsFullChains(t *testing.T) {
// Configure and generate a sample block chain
var (
- gendb = ethdb.NewMemDatabase()
+ gendb = rawdb.NewMemoryDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
@@ -633,7 +633,7 @@ func TestFastVsFullChains(t *testing.T) {
}
})
// Import the chain as an archive node for the comparison baseline
- archiveDb := ethdb.NewMemDatabase()
+ archiveDb := rawdb.NewMemoryDatabase()
gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
defer archive.Stop()
@@ -642,7 +642,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 := rawdb.NewMemoryDatabase()
gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
defer fast.Stop()
@@ -691,7 +691,7 @@ func TestFastVsFullChains(t *testing.T) {
func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Configure and generate a sample block chain
var (
- gendb = ethdb.NewMemDatabase()
+ gendb = rawdb.NewMemoryDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
@@ -719,7 +719,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
}
}
// Import the chain as an archive node and ensure all pointers are updated
- archiveDb := ethdb.NewMemDatabase()
+ archiveDb := rawdb.NewMemoryDatabase()
gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
@@ -733,7 +733,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 := rawdb.NewMemoryDatabase()
gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
defer fast.Stop()
@@ -753,7 +753,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 := rawdb.NewMemoryDatabase()
gspec.MustCommit(lightDb)
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
@@ -776,7 +776,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 = rawdb.NewMemoryDatabase()
gspec = &Genesis{
Config: params.TestChainConfig,
GasLimit: 3141592,
@@ -888,7 +888,7 @@ func TestLogReorgs(t *testing.T) {
var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
// this code generates a log
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
@@ -932,7 +932,7 @@ func TestLogReorgs(t *testing.T) {
func TestReorgSideEvent(t *testing.T) {
var (
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
gspec = &Genesis{
@@ -1060,7 +1060,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
func TestEIP155Transition(t *testing.T) {
// Configure and generate a sample block chain
var (
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
@@ -1163,7 +1163,7 @@ func TestEIP155Transition(t *testing.T) {
func TestEIP161AccountRemoval(t *testing.T) {
// Configure and generate a sample block chain
var (
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000)
@@ -1235,7 +1235,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
// Generate a canonical chain to act as the main dataset
engine := ethash.NewFaker()
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := new(Genesis).MustCommit(db)
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
@@ -1251,7 +1251,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
}
// Import the canonical and fork chain side by side, verifying the current block
// and current header consistency
- diskdb := ethdb.NewMemDatabase()
+ diskdb := rawdb.NewMemoryDatabase()
new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
@@ -1280,7 +1280,7 @@ func TestTrieForkGC(t *testing.T) {
// Generate a canonical chain to act as the main dataset
engine := ethash.NewFaker()
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := new(Genesis).MustCommit(db)
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
@@ -1295,7 +1295,7 @@ func TestTrieForkGC(t *testing.T) {
forks[i] = fork[0]
}
// Import the canonical and fork chain side by side, forcing the trie cache to cache both
- diskdb := ethdb.NewMemDatabase()
+ diskdb := rawdb.NewMemoryDatabase()
new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
@@ -1326,7 +1326,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
// Generate the original common chain segment and the two competing forks
engine := ethash.NewFaker()
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := new(Genesis).MustCommit(db)
shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
@@ -1334,7 +1334,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
competitor, _ := GenerateChain(params.TestChainConfig, shared[len(shared)-1], engine, db, 2*triesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
// Import the shared chain and the original canonical one
- diskdb := ethdb.NewMemDatabase()
+ diskdb := rawdb.NewMemoryDatabase()
new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
@@ -1394,7 +1394,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
)
// Generate the original common chain segment and the two competing forks
engine := ethash.NewFaker()
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := gspec.MustCommit(db)
blockGenerator := func(i int, block *BlockGen) {
@@ -1416,7 +1416,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Import the shared chain and the original canonical one
- diskdb := ethdb.NewMemDatabase()
+ diskdb := rawdb.NewMemoryDatabase()
gspec.MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
@@ -1494,7 +1494,7 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) {
func TestLowDiffLongChain(t *testing.T) {
// Generate a canonical chain to act as the main dataset
engine := ethash.NewFaker()
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
genesis := new(Genesis).MustCommit(db)
// We must use a pretty long chain to ensure that the fork doesn't overtake us
@@ -1505,7 +1505,7 @@ func TestLowDiffLongChain(t *testing.T) {
})
// Import the canonical chain
- diskdb := ethdb.NewMemDatabase()
+ diskdb := rawdb.NewMemoryDatabase()
new(Genesis).MustCommit(diskdb)
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
diff --git a/core/chain_indexer.go b/core/chain_indexer.go
index 1adde1fcb4..2234dd9e81 100644
--- a/core/chain_indexer.go
+++ b/core/chain_indexer.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
)
@@ -67,8 +67,8 @@ type ChainIndexerChain interface {
// after an entire section has been finished or in case of rollbacks that might
// affect already finished sections.
type ChainIndexer struct {
- chainDb ethdb.Database // Chain database to index the data from
- indexDb ethdb.Database // Prefixed table-view of the db to write index metadata into
+ chainDb database.Database // Chain database to index the data from
+ indexDb database.Database // Prefixed table-view of the db to write index metadata into
backend ChainIndexerBackend // Background processor generating the index data content
children []*ChainIndexer // Child indexers to cascade chain updates to
@@ -97,7 +97,7 @@ type ChainIndexer struct {
// NewChainIndexer creates a new chain indexer to do background processing on
// chain segments of a given size after certain number of confirmations passed.
// The throttling parameter might be used to prevent database thrashing.
-func NewChainIndexer(chainDb, indexDb ethdb.Database, backend ChainIndexerBackend, section, confirm uint64, throttling time.Duration, kind string) *ChainIndexer {
+func NewChainIndexer(chainDb database.Database, indexDb database.Database, backend ChainIndexerBackend, section, confirm uint64, throttling time.Duration, kind string) *ChainIndexer {
c := &ChainIndexer{
chainDb: chainDb,
indexDb: indexDb,
diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go
index a029dec626..abf5b3cc14 100644
--- a/core/chain_indexer_test.go
+++ b/core/chain_indexer_test.go
@@ -27,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
)
// Runs multiple tests with randomized parameters.
@@ -49,7 +48,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 := rawdb.NewMemoryDatabase()
defer db.Close()
// Create a chain of indexers and ensure they all report empty
@@ -60,7 +59,7 @@ func testChainIndexer(t *testing.T, count int) {
confirmsReq = uint64(rand.Intn(10))
)
backends[i] = &testChainIndexBackend{t: t, processCh: make(chan uint64)}
- backends[i].indexer = NewChainIndexer(db, ethdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i))
+ backends[i].indexer = NewChainIndexer(db, rawdb.NewTable(db, string([]byte{byte(i)})), backends[i], sectionSize, confirmsReq, 0, fmt.Sprintf("indexer-%d", i))
if sections, _, _ := backends[i].indexer.Sections(); sections != 0 {
t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0)
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 0b5a3d1843..48a215bb83 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
)
@@ -169,7 +169,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
// Blocks created by GenerateChain do not contain valid proof of work
// values. Inserting them into BlockChain requires use of FakePow or
// a similar non-validating proof of work implementation.
-func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
+func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db database.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
if config == nil {
config = params.TestChainConfig
}
@@ -249,7 +249,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
}
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
-func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Header {
+func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db database.Database, seed int) []*types.Header {
blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed)
headers := make([]*types.Header, len(blocks))
for i, block := range blocks {
@@ -259,7 +259,7 @@ func makeHeaderChain(parent *types.Header, n int, engine consensus.Engine, db et
}
// makeBlockChain creates a deterministic chain of blocks rooted at parent.
-func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db ethdb.Database, seed int) []*types.Block {
+func makeBlockChain(parent *types.Block, n int, engine consensus.Engine, db database.Database, seed int) []*types.Block {
blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
})
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index 64b64fd6a3..32e3888d55 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -21,10 +21,10 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/consensus/ethash"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -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 = rawdb.NewMemoryDatabase()
)
// Ensure that key1 has some funds in the genesis block.
diff --git a/core/dao_test.go b/core/dao_test.go
index 966139bce3..4e8dba9e84 100644
--- a/core/dao_test.go
+++ b/core/dao_test.go
@@ -21,8 +21,8 @@ import (
"testing"
"github.com/ethereum/go-ethereum/consensus/ethash"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -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 := rawdb.NewMemoryDatabase()
gspec := new(Genesis)
genesis := gspec.MustCommit(db)
prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
// Create the concurrent, conflicting two nodes
- proDb := ethdb.NewMemDatabase()
+ proDb := rawdb.NewMemoryDatabase()
gspec.MustCommit(proDb)
proConf := *params.TestChainConfig
@@ -48,7 +48,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
defer proBc.Stop()
- conDb := ethdb.NewMemDatabase()
+ conDb := rawdb.NewMemoryDatabase()
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 = rawdb.NewMemoryDatabase()
gspec.MustCommit(db)
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
defer bc.Stop()
@@ -92,7 +92,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 = rawdb.NewMemoryDatabase()
gspec.MustCommit(db)
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
defer bc.Stop()
@@ -118,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
}
}
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
gspec.MustCommit(db)
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
defer bc.Stop()
@@ -138,7 +138,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 = rawdb.NewMemoryDatabase()
gspec.MustCommit(db)
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
defer bc.Stop()
diff --git a/core/genesis.go b/core/genesis.go
index cbb6eecd28..c5576bcf91 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -31,7 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
@@ -134,7 +134,7 @@ type GenesisMismatchError struct {
}
func (e *GenesisMismatchError) Error() string {
- return fmt.Sprintf("database already contains an incompatible genesis block (have %x, new %x)", e.Stored[:8], e.New[:8])
+ return fmt.Sprintf("database contains incompatible genesis (have %x, new %x)", e.Stored, e.New)
}
// SetupGenesisBlock writes or updates the genesis block in db.
@@ -150,10 +150,10 @@ func (e *GenesisMismatchError) Error() string {
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
//
// The returned chain configuration is never nil.
-func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
+func SetupGenesisBlock(db database.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlockWithOverride(db, genesis, nil)
}
-func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, constantinopleOverride *big.Int) (*params.ChainConfig, common.Hash, error) {
+func SetupGenesisBlockWithOverride(db database.Database, genesis *Genesis, constantinopleOverride *big.Int) (*params.ChainConfig, common.Hash, error) {
if genesis != nil && genesis.Config == nil {
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
}
@@ -226,9 +226,9 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
// ToBlock creates the genesis block and writes state of a genesis specification
// to the given database (or discards it if nil).
-func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
+func (g *Genesis) ToBlock(db database.Database) *types.Block {
if db == nil {
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
}
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
for addr, account := range g.Alloc {
@@ -267,7 +267,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
// Commit writes the block and state of a genesis specification to the database.
// The block is committed as the canonical head block.
-func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
+func (g *Genesis) Commit(db database.Database) (*types.Block, error) {
block := g.ToBlock(db)
if block.Number().Sign() != 0 {
return nil, fmt.Errorf("can't commit genesis block with number > 0")
@@ -289,7 +289,7 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
// MustCommit writes the genesis block and state to db, panicking on error.
// The block is committed as the canonical head block.
-func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
+func (g *Genesis) MustCommit(db database.Database) *types.Block {
block, err := g.Commit(db)
if err != nil {
panic(err)
@@ -298,7 +298,7 @@ func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
}
// GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
-func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
+func GenesisBlockForTesting(db database.Database, addr common.Address, balance *big.Int) *types.Block {
g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
return g.MustCommit(db)
}
diff --git a/core/genesis_test.go b/core/genesis_test.go
index c7d54f2057..aa5ecb4bcb 100644
--- a/core/genesis_test.go
+++ b/core/genesis_test.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
)
@@ -55,14 +55,14 @@ func TestSetupGenesis(t *testing.T) {
oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)}
tests := []struct {
name string
- fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
+ fn func(database.Database) (*params.ChainConfig, common.Hash, error)
wantConfig *params.ChainConfig
wantHash common.Hash
wantErr error
}{
{
name: "genesis without ChainConfig",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, new(Genesis))
},
wantErr: errGenesisNoConfig,
@@ -70,7 +70,7 @@ func TestSetupGenesis(t *testing.T) {
},
{
name: "no block in DB, genesis == nil",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainnetGenesisHash,
@@ -78,7 +78,7 @@ func TestSetupGenesis(t *testing.T) {
},
{
name: "mainnet block in DB, genesis == nil",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
DefaultGenesisBlock().MustCommit(db)
return SetupGenesisBlock(db, nil)
},
@@ -87,7 +87,7 @@ func TestSetupGenesis(t *testing.T) {
},
{
name: "custom block in DB, genesis == nil",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, nil)
},
@@ -96,7 +96,7 @@ func TestSetupGenesis(t *testing.T) {
},
{
name: "custom block in DB, genesis == testnet",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
},
@@ -106,7 +106,7 @@ func TestSetupGenesis(t *testing.T) {
},
{
name: "compatible config in DB",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
oldcustomg.MustCommit(db)
return SetupGenesisBlock(db, &customg)
},
@@ -115,7 +115,7 @@ func TestSetupGenesis(t *testing.T) {
},
{
name: "incompatible config in DB",
- fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
+ fn: func(db database.Database) (*params.ChainConfig, common.Hash, error) {
// Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg.
genesis := oldcustomg.MustCommit(db)
@@ -141,7 +141,7 @@ func TestSetupGenesis(t *testing.T) {
}
for _, test := range tests {
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
config, hash, err := test.fn(db)
// Check the return values.
if !reflect.DeepEqual(err, test.wantErr) {
diff --git a/core/headerchain.go b/core/headerchain.go
index 8904dd887b..4909aa471e 100644
--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/hashicorp/golang-lru"
@@ -50,7 +50,7 @@ const (
type HeaderChain struct {
config *params.ChainConfig
- chainDb ethdb.Database
+ chainDb database.Database
genesisHeader *types.Header
currentHeader atomic.Value // Current head of the header chain (may be above the block chain!)
@@ -70,7 +70,7 @@ type HeaderChain struct {
// getValidator should return the parent's validator
// procInterrupt points to the parent's interrupt semaphore
// wg points to the parent's shutdown wait group
-func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) {
+func NewHeaderChain(chainDb database.Database, config *params.ChainConfig, engine consensus.Engine, procInterrupt func() bool) (*HeaderChain, error) {
headerCache, _ := lru.New(headerCacheLimit)
tdCache, _ := lru.New(tdCacheLimit)
numberCache, _ := lru.New(numberCacheLimit)
@@ -455,7 +455,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
// DeleteCallback is a callback function that is called by SetHead before
// each header is deleted.
-type DeleteCallback func(rawdb.DatabaseDeleter, common.Hash, uint64)
+type DeleteCallback func(database.Deleter, common.Hash, uint64)
// SetHead rewinds the local chain to a new head. Everything above the new head
// will be deleted and the new one set.
diff --git a/core/helper_test.go b/core/helper_test.go
index 051384d854..e55609fc3b 100644
--- a/core/helper_test.go
+++ b/core/helper_test.go
@@ -19,8 +19,9 @@ package core
import (
"container/list"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
)
@@ -29,7 +30,7 @@ type TestManager struct {
// stateManager *StateManager
eventMux *event.TypeMux
- db ethdb.Database
+ db database.Database
txPool *TxPool
blockChain *BlockChain
Blocks []*types.Block
@@ -71,14 +72,14 @@ func (tm *TestManager) EventMux() *event.TypeMux {
// return nil
// }
-func (tm *TestManager) Db() ethdb.Database {
+func (tm *TestManager) Db() database.Database {
return tm.db
}
func NewTestManager() *TestManager {
testManager := &TestManager{}
testManager.eventMux = new(event.TypeMux)
- testManager.db = ethdb.NewMemDatabase()
+ testManager.db = rawdb.NewMemoryDatabase()
// testManager.txPool = NewTxPool(testManager)
// testManager.blockChain = NewBlockChain(testManager)
// testManager.stateManager = NewStateManager(testManager)
diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go
index 491a125c65..0a362dd09a 100644
--- a/core/rawdb/accessors_chain.go
+++ b/core/rawdb/accessors_chain.go
@@ -23,13 +23,17 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
-func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
- data, _ := db.Get(headerHashKey(number))
+func ReadCanonicalHash(db database.AncientReader, number uint64) common.Hash {
+ data, _ := db.Ancient("hashes", number)
+ if len(data) == 0 {
+ data, _ = db.Get(headerHashKey(number))
+ }
if len(data) == 0 {
return common.Hash{}
}
@@ -37,21 +41,39 @@ func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
}
// WriteCanonicalHash stores the hash assigned to a canonical block number.
-func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
+func WriteCanonicalHash(db database.Writer, hash common.Hash, number uint64) {
if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {
log.Crit("Failed to store number to hash mapping", "err", err)
}
}
// DeleteCanonicalHash removes the number to hash canonical mapping.
-func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
+func DeleteCanonicalHash(db database.Deleter, number uint64) {
if err := db.Delete(headerHashKey(number)); err != nil {
log.Crit("Failed to delete number to hash mapping", "err", err)
}
}
+// readAllHashes retrieves all the hashes assigned to blocks at a certain heights,
+// both canonical and reorged forks included.
+//
+// This method is a helper for the chain reader. It should never be exposed to the
+// outside world.
+func readAllHashes(db database.Iteratorer, number uint64) []common.Hash {
+ prefix := headerKeyPrefix(number)
+
+ hashes := make([]common.Hash, 0, 1)
+ it := db.NewIteratorWithPrefix(prefix)
+ for it.Next() {
+ if key := it.Key(); len(key) == len(prefix)+32 {
+ hashes = append(hashes, common.BytesToHash(key[len(key)-32:]))
+ }
+ }
+ return hashes
+}
+
// ReadHeaderNumber returns the header number assigned to a hash.
-func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
+func ReadHeaderNumber(db database.Reader, hash common.Hash) *uint64 {
data, _ := db.Get(headerNumberKey(hash))
if len(data) != 8 {
return nil
@@ -61,7 +83,7 @@ func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
}
// ReadHeadHeaderHash retrieves the hash of the current canonical head header.
-func ReadHeadHeaderHash(db DatabaseReader) common.Hash {
+func ReadHeadHeaderHash(db database.Reader) common.Hash {
data, _ := db.Get(headHeaderKey)
if len(data) == 0 {
return common.Hash{}
@@ -70,14 +92,14 @@ func ReadHeadHeaderHash(db DatabaseReader) common.Hash {
}
// WriteHeadHeaderHash stores the hash of the current canonical head header.
-func WriteHeadHeaderHash(db DatabaseWriter, hash common.Hash) {
+func WriteHeadHeaderHash(db database.Writer, hash common.Hash) {
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last header's hash", "err", err)
}
}
// ReadHeadBlockHash retrieves the hash of the current canonical head block.
-func ReadHeadBlockHash(db DatabaseReader) common.Hash {
+func ReadHeadBlockHash(db database.Reader) common.Hash {
data, _ := db.Get(headBlockKey)
if len(data) == 0 {
return common.Hash{}
@@ -86,14 +108,14 @@ func ReadHeadBlockHash(db DatabaseReader) common.Hash {
}
// WriteHeadBlockHash stores the head block's hash.
-func WriteHeadBlockHash(db DatabaseWriter, hash common.Hash) {
+func WriteHeadBlockHash(db database.Writer, hash common.Hash) {
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last block's hash", "err", err)
}
}
// ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block.
-func ReadHeadFastBlockHash(db DatabaseReader) common.Hash {
+func ReadHeadFastBlockHash(db database.Reader) common.Hash {
data, _ := db.Get(headFastBlockKey)
if len(data) == 0 {
return common.Hash{}
@@ -102,7 +124,7 @@ func ReadHeadFastBlockHash(db DatabaseReader) common.Hash {
}
// WriteHeadFastBlockHash stores the hash of the current fast-sync head block.
-func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) {
+func WriteHeadFastBlockHash(db database.Writer, hash common.Hash) {
if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil {
log.Crit("Failed to store last fast block's hash", "err", err)
}
@@ -110,7 +132,7 @@ func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) {
// ReadFastTrieProgress retrieves the number of tries nodes fast synced to allow
// reporting correct numbers across restarts.
-func ReadFastTrieProgress(db DatabaseReader) uint64 {
+func ReadFastTrieProgress(db database.Reader) uint64 {
data, _ := db.Get(fastTrieProgressKey)
if len(data) == 0 {
return 0
@@ -120,20 +142,26 @@ func ReadFastTrieProgress(db DatabaseReader) uint64 {
// WriteFastTrieProgress stores the fast sync trie process counter to support
// retrieving it across restarts.
-func WriteFastTrieProgress(db DatabaseWriter, count uint64) {
+func WriteFastTrieProgress(db database.Writer, count uint64) {
if err := db.Put(fastTrieProgressKey, new(big.Int).SetUint64(count).Bytes()); err != nil {
log.Crit("Failed to store fast sync trie progress", "err", err)
}
}
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
-func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
- data, _ := db.Get(headerKey(number, hash))
+func ReadHeaderRLP(db database.AncientReader, hash common.Hash, number uint64) rlp.RawValue {
+ data, _ := db.Ancient("headers", number)
+ if len(data) == 0 {
+ data, _ = db.Get(headerKey(number, hash))
+ }
return data
}
// HasHeader verifies the existence of a block header corresponding to the hash.
-func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
+func HasHeader(db database.AncientReader, hash common.Hash, number uint64) bool {
+ if has, err := db.Ancient("hashes", number); err == nil && common.BytesToHash(has) == hash {
+ return true
+ }
if has, err := db.Has(headerKey(number, hash)); !has || err != nil {
return false
}
@@ -141,7 +169,7 @@ func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
}
// ReadHeader retrieves the block header corresponding to the hash.
-func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header {
+func ReadHeader(db database.AncientReader, hash common.Hash, number uint64) *types.Header {
data := ReadHeaderRLP(db, hash, number)
if len(data) == 0 {
return nil
@@ -156,7 +184,7 @@ func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Heade
// WriteHeader stores a block header into the database and also stores the hash-
// to-number mapping.
-func WriteHeader(db DatabaseWriter, header *types.Header) {
+func WriteHeader(db database.Writer, header *types.Header) {
// Write the hash -> number mapping
var (
hash = header.Hash()
@@ -179,30 +207,42 @@ func WriteHeader(db DatabaseWriter, header *types.Header) {
}
// DeleteHeader removes all block header data associated with a hash.
-func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
- if err := db.Delete(headerKey(number, hash)); err != nil {
- log.Crit("Failed to delete header", "err", err)
- }
+func DeleteHeader(db database.Deleter, hash common.Hash, number uint64) {
+ deleteHeaderWithoutNumber(db, hash, number)
if err := db.Delete(headerNumberKey(hash)); err != nil {
log.Crit("Failed to delete hash to number mapping", "err", err)
}
}
+// deleteHeaderWithoutNumber removes only the block header but does not remove
+// the hash to number mapping.
+func deleteHeaderWithoutNumber(db database.Deleter, hash common.Hash, number uint64) {
+ if err := db.Delete(headerKey(number, hash)); err != nil {
+ log.Crit("Failed to delete header", "err", err)
+ }
+}
+
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
-func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
- data, _ := db.Get(blockBodyKey(number, hash))
+func ReadBodyRLP(db database.AncientReader, hash common.Hash, number uint64) rlp.RawValue {
+ data, _ := db.Ancient("bodies", number)
+ if len(data) == 0 {
+ data, _ = db.Get(blockBodyKey(number, hash))
+ }
return data
}
// WriteBodyRLP stores an RLP encoded block body into the database.
-func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
+func WriteBodyRLP(db database.Writer, hash common.Hash, number uint64, rlp rlp.RawValue) {
if err := db.Put(blockBodyKey(number, hash), rlp); err != nil {
log.Crit("Failed to store block body", "err", err)
}
}
// HasBody verifies the existence of a block body corresponding to the hash.
-func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
+func HasBody(db database.AncientReader, hash common.Hash, number uint64) bool {
+ if has, err := db.Ancient("hashes", number); err == nil && common.BytesToHash(has) == hash {
+ return true
+ }
if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil {
return false
}
@@ -210,7 +250,7 @@ func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
}
// ReadBody retrieves the block body corresponding to the hash.
-func ReadBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
+func ReadBody(db database.AncientReader, hash common.Hash, number uint64) *types.Body {
data := ReadBodyRLP(db, hash, number)
if len(data) == 0 {
return nil
@@ -224,7 +264,7 @@ func ReadBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
}
// WriteBody storea a block body into the database.
-func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.Body) {
+func WriteBody(db database.Writer, hash common.Hash, number uint64, body *types.Body) {
data, err := rlp.EncodeToBytes(body)
if err != nil {
log.Crit("Failed to RLP encode body", "err", err)
@@ -233,15 +273,24 @@ func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.B
}
// DeleteBody removes all block body data associated with a hash.
-func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
+func DeleteBody(db database.Deleter, hash common.Hash, number uint64) {
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
}
+// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding.
+func ReadTdRLP(db database.AncientReader, hash common.Hash, number uint64) rlp.RawValue {
+ data, _ := db.Ancient("diffs", number)
+ if len(data) == 0 {
+ data, _ = db.Get(headerTDKey(number, hash))
+ }
+ return data
+}
+
// ReadTd retrieves a block's total difficulty corresponding to the hash.
-func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
- data, _ := db.Get(headerTDKey(number, hash))
+func ReadTd(db database.AncientReader, hash common.Hash, number uint64) *big.Int {
+ data := ReadTdRLP(db, hash, number)
if len(data) == 0 {
return nil
}
@@ -254,7 +303,7 @@ func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
}
// WriteTd stores the total difficulty of a block into the database.
-func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) {
+func WriteTd(db database.Writer, hash common.Hash, number uint64, td *big.Int) {
data, err := rlp.EncodeToBytes(td)
if err != nil {
log.Crit("Failed to RLP encode block total difficulty", "err", err)
@@ -265,7 +314,7 @@ func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) {
}
// DeleteTd removes all block total difficulty data associated with a hash.
-func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
+func DeleteTd(db database.Deleter, hash common.Hash, number uint64) {
if err := db.Delete(headerTDKey(number, hash)); err != nil {
log.Crit("Failed to delete block total difficulty", "err", err)
}
@@ -273,17 +322,29 @@ func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
// HasReceipts verifies the existence of all the transaction receipts belonging
// to a block.
-func HasReceipts(db DatabaseReader, hash common.Hash, number uint64) bool {
+func HasReceipts(db database.AncientReader, hash common.Hash, number uint64) bool {
+ if has, err := db.Ancient("hashes", number); err == nil && common.BytesToHash(has) == hash {
+ return true
+ }
if has, err := db.Has(blockReceiptsKey(number, hash)); !has || err != nil {
return false
}
return true
}
+// ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding.
+func ReadReceiptsRLP(db database.AncientReader, hash common.Hash, number uint64) rlp.RawValue {
+ data, _ := db.Ancient("receipts", number)
+ if len(data) == 0 {
+ data, _ = db.Get(blockReceiptsKey(number, hash))
+ }
+ return data
+}
+
// ReadReceipts retrieves all the transaction receipts belonging to a block.
-func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
+func ReadReceipts(db database.AncientReader, hash common.Hash, number uint64) types.Receipts {
// Retrieve the flattened receipt slice
- data, _ := db.Get(blockReceiptsKey(number, hash))
+ data := ReadReceiptsRLP(db, hash, number)
if len(data) == 0 {
return nil
}
@@ -301,7 +362,7 @@ func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Rece
}
// WriteReceipts stores all the transaction receipts belonging to a block.
-func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts types.Receipts) {
+func WriteReceipts(db database.Writer, hash common.Hash, number uint64, receipts types.Receipts) {
// Convert the receipts into their storage form and serialize them
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
for i, receipt := range receipts {
@@ -318,7 +379,7 @@ func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts
}
// DeleteReceipts removes all receipt data associated with a block hash.
-func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
+func DeleteReceipts(db database.Deleter, hash common.Hash, number uint64) {
if err := db.Delete(blockReceiptsKey(number, hash)); err != nil {
log.Crit("Failed to delete block receipts", "err", err)
}
@@ -330,7 +391,7 @@ func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
//
// Note, due to concurrent download of header and block body the header and thus
// canonical hash can be stored in the database but the body data not (yet).
-func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block {
+func ReadBlock(db database.AncientReader, hash common.Hash, number uint64) *types.Block {
header := ReadHeader(db, hash, number)
if header == nil {
return nil
@@ -343,21 +404,30 @@ func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block
}
// WriteBlock serializes a block into the database, header and body separately.
-func WriteBlock(db DatabaseWriter, block *types.Block) {
+func WriteBlock(db database.Writer, block *types.Block) {
WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
WriteHeader(db, block.Header())
}
// DeleteBlock removes all block data associated with a hash.
-func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) {
+func DeleteBlock(db database.Deleter, hash common.Hash, number uint64) {
DeleteReceipts(db, hash, number)
DeleteHeader(db, hash, number)
DeleteBody(db, hash, number)
DeleteTd(db, hash, number)
}
+// deleteBlockWithoutNumber removes all block data associated with a hash, except
+// the hash to number mapping.
+func deleteBlockWithoutNumber(db database.Deleter, hash common.Hash, number uint64) {
+ DeleteReceipts(db, hash, number)
+ deleteHeaderWithoutNumber(db, hash, number)
+ DeleteBody(db, hash, number)
+ DeleteTd(db, hash, number)
+}
+
// FindCommonAncestor returns the last common ancestor of two block headers
-func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header {
+func FindCommonAncestor(db database.AncientReader, a, b *types.Header) *types.Header {
for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
if a == nil {
diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go
index fcc36dc2b4..c3b51c7ecc 100644
--- a/core/rawdb/accessors_chain_test.go
+++ b/core/rawdb/accessors_chain_test.go
@@ -23,14 +23,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
)
// Tests block header storage and retrieval operations.
func TestHeaderStorage(t *testing.T) {
- db := ethdb.NewMemDatabase()
+ db := NewMemoryDatabase()
// 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")}
@@ -63,7 +62,7 @@ func TestHeaderStorage(t *testing.T) {
// Tests block body storage and retrieval operations.
func TestBodyStorage(t *testing.T) {
- db := ethdb.NewMemDatabase()
+ db := NewMemoryDatabase()
// 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")}}}
@@ -101,7 +100,7 @@ func TestBodyStorage(t *testing.T) {
// Tests block storage and retrieval operations.
func TestBlockStorage(t *testing.T) {
- db := ethdb.NewMemDatabase()
+ db := NewMemoryDatabase()
// Create a test block to move around the database and make sure it's really new
block := types.NewBlockWithHeader(&types.Header{
@@ -151,7 +150,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 := NewMemoryDatabase()
block := types.NewBlockWithHeader(&types.Header{
Extra: []byte("test block"),
UncleHash: types.EmptyUncleHash,
@@ -185,7 +184,7 @@ func TestPartialBlockStorage(t *testing.T) {
// Tests block total difficulty storage and retrieval operations.
func TestTdStorage(t *testing.T) {
- db := ethdb.NewMemDatabase()
+ db := NewMemoryDatabase()
// Create a test TD to move around the database and make sure it's really new
hash, td := common.Hash{}, big.NewInt(314)
@@ -208,7 +207,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 := NewMemoryDatabase()
// Create a test canonical number and assinged hash to move around
hash, number := common.Hash{0: 0xff}, uint64(314)
@@ -231,7 +230,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 := NewMemoryDatabase()
blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")})
@@ -266,7 +265,7 @@ func TestHeadStorage(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 := NewMemoryDatabase()
receipt1 := &types.Receipt{
Status: types.ReceiptStatusFailed,
diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go
index 4ff7e5bd35..5f767a8383 100644
--- a/core/rawdb/accessors_indexes.go
+++ b/core/rawdb/accessors_indexes.go
@@ -19,13 +19,14 @@ package rawdb
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
// hash to allow retrieving the transaction or receipt by hash.
-func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
+func ReadTxLookupEntry(db database.Reader, hash common.Hash) (common.Hash, uint64, uint64) {
data, _ := db.Get(txLookupKey(hash))
if len(data) == 0 {
return common.Hash{}, 0, 0
@@ -40,7 +41,7 @@ func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64
// WriteTxLookupEntries stores a positional metadata for every transaction from
// a block, enabling hash based transaction and receipt lookups.
-func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
+func WriteTxLookupEntries(db database.Writer, block *types.Block) {
for i, tx := range block.Transactions() {
entry := TxLookupEntry{
BlockHash: block.Hash(),
@@ -58,13 +59,13 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
}
// DeleteTxLookupEntry removes all transaction data associated with a hash.
-func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
+func DeleteTxLookupEntry(db database.Deleter, hash common.Hash) {
db.Delete(txLookupKey(hash))
}
// ReadTransaction retrieves a specific transaction from the database, along with
// its added positional metadata.
-func ReadTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
+func ReadTransaction(db database.AncientReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
blockHash, blockNumber, txIndex := ReadTxLookupEntry(db, hash)
if blockHash == (common.Hash{}) {
return nil, common.Hash{}, 0, 0
@@ -79,7 +80,7 @@ func ReadTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, c
// ReadReceipt retrieves a specific transaction receipt from the database, along with
// its added positional metadata.
-func ReadReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) {
+func ReadReceipt(db database.AncientReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) {
blockHash, blockNumber, receiptIndex := ReadTxLookupEntry(db, hash)
if blockHash == (common.Hash{}) {
return nil, common.Hash{}, 0, 0
@@ -94,13 +95,13 @@ func ReadReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Ha
// ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
// section and bit index from the.
-func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
+func ReadBloomBits(db database.Reader, bit uint, section uint64, head common.Hash) ([]byte, error) {
return db.Get(bloomBitsKey(bit, section, head))
}
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
// section and bit index.
-func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) {
+func WriteBloomBits(db database.Writer, bit uint, section uint64, head common.Hash, bits []byte) {
if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
log.Crit("Failed to store bloom bits", "err", err)
}
diff --git a/core/rawdb/accessors_indexes_test.go b/core/rawdb/accessors_indexes_test.go
index d9c10e1490..3acb628a9a 100644
--- a/core/rawdb/accessors_indexes_test.go
+++ b/core/rawdb/accessors_indexes_test.go
@@ -22,12 +22,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
)
// Tests that positional lookup metadata can be stored and retrieved.
func TestLookupStorage(t *testing.T) {
- db := ethdb.NewMemDatabase()
+ db := NewMemoryDatabase()
tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go
index 82e4bf0455..7b7a5a2836 100644
--- a/core/rawdb/accessors_metadata.go
+++ b/core/rawdb/accessors_metadata.go
@@ -20,13 +20,14 @@ import (
"encoding/json"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
// ReadDatabaseVersion retrieves the version number of the database.
-func ReadDatabaseVersion(db DatabaseReader) *uint64 {
+func ReadDatabaseVersion(db database.Reader) *uint64 {
var version uint64
enc, _ := db.Get(databaseVerisionKey)
@@ -41,7 +42,7 @@ func ReadDatabaseVersion(db DatabaseReader) *uint64 {
}
// WriteDatabaseVersion stores the version number of the database
-func WriteDatabaseVersion(db DatabaseWriter, version uint64) {
+func WriteDatabaseVersion(db database.Writer, version uint64) {
enc, err := rlp.EncodeToBytes(version)
if err != nil {
log.Crit("Failed to encode database version", "err", err)
@@ -52,7 +53,7 @@ func WriteDatabaseVersion(db DatabaseWriter, version uint64) {
}
// ReadChainConfig retrieves the consensus settings based on the given genesis hash.
-func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
+func ReadChainConfig(db database.Reader, hash common.Hash) *params.ChainConfig {
data, _ := db.Get(configKey(hash))
if len(data) == 0 {
return nil
@@ -66,7 +67,7 @@ func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
}
// WriteChainConfig writes the chain config settings to the database.
-func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConfig) {
+func WriteChainConfig(db database.Writer, hash common.Hash, cfg *params.ChainConfig) {
if cfg == nil {
return
}
@@ -80,13 +81,13 @@ func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConf
}
// ReadPreimage retrieves a single preimage of the provided hash.
-func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
+func ReadPreimage(db database.Reader, hash common.Hash) []byte {
data, _ := db.Get(preimageKey(hash))
return data
}
// WritePreimages writes the provided set of preimages to the database.
-func WritePreimages(db DatabaseWriter, preimages map[common.Hash][]byte) {
+func WritePreimages(db database.Writer, preimages map[common.Hash][]byte) {
for hash, preimage := range preimages {
if err := db.Put(preimageKey(hash), preimage); err != nil {
log.Crit("Failed to store trie preimage", "err", err)
diff --git a/core/rawdb/database.go b/core/rawdb/database.go
new file mode 100644
index 0000000000..42ac61b38f
--- /dev/null
+++ b/core/rawdb/database.go
@@ -0,0 +1,100 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package rawdb
+
+import (
+ "github.com/ethereum/go-ethereum/database"
+ "github.com/ethereum/go-ethereum/internal/keyvalue"
+)
+
+// freezerdb is a databse wrapper that enabled freezer data retrievals.
+type freezerdb struct {
+ database.KeyValueStore
+ database.Ancienter
+}
+
+// nofreezedb is a database wrapper that disables freezer data retrievals.
+type nofreezedb struct {
+ database.KeyValueStore
+}
+
+// Frozen returns nil as we don't have a backing chain freezer.
+func (db *nofreezedb) Ancient(kind string, number uint64) ([]byte, error) {
+ return nil, errOutOfBounds
+}
+
+// NewDatabase creates a high level database on top of a given key-value data
+// store without a freezer moving immutable chain segments into cold storage.
+func NewDatabase(db database.KeyValueStore) database.Database {
+ return &nofreezedb{
+ KeyValueStore: db,
+ }
+}
+
+// NewDatabaseWithFreezer creates a high level database on top of a given key-
+// value data store with a freezer moving immutable chain segments into cold
+// storage.
+func NewDatabaseWithFreezer(db database.KeyValueStore, freezer string, namespace string) (database.Database, error) {
+ frdb, err := newFreezer(freezer, namespace)
+ if err != nil {
+ return nil, err
+ }
+ go frdb.freeze(db)
+
+ return &freezerdb{
+ KeyValueStore: db,
+ Ancienter: frdb,
+ }, nil
+}
+
+// NewMemoryDatabase creates an ephemeral in-memory key-value database without a
+// freezer moving immutable chain segments into cold storage.
+func NewMemoryDatabase() database.Database {
+ return NewDatabase(keyvalue.NewMemoryDatabase())
+}
+
+// NewMemoryDatabaseWithCap creates an ephemeral in-memory key-value database with
+// an initial starting capacity, but without a freezer moving immutable chain
+// segments into cold storage.
+func NewMemoryDatabaseWithCap(size int) database.Database {
+ return NewDatabase(keyvalue.NewMemoryDatabaseWithCap(size))
+}
+
+// NewLeveldbDatabase creates a persistent key-value database without a freezer
+// moving immutable chain segments into cold storage.
+func NewLeveldbDatabase(file string, cache int, handles int, namespace string) (database.Database, error) {
+ db, err := keyvalue.NewLeveldbDatabase(file, cache, handles, namespace)
+ if err != nil {
+ return nil, err
+ }
+ return NewDatabase(db), nil
+}
+
+// NewLeveldbDatabaseWithFreezer creates a persistent key-value database with a freezer
+// moving immutable chain segments into cold storage.
+func NewLeveldbDatabaseWithFreezer(file string, cache int, handles int, freezer string, namespace string) (database.Database, error) {
+ kvdb, err := keyvalue.NewLeveldbDatabase(file, cache, handles, namespace)
+ if err != nil {
+ return nil, err
+ }
+ frdb, err := NewDatabaseWithFreezer(kvdb, freezer, namespace)
+ if err != nil {
+ kvdb.Close()
+ return nil, err
+ }
+ return frdb, nil
+}
diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go
new file mode 100644
index 0000000000..eb7b84637c
--- /dev/null
+++ b/core/rawdb/freezer.go
@@ -0,0 +1,276 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package rawdb
+
+import (
+ "errors"
+ "fmt"
+ "math"
+ "sync/atomic"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/database"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/metrics"
+)
+
+// errUnknownTable is returned if the user attempts to read from a table that is
+// not tracked by the freezer.
+var errUnknownTable = errors.New("unknown table")
+
+const (
+ // freezerRecheckInterval is the frequency to check the key-value database for
+ // chain progression that might permit new blocks to be frozen into immutable
+ // storage.
+ freezerRecheckInterval = time.Minute
+
+ // freezerBlockGraduation is the number of confirmations a block must achieve
+ // before it becomes elligible for chain freezing. This must exceed any chain
+ // reorg depth, since the freezer also deletes all block siblings.
+ freezerBlockGraduation = 60000
+
+ // freezerBatchLimit is the maximum number of blocks to freeze in one batch
+ // before doing an fsync and deleting it from the key-value store.
+ freezerBatchLimit = 30000
+)
+
+// freezer is an memory mapped append-only database to store immutable chain data
+// into flat files:
+//
+// - The append only nature ensures that disk writes are minimized.
+// - The memory mapping ensures we can max out system memory for caching without
+// reserving it for go-ethereum. This would also reduce the memory requirements
+// of Geth, and thus also GC overhead.
+type freezer struct {
+ tables map[string]*freezerTable // Data tables for storing everything
+ frozen uint64 // Number of blocks already frozen
+}
+
+// newFreezer creates a chain freezer that moves ancient chain data into
+// append-only flat file containers.
+func newFreezer(datadir string, namespace string) (*freezer, error) {
+ // Create the initial freezer object
+ var (
+ readMeter = metrics.NewRegisteredMeter(namespace+"ancient/read", nil)
+ writeMeter = metrics.NewRegisteredMeter(namespace+"ancient/write", nil)
+ )
+ // Open all the supported data tables
+ freezer := &freezer{
+ tables: make(map[string]*freezerTable),
+ }
+ for _, name := range []string{"hashes", "headers", "bodies", "receipts", "diffs"} {
+ table, err := newTable(datadir, name, readMeter, writeMeter)
+ if err != nil {
+ for _, table := range freezer.tables {
+ table.Close()
+ }
+ return nil, err
+ }
+ freezer.tables[name] = table
+ }
+ // Truncate all data tables to the same length
+ freezer.frozen = math.MaxUint64
+ for _, table := range freezer.tables {
+ if freezer.frozen > table.items {
+ freezer.frozen = table.items
+ }
+ }
+ for _, table := range freezer.tables {
+ if err := table.truncate(freezer.frozen); err != nil {
+ for _, table := range freezer.tables {
+ table.Close()
+ }
+ return nil, err
+ }
+ }
+ return freezer, nil
+}
+
+// Close terminates the chain freezer, unmapping all the data files.
+func (f *freezer) Close() error {
+ var errs []error
+ for _, table := range f.tables {
+ if err := table.Close(); err != nil {
+ errs = append(errs, err)
+ }
+ }
+ if errs != nil {
+ return fmt.Errorf("%v", errs)
+ }
+ return nil
+}
+
+// sync flushes all data tables to disk.
+func (f *freezer) sync() error {
+ var errs []error
+ for _, table := range f.tables {
+ if err := table.Sync(); err != nil {
+ errs = append(errs, err)
+ }
+ }
+ if errs != nil {
+ return fmt.Errorf("%v", errs)
+ }
+ return nil
+}
+
+// Ancient retrieves an ancient binary blob from the append-only immutable files.
+func (f *freezer) Ancient(kind string, number uint64) ([]byte, error) {
+ if table := f.tables[kind]; table != nil {
+ return table.Retrieve(number)
+ }
+ return nil, errUnknownTable
+}
+
+// freeze is a background thread that periodically checks the blockchain for any
+// import progress and moves ancient data from the fast database into the freezer.
+//
+// This functionality is deliberately broken off from block importing to avoid
+// incurring additional data shuffling delays on block propagation.
+func (f *freezer) freeze(db database.KeyValueStore) {
+ nfdb := &nofreezedb{KeyValueStore: db}
+
+ for {
+ // Retrieve the freezing threshold. In theory we're interested only in full
+ // blocks post-sync, but that would keep the live database enormous during
+ // dast sync. By picking the fast block, we still get to deep freeze all the
+ // final immutable data without having to wait for sync to finish.
+ hash := ReadHeadFastBlockHash(nfdb)
+ if hash == (common.Hash{}) {
+ log.Debug("Current fast block hash unavailable") // new chain, empty database
+ time.Sleep(freezerRecheckInterval)
+ continue
+ }
+ number := ReadHeaderNumber(nfdb, hash)
+ switch {
+ case number == nil:
+ log.Error("Current fast block number unavailable", "hash", hash)
+ time.Sleep(freezerRecheckInterval)
+ continue
+
+ case *number < freezerBlockGraduation:
+ log.Debug("Current fast block not old enough", "number", *number, "hash", hash, "delay", freezerBlockGraduation)
+ time.Sleep(freezerRecheckInterval)
+ continue
+
+ case *number-freezerBlockGraduation <= f.frozen:
+ log.Debug("Ancient blocks frozen already", "number", *number, "hash", hash, "frozen", f.frozen)
+ time.Sleep(freezerRecheckInterval)
+ continue
+ }
+ head := ReadHeader(nfdb, hash, *number)
+ if head == nil {
+ log.Error("Current fast block unavailable", "number", *number, "hash", hash)
+ time.Sleep(freezerRecheckInterval)
+ continue
+ }
+ // Seems we have data ready to be frozen, process in usable batches
+ limit := *number - freezerBlockGraduation
+ if limit-f.frozen > freezerBatchLimit {
+ limit = f.frozen + freezerBatchLimit
+ }
+ var (
+ start = time.Now()
+ first = f.frozen
+ ancients = make([]common.Hash, 0, limit)
+ )
+ for f.frozen < limit {
+ // Retrieves all the components of the canonical block
+ hash := ReadCanonicalHash(nfdb, f.frozen)
+ if hash == (common.Hash{}) {
+ log.Error("Canonical hash missing, can't freeze", "number", f.frozen)
+ break
+ }
+ header := ReadHeaderRLP(nfdb, hash, f.frozen)
+ if len(header) == 0 {
+ log.Error("Block header missing, can't freeze", "number", f.frozen, "hash", hash)
+ break
+ }
+ body := ReadBodyRLP(nfdb, hash, f.frozen)
+ if len(body) == 0 {
+ log.Error("Block body missing, can't freeze", "number", f.frozen, "hash", hash)
+ break
+ }
+ receipts := ReadReceiptsRLP(nfdb, hash, f.frozen)
+ if len(receipts) == 0 {
+ log.Error("Block receipts missing, can't freeze", "number", f.frozen, "hash", hash)
+ break
+ }
+ td := ReadTdRLP(nfdb, hash, f.frozen)
+ if len(td) == 0 {
+ log.Error("Total difficulty missing, can't freeze", "number", f.frozen, "hash", hash)
+ break
+ }
+ // Inject all the components into the relevant data tables
+ if err := f.tables["hashes"].Append(f.frozen, hash[:]); err != nil {
+ log.Error("Failed to deep freeze hash", "number", f.frozen, "hash", hash, "err", err)
+ break
+ }
+ if err := f.tables["headers"].Append(f.frozen, header); err != nil {
+ log.Error("Failed to deep freeze header", "number", f.frozen, "hash", hash, "err", err)
+ break
+ }
+ if err := f.tables["bodies"].Append(f.frozen, body); err != nil {
+ log.Error("Failed to deep freeze body", "number", f.frozen, "hash", hash, "err", err)
+ break
+ }
+ if err := f.tables["receipts"].Append(f.frozen, receipts); err != nil {
+ log.Error("Failed to deep freeze receipts", "number", f.frozen, "hash", hash, "err", err)
+ break
+ }
+ if err := f.tables["diffs"].Append(f.frozen, td); err != nil {
+ log.Error("Failed to deep freeze difficulty", "number", f.frozen, "hash", hash, "err", err)
+ break
+ }
+ log.Trace("Deep froze ancient block", "number", f.frozen, "hash", hash)
+ atomic.AddUint64(&f.frozen, 1) // Only modify atomically
+ ancients = append(ancients, hash)
+ }
+ // Batch of blocks have been frozen, flush them before wiping from leveldb
+ if err := f.sync(); err != nil {
+ log.Crit("Failed to flush frozen tables", "err", err)
+ }
+ // Wipe out all data from the active database
+ batch := db.NewBatch()
+ for number := first; number < f.frozen; number++ {
+ for _, hash := range readAllHashes(db, number) {
+ if hash == ancients[number-first] {
+ deleteBlockWithoutNumber(batch, hash, number)
+ } else {
+ DeleteBlock(batch, hash, number)
+ }
+ }
+ }
+ if err := batch.Write(); err != nil {
+ log.Crit("Failed to delete frozen items", "err", err)
+ }
+ // Log something friendly for the user
+ context := []interface{}{
+ "blocks", f.frozen - first, "elapsed", common.PrettyDuration(time.Since(start)), "number", f.frozen - 1,
+ }
+ if n := len(ancients); n > 0 {
+ context = append(context, []interface{}{"hash", ancients[n-1]}...)
+ }
+ log.Info("Deep froze chain segment", context...)
+
+ // Avoid database thrashing with tiny writes
+ if f.frozen-first < freezerBatchLimit {
+ time.Sleep(freezerRecheckInterval)
+ }
+ }
+}
diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go
new file mode 100644
index 0000000000..546db0c656
--- /dev/null
+++ b/core/rawdb/freezer_table.go
@@ -0,0 +1,284 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package rawdb
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/metrics"
+ "github.com/golang/snappy"
+)
+
+var (
+ // errClosed is returned if an operation attempts to read from or write to the
+ // freezer table after it has already been closed.
+ errClosed = errors.New("closed")
+
+ // errOutOfBounds is returned if the item requested is not contained within the
+ // freezer table.
+ errOutOfBounds = errors.New("out of bounds")
+)
+
+// freezerTable represents a single chained data table within the freezer (e.g. blocks).
+// It consists of a data file (snappy encoded arbitrary data blobs) and an index
+// file (uncompressed 64 bit indices into the data file).
+type freezerTable struct {
+ content *os.File // File descriptor for the data content of the table
+ offsets *os.File // File descriptor for the index file of the table
+
+ items uint64 // Number of items stored in the table
+ bytes uint64 // Number of content bytes stored in the table
+
+ readMeter metrics.Meter // Meter for measuring the effective amount of data read
+ writeMeter metrics.Meter // Meter for measuring the effective amount of data written
+
+ logger log.Logger // Logger with database path and table name ambedded
+ lock sync.RWMutex // Mutex protecting the data file descriptors
+}
+
+// newTable opens a freezer table, creating the data and index files if they are
+// non existent. Both files are truncated to the shortest common length to ensure
+// they don't go out of sync.
+func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter) (*freezerTable, error) {
+ // Ensure the containing directory exists and open the two data files
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return nil, err
+ }
+ content, err := os.OpenFile(filepath.Join(path, name+".dat"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
+ if err != nil {
+ return nil, err
+ }
+ offsets, err := os.OpenFile(filepath.Join(path, name+".idx"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
+ if err != nil {
+ content.Close()
+ return nil, err
+ }
+ // Create the table and repair any past inconsistency
+ tab := &freezerTable{
+ content: content,
+ offsets: offsets,
+ readMeter: readMeter,
+ writeMeter: writeMeter,
+ logger: log.New("database", path, "table", name),
+ }
+ if err := tab.repair(); err != nil {
+ offsets.Close()
+ content.Close()
+ return nil, err
+ }
+ return tab, nil
+}
+
+// repair cross checks the content and the offsets file and truncates them to
+// be in sync with each other after a potential crash / data loss.
+func (t *freezerTable) repair() error {
+ // Create a temporary offset buffer to init files with and read offsts into
+ offset := make([]byte, 8)
+
+ // If we've just created the files, initialize the offsets with the 0 index
+ stat, err := t.offsets.Stat()
+ if err != nil {
+ return err
+ }
+ if stat.Size() == 0 {
+ if _, err := t.offsets.Write(offset); err != nil {
+ return err
+ }
+ }
+ // Ensure the offsets are a multiple of 8 bytes
+ if overflow := stat.Size() % 8; overflow != 0 {
+ t.offsets.Truncate(stat.Size() - overflow) // New file can't trigger this path
+ }
+ // Retrieve the file sizes and prepare for truncation
+ if stat, err = t.offsets.Stat(); err != nil {
+ return err
+ }
+ offsetsSize := stat.Size()
+
+ if stat, err = t.content.Stat(); err != nil {
+ return err
+ }
+ contentSize := stat.Size()
+
+ // Keep truncating both files until they come in sync
+ t.offsets.ReadAt(offset, offsetsSize-8)
+ contentExp := int64(binary.LittleEndian.Uint64(offset))
+
+ for contentExp != contentSize {
+ // Truncate the content file to the last offset pointer
+ if contentExp < contentSize {
+ t.logger.Warn("Truncating dangling content", "indexed", common.StorageSize(contentExp), "stored", common.StorageSize(contentSize))
+ if err := t.content.Truncate(contentExp); err != nil {
+ return err
+ }
+ contentSize = contentExp
+ }
+ // Truncate the offsets to point within the content file
+ if contentExp > contentSize {
+ t.logger.Warn("Truncating dangling offsets", "indexed", common.StorageSize(contentExp), "stored", common.StorageSize(contentSize))
+ if err := t.offsets.Truncate(offsetsSize - 8); err != nil {
+ return err
+ }
+ offsetsSize -= 8
+
+ t.offsets.ReadAt(offset, offsetsSize-8)
+ contentExp = int64(binary.LittleEndian.Uint64(offset))
+ }
+ }
+ // Ensure all reparation changes have been written to disk
+ if err := t.offsets.Sync(); err != nil {
+ return err
+ }
+ if err := t.content.Sync(); err != nil {
+ return err
+ }
+ // Update the item and byte counters and return
+ t.items = uint64(offsetsSize/8 - 1) // last index points to the end of the data file
+ t.bytes = uint64(contentSize)
+
+ t.logger.Debug("Chain freezer table opened", "items", t.items, "size", common.StorageSize(t.bytes))
+ return nil
+}
+
+// truncate discards any recent data above the provided threashold number.
+func (t *freezerTable) truncate(items uint64) error {
+ // If out item count is corrent, don't do anything
+ if t.items <= items {
+ return nil
+ }
+ // Something's out of sync, truncate the table's offset index
+ t.logger.Warn("Truncating freezer table", "items", t.items, "limit", items)
+ if err := t.offsets.Truncate(int64(items+1) * 8); err != nil {
+ return err
+ }
+ // Calculate the new expected size of the data file and truncate it
+ offset := make([]byte, 8)
+ t.offsets.ReadAt(offset, int64(items)*8)
+ expected := binary.LittleEndian.Uint64(offset)
+
+ if err := t.content.Truncate(int64(expected)); err != nil {
+ return err
+ }
+ // All data files truncated, set internal counters and return
+ t.items, t.bytes = items, expected
+ return nil
+}
+
+// Close unmaps all active memory mapped regions.
+func (t *freezerTable) Close() error {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ var errs []error
+ if err := t.offsets.Close(); err != nil {
+ errs = append(errs, err)
+ }
+ t.offsets = nil
+
+ if err := t.content.Close(); err != nil {
+ errs = append(errs, err)
+ }
+ t.content = nil
+
+ if errs != nil {
+ return fmt.Errorf("%v", errs)
+ }
+ return nil
+}
+
+// Append injects a binary blob at the end of the freezer table. The item index
+// is a precautionary parameter to ensure data correctness, but the table will
+// reject already existing data.
+//
+// Note, this method will *not* flush any data to disk so be sure to explicitly
+// fsync before irreversibly deleting data from the database.
+func (t *freezerTable) Append(item uint64, blob []byte) error {
+ // Ensure the table is still accessible
+ if t.offsets == nil || t.content == nil {
+ return errClosed
+ }
+ // Ensure only the next item can be written, nothing else
+ if t.items != item {
+ panic(fmt.Sprintf("appending unexpected item: want %d, have %d", t.items, item))
+ }
+ // Encode the blob and write it into the data file
+ blob = snappy.Encode(nil, blob)
+ if _, err := t.content.Write(blob); err != nil {
+ return err
+ }
+ t.bytes += uint64(len(blob))
+
+ offset := make([]byte, 8)
+ binary.LittleEndian.PutUint64(offset, t.bytes)
+ if _, err := t.offsets.Write(offset); err != nil {
+ return err
+ }
+ t.items++
+
+ t.writeMeter.Mark(int64(len(blob) + 8)) // 8 = 1 x 8 byte offset
+ return nil
+}
+
+// Retrieve looks up the data offset of an item with the given index and retrieves
+// the raw binary blob from the data file.
+func (t *freezerTable) Retrieve(item uint64) ([]byte, error) {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ // Ensure the table and the item is accessible
+ if t.offsets == nil || t.content == nil {
+ return nil, errClosed
+ }
+ if t.items <= item {
+ return nil, errOutOfBounds
+ }
+ // Item reachable, retrieve the data content boundaries
+ offset := make([]byte, 8)
+ if _, err := t.offsets.ReadAt(offset, int64(item*8)); err != nil {
+ return nil, err
+ }
+ start := binary.LittleEndian.Uint64(offset)
+
+ if _, err := t.offsets.ReadAt(offset, int64((item+1)*8)); err != nil {
+ return nil, err
+ }
+ end := binary.LittleEndian.Uint64(offset)
+
+ // Retrieve the data itself, decompress and return
+ blob := make([]byte, end-start)
+ if _, err := t.content.ReadAt(blob, int64(start)); err != nil {
+ return nil, err
+ }
+ t.readMeter.Mark(int64(len(blob) + 16)) // 16 = 2 x 8 byte offset
+ return snappy.Decode(nil, blob)
+}
+
+// Sync pushes any pending data from memory out to disk. This is an expensive
+// operation, so use it with care.
+func (t *freezerTable) Sync() error {
+ if err := t.offsets.Sync(); err != nil {
+ return err
+ }
+ return t.content.Sync()
+}
diff --git a/core/rawdb/interfaces.go b/core/rawdb/interfaces.go
deleted file mode 100644
index 3bdf55124a..0000000000
--- a/core/rawdb/interfaces.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package rawdb
-
-// DatabaseReader wraps the Has and Get method of a backing data store.
-type DatabaseReader interface {
- Has(key []byte) (bool, error)
- Get(key []byte) ([]byte, error)
-}
-
-// DatabaseWriter wraps the Put method of a backing data store.
-type DatabaseWriter interface {
- Put(key []byte, value []byte) error
-}
-
-// DatabaseDeleter wraps the Delete method of a backing data store.
-type DatabaseDeleter interface {
- Delete(key []byte) error
-}
diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go
index 8a9921ef40..795920e689 100644
--- a/core/rawdb/schema.go
+++ b/core/rawdb/schema.go
@@ -78,6 +78,11 @@ func encodeBlockNumber(number uint64) []byte {
return enc
}
+// headerKeyPrefix = headerPrefix + num (uint64 big endian)
+func headerKeyPrefix(number uint64) []byte {
+ return append(headerPrefix, encodeBlockNumber(number)...)
+}
+
// headerKey = headerPrefix + num (uint64 big endian) + hash
func headerKey(number uint64, hash common.Hash) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
diff --git a/core/rawdb/table.go b/core/rawdb/table.go
new file mode 100644
index 0000000000..bc2d028600
--- /dev/null
+++ b/core/rawdb/table.go
@@ -0,0 +1,124 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package rawdb
+
+import (
+ "github.com/ethereum/go-ethereum/database"
+)
+
+// table is a wrapper around a database that prefixes each key access with a pre-
+// configured string.
+type table struct {
+ db database.Database
+ prefix string
+}
+
+// NewTable returns a database object that prefixes all keys with a given string.
+func NewTable(db database.Database, prefix string) database.Database {
+ return &table{
+ db: db,
+ prefix: prefix,
+ }
+}
+
+// Close is a noop to implement the Database interface.
+func (t *table) Close() error {
+ return nil
+}
+
+// Has retrieves if a prefixed version of a key is present in the database.
+func (t *table) Has(key []byte) (bool, error) {
+ return t.db.Has(append([]byte(t.prefix), key...))
+}
+
+// Get retrieves the given prefixed key if it's present in the database.
+func (t *table) Get(key []byte) ([]byte, error) {
+ return t.db.Get(append([]byte(t.prefix), key...))
+}
+
+// Ancient is a noop passthrough that just forwards the request to the underlying
+// database.
+func (t *table) Ancient(kind string, number uint64) ([]byte, error) {
+ return t.db.Ancient(kind, number)
+}
+
+// Put inserts the given value into the database at a prefixed version of the
+// provided key.
+func (t *table) Put(key []byte, value []byte) error {
+ return t.db.Put(append([]byte(t.prefix), key...), value)
+}
+
+// Delete removes the given prefixed key from the database.
+func (t *table) Delete(key []byte) error {
+ return t.db.Delete(append([]byte(t.prefix), key...))
+}
+
+// NewIterator creates a binary-alphabetical iterator over the entire keyspace
+// contained within the database.
+func (t *table) NewIterator() database.Iterator {
+ return t.NewIteratorWithPrefix(nil)
+}
+
+// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
+// of database content with a particular key prefix.
+func (t *table) NewIteratorWithPrefix(prefix []byte) database.Iterator {
+ return t.db.NewIteratorWithPrefix(append([]byte(t.prefix), prefix...))
+}
+
+// Stat returns a particular internal stat of the database.
+func (t *table) Stat(property string) (string, error) {
+ return t.db.Stat(property)
+}
+
+// NewBatch creates a write-only database that buffers changes to its host db
+// until a final write is called, each operation prefixing all keys with the
+// pre-configured string.
+func (t *table) NewBatch() database.Batch {
+ return &tableBatch{t.db.NewBatch(), t.prefix}
+}
+
+// tableBatch is a wrapper around a database batch that prefixes each key access
+// with a pre-configured string.
+type tableBatch struct {
+ batch database.Batch
+ prefix string
+}
+
+// Put inserts the given value into the batch for later committing.
+func (b *tableBatch) Put(key, value []byte) error {
+ return b.batch.Put(append([]byte(b.prefix), key...), value)
+}
+
+// Delete inserts the a key removal into the batch for later committing.
+func (b *tableBatch) Delete(key []byte) error {
+ return b.batch.Delete(append([]byte(b.prefix), key...))
+}
+
+// ValueSize retrieves the amount of data queued up for writing.
+func (b *tableBatch) ValueSize() int {
+ return b.batch.ValueSize()
+}
+
+// Write flushes any accumulated data to disk.
+func (b *tableBatch) Write() error {
+ return b.batch.Write()
+}
+
+// Reset resets the batch for reuse.
+func (b *tableBatch) Reset() {
+ b.batch.Reset()
+}
diff --git a/core/state/database.go b/core/state/database.go
index f6ea144b9b..bfcfef6ea8 100644
--- a/core/state/database.go
+++ b/core/state/database.go
@@ -21,7 +21,7 @@ import (
"sync"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/trie"
lru "github.com/hashicorp/golang-lru"
)
@@ -68,20 +68,20 @@ type Trie interface {
Hash() common.Hash
NodeIterator(startKey []byte) trie.NodeIterator
GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed
- Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error
+ Prove(key []byte, fromLevel uint, proofDb database.Writer) error
}
// NewDatabase creates a backing store for state. The returned database is safe for
// concurrent use and retains a few recent expanded trie nodes in memory. To keep
// more historical state in memory, use the NewDatabaseWithCache constructor.
-func NewDatabase(db ethdb.Database) Database {
+func NewDatabase(db database.Database) Database {
return NewDatabaseWithCache(db, 0)
}
// NewDatabase creates a backing store for state. The returned database is safe for
// concurrent use and retains both a few recent expanded trie nodes in memory, as
// well as a lot of collapsed RLP trie nodes in a large memory cache.
-func NewDatabaseWithCache(db ethdb.Database, cache int) Database {
+func NewDatabaseWithCache(db database.Database, cache int) Database {
csc, _ := lru.New(codeSizeCacheSize)
return &cachingDB{
db: trie.NewDatabaseWithCache(db, cache),
@@ -179,6 +179,6 @@ func (m cachedTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
return root, err
}
-func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
+func (m cachedTrie) Prove(key []byte, fromLevel uint, proofDb database.Writer) error {
return m.SecureTrie.Prove(key, fromLevel, proofDb)
}
diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go
index 9e46c851cd..561f9abae6 100644
--- a/core/state/iterator_test.go
+++ b/core/state/iterator_test.go
@@ -21,7 +21,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
)
// Tests that the node iterator indeed walks over the entire database contents.
@@ -51,7 +51,9 @@ func TestNodeIteratorCoverage(t *testing.T) {
t.Errorf("state entry not reported %x", hash)
}
}
- for _, key := range db.TrieDB().DiskDB().(*ethdb.MemDatabase).Keys() {
+ it := db.TrieDB().DiskDB().(database.Database).NewIterator()
+ for it.Next() {
+ key := it.Key()
if bytes.HasPrefix(key, []byte("secure-key-")) {
continue
}
@@ -59,4 +61,5 @@ func TestNodeIteratorCoverage(t *testing.T) {
t.Errorf("state entry not reported %x", key)
}
}
+ it.Release()
}
diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go
index 3d9c4e8676..fdfde96adf 100644
--- a/core/state/managed_state_test.go
+++ b/core/state/managed_state_test.go
@@ -20,13 +20,13 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/core/rawdb"
)
var addr = common.BytesToAddress([]byte("test"))
func create() (*ManagedState, *account) {
- statedb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
ms := ManageState(statedb)
ms.StateDB.SetNonce(addr, 100)
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
diff --git a/core/state/state_test.go b/core/state/state_test.go
index a09273f3b1..92a622de00 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -22,13 +22,14 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
checker "gopkg.in/check.v1"
)
type StateSuite struct {
- db *ethdb.MemDatabase
+ db database.Database
state *StateDB
}
@@ -87,7 +88,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
}
func (s *StateSuite) SetUpTest(c *checker.C) {
- s.db = ethdb.NewMemDatabase()
+ s.db = rawdb.NewMemoryDatabase()
s.state, _ = New(common.Hash{}, NewDatabase(s.db))
}
@@ -141,7 +142,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) {
- state, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
+ state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
stateobjaddr0 := toAddr([]byte("so0"))
stateobjaddr1 := toAddr([]byte("so1"))
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 69392d972e..c2d2b2f692 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -31,15 +31,15 @@ import (
check "gopkg.in/check.v1"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
)
// Tests that updating a state trie does not leak any database writes prior to
// actually committing the state.
func TestUpdateLeaks(t *testing.T) {
// Create an empty state database
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
state, _ := New(common.Hash{}, NewDatabase(db))
// Update it with some accounts
@@ -56,18 +56,19 @@ func TestUpdateLeaks(t *testing.T) {
state.IntermediateRoot(false)
}
// Ensure that no data was leaked into the database
- for _, key := range db.Keys() {
- value, _ := db.Get(key)
- t.Errorf("State leaked into database: %x -> %x", key, value)
+ it := db.NewIterator()
+ for it.Next() {
+ t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value())
}
+ it.Release()
}
// Tests that no intermediate state of an object is stored into the database,
// 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 := rawdb.NewMemoryDatabase()
+ finalDb := rawdb.NewMemoryDatabase()
transState, _ := New(common.Hash{}, NewDatabase(transDb))
finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
@@ -103,16 +104,20 @@ func TestIntermediateLeaks(t *testing.T) {
if _, err := finalState.Commit(false); err != nil {
t.Fatalf("failed to commit final state: %v", err)
}
- for _, key := range finalDb.Keys() {
+ it := finalDb.NewIterator()
+ for it.Next() {
+ key := it.Key()
if _, err := transDb.Get(key); err != nil {
- val, _ := finalDb.Get(key)
- t.Errorf("entry missing from the transition database: %x -> %x", key, val)
+ t.Errorf("entry missing from the transition database: %x -> %x", key, it.Value())
}
}
- for _, key := range transDb.Keys() {
+ it.Release()
+
+ it = transDb.NewIterator()
+ for it.Next() {
+ key := it.Key()
if _, err := finalDb.Get(key); err != nil {
- val, _ := transDb.Get(key)
- t.Errorf("extra entry in the transition database: %x -> %x", key, val)
+ t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value())
}
}
}
@@ -122,7 +127,7 @@ func TestIntermediateLeaks(t *testing.T) {
// https://github.com/ethereum/go-ethereum/pull/15549.
func TestCopy(t *testing.T) {
// Create a random state test to copy and modify "independently"
- orig, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
+ orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
@@ -342,7 +347,7 @@ func (test *snapshotTest) String() string {
func (test *snapshotTest) run() bool {
// Run all actions and create snapshots.
var (
- state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
+ state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
snapshotRevs = make([]int, len(test.snapshots))
sindex = 0
)
@@ -433,7 +438,7 @@ func (s *StateSuite) TestTouchDelete(c *check.C) {
// TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy.
// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
func TestCopyOfCopy(t *testing.T) {
- sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
+ sdb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
addr := common.HexToAddress("aaaa")
sdb.SetBalance(addr, big.NewInt(42))
diff --git a/core/state/sync.go b/core/state/sync.go
index c566e79073..8873c71a36 100644
--- a/core/state/sync.go
+++ b/core/state/sync.go
@@ -20,12 +20,13 @@ import (
"bytes"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
)
// NewStateSync create a new state trie download scheduler.
-func NewStateSync(root common.Hash, database trie.DatabaseReader) *trie.Sync {
+func NewStateSync(root common.Hash, database database.Reader) *trie.Sync {
var syncer *trie.Sync
callback := func(leaf []byte, parent common.Hash) error {
var obj Account
diff --git a/core/state/sync_test.go b/core/state/sync_test.go
index 3177401608..475534568f 100644
--- a/core/state/sync_test.go
+++ b/core/state/sync_test.go
@@ -22,8 +22,9 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/trie"
)
@@ -38,7 +39,7 @@ type testAccount struct {
// makeTestState create a sample test state to test node-wise reconstruction.
func makeTestState() (Database, common.Hash, []*testAccount) {
// Create an empty state
- db := NewDatabase(ethdb.NewMemDatabase())
+ db := NewDatabase(rawdb.NewMemoryDatabase())
state, _ := New(common.Hash{}, db)
// Fill it with some arbitrary data
@@ -68,7 +69,7 @@ func makeTestState() (Database, common.Hash, []*testAccount) {
// checkStateAccounts cross references a reconstructed state with an expected
// account array.
-func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) {
+func checkStateAccounts(t *testing.T, db database.Database, root common.Hash, accounts []*testAccount) {
// Check root availability and state contents
state, err := New(root, NewDatabase(db))
if err != nil {
@@ -91,7 +92,7 @@ func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accou
}
// checkTrieConsistency checks that all nodes in a (sub-)trie are indeed present.
-func checkTrieConsistency(db ethdb.Database, root common.Hash) error {
+func checkTrieConsistency(db database.Database, root common.Hash) error {
if v, _ := db.Get(root[:]); v == nil {
return nil // Consider a non existent state consistent.
}
@@ -106,7 +107,7 @@ func checkTrieConsistency(db ethdb.Database, root common.Hash) error {
}
// checkStateConsistency checks that all data of a state root is present.
-func checkStateConsistency(db ethdb.Database, root common.Hash) error {
+func checkStateConsistency(db database.Database, root common.Hash) error {
// Create and iterate a state trie rooted in a sub-node
if _, err := db.Get(root.Bytes()); err != nil {
return nil // Consider a non existent state consistent.
@@ -124,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")
- if req := NewStateSync(empty, ethdb.NewMemDatabase()).Missing(1); len(req) != 0 {
+ if req := NewStateSync(empty, rawdb.NewMemoryDatabase()).Missing(1); len(req) != 0 {
t.Errorf("content requested for empty state: %v", req)
}
}
@@ -139,7 +140,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler
- dstDb := ethdb.NewMemDatabase()
+ dstDb := rawdb.NewMemoryDatabase()
sched := NewStateSync(srcRoot, dstDb)
queue := append([]common.Hash{}, sched.Missing(batch)...)
@@ -171,7 +172,7 @@ func TestIterativeDelayedStateSync(t *testing.T) {
srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler
- dstDb := ethdb.NewMemDatabase()
+ dstDb := rawdb.NewMemoryDatabase()
sched := NewStateSync(srcRoot, dstDb)
queue := append([]common.Hash{}, sched.Missing(0)...)
@@ -208,7 +209,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler
- dstDb := ethdb.NewMemDatabase()
+ dstDb := rawdb.NewMemoryDatabase()
sched := NewStateSync(srcRoot, dstDb)
queue := make(map[common.Hash]struct{})
@@ -248,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
srcDb, srcRoot, srcAccounts := makeTestState()
// Create a destination state and sync with the scheduler
- dstDb := ethdb.NewMemDatabase()
+ dstDb := rawdb.NewMemoryDatabase()
sched := NewStateSync(srcRoot, dstDb)
queue := make(map[common.Hash]struct{})
@@ -292,10 +293,10 @@ func TestIncompleteStateSync(t *testing.T) {
// Create a random state to copy
srcDb, srcRoot, srcAccounts := makeTestState()
- checkTrieConsistency(srcDb.TrieDB().DiskDB().(ethdb.Database), srcRoot)
+ checkTrieConsistency(srcDb.TrieDB().DiskDB().(database.Database), srcRoot)
// Create a destination state and sync with the scheduler
- dstDb := ethdb.NewMemDatabase()
+ dstDb := rawdb.NewMemoryDatabase()
sched := NewStateSync(srcRoot, dstDb)
added := []common.Hash{}
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index 6d3bd7a5a5..b93cbd4836 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -27,10 +27,10 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
)
@@ -78,7 +78,7 @@ func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ec
}
func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
key, _ := crypto.GenerateKey()
@@ -163,7 +163,7 @@ func (c *testChain) State() (*state.StateDB, error) {
// a state change between those fetches.
stdb := c.statedb
if *c.trigger {
- c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
// simulate that the new head block included tx0 and tx1
c.statedb.SetNonce(c.address, 2)
c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether))
@@ -181,7 +181,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
var (
key, _ = crypto.GenerateKey()
address = crypto.PubkeyToAddress(key.PublicKey)
- statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
trigger = false
)
@@ -335,7 +335,7 @@ func TestTransactionChainFork(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
statedb.AddBalance(addr, big.NewInt(100000000000000))
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@@ -364,7 +364,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
statedb.AddBalance(addr, big.NewInt(100000000000000))
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@@ -554,7 +554,7 @@ func TestTransactionPostponing(t *testing.T) {
t.Parallel()
// Create the pool to test the postponing with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@@ -769,7 +769,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) {
t.Parallel()
// Create the pool to test the limit enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -857,7 +857,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
evictionInterval = time.Second
// Create the pool to test the non-expiration enforcement
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1011,7 +1011,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
t.Parallel()
// Create the pool to test the limit enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1057,7 +1057,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
t.Parallel()
// Create the pool to test the limit enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1091,7 +1091,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
t.Parallel()
// Create the pool to test the limit enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1139,7 +1139,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@@ -1260,7 +1260,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@@ -1322,7 +1322,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1428,7 +1428,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1494,7 +1494,7 @@ func TestTransactionReplacement(t *testing.T) {
t.Parallel()
// Create the pool to test the pricing enforcement with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
@@ -1588,7 +1588,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
os.Remove(journal)
// Create the original pool to inject transaction into the journal
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
config := testTxPoolConfig
@@ -1686,7 +1686,7 @@ func TestTransactionStatusCheck(t *testing.T) {
t.Parallel()
// Create the pool to test the status retrievals with
- statedb, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index cda49a34b4..db1f6f3822 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -22,10 +22,10 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -99,7 +99,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
setDefaults(cfg)
if cfg.State == nil {
- cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
}
var (
address = common.BytesToAddress([]byte("contract"))
@@ -129,7 +129,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
setDefaults(cfg)
if cfg.State == nil {
- cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
}
var (
vmenv = NewEnv(cfg)
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index bac06e524b..15f545ddca 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -23,9 +23,9 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -95,7 +95,7 @@ func TestExecute(t *testing.T) {
}
func TestCall(t *testing.T) {
- state, _ := state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ state, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
address := common.HexToAddress("0x0a")
state.SetCode(address, []byte{
byte(vm.PUSH1), 10,
@@ -151,7 +151,7 @@ func BenchmarkCall(b *testing.B) {
}
func benchmarkEVM_Create(bench *testing.B, code string) {
var (
- statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
sender = common.BytesToAddress([]byte("sender"))
receiver = common.BytesToAddress([]byte("receiver"))
)
diff --git a/ethdb/interface.go b/database/batch.go
similarity index 55%
rename from ethdb/interface.go
rename to database/batch.go
index af13557798..43de4720e5 100644
--- a/ethdb/interface.go
+++ b/database/batch.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The go-ethereum Authors
+// Copyright 2018 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -14,39 +14,31 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package ethdb
+package database
-// Code using batches should try to add this much data to the batch.
-// The value was determined empirically.
+// IdealBatchSize defines the size of the data batches should ideally add in one
+// write.
const IdealBatchSize = 100 * 1024
-// Putter wraps the database write operation supported by both batches and regular databases.
-type Putter interface {
- Put(key []byte, value []byte) error
-}
-
-// Deleter wraps the database delete operation supported by both batches and regular databases.
-type Deleter interface {
- Delete(key []byte) error
-}
-
-// Database wraps all database operations. All methods are safe for concurrent use.
-type Database interface {
- Putter
- Deleter
- Get(key []byte) ([]byte, error)
- Has(key []byte) (bool, error)
- Close()
- NewBatch() Batch
-}
-
// Batch is a write-only database that commits changes to its host database
-// when Write is called. Batch cannot be used concurrently.
+// when Write is called. A batch cannot be used concurrently.
type Batch interface {
- Putter
+ Writer
Deleter
- ValueSize() int // amount of data in the batch
+
+ // ValueSize retrieves the amount of data queued up for writing.
+ ValueSize() int
+
+ // Write flushes any accumulated data to disk.
Write() error
+
// Reset resets the batch for reuse
Reset()
}
+
+// Batcher wraps the NewBatch method of a backing data store.
+type Batcher interface {
+ // NewBatch creates a write-only database that buffers changes to its host db
+ // until a final write is called.
+ NewBatch() Batch
+}
diff --git a/database/database.go b/database/database.go
new file mode 100644
index 0000000000..08aea43d08
--- /dev/null
+++ b/database/database.go
@@ -0,0 +1,84 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Package database defines the interfaces for an Ethereum data store.
+package database
+
+import "io"
+
+// Reader wraps the Has and Get method of a backing data store.
+type Reader interface {
+ // Has retrieves if a key is present in the key-value data store.
+ Has(key []byte) (bool, error)
+
+ // Get retrieves the given key if it's present in the key-value data store.
+ Get(key []byte) ([]byte, error)
+}
+
+// Writer wraps the Put method of a backing data store.
+type Writer interface {
+ // Put inserts the given value into the key-value data store.
+ Put(key []byte, value []byte) error
+}
+
+// Deleter wraps the Delete method of a backing data store.
+type Deleter interface {
+ // Delete removes the key from the key-value data store.
+ Delete(key []byte) error
+}
+
+// Stater wraps the Stat method of a backing data store.
+type Stater interface {
+ // Stat returns a particular internal stat of the database.
+ Stat(property string) (string, error)
+}
+
+// KeyValueStore contains all the methods required to allow handling different
+// key-value data stores backing the high level database.
+type KeyValueStore interface {
+ Reader
+ Writer
+ Deleter
+ Batcher
+ Iteratorer
+ Stater
+ io.Closer
+}
+
+// Ancienter wraps the Ancient method for a backing immutable chain data store.
+type Ancienter interface {
+ // Ancient retrieves an ancient binary blob from the append-only immutable files.
+ Ancient(kind string, number uint64) ([]byte, error)
+}
+
+// AncientReader contains the methods required to access both key-value as well as
+// immutable ancient data.
+type AncientReader interface {
+ Reader
+ Ancienter
+}
+
+// Database contains all the methods required by the high level database to not
+// only access
+type Database interface {
+ AncientReader
+ Writer
+ Deleter
+ Batcher
+ Iteratorer
+ Stater
+ io.Closer
+}
diff --git a/database/iterator.go b/database/iterator.go
new file mode 100644
index 0000000000..c0b2909743
--- /dev/null
+++ b/database/iterator.go
@@ -0,0 +1,57 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package database
+
+// Iterator iterates over a databases key/value pairs in key order.
+//
+// When it encounters an error any seek will return false and will yield no key/
+// value pairs. The error can be queried by calling the Error method. Calling
+// Release is still necessary.
+//
+// An iterator must be released after use, but it is not necessary to read an
+// iterator until exhaustion. An iterator is not safe for concurrent use, but it
+// is safe to use multiple iterators concurrently.
+type Iterator interface {
+ // Next moves the iterator to the next key/value pair. It returns whether the
+ // iterator is exhausted.
+ Next() bool
+
+ // Key returns the key of the current key/value pair, or nil if done. The caller
+ // should not modify the contents of the returned slice, and its contents may
+ // change on the next call to Next.
+ Key() []byte
+
+ // Value returns the value of the current key/value pair, or nil if done. The
+ // caller should not modify the contents of the returned slice, and its contents
+ // may change on the next call to Next.
+ Value() []byte
+
+ // Release releases associated resources. Release should always succeed and can
+ // be called multiple times without causing error.
+ Release()
+}
+
+// Iteratorer wraps the NewIterator methods of a backing data store.
+type Iteratorer interface {
+ // NewIterator creates a binary-alphabetical iterator over the entire keyspace
+ // contained within the key-value database.
+ NewIterator() Iterator
+
+ // NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
+ // of database content with a particular key prefix.
+ NewIteratorWithPrefix(prefix []byte) Iterator
+}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index a48815e0db..15e72b682c 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -28,9 +28,9 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
@@ -201,7 +201,7 @@ func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestPrice(ctx)
}
-func (b *EthAPIBackend) ChainDb() ethdb.Database {
+func (b *EthAPIBackend) ChainDb() database.Database {
return b.eth.ChainDb()
}
diff --git a/eth/api_test.go b/eth/api_test.go
index 47b062a40c..cdd5bb8e34 100644
--- a/eth/api_test.go
+++ b/eth/api_test.go
@@ -22,8 +22,8 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/ethdb"
)
var dumper = spew.ConfigState{Indent: " "}
@@ -31,7 +31,7 @@ var dumper = spew.ConfigState{Indent: " "}
func TestStorageRangeAt(t *testing.T) {
// Create a state where account 0x010000... has a few storage entries.
var (
- state, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
+ state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
addr = common.Address{0x01}
keys = []common.Hash{ // hashes of Keys of storage
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
diff --git a/eth/backend.go b/eth/backend.go
index deed195563..08e555f868 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -24,7 +24,6 @@ import (
"runtime"
"sync"
"sync/atomic"
- "time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
@@ -37,12 +36,11 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/freezer"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
@@ -71,12 +69,11 @@ type Ethereum struct {
// Handlers
txPool *core.TxPool
blockchain *core.BlockChain
- freezer *freezer.Freezer
protocolManager *ProtocolManager
lesServer LesServer
// DB interfaces
- chainDb ethdb.Database // Block chain database
+ chainDb database.Database // Block chain database
eventMux *event.TypeMux
engine consensus.Engine
@@ -123,7 +120,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
// Assemble the Ethereum object
- chainDb, err := CreateDB(ctx, config, "chaindata")
+ chainDb, err := ctx.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/")
if err != nil {
return nil, err
}
@@ -171,12 +168,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if err != nil {
return nil, err
}
- eth.freezer, err = freezer.New(ctx.ResolvePath("freezer"))
- if err != nil {
- return nil, err
- }
- go eth.freezer.Freeze(eth.blockchain, chainDb, time.Minute, 60000)
-
// Rewind the chain in case of an incompatible config upgrade.
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
@@ -224,20 +215,8 @@ func makeExtraData(extra []byte) []byte {
return extra
}
-// CreateDB creates the chain database.
-func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) {
- db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles)
- if err != nil {
- return nil, err
- }
- if db, ok := db.(*ethdb.LDBDatabase); ok {
- db.Meter("eth/db/chaindata/")
- }
- return db, nil
-}
-
// CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
-func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
+func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db database.Database) consensus.Engine {
// If proof-of-authority is requested, set it up
if chainConfig.Clique != nil {
return clique.New(chainConfig.Clique, db)
@@ -482,7 +461,7 @@ func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain }
func (s *Ethereum) TxPool() *core.TxPool { return s.txPool }
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
func (s *Ethereum) Engine() consensus.Engine { return s.engine }
-func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
+func (s *Ethereum) ChainDb() database.Database { return s.chainDb }
func (s *Ethereum) IsListening() bool { return true } // Always listening
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
diff --git a/eth/bloombits.go b/eth/bloombits.go
index c7bb561402..272115ad52 100644
--- a/eth/bloombits.go
+++ b/eth/bloombits.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
)
const (
@@ -89,7 +89,7 @@ const (
// for the Ethereum header bloom filters, permitting blazing fast filtering.
type BloomIndexer struct {
size uint64 // section size to generate bloombits for
- db ethdb.Database // database instance to write index data and metadata into
+ db database.Database // database instance to write index data and metadata into
gen *bloombits.Generator // generator to rotate the bloom bits crating the bloom index
section uint64 // Section is the section number being processed currently
head common.Hash // Head is the hash of the last header processed
@@ -97,12 +97,12 @@ type BloomIndexer struct {
// NewBloomIndexer returns a chain indexer that generates bloom bits data for the
// canonical chain for fast logs filtering.
-func NewBloomIndexer(db ethdb.Database, size, confirms uint64) *core.ChainIndexer {
+func NewBloomIndexer(db database.Database, size, confirms uint64) *core.ChainIndexer {
backend := &BloomIndexer{
db: db,
size: size,
}
- table := ethdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
+ table := rawdb.NewTable(db, string(rawdb.BloomBitsIndexPrefix))
return core.NewChainIndexer(db, table, backend, size, confirms, bloomThrottling, "bloombits")
}
diff --git a/eth/config.go b/eth/config.go
index f71b8dfee4..f2d0235019 100644
--- a/eth/config.go
+++ b/eth/config.go
@@ -102,9 +102,11 @@ type Config struct {
SkipBcVersionCheck bool `toml:"-"`
DatabaseHandles int `toml:"-"`
DatabaseCache int
- TrieCleanCache int
- TrieDirtyCache int
- TrieTimeout time.Duration
+ DatabaseFreezer string
+
+ TrieCleanCache int
+ TrieDirtyCache int
+ TrieTimeout time.Duration
// Mining-related options
Etherbase common.Address `toml:",omitempty"`
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index 58d19254c2..2f9b131c5b 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -29,7 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@@ -102,7 +102,7 @@ type Downloader struct {
genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT)
queue *queue // Scheduler for selecting the hashes to download
peers *peerSet // Set of active peers from which download can proceed
- stateDB ethdb.Database
+ stateDB database.Database
rttEstimate uint64 // Round trip time to target for download requests
rttConfidence uint64 // Confidence in the estimated RTT (unit: millionths to allow atomic ops)
@@ -205,7 +205,7 @@ type BlockChain interface {
}
// New creates a new downloader to fetch hashes and blocks from remote peers.
-func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader {
+func New(mode SyncMode, stateDb database.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader {
if lightchain == nil {
lightchain = chain
}
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index 1a42965d39..cc246e64cf 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -28,8 +28,9 @@ import (
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/trie"
)
@@ -45,9 +46,9 @@ func init() {
type downloadTester struct {
downloader *Downloader
- genesis *types.Block // Genesis blocks used by the tester and peers
- stateDb ethdb.Database // Database used by the tester for syncing from peers
- peerDb ethdb.Database // Database of the peers containing all data
+ genesis *types.Block // Genesis blocks used by the tester and peers
+ stateDb database.Database // Database used by the tester for syncing from peers
+ peerDb database.Database // Database of the peers containing all data
peers map[string]*downloadTesterPeer
ownHashes []common.Hash // Hash chain belonging to the tester
@@ -71,8 +72,9 @@ func newTester() *downloadTester {
ownReceipts: map[common.Hash]types.Receipts{testGenesis.Hash(): nil},
ownChainTd: map[common.Hash]*big.Int{testGenesis.Hash(): testGenesis.Difficulty()},
}
- tester.stateDb = ethdb.NewMemDatabase()
+ tester.stateDb = rawdb.NewMemoryDatabase()
tester.stateDb.Put(testGenesis.Root().Bytes(), []byte{0x00})
+
tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer)
return tester
}
diff --git a/eth/downloader/fakepeer.go b/eth/downloader/fakepeer.go
index 59832facaa..00e4e8f63d 100644
--- a/eth/downloader/fakepeer.go
+++ b/eth/downloader/fakepeer.go
@@ -23,7 +23,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
)
// FakePeer is a mock downloader peer that operates on a local database instance
@@ -31,13 +31,13 @@ import (
// sync commands from an existing local database.
type FakePeer struct {
id string
- db ethdb.Database
+ db database.Database
hc *core.HeaderChain
dl *Downloader
}
// NewFakePeer creates a new mock downloader peer with the given data sources.
-func NewFakePeer(id string, db ethdb.Database, hc *core.HeaderChain, dl *Downloader) *FakePeer {
+func NewFakePeer(id string, db database.Database, hc *core.HeaderChain, dl *Downloader) *FakePeer {
return &FakePeer{id: id, db: db, hc: hc, dl: dl}
}
diff --git a/eth/downloader/statesync.go b/eth/downloader/statesync.go
index 0675a91cdc..f4bd6a0138 100644
--- a/eth/downloader/statesync.go
+++ b/eth/downloader/statesync.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"golang.org/x/crypto/sha3"
@@ -325,7 +325,7 @@ func (s *stateSync) loop() (err error) {
}
func (s *stateSync) commit(force bool) error {
- if !force && s.bytesUncommitted < ethdb.IdealBatchSize {
+ if !force && s.bytesUncommitted < database.IdealBatchSize {
return nil
}
start := time.Now()
diff --git a/eth/downloader/testchain_test.go b/eth/downloader/testchain_test.go
index 0b5a214257..4ae342dc63 100644
--- a/eth/downloader/testchain_test.go
+++ b/eth/downloader/testchain_test.go
@@ -24,9 +24,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -34,7 +34,7 @@ import (
var (
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
- testDB = ethdb.NewMemDatabase()
+ testDB = rawdb.NewMemoryDatabase()
testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000))
)
diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go
index a86e773e3b..83172c5348 100644
--- a/eth/fetcher/fetcher_test.go
+++ b/eth/fetcher/fetcher_test.go
@@ -27,14 +27,14 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
var (
- testdb = ethdb.NewMemDatabase()
+ testdb = rawdb.NewMemoryDatabase()
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))
diff --git a/eth/filters/api.go b/eth/filters/api.go
index 5ed80a8875..e2cf19ddc5 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -29,7 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -55,7 +55,7 @@ type PublicFilterAPI struct {
backend Backend
mux *event.TypeMux
quit chan struct{}
- chainDb ethdb.Database
+ chainDb database.Database
events *EventSystem
filtersMu sync.Mutex
filters map[rpc.ID]*filter
diff --git a/eth/filters/bench_test.go b/eth/filters/bench_test.go
index c5f681e024..ee498acd10 100644
--- a/eth/filters/bench_test.go
+++ b/eth/filters/bench_test.go
@@ -17,7 +17,6 @@
package filters
import (
- "bytes"
"context"
"fmt"
"testing"
@@ -28,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/node"
)
@@ -67,7 +66,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
fmt.Println("Running bloombits benchmark section size:", sectionSize)
- db, err := ethdb.NewLDBDatabase(benchDataDir, 128, 1024)
+ db, err := rawdb.NewLeveldbDatabase(benchDataDir, 128, 1024, "")
if err != nil {
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
}
@@ -129,7 +128,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
for i := 0; i < benchFilterCnt; i++ {
if i%20 == 0 {
db.Close()
- db, _ = ethdb.NewLDBDatabase(benchDataDir, 128, 1024)
+ db, _ = rawdb.NewLeveldbDatabase(benchDataDir, 128, 1024, "")
backend = &testBackend{mux, db, cnt, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)}
}
var addr common.Address
@@ -146,37 +145,21 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
db.Close()
}
-func forEachKey(db ethdb.Database, startPrefix, endPrefix []byte, fn func(key []byte)) {
- it := db.(*ethdb.LDBDatabase).NewIterator()
- it.Seek(startPrefix)
- for it.Valid() {
- key := it.Key()
- cmpLen := len(key)
- if len(endPrefix) < cmpLen {
- cmpLen = len(endPrefix)
- }
- if bytes.Compare(key[:cmpLen], endPrefix) == 1 {
- break
- }
- fn(common.CopyBytes(key))
- it.Next()
- }
- it.Release()
-}
-
var bloomBitsPrefix = []byte("bloomBits-")
-func clearBloomBits(db ethdb.Database) {
+func clearBloomBits(db database.Database) {
fmt.Println("Clearing bloombits data...")
- forEachKey(db, bloomBitsPrefix, bloomBitsPrefix, func(key []byte) {
- db.Delete(key)
- })
+ it := db.NewIteratorWithPrefix(bloomBitsPrefix)
+ for it.Next() {
+ db.Delete(it.Key())
+ }
+ it.Release()
}
func BenchmarkNoBloomBits(b *testing.B) {
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
fmt.Println("Running benchmark without bloombits")
- db, err := ethdb.NewLDBDatabase(benchDataDir, 128, 1024)
+ db, err := rawdb.NewLeveldbDatabase(benchDataDir, 128, 1024, "")
if err != nil {
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
}
diff --git a/eth/filters/filter.go b/eth/filters/filter.go
index 071613ad7a..1962ec3697 100644
--- a/eth/filters/filter.go
+++ b/eth/filters/filter.go
@@ -25,13 +25,13 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/rpc"
)
type Backend interface {
- ChainDb() ethdb.Database
+ ChainDb() database.Database
EventMux() *event.TypeMux
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
@@ -51,7 +51,7 @@ type Backend interface {
type Filter struct {
backend Backend
- db ethdb.Database
+ db database.Database
addresses []common.Address
topics [][]common.Hash
diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go
index e71080b1ab..8a78978d9e 100644
--- a/eth/filters/filter_system_test.go
+++ b/eth/filters/filter_system_test.go
@@ -32,7 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
@@ -40,7 +40,7 @@ import (
type testBackend struct {
mux *event.TypeMux
- db ethdb.Database
+ db database.Database
sections uint64
txFeed *event.Feed
rmLogsFeed *event.Feed
@@ -48,7 +48,7 @@ type testBackend struct {
chainFeed *event.Feed
}
-func (b *testBackend) ChainDb() ethdb.Database {
+func (b *testBackend) ChainDb() database.Database {
return b.db
}
@@ -161,7 +161,7 @@ func TestBlockSubscription(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
@@ -218,7 +218,7 @@ func TestPendingTxFilter(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
@@ -278,7 +278,7 @@ func TestPendingTxFilter(t *testing.T) {
func TestLogFilterCreation(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
@@ -327,7 +327,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
@@ -354,7 +354,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
func TestInvalidGetLogsRequest(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
@@ -384,7 +384,7 @@ func TestLogFilter(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
@@ -503,7 +503,7 @@ func TestPendingLogsSubscription(t *testing.T) {
var (
mux = new(event.TypeMux)
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
logsFeed = new(event.Feed)
diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go
index 396a03d611..970293e6bc 100644
--- a/eth/filters/filter_test.go
+++ b/eth/filters/filter_test.go
@@ -29,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
)
@@ -51,7 +50,7 @@ func BenchmarkFilters(b *testing.B) {
defer os.RemoveAll(dir)
var (
- db, _ = ethdb.NewLDBDatabase(dir, 0, 0)
+ db, _ = rawdb.NewLeveldbDatabase(dir, 0, 0, "")
mux = new(event.TypeMux)
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
@@ -110,7 +109,7 @@ func TestFilters(t *testing.T) {
defer os.RemoveAll(dir)
var (
- db, _ = ethdb.NewLDBDatabase(dir, 0, 0)
+ db, _ = rawdb.NewLeveldbDatabase(dir, 0, 0, "")
mux = new(event.TypeMux)
txFeed = new(event.Feed)
rmLogsFeed = new(event.Feed)
diff --git a/eth/handler.go b/eth/handler.go
index b42612a566..d5fafffec7 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -31,9 +31,9 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/fetcher"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
@@ -103,7 +103,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the Ethereum network.
-func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, whitelist map[uint64]common.Hash) (*ProtocolManager, error) {
+func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb database.Database, whitelist map[uint64]common.Hash) (*ProtocolManager, error) {
// Create the protocol manager with the base fields
manager := &ProtocolManager{
networkID: networkID,
diff --git a/eth/handler_test.go b/eth/handler_test.go
index 9fffd95811..7028d8d08e 100644
--- a/eth/handler_test.go
+++ b/eth/handler_test.go
@@ -27,12 +27,12 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
@@ -344,11 +344,15 @@ func testGetNodeData(t *testing.T, protocol int) {
// Fetch for now the entire chain db
hashes := []common.Hash{}
- for _, key := range db.Keys() {
- if len(key) == len(common.Hash{}) {
+
+ it := db.NewIterator()
+ for it.Next() {
+ if key := it.Key(); len(key) == common.HashLength {
hashes = append(hashes, common.BytesToHash(key))
}
}
+ it.Release()
+
p2p.Send(peer.app, 0x0d, hashes)
msg, err := peer.app.ReadMsg()
if err != nil {
@@ -367,7 +371,7 @@ func testGetNodeData(t *testing.T, protocol int) {
t.Errorf("data hash mismatch: have %x, want %x", hash, want)
}
}
- statedb := ethdb.NewMemDatabase()
+ statedb := rawdb.NewMemoryDatabase()
for i := 0; i < len(data); i++ {
statedb.Put(hashes[i].Bytes(), data[i])
}
@@ -469,7 +473,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
var (
evmux = new(event.TypeMux)
pow = ethash.NewFaker()
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
gspec = &core.Genesis{Config: config}
genesis = gspec.MustCommit(db)
@@ -550,7 +554,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
var (
evmux = new(event.TypeMux)
pow = ethash.NewFaker()
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
config = ¶ms.ChainConfig{}
gspec = &core.Genesis{Config: config}
genesis = gspec.MustCommit(db)
diff --git a/eth/helper_test.go b/eth/helper_test.go
index b18a02baf9..1383720957 100644
--- a/eth/helper_test.go
+++ b/eth/helper_test.go
@@ -30,11 +30,12 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -49,11 +50,11 @@ var (
// newTestProtocolManager creates a new protocol manager for testing purposes,
// with the given number of blocks already known, and potential notification
// channels for different events.
-func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase, error) {
+func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, database.Database, error) {
var (
evmux = new(event.TypeMux)
engine = ethash.NewFaker()
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
gspec = &core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
@@ -78,7 +79,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
// with the given number of blocks already known, and potential notification
// channels for different events. In case of an error, the constructor force-
// fails the test.
-func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase) {
+func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, database.Database) {
pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx)
if err != nil {
t.Fatalf("Failed to create protocol manager: %v", err)
diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go
index b435b1694b..972e056e73 100644
--- a/eth/tracers/tracers_test.go
+++ b/eth/tracers/tracers_test.go
@@ -31,10 +31,10 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests"
@@ -155,6 +155,7 @@ func TestPrestateTracerCreate2(t *testing.T) {
GasPrice: big.NewInt(1),
}
alloc := core.GenesisAlloc{}
+
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
// the address
alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{
@@ -167,7 +168,8 @@ func TestPrestateTracerCreate2(t *testing.T) {
Code: []byte{},
Balance: big.NewInt(500000000000000),
}
- statedb := tests.MakePreState(ethdb.NewMemDatabase(), alloc)
+ statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc)
+
// Create the tracer, the EVM environment and run it
tracer, err := New("prestateTracer")
if err != nil {
@@ -240,7 +242,7 @@ func TestCallTracer(t *testing.T) {
GasLimit: uint64(test.Context.GasLimit),
GasPrice: tx.GasPrice(),
}
- statedb := tests.MakePreState(ethdb.NewMemDatabase(), test.Genesis.Alloc)
+ statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc)
// Create the tracer, the EVM environment and run it
tracer, err := New("callTracer")
diff --git a/ethdb/.gitignore b/ethdb/.gitignore
deleted file mode 100644
index f725d58d14..0000000000
--- a/ethdb/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://help.github.com/ignore-files/ for more about ignoring files.
-#
-# If you find yourself ignoring temporary files generated by your text editor
-# or operating system, you probably want to add a global ignore instead:
-# git config --global core.excludesfile ~/.gitignore_global
-
-/tmp
-*/**/*un~
-*un~
-.DS_Store
-*/**/.DS_Store
-
diff --git a/ethdb/database_js.go b/ethdb/database_js.go
deleted file mode 100644
index ba6eeb5a23..0000000000
--- a/ethdb/database_js.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build js
-
-package ethdb
-
-import (
- "errors"
-)
-
-var errNotSupported = errors.New("ethdb: not supported")
-
-type LDBDatabase struct {
-}
-
-// NewLDBDatabase returns a LevelDB wrapped object.
-func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
- return nil, errNotSupported
-}
-
-// Path returns the path to the database directory.
-func (db *LDBDatabase) Path() string {
- return ""
-}
-
-// Put puts the given key / value to the queue
-func (db *LDBDatabase) Put(key []byte, value []byte) error {
- return errNotSupported
-}
-
-func (db *LDBDatabase) Has(key []byte) (bool, error) {
- return false, errNotSupported
-}
-
-// Get returns the given key if it's present.
-func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
- return nil, errNotSupported
-}
-
-// Delete deletes the key from the queue and database
-func (db *LDBDatabase) Delete(key []byte) error {
- return errNotSupported
-}
-
-func (db *LDBDatabase) Close() {
-}
-
-// Meter configures the database metrics collectors and
-func (db *LDBDatabase) Meter(prefix string) {
-}
-
-func (db *LDBDatabase) NewBatch() Batch {
- return nil
-}
diff --git a/ethdb/database_js_test.go b/ethdb/database_js_test.go
deleted file mode 100644
index b4c12ae0bc..0000000000
--- a/ethdb/database_js_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build js
-
-package ethdb_test
-
-import (
- "github.com/ethereum/go-ethereum/ethdb"
-)
-
-var _ ethdb.Database = ðdb.LDBDatabase{}
diff --git a/ethdb/database_test.go b/ethdb/database_test.go
deleted file mode 100644
index 382fedbf9e..0000000000
--- a/ethdb/database_test.go
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// +build !js
-
-package ethdb_test
-
-import (
- "bytes"
- "fmt"
- "io/ioutil"
- "os"
- "strconv"
- "sync"
- "testing"
-
- "github.com/ethereum/go-ethereum/ethdb"
-)
-
-func newTestLDB() (*ethdb.LDBDatabase, func()) {
- dirname, err := ioutil.TempDir(os.TempDir(), "ethdb_test_")
- if err != nil {
- panic("failed to create test file: " + err.Error())
- }
- db, err := ethdb.NewLDBDatabase(dirname, 0, 0)
- if err != nil {
- panic("failed to create test database: " + err.Error())
- }
-
- return db, func() {
- db.Close()
- os.RemoveAll(dirname)
- }
-}
-
-var test_values = []string{"", "a", "1251", "\x00123\x00"}
-
-func TestLDB_PutGet(t *testing.T) {
- db, remove := newTestLDB()
- defer remove()
- testPutGet(db, t)
-}
-
-func TestMemoryDB_PutGet(t *testing.T) {
- testPutGet(ethdb.NewMemDatabase(), t)
-}
-
-func testPutGet(db ethdb.Database, t *testing.T) {
- t.Parallel()
-
- for _, k := range test_values {
- err := db.Put([]byte(k), nil)
- if err != nil {
- t.Fatalf("put failed: %v", err)
- }
- }
-
- for _, k := range test_values {
- data, err := db.Get([]byte(k))
- if err != nil {
- t.Fatalf("get failed: %v", err)
- }
- if len(data) != 0 {
- t.Fatalf("get returned wrong result, got %q expected nil", string(data))
- }
- }
-
- _, err := db.Get([]byte("non-exist-key"))
- if err == nil {
- t.Fatalf("expect to return a not found error")
- }
-
- for _, v := range test_values {
- err := db.Put([]byte(v), []byte(v))
- if err != nil {
- t.Fatalf("put failed: %v", err)
- }
- }
-
- for _, v := range test_values {
- data, err := db.Get([]byte(v))
- if err != nil {
- t.Fatalf("get failed: %v", err)
- }
- if !bytes.Equal(data, []byte(v)) {
- t.Fatalf("get returned wrong result, got %q expected %q", string(data), v)
- }
- }
-
- for _, v := range test_values {
- err := db.Put([]byte(v), []byte("?"))
- if err != nil {
- t.Fatalf("put override failed: %v", err)
- }
- }
-
- for _, v := range test_values {
- data, err := db.Get([]byte(v))
- if err != nil {
- t.Fatalf("get failed: %v", err)
- }
- if !bytes.Equal(data, []byte("?")) {
- t.Fatalf("get returned wrong result, got %q expected ?", string(data))
- }
- }
-
- for _, v := range test_values {
- orig, err := db.Get([]byte(v))
- if err != nil {
- t.Fatalf("get failed: %v", err)
- }
- orig[0] = byte(0xff)
- data, err := db.Get([]byte(v))
- if err != nil {
- t.Fatalf("get failed: %v", err)
- }
- if !bytes.Equal(data, []byte("?")) {
- t.Fatalf("get returned wrong result, got %q expected ?", string(data))
- }
- }
-
- for _, v := range test_values {
- err := db.Delete([]byte(v))
- if err != nil {
- t.Fatalf("delete %q failed: %v", v, err)
- }
- }
-
- for _, v := range test_values {
- _, err := db.Get([]byte(v))
- if err == nil {
- t.Fatalf("got deleted value %q", v)
- }
- }
-}
-
-func TestLDB_ParallelPutGet(t *testing.T) {
- db, remove := newTestLDB()
- defer remove()
- testParallelPutGet(db, t)
-}
-
-func TestMemoryDB_ParallelPutGet(t *testing.T) {
- testParallelPutGet(ethdb.NewMemDatabase(), t)
-}
-
-func testParallelPutGet(db ethdb.Database, t *testing.T) {
- const n = 8
- var pending sync.WaitGroup
-
- pending.Add(n)
- for i := 0; i < n; i++ {
- go func(key string) {
- defer pending.Done()
- err := db.Put([]byte(key), []byte("v"+key))
- if err != nil {
- panic("put failed: " + err.Error())
- }
- }(strconv.Itoa(i))
- }
- pending.Wait()
-
- pending.Add(n)
- for i := 0; i < n; i++ {
- go func(key string) {
- defer pending.Done()
- data, err := db.Get([]byte(key))
- if err != nil {
- panic("get failed: " + err.Error())
- }
- if !bytes.Equal(data, []byte("v"+key)) {
- panic(fmt.Sprintf("get failed, got %q expected %q", []byte(data), []byte("v"+key)))
- }
- }(strconv.Itoa(i))
- }
- pending.Wait()
-
- pending.Add(n)
- for i := 0; i < n; i++ {
- go func(key string) {
- defer pending.Done()
- err := db.Delete([]byte(key))
- if err != nil {
- panic("delete failed: " + err.Error())
- }
- }(strconv.Itoa(i))
- }
- pending.Wait()
-
- pending.Add(n)
- for i := 0; i < n; i++ {
- go func(key string) {
- defer pending.Done()
- _, err := db.Get([]byte(key))
- if err == nil {
- panic("get succeeded")
- }
- }(strconv.Itoa(i))
- }
- pending.Wait()
-}
diff --git a/ethdb/memory_database.go b/ethdb/memory_database.go
deleted file mode 100644
index 727f2f7ca3..0000000000
--- a/ethdb/memory_database.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package ethdb
-
-import (
- "errors"
- "sync"
-
- "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 {
- return &MemDatabase{
- db: make(map[string][]byte),
- }
-}
-
-func NewMemDatabaseWithCap(size int) *MemDatabase {
- return &MemDatabase{
- db: make(map[string][]byte, size),
- }
-}
-
-func (db *MemDatabase) Put(key []byte, value []byte) error {
- db.lock.Lock()
- defer db.lock.Unlock()
-
- db.db[string(key)] = common.CopyBytes(value)
- return nil
-}
-
-func (db *MemDatabase) Has(key []byte) (bool, error) {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- _, ok := db.db[string(key)]
- return ok, nil
-}
-
-func (db *MemDatabase) Get(key []byte) ([]byte, error) {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- if entry, ok := db.db[string(key)]; ok {
- return common.CopyBytes(entry), nil
- }
- return nil, errors.New("not found")
-}
-
-func (db *MemDatabase) Keys() [][]byte {
- db.lock.RLock()
- defer db.lock.RUnlock()
-
- keys := [][]byte{}
- for key := range db.db {
- keys = append(keys, []byte(key))
- }
- return keys
-}
-
-func (db *MemDatabase) Delete(key []byte) error {
- db.lock.Lock()
- defer db.lock.Unlock()
-
- delete(db.db, string(key))
- return nil
-}
-
-func (db *MemDatabase) Close() {}
-
-func (db *MemDatabase) NewBatch() Batch {
- return &memBatch{db: db}
-}
-
-func (db *MemDatabase) Len() int { return len(db.db) }
-
-type kv struct {
- k, v []byte
- del bool
-}
-
-type memBatch struct {
- db *MemDatabase
- writes []kv
- size int
-}
-
-func (b *memBatch) Put(key, value []byte) error {
- b.writes = append(b.writes, kv{common.CopyBytes(key), common.CopyBytes(value), false})
- b.size += len(value)
- return nil
-}
-
-func (b *memBatch) Delete(key []byte) error {
- b.writes = append(b.writes, kv{common.CopyBytes(key), nil, true})
- b.size += 1
- return nil
-}
-
-func (b *memBatch) Write() error {
- b.db.lock.Lock()
- defer b.db.lock.Unlock()
-
- for _, kv := range b.writes {
- if kv.del {
- delete(b.db.db, string(kv.k))
- continue
- }
- b.db.db[string(kv.k)] = kv.v
- }
- return nil
-}
-
-func (b *memBatch) ValueSize() int {
- return b.size
-}
-
-func (b *memBatch) Reset() {
- b.writes = b.writes[:0]
- b.size = 0
-}
diff --git a/ethdb/table.go b/ethdb/table.go
deleted file mode 100644
index 28069c078e..0000000000
--- a/ethdb/table.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package ethdb
-
-type table struct {
- db Database
- prefix string
-}
-
-// NewTable returns a Database object that prefixes all keys with a given
-// string.
-func NewTable(db Database, prefix string) Database {
- return &table{
- db: db,
- prefix: prefix,
- }
-}
-
-func (dt *table) Put(key []byte, value []byte) error {
- return dt.db.Put(append([]byte(dt.prefix), key...), value)
-}
-
-func (dt *table) Has(key []byte) (bool, error) {
- return dt.db.Has(append([]byte(dt.prefix), key...))
-}
-
-func (dt *table) Get(key []byte) ([]byte, error) {
- return dt.db.Get(append([]byte(dt.prefix), key...))
-}
-
-func (dt *table) Delete(key []byte) error {
- return dt.db.Delete(append([]byte(dt.prefix), key...))
-}
-
-func (dt *table) Close() {
- // Do nothing; don't close the underlying DB.
-}
diff --git a/ethdb/table_batch.go b/ethdb/table_batch.go
deleted file mode 100644
index ae83e79ced..0000000000
--- a/ethdb/table_batch.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package ethdb
-
-type tableBatch struct {
- batch Batch
- prefix string
-}
-
-// NewTableBatch returns a Batch object which prefixes all keys with a given string.
-func NewTableBatch(db Database, prefix string) Batch {
- return &tableBatch{db.NewBatch(), prefix}
-}
-
-func (dt *table) NewBatch() Batch {
- return &tableBatch{dt.db.NewBatch(), dt.prefix}
-}
-
-func (tb *tableBatch) Put(key, value []byte) error {
- return tb.batch.Put(append([]byte(tb.prefix), key...), value)
-}
-
-func (tb *tableBatch) Delete(key []byte) error {
- return tb.batch.Delete(append([]byte(tb.prefix), key...))
-}
-
-func (tb *tableBatch) Write() error {
- return tb.batch.Write()
-}
-
-func (tb *tableBatch) ValueSize() int {
- return tb.batch.ValueSize()
-}
-
-func (tb *tableBatch) Reset() {
- tb.batch.Reset()
-}
diff --git a/freezer/freezer.go b/freezer/freezer.go
deleted file mode 100644
index 0c6951c37a..0000000000
--- a/freezer/freezer.go
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-// Package freezer implements an append-only immutable mmap chain database.
-package freezer
-
-import (
- "time"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/metrics"
- "github.com/ethereum/go-ethereum/rlp"
-)
-
-// Freezer is an memory mapped append-only database to store immutable chain data
-// into flat files:
-//
-// - The append only nature ensures that disk writes are minimized.
-// - The memory mapping ensures we can max out system memory for caching without
-// reserving it for go-ethereum. This would also reduce the memory requirements
-// of Geth, and thus also GC overhead.
-type Freezer struct {
- frozen uint64 // Number of blocks already frozen
-
- headers *table // Data table for storing the block headers
- bodies *table // Data table for storing the block bodies
- receipts *table // Data table for storing the block receipts
- diffs *table // Data table for storing the block tds
-
- logger log.Logger // Contextual logger for the freezer database
-}
-
-// New creates a chain freezer that moves ancient chain data into immutable flat
-// file containers.
-func New(datadir string) (*Freezer, error) {
- // Create the initial freezer object
- var (
- freezer = &Freezer{
- logger: log.New("path", datadir),
- }
- readMeter = metrics.NewRegisteredMeter("eth/db/freezer/read", nil)
- writeMeter = metrics.NewRegisteredMeter("eth/db/freezer/write", nil)
- err error
- )
- // Open all the supported data tables
- if freezer.headers, err = newTable(datadir, "headers", readMeter, writeMeter); err != nil {
- return nil, err
- }
- if freezer.bodies, err = newTable(datadir, "bodies", readMeter, writeMeter); err != nil {
- freezer.headers.Close()
- return nil, err
- }
- if freezer.receipts, err = newTable(datadir, "receipts", readMeter, writeMeter); err != nil {
- freezer.bodies.Close()
- freezer.headers.Close()
- return nil, err
- }
- if freezer.diffs, err = newTable(datadir, "diffs", readMeter, writeMeter); err != nil {
- freezer.receipts.Close()
- freezer.bodies.Close()
- freezer.headers.Close()
- return nil, err
- }
- return freezer, nil
-}
-
-// Close terminates the chain freezer, unmapping all the data files.
-func (f *Freezer) Close() error {
- f.diffs.Close()
- f.receipts.Close()
- f.bodies.Close()
- f.headers.Close()
-
- return nil
-}
-
-// Freeze is a background thread that periodically checks the blockchain for any
-// import progress and moves ancient data from the fast database into the freezer.
-//
-// This functionality is deliberately broken off from block importing to avoid
-// incurring additional data shuffling delays on block propagation.
-func (f *Freezer) Freeze(chain *core.BlockChain, db ethdb.Database, recheck time.Duration, delay uint64) {
- for {
- // Retrieve the freezing threshold. In theory we're interested only in full
- // blocks post-sync, but that would keep the live database enormous during
- // dast sync. By picking the fast block, we still get to deep freeze all the
- // final immutable data without having to wait for sync to finish.
- head := chain.CurrentFastBlock()
- if head == nil {
- log.Error("Current fast block is nil")
- time.Sleep(recheck)
- continue
- }
- if head.NumberU64() < delay {
- log.Debug("Current block not old enough", "number", head.Number(), "hash", head.Hash(), "age", common.PrettyAge(time.Unix(head.Time().Int64(), 0)), "delay", delay)
- time.Sleep(recheck)
- continue
- }
- limit := head.NumberU64() - delay
- if limit <= f.frozen {
- log.Debug("Ancient blocks frozen already")
- time.Sleep(recheck)
- continue
- }
- // Seems we have data ready to be frozen, process in usable batches
- if limit-f.frozen > 30000 {
- limit = f.frozen + 30000
- }
- var (
- start = time.Now()
- first = f.frozen
- last *types.Block
- )
- for f.frozen < limit {
- // Deep freeze the next canonical block if it's available
- if block := chain.GetBlockByNumber(f.frozen); block != nil {
- // Deep freeze the block header and body
- blob, _ := rlp.EncodeToBytes(block.Header())
- if err := f.headers.Append(f.frozen, blob); err != nil {
- log.Error("Failed to deep freeze header", "number", block.Number(), "hash", block.Hash(), "age", common.PrettyAge(time.Unix(block.Time().Int64(), 0)), "err", err)
- break
- }
- blob, _ = rlp.EncodeToBytes(block.Body())
- if err := f.bodies.Append(f.frozen, blob); err != nil {
- log.Error("Failed to deep freeze body", "number", block.Number(), "hash", block.Hash(), "age", common.PrettyAge(time.Unix(block.Time().Int64(), 0)), "err", err)
- break
- }
- // Deep freeze the block receipts and total difficulty
- if receipts := chain.GetReceiptsByHash(block.Hash()); receipts != nil {
- blob, _ = rlp.EncodeToBytes(receipts)
- if err := f.receipts.Append(f.frozen, blob); err != nil {
- log.Error("Failed to deep freeze receipts", "number", block.Number(), "hash", block.Hash(), "age", common.PrettyAge(time.Unix(block.Time().Int64(), 0)), "err", err)
- break
- }
- }
- if td := chain.GetTd(block.Hash(), block.NumberU64()); td != nil {
- blob, _ = rlp.EncodeToBytes(td)
- if err := f.diffs.Append(f.frozen, blob); err != nil {
- log.Error("Failed to deep freeze difficulty", "number", block.Number(), "hash", block.Hash(), "age", common.PrettyAge(time.Unix(block.Time().Int64(), 0)), "err", err)
- break
- }
- }
- log.Trace("Deep froze ancient block", "number", block.Number(), "hash", block.Hash(), "age", common.PrettyAge(time.Unix(block.Time().Int64(), 0)))
- f.frozen++
-
- // If it's the last block, save for reporting
- if f.frozen == limit-1 {
- last = block
- }
- }
- }
- // Batch of blocks have been frozen, flush them before wiping from leveldb
- if err := f.headers.Flush(); err != nil {
- f.logger.Error("Failed to flush frozen headers", "err", err)
- time.Sleep(recheck)
- continue
- }
- if err := f.bodies.Flush(); err != nil {
- f.logger.Error("Failed to flush frozen bodies", "err", err)
- time.Sleep(recheck)
- continue
- }
- if err := f.receipts.Flush(); err != nil {
- f.logger.Error("Failed to flush frozen receipts", "err", err)
- time.Sleep(recheck)
- continue
- }
- if err := f.diffs.Flush(); err != nil {
- f.logger.Error("Failed to flush frozen diffs", "err", err)
- time.Sleep(recheck)
- continue
- }
- // Wipe out all data from the active database
- for number := first; number < f.frozen; number++ {
- if number == 0 {
- // Skip deleting the genesis for the PoC
- continue
- }
- rawdb.DeleteBlock(db, rawdb.ReadCanonicalHash(db, number), number)
- }
- // Log something friendly for the user
- context := []interface{}{
- "count", f.frozen - first, "elapsed", common.PrettyDuration(time.Since(start)), "number", f.frozen - 1,
- }
- if last != nil {
- context = append(context, []interface{}{"hash", last.Hash(), "age", common.PrettyAge(time.Unix(last.Time().Int64(), 0))}...)
- }
- log.Info("Deep froze chain segment", context...)
-
- // Avoid database thrashing with tiny writes
- if f.frozen-first < 30000 {
- time.Sleep(recheck)
- }
- }
-}
diff --git a/freezer/mmap.go b/freezer/mmap.go
deleted file mode 100644
index 40d3836fe8..0000000000
--- a/freezer/mmap.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package freezer
-
-import (
- "os"
- "reflect"
- "unsafe"
-
- "github.com/edsrzf/mmap-go"
-)
-
-// openWithSize opens a file and ensures it is at least the provided bytes in
-// size, growing it if necessary.
-func openWithSize(path string, size uint64) (*os.File, error) {
- // Open the file for writing, potentially creating it
- file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
- if err != nil {
- return nil, err
- }
- // Ensure the file's size is at least as much as requested
- info, err := file.Stat()
- if err != nil {
- file.Close()
- return nil, err
- }
- if info.Size() < int64(size) {
- if err := file.Truncate(int64(size)); err != nil {
- file.Close()
- return nil, err
- }
- }
- // File is correctly open and of the correct size
- return file, err
-}
-
-// mmapBytes tries to memory map a file, creating it if it's non existent.
-func mmapBytes(path string, size uint64) (*os.File, mmap.MMap, []byte, error) {
- // Open the file to memory map and ensure it's large enough
- file, err := openWithSize(path, size)
- if err != nil {
- return nil, nil, nil, err
- }
- // Memory map the file, cast to a byte slice and return
- mem, err := mmap.Map(file, mmap.RDWR, 0)
- if err != nil {
- file.Close()
- return nil, nil, nil, err
- }
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem))
- return file, mem, *(*[]byte)(unsafe.Pointer(&header)), nil
-}
-
-// mmapUints tries to memory map a file, creating it if it's non existent.
-func mmapUints(path string, size uint64) (*os.File, mmap.MMap, []uint64, error) {
- // Open the file to memory map and ensure it's large enough
- file, err := openWithSize(path, size)
- if err != nil {
- return nil, nil, nil, err
- }
- // Memory map the file, cast to an uint64 slice and return
- mem, err := mmap.Map(file, mmap.RDWR, 0)
- if err != nil {
- file.Close()
- return nil, nil, nil, err
- }
- header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem))
- header.Len /= 8
- header.Cap /= 8
-
- return file, mem, *(*[]uint64)(unsafe.Pointer(&header)), nil
-}
diff --git a/freezer/table.go b/freezer/table.go
deleted file mode 100644
index 81aa673c94..0000000000
--- a/freezer/table.go
+++ /dev/null
@@ -1,290 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package freezer
-
-import (
- "errors"
- "os"
- "path/filepath"
- "sync"
-
- "github.com/edsrzf/mmap-go"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/metrics"
- "github.com/golang/snappy"
-)
-
-const (
- growthIndex uint64 = 1024 * 1024 // Growth rate of the index file when remapping
- growthData uint64 = 128 * 1024 * 1024 // Growth rate of the data file when remapping
-)
-
-var (
- // errAlreadyExists is returned if the user attempts to append an item to the
- // freezer table that already exists (i.e. it's offset is lower or equal to
- // the head of the immutable file).
- errAlreadyExists = errors.New("item already exists")
-
- // errGappedWrite is returned if the user attempts to append an item to the
- // freezer table that would produce a data gap (i.e. it's offset is larger than
- // the head of the immutable file).
- errGappedWrite = errors.New("item produces data gap")
-
- // errTableInaccessible is returned if a previously well functioning freezer
- // table becomes non-accessible after a memory remap (resize).
- errTableInaccessible = errors.New("table not accessible")
-
- // errOutOfBounds is returned if the item requested is not contained within the
- // freezer table.
- errOutOfBounds = errors.New("out of bounds")
-)
-
-// table represents a single chained data table within the freezer (e.g. blocks).
-// It consists of a data file (snappy encoded arbitrary data blobs) and an index
-// file (uncompressed 64 bit indices into the data file). In addition a counter
-// (binary) file is also created which simply contains the number of items.
-type table struct {
- path string // Database folder to store the files into
- name string // Table name to multiplex multiple tables into the same folder
-
- fileData *os.File // File descriptor for the data region
- fileIndex *os.File // File descriptor for the offset region
- fileCounter *os.File // File descriptor for the counter region
-
- mmapData mmap.MMap // Memory mapping for the data region
- mmapIndex mmap.MMap // Memory mapping for the offset region
- mmapCounter mmap.MMap // Memory mapping for the counter region
-
- rawData []byte // Direct memory region for the data file
- rawIndex []uint64 // Direct memory region for the offset file
- rawCounter []uint64 // Direct memory region for the counter (single item)
-
- readMeter metrics.Meter // Meter for measuring the effective amount of data read
- writeMeter metrics.Meter // Meter for measuring the effective amount of data written
-
- logger log.Logger // Logger with database path and table name ambedded
- lock sync.RWMutex // Lock protecting the reads from remaps
-}
-
-// newTable attempts to new freezer table by memory mapping the composing files.
-// If no file exists, it will create new ones.
-func newTable(path string, name string, readMeter metrics.Meter, writeMeter metrics.Meter) (*table, error) {
- if err := os.MkdirAll(path, 0755); err != nil {
- return nil, err
- }
- tab := &table{
- path: path,
- name: name,
- readMeter: readMeter,
- writeMeter: writeMeter,
- logger: log.New("path", path, "table", name),
- }
- if err := tab.ensure(); err != nil {
- return nil, err
- }
- return tab, nil
-}
-
-// ensure checks all the memory region limits and ensures that they conform to
-// the required data counts. If anything is off, this method will recreate and
-// remap accordingly.
-func (t *table) ensure() error {
- // Figure out if we need to remap or not
- // If the regions are already open and large enough, leave as is
- if t.rawCounter != nil {
- // Ensure the data file is large enough, unmap it otherwise
- wantData := (t.rawIndex[t.rawCounter[0]]/growthData + 1) * growthData
- if uint64(len(t.rawData)) < wantData {
- if err := t.mmapData.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer datastore", "err", err)
- }
- if err := t.fileData.Close(); err != nil {
- t.logger.Error("Failed to close freezer datastore", "err", err)
- }
- t.fileData, t.mmapData, t.rawData = nil, nil, nil
- }
- // Ensure the index file is large enough, unmap it otherwise
- wantIndex := (((t.rawCounter[0]+1)*8)/growthIndex + 1) * growthIndex
- if uint64(len(t.rawIndex)) < wantIndex {
- if err := t.mmapIndex.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer index", "err", err)
- }
- if err := t.fileIndex.Close(); err != nil {
- t.logger.Error("Failed to close freezer index", "err", err)
- }
- t.fileIndex, t.mmapIndex, t.rawIndex = nil, nil, nil
- }
- }
- // Memory map the counter and retrieve the size of the offset file
- var err error
-
- if t.rawCounter == nil {
- if t.fileCounter, t.mmapCounter, t.rawCounter, err = mmapUints(filepath.Join(t.path, t.name+".len"), 8); err != nil {
- return err
- }
- }
- // Memory map the index file and retrieve the size of the data file
- if t.rawIndex == nil {
- size := (((t.rawCounter[0]+1)*8)/growthIndex + 1) * growthIndex
- if t.fileIndex, t.mmapIndex, t.rawIndex, err = mmapUints(filepath.Join(t.path, t.name+".idx"), size); err != nil {
- if err := t.mmapCounter.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer counter", "err", err)
- }
- if err := t.fileCounter.Close(); err != nil {
- t.logger.Error("Failed to close freezer counter", "err", err)
- }
- t.fileCounter, t.mmapCounter, t.rawCounter = nil, nil, nil
- return err
- }
- }
- // Memory map the data file and return the final freezer table
- if t.rawData == nil {
- size := growthData
- if t.rawCounter[0] > 0 {
- size = (t.rawIndex[t.rawCounter[0]]/growthData + 1) * growthData
- }
- if t.fileData, t.mmapData, t.rawData, err = mmapBytes(filepath.Join(t.path, t.name+".dat"), size); err != nil {
- if err := t.mmapIndex.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer index", "err", err)
- }
- if err := t.fileIndex.Close(); err != nil {
- t.logger.Error("Failed to close freezer index", "err", err)
- }
- t.fileIndex, t.mmapIndex, t.rawIndex = nil, nil, nil
-
- if err := t.mmapCounter.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer counter", "err", err)
- }
- if err := t.fileCounter.Close(); err != nil {
- t.logger.Error("Failed to close freezer counter", "err", err)
- }
- t.fileCounter, t.mmapCounter, t.rawCounter = nil, nil, nil
-
- return err
- }
- }
- return nil
-}
-
-// Close unmaps all active memory mapped regions.
-func (t *table) Close() error {
- t.lock.Lock()
- defer t.lock.Unlock()
-
- if t.mmapData != nil {
- if err := t.mmapData.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer datastore", "err", err)
- }
- if err := t.fileData.Close(); err != nil {
- t.logger.Error("Failed to close freezer datastore", "err", err)
- }
- t.fileData, t.mmapData, t.rawData = nil, nil, nil
- }
- if t.mmapIndex != nil {
- if err := t.mmapIndex.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer index", "err", err)
- }
- if err := t.fileIndex.Close(); err != nil {
- t.logger.Error("Failed to close freezer index", "err", err)
- }
- t.fileIndex, t.mmapIndex, t.rawIndex = nil, nil, nil
- }
- if t.mmapCounter != nil {
- if err := t.mmapCounter.Unmap(); err != nil {
- t.logger.Error("Failed to unmap freezer counter", "err", err)
- }
- if err := t.fileCounter.Close(); err != nil {
- t.logger.Error("Failed to close freezer counter", "err", err)
- }
- t.fileCounter, t.mmapCounter, t.rawCounter = nil, nil, nil
- }
- return nil
-}
-
-// Append injects a binary blob at the end of the freezer table. The item index
-// is a precautionary parameter to ensure data correctness, but the table will
-// reject already existing data.
-//
-// Note, this method will *not* flush any data to disk (unless the files need to
-// be resized). Be sure to explicitly flush before irreversibly deleting data
-// from the fast chain database.
-func (t *table) Append(item uint64, blob []byte) error {
- t.lock.Lock()
- defer t.lock.Unlock()
-
- // Ensure the table is still accessible
- if t.rawCounter == nil {
- if err := t.ensure(); err != nil {
- t.logger.Error("Failed to re-access table", "err", err)
- return errTableInaccessible
- }
- }
- // Ensure only the next item can be written, nothing else
- items := t.rawCounter[0]
- if items > item {
- return errAlreadyExists
- }
- if items < item {
- return errGappedWrite
- }
- // Encode the blob and write it into the data file
- blob = snappy.Encode(nil, blob)
-
- t.rawIndex[items+1] = t.rawIndex[items] + uint64(len(blob))
- copy(t.rawData[t.rawIndex[items]:], blob)
- t.rawCounter[0]++
-
- t.writeMeter.Mark(int64(len(blob)))
-
- // Ensure we have enough space for future appends
- return t.ensure()
-}
-
-// Retrieve looks up the data offset of an item with the given index and retrieves
-// the raw binary blob from the data file.
-func (t *table) Retrieve(item uint64) ([]byte, error) {
- t.lock.RLock()
- defer t.lock.RUnlock()
-
- // Ensure the table and the item is accessible
- if t.rawCounter == nil {
- return nil, errTableInaccessible
- }
- if t.rawCounter[0] <= item {
- return nil, errOutOfBounds
- }
- // Item reachable, retrive and return to the user
- blob := t.rawData[t.rawIndex[item]:t.rawIndex[item+1]]
- t.writeMeter.Mark(int64(len(blob)))
-
- return snappy.Decode(nil, blob)
-}
-
-// Flush pushes any pending data from memory out to disk. This is an expensive
-// operation, so use it with care.
-func (t *table) Flush() error {
- if err := t.mmapData.Flush(); err != nil {
- return err
- }
- if err := t.mmapIndex.Flush(); err != nil {
- return err
- }
- if err := t.mmapCounter.Flush(); err != nil {
- return err
- }
- return nil
-}
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index e23ee03b15..78223f362a 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -27,8 +27,8 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
@@ -41,7 +41,7 @@ type Backend interface {
Downloader() *downloader.Downloader
ProtocolVersion() int
SuggestPrice(ctx context.Context) (*big.Int, error)
- ChainDb() ethdb.Database
+ ChainDb() database.Database
EventMux() *event.TypeMux
AccountManager() *accounts.Manager
diff --git a/ethdb/database.go b/internal/keyvalue/leveldb.go
similarity index 65%
rename from ethdb/database.go
rename to internal/keyvalue/leveldb.go
index 17f1478e5b..ac20582ce6 100644
--- a/ethdb/database.go
+++ b/internal/keyvalue/leveldb.go
@@ -16,7 +16,7 @@
// +build !js
-package ethdb
+package keyvalue
import (
"fmt"
@@ -26,23 +26,38 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
"github.com/syndtr/goleveldb/leveldb/filter"
- "github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/util"
)
const (
- writePauseWarningThrottler = 1 * time.Minute
+ // leveldbDegradationWarnInterval specifies how often warning should be printed
+ // if the leveldb database cannot keep up with requested writes.
+ leveldbDegradationWarnInterval = time.Minute
+
+ // leveldbMinCache is the minimum amount of memory in megabytes to allocate to
+ // leveldb read and write caching, split half and half.
+ leveldbMinCache = 16
+
+ // leveldbMinHandles is the minimum number of files handles to allocate to the
+ // open database files.
+ leveldbMinHandles = 16
+
+ // metricsGatheringInterval specifies the interval to retrieve leveldb database
+ // compaction, io and pause stats to report to the user.
+ metricsGatheringInterval = 3 * time.Second
)
-var OpenFileLimit = 64
-
-type LDBDatabase struct {
+// LeveldbDatabase is a persistent key-value store. Apart from basic data storage
+// functionality it also supports batch writes and iterating over the keyspace in
+// binary-alphabetical order.
+type LeveldbDatabase struct {
fn string // filename for reporting
db *leveldb.DB // LevelDB instance
@@ -60,17 +75,16 @@ type LDBDatabase struct {
log log.Logger // Contextual logger tracking the database path
}
-// NewLDBDatabase returns a LevelDB wrapped object.
-func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
- logger := log.New("database", file)
-
+// NewLeveldbDatabase returns a wrapped LevelDB object.
+func NewLeveldbDatabase(file string, cache int, handles int, namespace string) (database.KeyValueStore, error) {
// Ensure we have some minimal caching and file guarantees
- if cache < 16 {
- cache = 16
+ if cache < leveldbMinCache {
+ cache = leveldbMinCache
}
- if handles < 16 {
- handles = 16
+ if handles < leveldbMinHandles {
+ handles = leveldbMinHandles
}
+ logger := log.New("database", file)
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles)
// Open the db and recover any potential corruptions
@@ -83,56 +97,32 @@ func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
db, err = leveldb.RecoverFile(file, nil)
}
- // (Re)check for errors and abort if opening of the db failed
if err != nil {
return nil, err
}
- return &LDBDatabase{
- fn: file,
- db: db,
- log: logger,
- }, nil
-}
-
-// Path returns the path to the database directory.
-func (db *LDBDatabase) Path() string {
- return db.fn
-}
-
-// Put puts the given key / value to the queue
-func (db *LDBDatabase) Put(key []byte, value []byte) error {
- return db.db.Put(key, value, nil)
-}
-
-func (db *LDBDatabase) Has(key []byte) (bool, error) {
- return db.db.Has(key, nil)
-}
-
-// Get returns the given key if it's present.
-func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
- dat, err := db.db.Get(key, nil)
- if err != nil {
- return nil, err
+ // Assemble the wrapper with all the registered metrics
+ ldb := &LeveldbDatabase{
+ fn: file,
+ db: db,
+ log: logger,
+ quitChan: make(chan chan error),
}
- return dat, nil
+ ldb.compTimeMeter = metrics.NewRegisteredMeter(namespace+"compact/time", nil)
+ ldb.compReadMeter = metrics.NewRegisteredMeter(namespace+"compact/input", nil)
+ ldb.compWriteMeter = metrics.NewRegisteredMeter(namespace+"compact/output", nil)
+ ldb.diskReadMeter = metrics.NewRegisteredMeter(namespace+"disk/read", nil)
+ ldb.diskWriteMeter = metrics.NewRegisteredMeter(namespace+"disk/write", nil)
+ ldb.writeDelayMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/duration", nil)
+ ldb.writeDelayNMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/counter", nil)
+
+ // Start up the metrics gathering and return
+ go ldb.meter(metricsGatheringInterval)
+ return ldb, nil
}
-// Delete deletes the key from the queue and database
-func (db *LDBDatabase) Delete(key []byte) error {
- return db.db.Delete(key, nil)
-}
-
-func (db *LDBDatabase) NewIterator() iterator.Iterator {
- return db.db.NewIterator(nil, nil)
-}
-
-// NewIteratorWithPrefix returns a iterator to iterate over subset of database content with a particular prefix.
-func (db *LDBDatabase) NewIteratorWithPrefix(prefix []byte) iterator.Iterator {
- return db.db.NewIterator(util.BytesPrefix(prefix), nil)
-}
-
-func (db *LDBDatabase) Close() {
- // Stop the metrics collection to avoid internal database races
+// Close stops th emetrics collection, flushes any pending data to disk and closes
+// all io access to the underlying key-value store.
+func (db *LeveldbDatabase) Close() error {
db.quitLock.Lock()
defer db.quitLock.Unlock()
@@ -144,41 +134,68 @@ func (db *LDBDatabase) Close() {
}
db.quitChan = nil
}
- err := db.db.Close()
- if err == nil {
- db.log.Info("Database closed")
- } else {
- db.log.Error("Failed to close database", "err", err)
+ return db.db.Close()
+}
+
+// Has retrieves if a key is present in the key-value store.
+func (db *LeveldbDatabase) Has(key []byte) (bool, error) {
+ return db.db.Has(key, nil)
+}
+
+// Get retrieves the given key if it's present in the key-value store.
+func (db *LeveldbDatabase) Get(key []byte) ([]byte, error) {
+ dat, err := db.db.Get(key, nil)
+ if err != nil {
+ return nil, err
+ }
+ return dat, nil
+}
+
+// Put inserts the given value into the key-value store.
+func (db *LeveldbDatabase) Put(key []byte, value []byte) error {
+ return db.db.Put(key, value, nil)
+}
+
+// Delete removes the key from the key-value store.
+func (db *LeveldbDatabase) Delete(key []byte) error {
+ return db.db.Delete(key, nil)
+}
+
+// NewBatch creates a write-only key-value store that buffers changes to its host
+// database until a final write is called.
+func (db *LeveldbDatabase) NewBatch() database.Batch {
+ return &leveldbBatch{
+ db: db.db,
+ b: new(leveldb.Batch),
}
}
-func (db *LDBDatabase) LDB() *leveldb.DB {
- return db.db
+// NewIterator creates a binary-alphabetical iterator over the entire keyspace
+// contained within the leveldb database.
+func (db *LeveldbDatabase) NewIterator() database.Iterator {
+ return db.NewIteratorWithPrefix(nil)
}
-// Meter configures the database metrics collectors and
-func (db *LDBDatabase) Meter(prefix string) {
- // Initialize all the metrics collector at the requested prefix
- db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
- db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
- db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
- db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
- db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
- db.writeDelayMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil)
- db.writeDelayNMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", nil)
+// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
+// of database content with a particular key prefix.
+func (db *LeveldbDatabase) NewIteratorWithPrefix(prefix []byte) database.Iterator {
+ return db.db.NewIterator(util.BytesPrefix(prefix), nil)
+}
- // Create a quit channel for the periodic collector and run it
- db.quitLock.Lock()
- db.quitChan = make(chan chan error)
- db.quitLock.Unlock()
+// Stat returns a particular internal stat of the database.
+func (db *LeveldbDatabase) Stat(property string) (string, error) {
+ return db.db.GetProperty(property)
+}
- go db.meter(3 * time.Second)
+// Path returns the path to the database directory.
+func (db *LeveldbDatabase) Path() string {
+ return db.fn
}
// meter periodically retrieves internal leveldb counters and reports them to
// the metrics subsystem.
//
-// This is how a stats table look like (currently):
+// This is how a stats leveldbTable look like (currently):
// Compactions
// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
// -------+------------+---------------+---------------+---------------+---------------
@@ -192,7 +209,7 @@ func (db *LDBDatabase) Meter(prefix string) {
//
// This is how the iostats look like (currently):
// Read(MB):3895.04860 Write(MB):3654.64712
-func (db *LDBDatabase) meter(refresh time.Duration) {
+func (db *LeveldbDatabase) meter(refresh time.Duration) {
// Create the counters to store current and previous compaction values
compactions := make([][]float64, 2)
for i := 0; i < 2; i++ {
@@ -221,19 +238,19 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
merr = err
continue
}
- // Find the compaction table, skip the header
+ // Find the compaction leveldbTable, skip the header
lines := strings.Split(stats, "\n")
for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" {
lines = lines[1:]
}
if len(lines) <= 3 {
- db.log.Error("Compaction table not found")
- merr = errors.New("compaction table not found")
+ db.log.Error("Compaction leveldbTable not found")
+ merr = errors.New("compaction leveldbTable not found")
continue
}
lines = lines[3:]
- // Iterate over all the table rows, and accumulate the entries
+ // Iterate over all the leveldbTable rows, and accumulate the entries
for j := 0; j < len(compactions[i%2]); j++ {
compactions[i%2][j] = 0
}
@@ -296,7 +313,7 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
// If a warning that db is performing compaction has been displayed, any subsequent
// warnings will be withheld for one minute not to overwhelm the user.
if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
- time.Now().After(lastWritePaused.Add(writePauseWarningThrottler)) {
+ time.Now().After(lastWritePaused.Add(leveldbDegradationWarnInterval)) {
db.log.Warn("Database compacting, degraded performance")
lastWritePaused = time.Now()
}
@@ -349,37 +366,40 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
errc <- merr
}
-func (db *LDBDatabase) NewBatch() Batch {
- return &ldbBatch{db: db.db, b: new(leveldb.Batch)}
-}
-
-type ldbBatch struct {
+// leveldbBatch is a write-only leveldb batch that commits changes to its host
+// database when Write is called. A batch cannot be used concurrently.
+type leveldbBatch struct {
db *leveldb.DB
b *leveldb.Batch
size int
}
-func (b *ldbBatch) Put(key, value []byte) error {
+// Put inserts the given value into the batch for later committing.
+func (b *leveldbBatch) Put(key, value []byte) error {
b.b.Put(key, value)
b.size += len(value)
return nil
}
-func (b *ldbBatch) Delete(key []byte) error {
+// Delete inserts the a key removal into the batch for later committing.
+func (b *leveldbBatch) Delete(key []byte) error {
b.b.Delete(key)
b.size += 1
return nil
}
-func (b *ldbBatch) Write() error {
- return b.db.Write(b.b, nil)
-}
-
-func (b *ldbBatch) ValueSize() int {
+// ValueSize retrieves the amount of data queued up for writing.
+func (b *leveldbBatch) ValueSize() int {
return b.size
}
-func (b *ldbBatch) Reset() {
+// Write flushes any accumulated data to disk.
+func (b *leveldbBatch) Write() error {
+ return b.db.Write(b.b, nil)
+}
+
+// Reset resets the batch for reuse.
+func (b *leveldbBatch) Reset() {
b.b.Reset()
b.size = 0
}
diff --git a/internal/keyvalue/memorydb.go b/internal/keyvalue/memorydb.go
new file mode 100644
index 0000000000..eca99d017b
--- /dev/null
+++ b/internal/keyvalue/memorydb.go
@@ -0,0 +1,295 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package keyvalue
+
+import (
+ "errors"
+ "sort"
+ "strings"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/database"
+)
+
+var (
+ // errMemorydbClosed is returned if a memory database was already closed at the
+ // invocation of a data access operation.
+ errMemorydbClosed = errors.New("database closed")
+
+ // errMemorydbNotFound is returned if a key is requested that is not found in
+ // the provided memory database.
+ errMemorydbNotFound = errors.New("not found")
+)
+
+// MemoryDatabase is an ephemeral key-value store. Apart from basic data storage
+// functionality it also supports batch writes and iterating over the keyspace in
+// binary-alphabetical order.
+type MemoryDatabase struct {
+ db map[string][]byte
+ lock sync.RWMutex
+}
+
+// NewMemoryDatabase returns a wrapped map with all the required database interface
+// methods implemented.
+func NewMemoryDatabase() *MemoryDatabase {
+ return &MemoryDatabase{
+ db: make(map[string][]byte),
+ }
+}
+
+// NewMemoryDatabaseWithCap returns a wrapped map pre-allocated to the provided
+// capcity with all the required database interface methods implemented.
+func NewMemoryDatabaseWithCap(size int) database.KeyValueStore {
+ return &MemoryDatabase{
+ db: make(map[string][]byte, size),
+ }
+}
+
+// Close deallocates the internal map and ensures any consecutive data access op
+// failes with an error.
+func (db *MemoryDatabase) Close() error {
+ db.lock.Lock()
+ defer db.lock.Unlock()
+
+ db.db = nil
+ return nil
+}
+
+// Has retrieves if a key is present in the key-value store.
+func (db *MemoryDatabase) Has(key []byte) (bool, error) {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ if db.db == nil {
+ return false, errMemorydbClosed
+ }
+ _, ok := db.db[string(key)]
+ return ok, nil
+}
+
+// Get retrieves the given key if it's present in the key-value store.
+func (db *MemoryDatabase) Get(key []byte) ([]byte, error) {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ if db.db == nil {
+ return nil, errMemorydbClosed
+ }
+ if entry, ok := db.db[string(key)]; ok {
+ return common.CopyBytes(entry), nil
+ }
+ return nil, errMemorydbNotFound
+}
+
+// Put inserts the given value into the key-value store.
+func (db *MemoryDatabase) Put(key []byte, value []byte) error {
+ db.lock.Lock()
+ defer db.lock.Unlock()
+
+ if db.db == nil {
+ return errMemorydbClosed
+ }
+ db.db[string(key)] = common.CopyBytes(value)
+ return nil
+}
+
+// Delete removes the key from the key-value store.
+func (db *MemoryDatabase) Delete(key []byte) error {
+ db.lock.Lock()
+ defer db.lock.Unlock()
+
+ if db.db == nil {
+ return errMemorydbClosed
+ }
+ delete(db.db, string(key))
+ return nil
+}
+
+// NewBatch creates a write-only key-value store that buffers changes to its host
+// database until a final write is called.
+func (db *MemoryDatabase) NewBatch() database.Batch {
+ return &memoryBatch{
+ db: db,
+ }
+}
+
+// NewIterator creates a binary-alphabetical iterator over the entire keyspace
+// contained within the memory database.
+func (db *MemoryDatabase) NewIterator() database.Iterator {
+ return db.NewIteratorWithPrefix(nil)
+}
+
+// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
+// of database content with a particular key prefix.
+func (db *MemoryDatabase) NewIteratorWithPrefix(prefix []byte) database.Iterator {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ var (
+ pr = string(prefix)
+ keys = []string{"FAKE KEY TO SIMPLIFY NEXT"}
+ values = [][]byte{[]byte("FAKE VAL TO SIMPLIFY NEXT")}
+ )
+ // Collect the keys from the memory database corresponding to the given prefix
+ for key, _ := range db.db {
+ if strings.HasPrefix(key, pr) {
+ keys = append(keys, key)
+ }
+ }
+ // Sort the items and retrieve the associated values
+ sort.Strings(keys[1:])
+ for _, key := range keys[1:] {
+ values = append(values, db.db[key])
+ }
+ return &memoryIterator{
+ keys: keys,
+ values: values,
+ }
+}
+
+// Stat returns a particular internal stat of the database.
+func (db *MemoryDatabase) Stat(property string) (string, error) {
+ return "", errors.New("unknown property")
+}
+
+// Len returns the number of entries currently present in the memory database.
+//
+// Note, this method is only used for testing (i.e. not public in general) and
+// does not have explicit checks for closed-ness to allow simpler testing code.
+func (db *MemoryDatabase) Len() int {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ return len(db.db)
+}
+
+/*
+// Keys retrieves a copy of all the keys present in the database.
+//
+// Note, this method is only used for testing (i.e. not public in general) and
+// does not have explicit checks for closed-ness to allow simpler testing code.
+func (db *MemoryDatabase) Keys() [][]byte {
+ db.lock.RLock()
+ defer db.lock.RUnlock()
+
+ keys := [][]byte{}
+ for key := range db.db {
+ keys = append(keys, []byte(key))
+ }
+ return keys
+}*/
+
+// keyvalue is a key-value tuple tagged with a deletion field to allow creating
+// memory-database write batches.
+type keyvalue struct {
+ key []byte
+ value []byte
+ delete bool
+}
+
+// memoryBatch is a write-only memory batch that commits changes to its host
+// database when Write is called. A batch cannot be used concurrently.
+type memoryBatch struct {
+ db *MemoryDatabase
+ writes []keyvalue
+ size int
+}
+
+// Put inserts the given value into the batch for later committing.
+func (b *memoryBatch) Put(key, value []byte) error {
+ b.writes = append(b.writes, keyvalue{common.CopyBytes(key), common.CopyBytes(value), false})
+ b.size += len(value)
+ return nil
+}
+
+// Delete inserts the a key removal into the batch for later committing.
+func (b *memoryBatch) Delete(key []byte) error {
+ b.writes = append(b.writes, keyvalue{common.CopyBytes(key), nil, true})
+ b.size += 1
+ return nil
+}
+
+// ValueSize retrieves the amount of data queued up for writing.
+func (b *memoryBatch) ValueSize() int {
+ return b.size
+}
+
+// Write flushes any accumulated data to the memory database.
+func (b *memoryBatch) Write() error {
+ b.db.lock.Lock()
+ defer b.db.lock.Unlock()
+
+ for _, keyvalue := range b.writes {
+ if keyvalue.delete {
+ delete(b.db.db, string(keyvalue.key))
+ continue
+ }
+ b.db.db[string(keyvalue.key)] = keyvalue.value
+ }
+ return nil
+}
+
+// Reset resets the batch for reuse.
+func (b *memoryBatch) Reset() {
+ b.writes = b.writes[:0]
+ b.size = 0
+}
+
+// memoryIterator can walk over the (potentially partial) keyspace of a memory
+// key value store. Internally it is a deep copy of the entire iterated state,
+// sorted by keys.
+type memoryIterator struct {
+ keys []string
+ values [][]byte
+}
+
+// Next moves the iterator to the next key/value pair. It returns whether the
+// iterator is exhausted.
+func (it *memoryIterator) Next() bool {
+ if len(it.keys) > 0 {
+ it.keys = it.keys[1:]
+ it.values = it.values[1:]
+ }
+ return len(it.keys) > 0
+}
+
+// Key returns the key of the current key/value pair, or nil if done. The caller
+// should not modify the contents of the returned slice, and its contents may
+// change on the next call to Next.
+func (it *memoryIterator) Key() []byte {
+ if len(it.keys) > 0 {
+ return []byte(it.keys[0])
+ }
+ return nil
+}
+
+// Value returns the value of the current key/value pair, or nil if done. The
+// caller should not modify the contents of the returned slice, and its contents
+// may change on the next call to Next.
+func (it *memoryIterator) Value() []byte {
+ if len(it.values) > 0 {
+ return it.values[0]
+ }
+ return nil
+}
+
+// Release releases associated resources. Release should always succeed and can
+// be called multiple times without causing error.
+func (it *memoryIterator) Release() {
+ it.keys, it.values = nil, nil
+}
diff --git a/les/api_backend.go b/les/api_backend.go
index 7531396235..6f79487904 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -29,9 +29,9 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/params"
@@ -175,7 +175,7 @@ func (b *LesApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestPrice(ctx)
}
-func (b *LesApiBackend) ChainDb() ethdb.Database {
+func (b *LesApiBackend) ChainDb() database.Database {
return b.eth.chainDb
}
diff --git a/les/backend.go b/les/backend.go
index cd99f8f813..d4707821c1 100644
--- a/les/backend.go
+++ b/les/backend.go
@@ -78,7 +78,7 @@ type LightEthereum struct {
}
func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
- chainDb, err := eth.CreateDB(ctx, config, "lightchaindata")
+ chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
if err != nil {
return nil, err
}
diff --git a/les/commons.go b/les/commons.go
index 21fb25714a..f857eb2a98 100644
--- a/les/commons.go
+++ b/les/commons.go
@@ -22,8 +22,8 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -34,7 +34,7 @@ import (
type lesCommons struct {
config *eth.Config
iConfig *light.IndexerConfig
- chainDb ethdb.Database
+ chainDb database.Database
protocolManager *ProtocolManager
chtIndexer, bloomTrieIndexer *core.ChainIndexer
}
diff --git a/les/freeclient.go b/les/freeclient.go
index 5ee607be8f..9e93a25a85 100644
--- a/les/freeclient.go
+++ b/les/freeclient.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/common/prque"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -44,7 +44,7 @@ import (
// value for the client. Currently the LES protocol manager uses IP addresses
// (without port address) to identify clients.
type freeClientPool struct {
- db ethdb.Database
+ db database.Database
lock sync.Mutex
clock mclock.Clock
closed bool
@@ -64,7 +64,7 @@ const (
)
// newFreeClientPool creates a new free client pool
-func newFreeClientPool(db ethdb.Database, connectedLimit, totalLimit int, clock mclock.Clock) *freeClientPool {
+func newFreeClientPool(db database.Database, connectedLimit, totalLimit int, clock mclock.Clock) *freeClientPool {
pool := &freeClientPool{
db: db,
clock: clock,
diff --git a/les/freeclient_test.go b/les/freeclient_test.go
index e95abc7aad..51c4de39e9 100644
--- a/les/freeclient_test.go
+++ b/les/freeclient_test.go
@@ -25,7 +25,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common/mclock"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/core/rawdb"
)
func TestFreeClientPoolL10C100(t *testing.T) {
@@ -45,7 +45,7 @@ const testFreeClientPoolTicks = 500000
func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
var (
clock mclock.Simulated
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
pool = newFreeClientPool(db, connLimit, 10000, &clock)
connected = make([]bool, clientCount)
connTicks = make([]int, clientCount)
diff --git a/les/handler.go b/les/handler.go
index 46a1ed2d7b..d12066693c 100644
--- a/les/handler.go
+++ b/les/handler.go
@@ -33,9 +33,9 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
@@ -97,7 +97,7 @@ type ProtocolManager struct {
chainConfig *params.ChainConfig
iConfig *light.IndexerConfig
blockchain BlockChain
- chainDb ethdb.Database
+ chainDb database.Database
odr *LesOdr
server *LesServer
serverPool *serverPool
@@ -136,7 +136,7 @@ func NewProtocolManager(
peers *peerSet,
blockchain BlockChain,
txpool txPool,
- chainDb ethdb.Database,
+ chainDb database.Database,
odr *LesOdr,
txrelay *LesTxRelay,
serverPool *serverPool,
@@ -907,7 +907,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if reject(uint64(reqCnt), MaxHelperTrieProofsFetch) {
return errResp(ErrRequestRejected, "")
}
- trieDb := trie.NewDatabase(ethdb.NewTable(pm.chainDb, light.ChtTablePrefix))
+ trieDb := trie.NewDatabase(rawdb.NewTable(pm.chainDb, light.ChtTablePrefix))
for _, req := range req.Reqs {
if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil {
sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*pm.iConfig.ChtSize-1)
@@ -966,7 +966,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
var prefix string
if root, prefix = pm.getHelperTrie(req.Type, req.TrieIdx); root != (common.Hash{}) {
- auxTrie, _ = trie.New(root, trie.NewDatabase(ethdb.NewTable(pm.chainDb, prefix)))
+ auxTrie, _ = trie.New(root, trie.NewDatabase(rawdb.NewTable(pm.chainDb, prefix)))
}
}
if req.AuxReq == auxRoot {
diff --git a/les/handler_test.go b/les/handler_test.go
index 72ba266b3a..91f55e3b67 100644
--- a/les/handler_test.go
+++ b/les/handler_test.go
@@ -30,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
@@ -405,7 +404,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
switch protocol {
case 1:
root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(frequency-1).Hash())
- trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(server.db, light.ChtTablePrefix)))
+ trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix)))
var proof light.NodeList
trie.Prove(key, 0, &proof)
@@ -413,7 +412,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
case 2:
root := light.GetChtRoot(server.db, (frequency/config.ChtSize)-1, bc.GetHeaderByNumber(frequency-1).Hash())
- trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(server.db, light.ChtTablePrefix)))
+ trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.ChtTablePrefix)))
trie.Prove(key, 0, &proofsV2.Proofs)
}
// Assemble the requests for the different protocols
@@ -480,7 +479,7 @@ func TestGetBloombitsProofs(t *testing.T) {
var proofs HelperTrieResps
root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash())
- trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(server.db, light.BloomTrieTablePrefix)))
+ trie, _ := trie.New(root, trie.NewDatabase(rawdb.NewTable(server.db, light.BloomTrieTablePrefix)))
trie.Prove(key, 0, &proofs.Proofs)
// Send the proof request and verify the response
@@ -493,7 +492,7 @@ func TestGetBloombitsProofs(t *testing.T) {
}
func TestTransactionStatusLes2(t *testing.T) {
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db, nil)
chain := pm.blockchain.(*core.BlockChain)
config := core.DefaultTxPoolConfig
diff --git a/les/helper_test.go b/les/helper_test.go
index 02b1668c84..73ca283ded 100644
--- a/les/helper_test.go
+++ b/les/helper_test.go
@@ -29,11 +29,12 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/light"
@@ -125,7 +126,7 @@ func testChainGen(i int, block *core.BlockGen) {
}
// testIndexers creates a set of indexers with specified params for testing purpose.
-func testIndexers(db ethdb.Database, odr light.OdrBackend, iConfig *light.IndexerConfig) (*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer) {
+func testIndexers(db database.Database, odr light.OdrBackend, iConfig *light.IndexerConfig) (*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer) {
chtIndexer := light.NewChtIndexer(db, odr, iConfig.ChtSize, iConfig.ChtConfirms)
bloomIndexer := eth.NewBloomIndexer(db, iConfig.BloomSize, iConfig.BloomConfirms)
bloomTrieIndexer := light.NewBloomTrieIndexer(db, odr, iConfig.BloomSize, iConfig.BloomTrieSize)
@@ -146,7 +147,7 @@ func testRCL() RequestCostList {
// newTestProtocolManager creates a new protocol manager for testing purposes,
// with the given number of blocks already known, potential notification
// channels for different events and relative chain indexers array.
-func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) (*ProtocolManager, error) {
+func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db database.Database, ulcConfig *eth.ULCConfig) (*ProtocolManager, error) {
var (
evmux = new(event.TypeMux)
engine = ethash.NewFaker()
@@ -200,7 +201,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
// with the given number of blocks already known, potential notification
// channels for different events and relative chain indexers array. In case of an error, the constructor force-
// fails the test.
-func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db ethdb.Database, ulcConfig *eth.ULCConfig) *ProtocolManager {
+func newTestProtocolManagerMust(t *testing.T, lightSync bool, blocks int, generator func(int, *core.BlockGen), odr *LesOdr, peers *peerSet, db database.Database, ulcConfig *eth.ULCConfig) *ProtocolManager {
pm, err := newTestProtocolManager(lightSync, blocks, generator, odr, peers, db, ulcConfig)
if err != nil {
t.Fatalf("Failed to create protocol manager: %v", err)
@@ -327,7 +328,7 @@ func (p *testPeer) close() {
// TestEntity represents a network entity for testing with necessary auxiliary fields.
type TestEntity struct {
- db ethdb.Database
+ db database.Database
rPeer *peer
tPeer *testPeer
peers *peerSet
@@ -340,7 +341,7 @@ type TestEntity struct {
// newServerEnv creates a server testing environment with a connected test peer for testing purpose.
func newServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer)) (*TestEntity, func()) {
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
cIndexer, bIndexer, btIndexer := testIndexers(db, nil, light.TestServerIndexerConfig)
pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, nil, db, nil)
@@ -372,7 +373,7 @@ func newServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*cor
// newClientServerEnv creates a client/server arch environment with a connected les server and light client pair
// for testing purpose.
func newClientServerEnv(t *testing.T, blocks int, protocol int, waitIndexers func(*core.ChainIndexer, *core.ChainIndexer, *core.ChainIndexer), newPeer bool) (*TestEntity, *TestEntity, func()) {
- db, ldb := ethdb.NewMemDatabase(), ethdb.NewMemDatabase()
+ db, ldb := rawdb.NewMemoryDatabase(), rawdb.NewMemoryDatabase()
peers, lPeers := newPeerSet(), newPeerSet()
dist := newRequestDistributor(lPeers, make(chan struct{}))
diff --git a/les/odr.go b/les/odr.go
index f7592354de..5ee4fdfd9a 100644
--- a/les/odr.go
+++ b/les/odr.go
@@ -20,21 +20,21 @@ import (
"context"
"github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
)
// LesOdr implements light.OdrBackend
type LesOdr struct {
- db ethdb.Database
+ db database.Database
indexerConfig *light.IndexerConfig
chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer
retriever *retrieveManager
stop chan struct{}
}
-func NewLesOdr(db ethdb.Database, config *light.IndexerConfig, retriever *retrieveManager) *LesOdr {
+func NewLesOdr(db database.Database, config *light.IndexerConfig, retriever *retrieveManager) *LesOdr {
return &LesOdr{
db: db,
indexerConfig: config,
@@ -49,7 +49,7 @@ func (odr *LesOdr) Stop() {
}
// Database returns the backing database
-func (odr *LesOdr) Database() ethdb.Database {
+func (odr *LesOdr) Database() database.Database {
return odr.db
}
diff --git a/les/odr_requests.go b/les/odr_requests.go
index 0f2e5dd9ec..45060ee97a 100644
--- a/les/odr_requests.go
+++ b/les/odr_requests.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
@@ -51,7 +51,7 @@ type LesOdrRequest interface {
GetCost(*peer) uint64
CanSend(*peer) bool
Request(uint64, *peer) error
- Validate(ethdb.Database, *Msg) error
+ Validate(database.Database, *Msg) error
}
func LesRequest(req light.OdrRequest) LesOdrRequest {
@@ -96,7 +96,7 @@ func (r *BlockRequest) Request(reqID uint64, peer *peer) error {
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error {
+func (r *BlockRequest) Validate(db database.Database, msg *Msg) error {
log.Debug("Validating block body", "hash", r.Hash)
// Ensure we have a correct message with a single block body
@@ -152,7 +152,7 @@ func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
+func (r *ReceiptsRequest) Validate(db database.Database, msg *Msg) error {
log.Debug("Validating block receipts", "hash", r.Hash)
// Ensure we have a correct message with a single block receipt
@@ -219,7 +219,7 @@ func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
+func (r *TrieRequest) Validate(db database.Database, msg *Msg) error {
log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key)
switch msg.MsgType {
@@ -288,7 +288,7 @@ func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
+func (r *CodeRequest) Validate(db database.Database, msg *Msg) error {
log.Debug("Validating code data", "hash", r.Hash)
// Ensure we have a correct message with a single code element
@@ -399,7 +399,7 @@ func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
+func (r *ChtRequest) Validate(db database.Database, msg *Msg) error {
log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum)
switch msg.MsgType {
@@ -523,7 +523,7 @@ func (r *BloomRequest) Request(reqID uint64, peer *peer) error {
// Valid processes an ODR request reply message from the LES network
// returns true and stores results in memory if the message was a valid reply
// to the request (implementation of LesOdrRequest)
-func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
+func (r *BloomRequest) Validate(db database.Database, msg *Msg) error {
log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
// Ensure we have a correct message with a single proof element
@@ -560,7 +560,7 @@ func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error {
// readTraceDB stores the keys of database reads. We use this to check that received node
// sets contain only the trie nodes necessary to make proofs pass.
type readTraceDB struct {
- db trie.DatabaseReader
+ db database.Reader
reads map[string]struct{}
}
diff --git a/les/odr_test.go b/les/odr_test.go
index ac81fbcf02..861cda0c7b 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -30,19 +30,19 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
-type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
+type odrTestFn func(ctx context.Context, db database.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) }
func TestOdrGetBlockLes2(t *testing.T) { testOdr(t, 2, 1, odrGetBlock) }
-func odrGetBlock(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrGetBlock(ctx context.Context, db database.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
var block *types.Block
if bc != nil {
block = bc.GetBlockByHash(bhash)
@@ -60,7 +60,7 @@ func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) }
func TestOdrGetReceiptsLes2(t *testing.T) { testOdr(t, 2, 1, odrGetReceipts) }
-func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrGetReceipts(ctx context.Context, db database.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
var receipts types.Receipts
if bc != nil {
if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
@@ -82,7 +82,7 @@ func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) }
func TestOdrAccountsLes2(t *testing.T) { testOdr(t, 2, 1, odrAccounts) }
-func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrAccounts(ctx context.Context, db database.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
@@ -118,7 +118,7 @@ type callmsg struct {
func (callmsg) CheckNonce() bool { return false }
-func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
+func odrContractCall(ctx context.Context, db database.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
var res []byte
diff --git a/les/request_test.go b/les/request_test.go
index c9c1851982..594511cbad 100644
--- a/les/request_test.go
+++ b/les/request_test.go
@@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/light"
)
@@ -34,13 +34,13 @@ func secAddr(addr common.Address) []byte {
return crypto.Keccak256(addr[:])
}
-type accessTestFn func(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest
+type accessTestFn func(db database.Database, bhash common.Hash, number uint64) light.OdrRequest
func TestBlockAccessLes1(t *testing.T) { testAccess(t, 1, tfBlockAccess) }
func TestBlockAccessLes2(t *testing.T) { testAccess(t, 2, tfBlockAccess) }
-func tfBlockAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
+func tfBlockAccess(db database.Database, bhash common.Hash, number uint64) light.OdrRequest {
return &light.BlockRequest{Hash: bhash, Number: number}
}
@@ -48,7 +48,7 @@ func TestReceiptsAccessLes1(t *testing.T) { testAccess(t, 1, tfReceiptsAccess) }
func TestReceiptsAccessLes2(t *testing.T) { testAccess(t, 2, tfReceiptsAccess) }
-func tfReceiptsAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
+func tfReceiptsAccess(db database.Database, bhash common.Hash, number uint64) light.OdrRequest {
return &light.ReceiptsRequest{Hash: bhash, Number: number}
}
@@ -56,7 +56,7 @@ func TestTrieEntryAccessLes1(t *testing.T) { testAccess(t, 1, tfTrieEntryAccess)
func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) }
-func tfTrieEntryAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
+func tfTrieEntryAccess(db database.Database, bhash common.Hash, number uint64) light.OdrRequest {
if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
return &light.TrieRequest{Id: light.StateTrieID(rawdb.ReadHeader(db, bhash, *number)), Key: testBankSecureTrieKey}
}
@@ -67,7 +67,7 @@ func TestCodeAccessLes1(t *testing.T) { testAccess(t, 1, tfCodeAccess) }
func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) }
-func tfCodeAccess(db ethdb.Database, bhash common.Hash, num uint64) light.OdrRequest {
+func tfCodeAccess(db database.Database, bhash common.Hash, num uint64) light.OdrRequest {
number := rawdb.ReadHeaderNumber(db, bhash)
if number != nil {
return nil
diff --git a/les/server.go b/les/server.go
index 2ded3c184b..8d0c536a24 100644
--- a/les/server.go
+++ b/les/server.go
@@ -27,8 +27,8 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
@@ -247,7 +247,7 @@ func linRegFromBytes(data []byte) *linReg {
type requestCostStats struct {
lock sync.RWMutex
- db ethdb.Database
+ db database.Database
stats map[uint64]*linReg
}
@@ -258,7 +258,7 @@ type requestCostStatsRlp []struct {
var rcStatsKey = []byte("_requestCostStats")
-func newCostStats(db ethdb.Database) *requestCostStats {
+func newCostStats(db database.Database) *requestCostStats {
stats := make(map[uint64]*linReg)
for _, code := range reqList {
stats[code] = &linReg{cnt: 100}
diff --git a/les/serverpool.go b/les/serverpool.go
index 3f4d0a1d9b..0406db18a6 100644
--- a/les/serverpool.go
+++ b/les/serverpool.go
@@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discv5"
@@ -113,7 +113,7 @@ type registerReq struct {
// known light server nodes. It received discovered nodes, stores statistics about
// known nodes and takes care of always having enough good quality servers connected.
type serverPool struct {
- db ethdb.Database
+ db database.Database
dbKey []byte
server *p2p.Server
quit chan struct{}
@@ -141,7 +141,7 @@ type serverPool struct {
}
// newServerPool creates a new serverPool instance
-func newServerPool(db ethdb.Database, quit chan struct{}, wg *sync.WaitGroup, trustedNodes []string) *serverPool {
+func newServerPool(db database.Database, quit chan struct{}, wg *sync.WaitGroup, trustedNodes []string) *serverPool {
pool := &serverPool{
db: db,
quit: quit,
diff --git a/les/ulc_test.go b/les/ulc_test.go
index 3b95e6368e..d82de29234 100644
--- a/les/ulc_test.go
+++ b/les/ulc_test.go
@@ -1,20 +1,18 @@
package les
import (
+ "crypto/ecdsa"
"fmt"
+ "math/big"
+ "net"
"reflect"
"testing"
"time"
- "net"
-
- "crypto/ecdsa"
- "math/big"
-
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -197,7 +195,7 @@ func connectPeers(full, light pairPeer, version int) (*peer, *peer, error) {
// newFullPeerPair creates node with full sync mode
func newFullPeerPair(t *testing.T, index int, numberOfblocks int, chainGen func(int, *core.BlockGen)) pairPeer {
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
pmFull := newTestProtocolManagerMust(t, false, numberOfblocks, chainGen, nil, nil, db, nil)
@@ -219,7 +217,7 @@ func newLightPeer(t *testing.T, ulcConfig *eth.ULCConfig) pairPeer {
peers := newPeerSet()
dist := newRequestDistributor(peers, make(chan struct{}))
rm := newRetrieveManager(peers, dist, nil)
- ldb := ethdb.NewMemDatabase()
+ ldb := rawdb.NewMemoryDatabase()
odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm)
diff --git a/light/lightchain.go b/light/lightchain.go
index 5019622c79..9caf00ad5c 100644
--- a/light/lightchain.go
+++ b/light/lightchain.go
@@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
@@ -49,7 +49,7 @@ var (
type LightChain struct {
hc *core.HeaderChain
indexerConfig *IndexerConfig
- chainDb ethdb.Database
+ chainDb database.Database
engine consensus.Engine
odr OdrBackend
chainFeed event.Feed
diff --git a/light/lightchain_test.go b/light/lightchain_test.go
index 374cb53198..b3f1de45b4 100644
--- a/light/lightchain_test.go
+++ b/light/lightchain_test.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
)
@@ -37,7 +37,7 @@ var (
)
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
-func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
+func makeHeaderChain(parent *types.Header, n int, db database.Database, seed int) []*types.Header {
blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), ethash.NewFaker(), db, n, func(i int, b *core.BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
})
@@ -51,8 +51,8 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
// newCanonical creates a chain database, and injects a deterministic canonical
// 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()
+func newCanonical(n int) (database.Database, *LightChain, error) {
+ db := rawdb.NewMemoryDatabase()
gspec := core.Genesis{Config: params.TestChainConfig}
genesis := gspec.MustCommit(db)
blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker())
@@ -69,7 +69,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 := rawdb.NewMemoryDatabase()
gspec := &core.Genesis{
Difficulty: big.NewInt(1),
Config: params.TestChainConfig,
@@ -265,11 +265,11 @@ func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.
type dummyOdr struct {
OdrBackend
- db ethdb.Database
+ db database.Database
indexerConfig *IndexerConfig
}
-func (odr *dummyOdr) Database() ethdb.Database {
+func (odr *dummyOdr) Database() database.Database {
return odr.db
}
diff --git a/light/nodeset.go b/light/nodeset.go
index 6f25219c13..301b289661 100644
--- a/light/nodeset.go
+++ b/light/nodeset.go
@@ -22,7 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -106,7 +106,7 @@ func (db *NodeSet) NodeList() NodeList {
}
// Store writes the contents of the set to the given database
-func (db *NodeSet) Store(target ethdb.Putter) {
+func (db *NodeSet) Store(target database.Writer) {
db.lock.RLock()
defer db.lock.RUnlock()
@@ -115,11 +115,11 @@ func (db *NodeSet) Store(target ethdb.Putter) {
}
}
-// NodeList stores an ordered list of trie nodes. It implements ethdb.Putter.
+// NodeList stores an ordered list of trie nodes. It implements database.Writer.
type NodeList []rlp.RawValue
// Store writes the contents of the list to the given database
-func (n NodeList) Store(db ethdb.Putter) {
+func (n NodeList) Store(db database.Writer) {
for _, node := range n {
db.Put(crypto.Keccak256(node), node)
}
diff --git a/light/odr.go b/light/odr.go
index 900be05440..3cf922aa84 100644
--- a/light/odr.go
+++ b/light/odr.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
)
// NoOdr is the default context passed to an ODR capable function when the ODR
@@ -39,7 +39,7 @@ var ErrNoPeers = errors.New("no suitable peers available")
// OdrBackend is an interface to a backend service that handles ODR retrievals type
type OdrBackend interface {
- Database() ethdb.Database
+ Database() database.Database
ChtIndexer() *core.ChainIndexer
BloomTrieIndexer() *core.ChainIndexer
BloomIndexer() *core.ChainIndexer
@@ -49,7 +49,7 @@ type OdrBackend interface {
// OdrRequest is an interface for retrieval requests
type OdrRequest interface {
- StoreResult(db ethdb.Database)
+ StoreResult(db database.Database)
}
// TrieID identifies a state or account storage trie
@@ -91,7 +91,7 @@ type TrieRequest struct {
}
// StoreResult stores the retrieved data in local database
-func (req *TrieRequest) StoreResult(db ethdb.Database) {
+func (req *TrieRequest) StoreResult(db database.Database) {
req.Proof.Store(db)
}
@@ -104,7 +104,7 @@ type CodeRequest struct {
}
// StoreResult stores the retrieved data in local database
-func (req *CodeRequest) StoreResult(db ethdb.Database) {
+func (req *CodeRequest) StoreResult(db database.Database) {
db.Put(req.Hash[:], req.Data)
}
@@ -117,7 +117,7 @@ type BlockRequest struct {
}
// StoreResult stores the retrieved data in local database
-func (req *BlockRequest) StoreResult(db ethdb.Database) {
+func (req *BlockRequest) StoreResult(db database.Database) {
rawdb.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp)
}
@@ -130,7 +130,7 @@ type ReceiptsRequest struct {
}
// StoreResult stores the retrieved data in local database
-func (req *ReceiptsRequest) StoreResult(db ethdb.Database) {
+func (req *ReceiptsRequest) StoreResult(db database.Database) {
rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts)
}
@@ -146,7 +146,7 @@ type ChtRequest struct {
}
// StoreResult stores the retrieved data in local database
-func (req *ChtRequest) StoreResult(db ethdb.Database) {
+func (req *ChtRequest) StoreResult(db database.Database) {
hash, num := req.Header.Hash(), req.Header.Number.Uint64()
rawdb.WriteHeader(db, req.Header)
@@ -167,7 +167,7 @@ type BloomRequest struct {
}
// StoreResult stores the retrieved data in local database
-func (req *BloomRequest) StoreResult(db ethdb.Database) {
+func (req *BloomRequest) StoreResult(db database.Database) {
for i, sectionIdx := range req.SectionIndexList {
sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1)
// if we don't have the canonical hash stored for this section head number, we'll still store it under
diff --git a/light/odr_test.go b/light/odr_test.go
index 3da7b3055e..a10408e1a6 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
@@ -56,11 +56,11 @@ var (
type testOdr struct {
OdrBackend
indexerConfig *IndexerConfig
- sdb, ldb ethdb.Database
+ sdb, ldb database.Database
disable bool
}
-func (odr *testOdr) Database() ethdb.Database {
+func (odr *testOdr) Database() database.Database {
return odr.ldb
}
@@ -97,11 +97,11 @@ func (odr *testOdr) IndexerConfig() *IndexerConfig {
return odr.indexerConfig
}
-type odrTestFn func(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error)
+type odrTestFn func(ctx context.Context, db database.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error)
func TestOdrGetBlockLes1(t *testing.T) { testChainOdr(t, 1, odrGetBlock) }
-func odrGetBlock(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
+func odrGetBlock(ctx context.Context, db database.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
var block *types.Block
if bc != nil {
block = bc.GetBlockByHash(bhash)
@@ -117,7 +117,7 @@ func odrGetBlock(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
func TestOdrGetReceiptsLes1(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) }
-func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
+func odrGetReceipts(ctx context.Context, db database.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
var receipts types.Receipts
if bc != nil {
number := rawdb.ReadHeaderNumber(db, bhash)
@@ -139,7 +139,7 @@ func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain,
func TestOdrAccountsLes1(t *testing.T) { testChainOdr(t, 1, odrAccounts) }
-func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
+func odrAccounts(ctx context.Context, db database.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
@@ -169,7 +169,7 @@ type callmsg struct {
func (callmsg) CheckNonce() bool { return false }
-func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
+func odrContractCall(ctx context.Context, db database.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
config := params.TestChainConfig
@@ -250,8 +250,8 @@ func testChainGen(i int, block *core.BlockGen) {
func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
var (
- sdb = ethdb.NewMemDatabase()
- ldb = ethdb.NewMemDatabase()
+ sdb = rawdb.NewMemoryDatabase()
+ ldb = rawdb.NewMemoryDatabase()
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb)
)
diff --git a/light/postprocess.go b/light/postprocess.go
index dd1b74a7be..4b98832b9a 100644
--- a/light/postprocess.go
+++ b/light/postprocess.go
@@ -29,7 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
@@ -127,7 +127,7 @@ type ChtNode struct {
// GetChtRoot reads the CHT root associated to the given section from the database
// Note that sectionIdx is specified according to LES/1 CHT section size.
-func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash {
+func GetChtRoot(db database.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash {
var encNumber [8]byte
binary.BigEndian.PutUint64(encNumber[:], sectionIdx)
data, _ := db.Get(append(append(chtPrefix, encNumber[:]...), sectionHead.Bytes()...))
@@ -136,7 +136,7 @@ func GetChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) c
// StoreChtRoot writes the CHT root associated to the given section into the database
// Note that sectionIdx is specified according to LES/1 CHT section size.
-func StoreChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) {
+func StoreChtRoot(db database.Database, sectionIdx uint64, sectionHead, root common.Hash) {
var encNumber [8]byte
binary.BigEndian.PutUint64(encNumber[:], sectionIdx)
db.Put(append(append(chtPrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes())
@@ -144,7 +144,7 @@ func StoreChtRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common
// ChtIndexerBackend implements core.ChainIndexerBackend.
type ChtIndexerBackend struct {
- diskdb, trieTable ethdb.Database
+ diskdb, trieTable database.Database
odr OdrBackend
triedb *trie.Database
section, sectionSize uint64
@@ -153,8 +153,8 @@ type ChtIndexerBackend struct {
}
// NewChtIndexer creates a Cht chain indexer
-func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64) *core.ChainIndexer {
- trieTable := ethdb.NewTable(db, ChtTablePrefix)
+func NewChtIndexer(db database.Database, odr OdrBackend, size, confirms uint64) *core.ChainIndexer {
+ trieTable := rawdb.NewTable(db, ChtTablePrefix)
backend := &ChtIndexerBackend{
diskdb: db,
odr: odr,
@@ -162,7 +162,7 @@ func NewChtIndexer(db ethdb.Database, odr OdrBackend, size, confirms uint64) *co
triedb: trie.NewDatabaseWithCache(trieTable, 1), // Use a tiny cache only to keep memory down
sectionSize: size,
}
- return core.NewChainIndexer(db, ethdb.NewTable(db, "chtIndex-"), backend, size, confirms, time.Millisecond*100, "cht")
+ return core.NewChainIndexer(db, rawdb.NewTable(db, "chtIndex-"), backend, size, confirms, time.Millisecond*100, "cht")
}
// fetchMissingNodes tries to retrieve the last entry of the latest trusted CHT from the
@@ -247,7 +247,7 @@ var (
)
// GetBloomTrieRoot reads the BloomTrie root assoctiated to the given section from the database
-func GetBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash {
+func GetBloomTrieRoot(db database.Database, sectionIdx uint64, sectionHead common.Hash) common.Hash {
var encNumber [8]byte
binary.BigEndian.PutUint64(encNumber[:], sectionIdx)
data, _ := db.Get(append(append(bloomTriePrefix, encNumber[:]...), sectionHead.Bytes()...))
@@ -255,7 +255,7 @@ func GetBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead common.H
}
// StoreBloomTrieRoot writes the BloomTrie root assoctiated to the given section into the database
-func StoreBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root common.Hash) {
+func StoreBloomTrieRoot(db database.Database, sectionIdx uint64, sectionHead, root common.Hash) {
var encNumber [8]byte
binary.BigEndian.PutUint64(encNumber[:], sectionIdx)
db.Put(append(append(bloomTriePrefix, encNumber[:]...), sectionHead.Bytes()...), root.Bytes())
@@ -263,7 +263,7 @@ func StoreBloomTrieRoot(db ethdb.Database, sectionIdx uint64, sectionHead, root
// BloomTrieIndexerBackend implements core.ChainIndexerBackend
type BloomTrieIndexerBackend struct {
- diskdb, trieTable ethdb.Database
+ diskdb, trieTable database.Database
triedb *trie.Database
odr OdrBackend
section uint64
@@ -275,8 +275,8 @@ type BloomTrieIndexerBackend struct {
}
// NewBloomTrieIndexer creates a BloomTrie chain indexer
-func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uint64) *core.ChainIndexer {
- trieTable := ethdb.NewTable(db, BloomTrieTablePrefix)
+func NewBloomTrieIndexer(db database.Database, odr OdrBackend, parentSize, size uint64) *core.ChainIndexer {
+ trieTable := rawdb.NewTable(db, BloomTrieTablePrefix)
backend := &BloomTrieIndexerBackend{
diskdb: db,
odr: odr,
@@ -287,7 +287,7 @@ func NewBloomTrieIndexer(db ethdb.Database, odr OdrBackend, parentSize, size uin
}
backend.bloomTrieRatio = size / parentSize
backend.sectionHeads = make([]common.Hash, backend.bloomTrieRatio)
- return core.NewChainIndexer(db, ethdb.NewTable(db, "bltIndex-"), backend, size, 0, time.Millisecond*100, "bloomtrie")
+ return core.NewChainIndexer(db, rawdb.NewTable(db, "bltIndex-"), backend, size, 0, time.Millisecond*100, "bloomtrie")
}
// fetchMissingNodes tries to retrieve the last entries of the latest trusted bloom trie from the
diff --git a/light/trie.go b/light/trie.go
index ab4e18b43e..2102f14c89 100644
--- a/light/trie.go
+++ b/light/trie.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/trie"
)
@@ -141,7 +141,7 @@ func (t *odrTrie) GetKey(sha []byte) []byte {
return nil
}
-func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
+func (t *odrTrie) Prove(key []byte, fromLevel uint, proofDb database.Writer) error {
return errors.New("not implemented, needs client/server interface split")
}
diff --git a/light/trie_test.go b/light/trie_test.go
index 5b5fce31d9..4919f89641 100644
--- a/light/trie_test.go
+++ b/light/trie_test.go
@@ -25,17 +25,17 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)
func TestNodeIterator(t *testing.T) {
var (
- fulldb = ethdb.NewMemDatabase()
- lightdb = ethdb.NewMemDatabase()
+ fulldb = rawdb.NewMemoryDatabase()
+ lightdb = rawdb.NewMemoryDatabase()
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(fulldb)
)
diff --git a/light/txpool.go b/light/txpool.go
index e945ef2ec1..0e73587f44 100644
--- a/light/txpool.go
+++ b/light/txpool.go
@@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
@@ -59,7 +59,7 @@ type TxPool struct {
mu sync.RWMutex
chain *LightChain
odr OdrBackend
- chainDb ethdb.Database
+ chainDb database.Database
relay TxRelayBackend
head common.Hash
nonce map[common.Address]uint64 // "pending" nonce
diff --git a/light/txpool_test.go b/light/txpool_test.go
index ce77573efd..4f446c6ca2 100644
--- a/light/txpool_test.go
+++ b/light/txpool_test.go
@@ -26,9 +26,9 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -81,8 +81,8 @@ func TestTxPool(t *testing.T) {
}
var (
- sdb = ethdb.NewMemDatabase()
- ldb = ethdb.NewMemDatabase()
+ sdb = rawdb.NewMemoryDatabase()
+ ldb = rawdb.NewMemoryDatabase()
gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb)
)
diff --git a/miner/worker_test.go b/miner/worker_test.go
index bfa9cbd21d..62fa6e2a63 100644
--- a/miner/worker_test.go
+++ b/miner/worker_test.go
@@ -26,10 +26,11 @@ import (
"github.com/ethereum/go-ethereum/consensus/clique"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
)
@@ -70,7 +71,7 @@ func init() {
// testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing.
type testWorkerBackend struct {
- db ethdb.Database
+ db database.Database
txPool *core.TxPool
chain *core.BlockChain
testTxFeed event.Feed
@@ -79,7 +80,7 @@ type testWorkerBackend struct {
func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, n int) *testWorkerBackend {
var (
- db = ethdb.NewMemDatabase()
+ db = rawdb.NewMemoryDatabase()
gspec = core.Genesis{
Config: chainConfig,
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
@@ -142,7 +143,7 @@ func TestPendingStateAndBlockEthash(t *testing.T) {
testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker())
}
func TestPendingStateAndBlockClique(t *testing.T) {
- testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase()))
+ testPendingStateAndBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase()))
}
func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
@@ -174,7 +175,7 @@ func TestEmptyWorkEthash(t *testing.T) {
testEmptyWork(t, ethashChainConfig, ethash.NewFaker())
}
func TestEmptyWorkClique(t *testing.T) {
- testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase()))
+ testEmptyWork(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase()))
}
func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
@@ -291,7 +292,7 @@ func TestRegenerateMiningBlockEthash(t *testing.T) {
}
func TestRegenerateMiningBlockClique(t *testing.T) {
- testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase()))
+ testRegenerateMiningBlock(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase()))
}
func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
@@ -356,7 +357,7 @@ func TestAdjustIntervalEthash(t *testing.T) {
}
func TestAdjustIntervalClique(t *testing.T) {
- testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, ethdb.NewMemDatabase()))
+ testAdjustInterval(t, cliqueChainConfig, clique.New(cliqueChainConfig.Clique, rawdb.NewMemoryDatabase()))
}
func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
diff --git a/node/node.go b/node/node.go
index f267cdc461..e1f65f2d83 100644
--- a/node/node.go
+++ b/node/node.go
@@ -27,7 +27,8 @@ import (
"sync"
"github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
@@ -601,11 +602,11 @@ func (n *Node) EventMux() *event.TypeMux {
// OpenDatabase opens an existing database with the given name (or creates one if no
// previous can be found) from within the node's instance directory. If the node is
// ephemeral, a memory database is returned.
-func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) {
+func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (database.Database, error) {
if n.config.DataDir == "" {
- return ethdb.NewMemDatabase(), nil
+ return rawdb.NewMemoryDatabase(), nil
}
- return ethdb.NewLDBDatabase(n.config.ResolvePath(name), cache, handles)
+ return rawdb.NewLeveldbDatabase(n.config.ResolvePath(name), cache, handles, namespace)
}
// ResolvePath returns the absolute path of a resource in the instance directory.
diff --git a/node/service.go b/node/service.go
index 6a96d9b1e1..a081e128c9 100644
--- a/node/service.go
+++ b/node/service.go
@@ -17,10 +17,12 @@
package node
import (
+ "path/filepath"
"reflect"
"github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
@@ -39,11 +41,35 @@ type ServiceContext struct {
// OpenDatabase opens an existing database with the given name (or creates one
// if no previous can be found) from within the node's data directory. If the
// node is an ephemeral one, a memory database is returned.
-func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int) (ethdb.Database, error) {
+func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string) (database.Database, error) {
if ctx.config.DataDir == "" {
- return ethdb.NewMemDatabase(), nil
+ return rawdb.NewMemoryDatabase(), nil
}
- db, err := ethdb.NewLDBDatabase(ctx.config.ResolvePath(name), cache, handles)
+ db, err := rawdb.NewLeveldbDatabase(ctx.config.ResolvePath(name), cache, handles, namespace)
+ if err != nil {
+ return nil, err
+ }
+ return db, nil
+}
+
+// OpenDatabaseWithFreezer opens an existing database with the given name (or
+// creates one if no previous can be found) from within the node's data directory,
+// also attaching a chain freezer to it that moves ancient chain data from the
+// database to immutable append-only files. If the node is an ephemeral one, a
+// memory database is returned.
+func (ctx *ServiceContext) OpenDatabaseWithFreezer(name string, cache int, handles int, freezer string, namespace string) (database.Database, error) {
+ if ctx.config.DataDir == "" {
+ return rawdb.NewMemoryDatabase(), nil
+ }
+ root := ctx.config.ResolvePath(name)
+
+ switch {
+ case freezer == "":
+ freezer = filepath.Join(root, "ancient")
+ case !filepath.IsAbs(freezer):
+ freezer = ctx.config.ResolvePath(freezer)
+ }
+ db, err := rawdb.NewLeveldbDatabaseWithFreezer(root, cache, handles, freezer, namespace)
if err != nil {
return nil, err
}
diff --git a/node/service_test.go b/node/service_test.go
index 73c51eccbb..63004a51ab 100644
--- a/node/service_test.go
+++ b/node/service_test.go
@@ -39,7 +39,7 @@ func TestContextDatabases(t *testing.T) {
}
// Request the opening/creation of a database and ensure it persists to disk
ctx := &ServiceContext{config: &Config{Name: "unit-test", DataDir: dir}}
- db, err := ctx.OpenDatabase("persistent", 0, 0)
+ db, err := ctx.OpenDatabase("persistent", 0, 0, "")
if err != nil {
t.Fatalf("failed to open persistent database: %v", err)
}
@@ -50,7 +50,7 @@ func TestContextDatabases(t *testing.T) {
}
// Request th opening/creation of an ephemeral database and ensure it's not persisted
ctx = &ServiceContext{config: &Config{DataDir: ""}}
- db, err = ctx.OpenDatabase("ephemeral", 0, 0)
+ db, err = ctx.OpenDatabase("ephemeral", 0, 0, "")
if err != nil {
t.Fatalf("failed to open ephemeral database: %v", err)
}
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 9fa69bf4ed..d40a3726c0 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -30,10 +30,10 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -101,7 +101,7 @@ func (t *BlockTest) Run() error {
}
// import pre accounts & construct test genesis block & state root
- db := ethdb.NewMemDatabase()
+ db := rawdb.NewMemoryDatabase()
gblock, err := t.genesis(config).Commit(db)
if err != nil {
return err
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index 436284196d..ff275f8afd 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -27,11 +27,12 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"golang.org/x/crypto/sha3"
@@ -126,7 +127,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateD
return nil, UnsupportedForkError{subtest.Fork}
}
block := t.genesis(config).ToBlock(nil)
- statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre)
+ statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre)
post := t.json.Post[subtest.Fork][subtest.Index]
msg, err := t.json.Tx.toMessage(post)
@@ -168,7 +169,7 @@ func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas]
}
-func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
+func MakePreState(db database.Database, accounts core.GenesisAlloc) *state.StateDB {
sdb := state.NewDatabase(db)
statedb, _ := state.New(common.Hash{}, sdb)
for addr, a := range accounts {
diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go
index cb81c5b94e..91566c47e3 100644
--- a/tests/vm_test_util.go
+++ b/tests/vm_test_util.go
@@ -26,10 +26,10 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
)
@@ -79,7 +79,7 @@ type vmExecMarshaling struct {
}
func (t *VMTest) Run(vmconfig vm.Config) error {
- statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre)
+ statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre)
ret, gasRemaining, err := t.exec(statedb, vmconfig)
if t.json.GasRemaining == nil {
diff --git a/trie/database.go b/trie/database.go
index aba5943f5a..45aeedee51 100644
--- a/trie/database.go
+++ b/trie/database.go
@@ -24,7 +24,7 @@ import (
"github.com/allegro/bigcache"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp"
@@ -55,20 +55,11 @@ var secureKeyPrefix = []byte("secure-key-")
// secureKeyLength is the length of the above prefix + 32byte hash.
const secureKeyLength = 11 + 32
-// DatabaseReader wraps the Get and Has method of a backing store for the trie.
-type DatabaseReader interface {
- // Get retrieves the value associated with key from the database.
- Get(key []byte) (value []byte, err error)
-
- // Has retrieves whether a key is present in the database.
- Has(key []byte) (bool, error)
-}
-
// Database is an intermediate write layer between the trie data structures and
// the disk database. The aim is to accumulate trie writes in-memory and only
// periodically flush a couple tries to disk, garbage collecting the remainder.
type Database struct {
- diskdb ethdb.Database // Persistent storage for matured trie nodes
+ diskdb database.KeyValueStore // Persistent storage for matured trie nodes
cleans *bigcache.BigCache // GC friendly memory cache of clean node RLPs
dirties map[common.Hash]*cachedNode // Data and references relationships of dirty nodes
@@ -271,14 +262,14 @@ func expandNode(hash hashNode, n node, cachegen uint16) node {
// NewDatabase creates a new trie database to store ephemeral trie content before
// its written out to disk or garbage collected. No read cache is created, so all
// data retrievals will hit the underlying disk database.
-func NewDatabase(diskdb ethdb.Database) *Database {
+func NewDatabase(diskdb database.KeyValueStore) *Database {
return NewDatabaseWithCache(diskdb, 0)
}
// NewDatabaseWithCache creates a new trie database to store ephemeral trie content
// before its written out to disk or garbage collected. It also acts as a read cache
// for nodes loaded from disk.
-func NewDatabaseWithCache(diskdb ethdb.Database, cache int) *Database {
+func NewDatabaseWithCache(diskdb database.KeyValueStore, cache int) *Database {
var cleans *bigcache.BigCache
if cache > 0 {
cleans, _ = bigcache.NewBigCache(bigcache.Config{
@@ -298,7 +289,7 @@ func NewDatabaseWithCache(diskdb ethdb.Database, cache int) *Database {
}
// DiskDB retrieves the persistent storage backing the trie database.
-func (db *Database) DiskDB() DatabaseReader {
+func (db *Database) DiskDB() database.Reader {
return db.diskdb
}
@@ -582,7 +573,7 @@ func (db *Database) Cap(limit common.StorageSize) error {
db.lock.RUnlock()
return err
}
- if batch.ValueSize() > ethdb.IdealBatchSize {
+ if batch.ValueSize() > database.IdealBatchSize {
if err := batch.Write(); err != nil {
db.lock.RUnlock()
return err
@@ -601,7 +592,7 @@ func (db *Database) Cap(limit common.StorageSize) error {
return err
}
// If we exceeded the ideal batch size, commit and reset
- if batch.ValueSize() >= ethdb.IdealBatchSize {
+ if batch.ValueSize() >= database.IdealBatchSize {
if err := batch.Write(); err != nil {
log.Error("Failed to write flush list to disk", "err", err)
db.lock.RUnlock()
@@ -677,7 +668,7 @@ func (db *Database) Commit(node common.Hash, report bool) error {
db.lock.RUnlock()
return err
}
- if batch.ValueSize() > ethdb.IdealBatchSize {
+ if batch.ValueSize() > database.IdealBatchSize {
if err := batch.Write(); err != nil {
db.lock.RUnlock()
return err
@@ -728,7 +719,7 @@ func (db *Database) Commit(node common.Hash, report bool) error {
}
// commit is the private locked version of Commit.
-func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error {
+func (db *Database) commit(hash common.Hash, batch database.Batch) error {
// If the node does not exist, it's a previously committed node
node, ok := db.dirties[hash]
if !ok {
@@ -743,7 +734,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch) error {
return err
}
// If we've reached an optimal batch size, commit and start over
- if batch.ValueSize() >= ethdb.IdealBatchSize {
+ if batch.ValueSize() >= database.IdealBatchSize {
if err := batch.Write(); err != nil {
return err
}
diff --git a/trie/iterator_test.go b/trie/iterator_test.go
index 4f633b195f..7883f87af0 100644
--- a/trie/iterator_test.go
+++ b/trie/iterator_test.go
@@ -23,7 +23,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/internal/keyvalue"
)
func TestIterator(t *testing.T) {
@@ -120,11 +120,14 @@ func TestNodeIteratorCoverage(t *testing.T) {
}
}
}
- for _, key := range db.diskdb.(*ethdb.MemDatabase).Keys() {
+ it := db.diskdb.NewIterator()
+ for it.Next() {
+ key := it.Key()
if _, ok := hashes[common.BytesToHash(key)]; !ok {
t.Errorf("state entry not reported %x", key)
}
}
+ it.Release()
}
type kvs struct{ k, v string }
@@ -289,7 +292,7 @@ func TestIteratorContinueAfterErrorDisk(t *testing.T) { testIteratorContinueA
func TestIteratorContinueAfterErrorMemonly(t *testing.T) { testIteratorContinueAfterError(t, true) }
func testIteratorContinueAfterError(t *testing.T, memonly bool) {
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
tr, _ := New(common.Hash{}, triedb)
@@ -309,7 +312,11 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool) {
if memonly {
memKeys = triedb.Nodes()
} else {
- diskKeys = diskdb.Keys()
+ it := diskdb.NewIterator()
+ for it.Next() {
+ diskKeys = append(diskKeys, it.Key())
+ }
+ it.Release()
}
for i := 0; i < 20; i++ {
// Create trie that will load all nodes from DB.
@@ -376,7 +383,7 @@ func TestIteratorContinueAfterSeekErrorMemonly(t *testing.T) {
func testIteratorContinueAfterSeekError(t *testing.T, memonly bool) {
// Commit test trie to db, then remove the node containing "bars".
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
ctr, _ := New(common.Hash{}, triedb)
diff --git a/trie/proof.go b/trie/proof.go
index f90ecd7d88..b2401c31c8 100644
--- a/trie/proof.go
+++ b/trie/proof.go
@@ -22,7 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -34,7 +34,7 @@ import (
// If the trie does not contain a value for key, the returned proof contains all
// nodes of the longest existing prefix of the key (at least the root node), ending
// with the node that proves the absence of the key.
-func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
+func (t *Trie) Prove(key []byte, fromLevel uint, proofDb database.Writer) error {
// Collect all nodes on the path to key.
key = keybytesToHex(key)
nodes := []node{}
@@ -97,14 +97,14 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
// If the trie does not contain a value for key, the returned proof contains all
// nodes of the longest existing prefix of the key (at least the root node), ending
// with the node that proves the absence of the key.
-func (t *SecureTrie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error {
+func (t *SecureTrie) Prove(key []byte, fromLevel uint, proofDb database.Writer) error {
return t.trie.Prove(key, fromLevel, proofDb)
}
// VerifyProof checks merkle proofs. The given proof must contain the value for
// key in a trie with the given root hash. VerifyProof returns an error if the
// proof contains invalid trie nodes or the wrong value.
-func VerifyProof(rootHash common.Hash, key []byte, proofDb DatabaseReader) (value []byte, nodes int, err error) {
+func VerifyProof(rootHash common.Hash, key []byte, proofDb database.Reader) (value []byte, nodes int, err error) {
key = keybytesToHex(key)
wantHash := rootHash
for i := 0; ; i++ {
diff --git a/trie/proof_test.go b/trie/proof_test.go
index 996f874781..24222c6400 100644
--- a/trie/proof_test.go
+++ b/trie/proof_test.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/internal/keyvalue"
)
func init() {
@@ -34,18 +34,18 @@ func init() {
// makeProvers creates Merkle trie provers based on different implementations to
// test all variations.
-func makeProvers(trie *Trie) []func(key []byte) *ethdb.MemDatabase {
- var provers []func(key []byte) *ethdb.MemDatabase
+func makeProvers(trie *Trie) []func(key []byte) *keyvalue.MemoryDatabase {
+ var provers []func(key []byte) *keyvalue.MemoryDatabase
// Create a direct trie based Merkle prover
- provers = append(provers, func(key []byte) *ethdb.MemDatabase {
- proof := ethdb.NewMemDatabase()
+ provers = append(provers, func(key []byte) *keyvalue.MemoryDatabase {
+ proof := keyvalue.NewMemoryDatabase()
trie.Prove(key, 0, proof)
return proof
})
// Create a leaf iterator based Merkle prover
- provers = append(provers, func(key []byte) *ethdb.MemDatabase {
- proof := ethdb.NewMemDatabase()
+ provers = append(provers, func(key []byte) *keyvalue.MemoryDatabase {
+ proof := keyvalue.NewMemoryDatabase()
if it := NewIterator(trie.NodeIterator(key)); it.Next() && bytes.Equal(key, it.Key) {
for _, p := range it.Prove() {
proof.Put(crypto.Keccak256(p), p)
@@ -106,9 +106,14 @@ func TestBadProof(t *testing.T) {
if proof == nil {
t.Fatalf("prover %d: nil proof", i)
}
- key := proof.Keys()[mrand.Intn(proof.Len())]
+ it := proof.NewIterator()
+ for i, d := 0, mrand.Intn(proof.Len()); i <= d; i++ {
+ it.Next()
+ }
+ key := it.Key()
val, _ := proof.Get(key)
proof.Delete(key)
+ it.Release()
mutateByte(val)
proof.Put(crypto.Keccak256(val), val)
@@ -127,7 +132,7 @@ func TestMissingKeyProof(t *testing.T) {
updateString(trie, "k", "v")
for i, key := range []string{"a", "j", "l", "z"} {
- proof := ethdb.NewMemDatabase()
+ proof := keyvalue.NewMemoryDatabase()
trie.Prove([]byte(key), 0, proof)
if proof.Len() != 1 {
@@ -164,8 +169,8 @@ func BenchmarkProve(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
kv := vals[keys[i%len(keys)]]
- proofs := ethdb.NewMemDatabase()
- if trie.Prove(kv.k, 0, proofs); len(proofs.Keys()) == 0 {
+ proofs := keyvalue.NewMemoryDatabase()
+ if trie.Prove(kv.k, 0, proofs); proofs.Len() == 0 {
b.Fatalf("zero length proof for %x", kv.k)
}
}
@@ -175,10 +180,10 @@ func BenchmarkVerifyProof(b *testing.B) {
trie, vals := randomTrie(100)
root := trie.Hash()
var keys []string
- var proofs []*ethdb.MemDatabase
+ var proofs []*keyvalue.MemoryDatabase
for k := range vals {
keys = append(keys, k)
- proof := ethdb.NewMemDatabase()
+ proof := keyvalue.NewMemoryDatabase()
trie.Prove([]byte(k), 0, proof)
proofs = append(proofs, proof)
}
diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go
index d16d999684..52ee7c9d31 100644
--- a/trie/secure_trie_test.go
+++ b/trie/secure_trie_test.go
@@ -24,18 +24,18 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/internal/keyvalue"
)
func newEmptySecure() *SecureTrie {
- trie, _ := NewSecure(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()), 0)
+ trie, _ := NewSecure(common.Hash{}, NewDatabase(keyvalue.NewMemoryDatabase()), 0)
return trie
}
// makeTestSecureTrie creates a large enough secure trie for testing.
func makeTestSecureTrie() (*Database, *SecureTrie, map[string][]byte) {
// Create an empty trie
- triedb := NewDatabase(ethdb.NewMemDatabase())
+ triedb := NewDatabase(keyvalue.NewMemoryDatabase())
trie, _ := NewSecure(common.Hash{}, triedb, 0)
diff --git a/trie/sync.go b/trie/sync.go
index 67dff5a8b6..d6f4eace5a 100644
--- a/trie/sync.go
+++ b/trie/sync.go
@@ -22,7 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/prque"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
)
// ErrNotRequested is returned by the trie sync when it's requested to process a
@@ -72,14 +72,14 @@ func newSyncMemBatch() *syncMemBatch {
// unknown trie hashes to retrieve, accepts node data associated with said hashes
// and reconstructs the trie step by step until all is done.
type Sync struct {
- database DatabaseReader // Persistent database to check for existing entries
+ database database.Reader // Persistent database to check for existing entries
membatch *syncMemBatch // Memory buffer to avoid frequent database writes
requests map[common.Hash]*request // Pending requests pertaining to a key hash
queue *prque.Prque // Priority queue with the pending requests
}
// NewSync creates a new trie data download scheduler.
-func NewSync(root common.Hash, database DatabaseReader, callback LeafCallback) *Sync {
+func NewSync(root common.Hash, database database.Reader, callback LeafCallback) *Sync {
ts := &Sync{
database: database,
membatch: newSyncMemBatch(),
@@ -213,7 +213,7 @@ func (s *Sync) Process(results []SyncResult) (bool, int, error) {
// Commit flushes the data stored in the internal membatch out to persistent
// storage, returning the number of items written and any occurred error.
-func (s *Sync) Commit(dbw ethdb.Putter) (int, error) {
+func (s *Sync) Commit(dbw database.Writer) (int, error) {
// Dump the membatch into a database dbw
for i, key := range s.membatch.order {
if err := dbw.Put(key[:], s.membatch.batch[key]); err != nil {
diff --git a/trie/sync_test.go b/trie/sync_test.go
index c76779e5c7..86dbe3d243 100644
--- a/trie/sync_test.go
+++ b/trie/sync_test.go
@@ -21,13 +21,13 @@ import (
"testing"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/internal/keyvalue"
)
// makeTestTrie create a sample test trie to test node-wise reconstruction.
func makeTestTrie() (*Database, *Trie, map[string][]byte) {
// Create an empty trie
- triedb := NewDatabase(ethdb.NewMemDatabase())
+ triedb := NewDatabase(keyvalue.NewMemoryDatabase())
trie, _ := New(common.Hash{}, triedb)
// Fill it with some arbitrary data
@@ -88,13 +88,13 @@ func checkTrieConsistency(db *Database, root common.Hash) error {
// Tests that an empty trie is not scheduled for syncing.
func TestEmptySync(t *testing.T) {
- dbA := NewDatabase(ethdb.NewMemDatabase())
- dbB := NewDatabase(ethdb.NewMemDatabase())
+ dbA := NewDatabase(keyvalue.NewMemoryDatabase())
+ dbB := NewDatabase(keyvalue.NewMemoryDatabase())
emptyA, _ := New(common.Hash{}, dbA)
emptyB, _ := New(emptyRoot, dbB)
for i, trie := range []*Trie{emptyA, emptyB} {
- if req := NewSync(trie.Hash(), ethdb.NewMemDatabase(), nil).Missing(1); len(req) != 0 {
+ if req := NewSync(trie.Hash(), keyvalue.NewMemoryDatabase(), nil).Missing(1); len(req) != 0 {
t.Errorf("test %d: content requested for empty trie: %v", i, req)
}
}
@@ -110,7 +110,7 @@ func testIterativeSync(t *testing.T, batch int) {
srcDb, srcTrie, srcData := makeTestTrie()
// Create a destination trie and sync with the scheduler
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
sched := NewSync(srcTrie.Hash(), diskdb, nil)
@@ -143,7 +143,7 @@ func TestIterativeDelayedSync(t *testing.T) {
srcDb, srcTrie, srcData := makeTestTrie()
// Create a destination trie and sync with the scheduler
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
sched := NewSync(srcTrie.Hash(), diskdb, nil)
@@ -181,7 +181,7 @@ func testIterativeRandomSync(t *testing.T, batch int) {
srcDb, srcTrie, srcData := makeTestTrie()
// Create a destination trie and sync with the scheduler
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
sched := NewSync(srcTrie.Hash(), diskdb, nil)
@@ -222,7 +222,7 @@ func TestIterativeRandomDelayedSync(t *testing.T) {
srcDb, srcTrie, srcData := makeTestTrie()
// Create a destination trie and sync with the scheduler
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
sched := NewSync(srcTrie.Hash(), diskdb, nil)
@@ -269,7 +269,7 @@ func TestDuplicateAvoidanceSync(t *testing.T) {
srcDb, srcTrie, srcData := makeTestTrie()
// Create a destination trie and sync with the scheduler
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
sched := NewSync(srcTrie.Hash(), diskdb, nil)
@@ -309,7 +309,7 @@ func TestIncompleteSync(t *testing.T) {
srcDb, srcTrie, _ := makeTestTrie()
// Create a destination trie and sync with the scheduler
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
sched := NewSync(srcTrie.Hash(), diskdb, nil)
diff --git a/trie/trie_test.go b/trie/trie_test.go
index f9d6029c99..4203f5b823 100644
--- a/trie/trie_test.go
+++ b/trie/trie_test.go
@@ -32,7 +32,8 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/database"
+ "github.com/ethereum/go-ethereum/internal/keyvalue"
"github.com/ethereum/go-ethereum/rlp"
)
@@ -43,7 +44,7 @@ func init() {
// Used for testing
func newEmpty() *Trie {
- trie, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
+ trie, _ := New(common.Hash{}, NewDatabase(keyvalue.NewMemoryDatabase()))
return trie
}
@@ -67,7 +68,7 @@ func TestNull(t *testing.T) {
}
func TestMissingRoot(t *testing.T) {
- trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(ethdb.NewMemDatabase()))
+ trie, err := New(common.HexToHash("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"), NewDatabase(keyvalue.NewMemoryDatabase()))
if trie != nil {
t.Error("New returned non-nil trie for invalid root")
}
@@ -80,7 +81,7 @@ func TestMissingNodeDisk(t *testing.T) { testMissingNode(t, false) }
func TestMissingNodeMemonly(t *testing.T) { testMissingNode(t, true) }
func testMissingNode(t *testing.T, memonly bool) {
- diskdb := ethdb.NewMemDatabase()
+ diskdb := keyvalue.NewMemoryDatabase()
triedb := NewDatabase(diskdb)
trie, _ := New(common.Hash{}, triedb)
@@ -317,13 +318,13 @@ func TestLargeValue(t *testing.T) {
}
type countingDB struct {
- ethdb.Database
+ database.KeyValueStore
gets map[string]int
}
func (db *countingDB) Get(key []byte) ([]byte, error) {
db.gets[string(key)]++
- return db.Database.Get(key)
+ return db.KeyValueStore.Get(key)
}
// TestCacheUnload checks that decoded nodes are unloaded after a
@@ -342,7 +343,7 @@ func TestCacheUnload(t *testing.T) {
// Commit the trie repeatedly and access key1.
// The branch containing it is loaded from DB exactly two times:
// in the 0th and 6th iteration.
- diskdb := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)}
+ diskdb := &countingDB{KeyValueStore: trie.db.diskdb, gets: make(map[string]int)}
triedb := NewDatabase(diskdb)
trie, _ = New(root, triedb)
trie.SetCacheLimit(5)
@@ -412,7 +413,7 @@ func (randTest) Generate(r *rand.Rand, size int) reflect.Value {
}
func runRandTest(rt randTest) bool {
- triedb := NewDatabase(ethdb.NewMemDatabase())
+ triedb := NewDatabase(keyvalue.NewMemoryDatabase())
tr, _ := New(common.Hash{}, triedb)
values := make(map[string]string) // tracks content of the trie
@@ -540,7 +541,7 @@ func benchGet(b *testing.B, commit bool) {
b.StopTimer()
if commit {
- ldb := trie.db.diskdb.(*ethdb.LDBDatabase)
+ ldb := trie.db.diskdb.(*keyvalue.LeveldbDatabase)
ldb.Close()
os.RemoveAll(ldb.Path())
}
@@ -596,7 +597,7 @@ func tempDB() (string, *Database) {
if err != nil {
panic(fmt.Sprintf("can't create temporary directory: %v", err))
}
- diskdb, err := ethdb.NewLDBDatabase(dir, 256, 0)
+ diskdb, err := keyvalue.NewLeveldbDatabase(dir, 256, 0, "")
if err != nil {
panic(fmt.Sprintf("can't create temporary database: %v", err))
}