all: integrate chain freezer and polish database accesses

This commit is contained in:
Péter Szilágyi 2018-10-02 10:46:46 +03:00
parent 39ac0e38e8
commit 2955566655
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
121 changed files with 2061 additions and 1917 deletions

View file

@ -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,7 +51,7 @@ 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
database database.Database // In memory database to store our testing data
blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
mu sync.Mutex
@ -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,11 +422,11 @@ 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) 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) {

View file

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

View file

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

View file

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

View file

@ -61,6 +61,7 @@ var (
utils.BootnodesV4Flag,
utils.BootnodesV5Flag,
utils.DataDirFlag,
utils.AncientFlag,
utils.KeyStoreDirFlag,
utils.ExternalSignerFlag,
utils.NoUSBFlag,

View file

@ -69,6 +69,7 @@ var AppHelpFlagGroups = []flagGroup{
Flags: []cli.Flag{
configFileFlag,
utils.DataDirFlag,
utils.AncientFlag,
utils.KeyStoreDirFlag,
utils.NoUSBFlag,
utils.NetworkIdFlag,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 = &params.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) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

100
core/rawdb/database.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

276
core/rawdb/freezer.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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)
}
}
}

284
core/rawdb/freezer_table.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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()
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

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

124
core/rawdb/table.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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()
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

84
database/database.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
// 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
}

57
database/iterator.go Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

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

View file

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

View file

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

View file

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

View file

@ -102,6 +102,8 @@ type Config struct {
SkipBcVersionCheck bool `toml:"-"`
DatabaseHandles int `toml:"-"`
DatabaseCache int
DatabaseFreezer string
TrieCleanCache int
TrieDirtyCache int
TrieTimeout time.Duration

View file

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

View file

@ -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"
)
@ -46,8 +47,8 @@ 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
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
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 = &params.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 = &params.ChainConfig{}
gspec = &core.Genesis{Config: config}
genesis = gspec.MustCommit(db)

View file

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

View file

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

12
ethdb/.gitignore vendored
View file

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

View file

@ -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 <http://www.gnu.org/licenses/>.
// +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
}

View file

@ -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 <http://www.gnu.org/licenses/>.
// +build js
package ethdb_test
import (
"github.com/ethereum/go-ethereum/ethdb"
)
var _ ethdb.Database = &ethdb.LDBDatabase{}

View file

@ -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 <http://www.gnu.org/licenses/>.
// +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()
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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.
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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()
}

View file

@ -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 <http://www.gnu.org/licenses/>.
// 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)
}
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

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

View file

@ -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{
// Assemble the wrapper with all the registered metrics
ldb := &LeveldbDatabase{
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
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
}

View file

@ -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 <http://www.gnu.org/licenses/>.
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
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

Some files were not shown because too many files have changed in this diff Show more