mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
all: integrate chain freezer and polish database accesses
This commit is contained in:
parent
39ac0e38e8
commit
2955566655
121 changed files with 2061 additions and 1917 deletions
|
|
@ -35,8 +35,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
@ -51,8 +51,8 @@ var errGasEstimationFailed = errors.New("gas required exceeds allowance or alway
|
||||||
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
||||||
// the background. Its main purpose is to allow easily testing contract bindings.
|
// the background. Its main purpose is to allow easily testing contract bindings.
|
||||||
type SimulatedBackend struct {
|
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
|
blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
pendingBlock *types.Block // Currently pending block that will be imported on request
|
pendingBlock *types.Block // Currently pending block that will be imported on request
|
||||||
|
|
@ -66,7 +66,7 @@ type SimulatedBackend struct {
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
// for testing purposes.
|
// for testing purposes.
|
||||||
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
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 := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
||||||
genesis.MustCommit(database)
|
genesis.MustCommit(database)
|
||||||
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
|
|
@ -422,12 +422,12 @@ func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||||
// filterBackend implements filters.Backend to support filtering for logs without
|
// filterBackend implements filters.Backend to support filtering for logs without
|
||||||
// taking bloom-bits acceleration structures into account.
|
// taking bloom-bits acceleration structures into account.
|
||||||
type filterBackend struct {
|
type filterBackend struct {
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
bc *core.BlockChain
|
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) EventMux() *event.TypeMux { panic("not supported") }
|
||||||
|
|
||||||
func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
|
func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
|
||||||
if block == rpc.LatestBlockNumber {
|
if block == rpc.LatestBlockNumber {
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
cli "gopkg.in/urfave/cli.v1"
|
cli "gopkg.in/urfave/cli.v1"
|
||||||
|
|
@ -99,12 +99,12 @@ func runCmd(ctx *cli.Context) error {
|
||||||
if ctx.GlobalString(GenesisFlag.Name) != "" {
|
if ctx.GlobalString(GenesisFlag.Name) != "" {
|
||||||
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
|
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
|
||||||
genesisConfig = gen
|
genesisConfig = gen
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis := gen.ToBlock(db)
|
genesis := gen.ToBlock(db)
|
||||||
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
|
statedb, _ = state.New(genesis.Root(), state.NewDatabase(db))
|
||||||
chainConfig = gen.Config
|
chainConfig = gen.Config
|
||||||
} else {
|
} else {
|
||||||
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
|
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
genesisConfig = new(core.Genesis)
|
genesisConfig = new(core.Genesis)
|
||||||
}
|
}
|
||||||
if ctx.GlobalString(SenderFlag.Name) != "" {
|
if ctx.GlobalString(SenderFlag.Name) != "" {
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/console"
|
"github.com/ethereum/go-ethereum/console"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -193,7 +192,7 @@ func initGenesis(ctx *cli.Context) error {
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
for _, name := range []string{"chaindata", "lightchaindata"} {
|
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||||
chaindb, err := stack.OpenDatabase(name, 0, 0)
|
chaindb, err := stack.OpenDatabase(name, 0, 0, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to open database: %v", err)
|
utils.Fatalf("Failed to open database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -201,6 +200,7 @@ func initGenesis(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to write genesis block: %v", err)
|
utils.Fatalf("Failed to write genesis block: %v", err)
|
||||||
}
|
}
|
||||||
|
chaindb.Close()
|
||||||
log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
|
log.Info("Successfully wrote genesis state", "database", name, "hash", hash)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -213,8 +213,8 @@ func importChain(ctx *cli.Context) error {
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chainDb := utils.MakeChain(ctx, stack)
|
chain, db := utils.MakeChain(ctx, stack)
|
||||||
defer chainDb.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Start periodically gathering memory profiles
|
// Start periodically gathering memory profiles
|
||||||
var peakMemAlloc, peakMemSys uint64
|
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))
|
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
||||||
|
|
||||||
// Output pre-compaction stats mostly to see the import trashing
|
// Output pre-compaction stats mostly to see the import trashing
|
||||||
db := chainDb.(*ethdb.LDBDatabase)
|
stats, err := db.Stat("leveldb.stats")
|
||||||
|
|
||||||
stats, err := db.LDB().GetProperty("leveldb.stats")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to read database stats: %v", err)
|
utils.Fatalf("Failed to read database stats: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(stats)
|
fmt.Println(stats)
|
||||||
|
|
||||||
ioStats, err := db.LDB().GetProperty("leveldb.iostats")
|
ioStats, err := db.Stat("leveldb.iostats")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to read database iostats: %v", err)
|
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
|
// 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...")
|
fmt.Println("Compacting entire database...")
|
||||||
if err = db.LDB().CompactRange(util.Range{}); err != nil {
|
if err = db.LDB().CompactRange(util.Range{}); err != nil {
|
||||||
utils.Fatalf("Compaction failed: %v", err)
|
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))
|
||||||
|
|
||||||
stats, err = db.LDB().GetProperty("leveldb.stats")
|
stats, err = db.Stat("leveldb.stats")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to read database stats: %v", err)
|
utils.Fatalf("Failed to read database stats: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(stats)
|
fmt.Println(stats)
|
||||||
|
|
||||||
ioStats, err = db.LDB().GetProperty("leveldb.iostats")
|
ioStats, err = db.Stat("leveldb.iostats")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf("Failed to read database iostats: %v", err)
|
utils.Fatalf("Failed to read database iostats: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Println(ioStats)
|
fmt.Println(ioStats)*/
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -344,10 +342,10 @@ func importPreimages(ctx *cli.Context) error {
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
db := utils.MakeChainDatabase(ctx, stack)
|
||||||
start := time.Now()
|
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)
|
utils.Fatalf("Import error: %v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Import done in %v\n", time.Since(start))
|
fmt.Printf("Import done in %v\n", time.Since(start))
|
||||||
|
|
@ -362,10 +360,10 @@ func exportPreimages(ctx *cli.Context) error {
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
diskdb := utils.MakeChainDatabase(ctx, stack).(*ethdb.LDBDatabase)
|
db := utils.MakeChainDatabase(ctx, stack)
|
||||||
start := time.Now()
|
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)
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Export done in %v\n", time.Since(start))
|
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 {
|
func copyDb(ctx *cli.Context) error {
|
||||||
// Ensure we have a source chain directory to copy
|
// 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")
|
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
|
// Initialize a new chain for the running node to sync into
|
||||||
stack := makeFullNode(ctx)
|
stack := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
@ -386,7 +387,7 @@ func copyDb(ctx *cli.Context) error {
|
||||||
dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil)
|
dl := downloader.New(syncmode, chainDb, new(event.TypeMux), chain, nil, nil)
|
||||||
|
|
||||||
// Create a source peer to satisfy downloader requests from
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -411,12 +412,12 @@ func copyDb(ctx *cli.Context) error {
|
||||||
fmt.Printf("Database copy done in %v\n", time.Since(start))
|
fmt.Printf("Database copy done in %v\n", time.Since(start))
|
||||||
|
|
||||||
// Compact the entire database to remove any sync overhead
|
// Compact the entire database to remove any sync overhead
|
||||||
start = time.Now()
|
/*start = time.Now()
|
||||||
fmt.Println("Compacting entire database...")
|
fmt.Println("Compacting entire database...")
|
||||||
if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil {
|
if err = chainDb.(*ethdb.LDBDatabase).LDB().CompactRange(util.Range{}); err != nil {
|
||||||
utils.Fatalf("Compaction failed: %v", err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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
|
// Retrieve the DAO config flag from the database
|
||||||
path := filepath.Join(datadir, "geth", "chaindata")
|
path := filepath.Join(datadir, "geth", "chaindata")
|
||||||
db, err := ethdb.NewLDBDatabase(path, 0, 0)
|
db, err := rawdb.NewLeveldbDatabase(path, 0, 0, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
t.Fatalf("test %d: failed to open test database: %v", test, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ var (
|
||||||
utils.BootnodesV4Flag,
|
utils.BootnodesV4Flag,
|
||||||
utils.BootnodesV5Flag,
|
utils.BootnodesV5Flag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
|
utils.AncientFlag,
|
||||||
utils.KeyStoreDirFlag,
|
utils.KeyStoreDirFlag,
|
||||||
utils.ExternalSignerFlag,
|
utils.ExternalSignerFlag,
|
||||||
utils.NoUSBFlag,
|
utils.NoUSBFlag,
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
configFileFlag,
|
configFileFlag,
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
|
utils.AncientFlag,
|
||||||
utils.KeyStoreDirFlag,
|
utils.KeyStoreDirFlag,
|
||||||
utils.NoUSBFlag,
|
utils.NoUSBFlag,
|
||||||
utils.NetworkIdFlag,
|
utils.NetworkIdFlag,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"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/internal/debug"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"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.
|
// 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)
|
log.Info("Importing preimages", "file", fn)
|
||||||
|
|
||||||
// Open the file handle and potentially unwrap the gzip stream
|
// 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,
|
// ExportPreimages exports all known hash preimages into the specified file,
|
||||||
// truncating any data already present in the 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)
|
log.Info("Exporting preimages", "file", fn)
|
||||||
|
|
||||||
// Open the file handle and potentially wrap with a gzip stream
|
// Open the file handle and potentially wrap with a gzip stream
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/dashboard"
|
"github.com/ethereum/go-ethereum/dashboard"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/ethstats"
|
"github.com/ethereum/go-ethereum/ethstats"
|
||||||
"github.com/ethereum/go-ethereum/les"
|
"github.com/ethereum/go-ethereum/les"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -120,6 +120,10 @@ var (
|
||||||
Usage: "Data directory for the databases and keystore",
|
Usage: "Data directory for the databases and keystore",
|
||||||
Value: DirectoryString{node.DefaultDataDir()},
|
Value: DirectoryString{node.DefaultDataDir()},
|
||||||
}
|
}
|
||||||
|
AncientFlag = DirectoryFlag{
|
||||||
|
Name: "datadir.ancient",
|
||||||
|
Usage: "Data directory for ancient chain segments (default = inside chaindata)",
|
||||||
|
}
|
||||||
KeyStoreDirFlag = DirectoryFlag{
|
KeyStoreDirFlag = DirectoryFlag{
|
||||||
Name: "keystore",
|
Name: "keystore",
|
||||||
Usage: "Directory for the keystore (default = inside the datadir)",
|
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.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
|
||||||
}
|
}
|
||||||
cfg.DatabaseHandles = makeDatabaseHandles()
|
cfg.DatabaseHandles = makeDatabaseHandles()
|
||||||
|
if ctx.GlobalIsSet(AncientFlag.Name) {
|
||||||
|
cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
|
||||||
Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
|
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.
|
// 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 (
|
var (
|
||||||
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
|
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
|
||||||
handles = makeDatabaseHandles()
|
handles = makeDatabaseHandles()
|
||||||
|
|
@ -1535,7 +1542,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
|
||||||
if ctx.GlobalString(SyncModeFlag.Name) == "light" {
|
if ctx.GlobalString(SyncModeFlag.Name) == "light" {
|
||||||
name = "lightchaindata"
|
name = "lightchaindata"
|
||||||
}
|
}
|
||||||
chainDb, err := stack.OpenDatabase(name, cache, handles)
|
chainDb, err := stack.OpenDatabase(name, cache, handles, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Could not open database: %v", err)
|
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.
|
// 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
|
var err error
|
||||||
chainDb = MakeChainDatabase(ctx, stack)
|
chainDb = MakeChainDatabase(ctx, stack)
|
||||||
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
|
config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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.
|
// Ethereum testnet following the Ropsten attacks.
|
||||||
type Clique struct {
|
type Clique struct {
|
||||||
config *params.CliqueConfig // Consensus engine configuration parameters
|
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
|
recents *lru.ARCCache // Snapshots for recent block to speed up reorgs
|
||||||
signatures *lru.ARCCache // Signatures of recent blocks to speed up mining
|
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
|
// New creates a Clique proof-of-authority consensus engine with the initial
|
||||||
// signers set to the ones provided by the user.
|
// 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
|
// Set any missing consensus parameters to their defaults
|
||||||
conf := *config
|
conf := *config
|
||||||
if conf.Epoch == 0 {
|
if conf.Epoch == 0 {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
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.
|
// 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[:]...))
|
blob, err := db.Get(append([]byte("clique-"), hash[:]...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -100,7 +100,7 @@ func loadSnapshot(config *params.CliqueConfig, sigcache *lru.ARCCache, db ethdb.
|
||||||
}
|
}
|
||||||
|
|
||||||
// store inserts the snapshot into the database.
|
// 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)
|
blob, err := json.Marshal(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -400,7 +400,7 @@ func TestClique(t *testing.T) {
|
||||||
copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:])
|
copy(genesis.ExtraData[extraVanity+j*common.AddressLength:], signer[:])
|
||||||
}
|
}
|
||||||
// Create a pristine blockchain with the genesis injected
|
// Create a pristine blockchain with the genesis injected
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis.Commit(db)
|
genesis.Commit(db)
|
||||||
|
|
||||||
// Assemble a chain of headers from the cast votes
|
// Assemble a chain of headers from the cast votes
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -148,16 +148,16 @@ func genUncles(i int, gen *BlockGen) {
|
||||||
|
|
||||||
func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
// Create the database in memory or in a temporary directory.
|
// Create the database in memory or in a temporary directory.
|
||||||
var db ethdb.Database
|
var db database.Database
|
||||||
if !disk {
|
if !disk {
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
} else {
|
} else {
|
||||||
dir, err := ioutil.TempDir("", "eth-core-bench")
|
dir, err := ioutil.TempDir("", "eth-core-bench")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("cannot create temporary directory: %v", err)
|
b.Fatalf("cannot create temporary directory: %v", err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
db, err = ethdb.NewLDBDatabase(dir, 128, 128)
|
db, err = rawdb.NewLeveldbDatabase(dir, 128, 128, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("cannot create temporary database: %v", err)
|
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
|
// makeChainForBench writes a given number of headers or empty blocks/receipts
|
||||||
// into a database.
|
// 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
|
var hash common.Hash
|
||||||
for n := uint64(0); n < count; n++ {
|
for n := uint64(0); n < count; n++ {
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
|
|
@ -255,7 +255,7 @@ func benchWriteChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("cannot create temporary directory: %v", err)
|
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 {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
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)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
db, err := ethdb.NewLDBDatabase(dir, 128, 1024)
|
db, err := rawdb.NewLeveldbDatabase(dir, 128, 1024, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
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()
|
b.ResetTimer()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
db, err := ethdb.NewLDBDatabase(dir, 128, 1024)
|
db, err := rawdb.NewLeveldbDatabase(dir, 128, 1024, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
func TestHeaderVerification(t *testing.T) {
|
func TestHeaderVerification(t *testing.T) {
|
||||||
// Create a simple chain to verify
|
// Create a simple chain to verify
|
||||||
var (
|
var (
|
||||||
testdb = ethdb.NewMemDatabase()
|
testdb = rawdb.NewMemoryDatabase()
|
||||||
gspec = &Genesis{Config: params.TestChainConfig}
|
gspec = &Genesis{Config: params.TestChainConfig}
|
||||||
genesis = gspec.MustCommit(testdb)
|
genesis = gspec.MustCommit(testdb)
|
||||||
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil)
|
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) {
|
func testHeaderConcurrentVerification(t *testing.T, threads int) {
|
||||||
// Create a simple chain to verify
|
// Create a simple chain to verify
|
||||||
var (
|
var (
|
||||||
testdb = ethdb.NewMemDatabase()
|
testdb = rawdb.NewMemoryDatabase()
|
||||||
gspec = &Genesis{Config: params.TestChainConfig}
|
gspec = &Genesis{Config: params.TestChainConfig}
|
||||||
genesis = gspec.MustCommit(testdb)
|
genesis = gspec.MustCommit(testdb)
|
||||||
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 8, nil)
|
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) {
|
func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
||||||
// Create a simple chain to verify
|
// Create a simple chain to verify
|
||||||
var (
|
var (
|
||||||
testdb = ethdb.NewMemDatabase()
|
testdb = rawdb.NewMemoryDatabase()
|
||||||
gspec = &Genesis{Config: params.TestChainConfig}
|
gspec = &Genesis{Config: params.TestChainConfig}
|
||||||
genesis = gspec.MustCommit(testdb)
|
genesis = gspec.MustCommit(testdb)
|
||||||
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil)
|
blocks, _ = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), testdb, 1024, nil)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
|
@ -95,9 +95,9 @@ type BlockChain struct {
|
||||||
chainConfig *params.ChainConfig // Chain & network configuration
|
chainConfig *params.ChainConfig // Chain & network configuration
|
||||||
cacheConfig *CacheConfig // Cache configuration for pruning
|
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
|
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
|
||||||
gcproc time.Duration // Accumulates canonical block processing for trie dumping
|
gcproc time.Duration // Accumulates canonical block processing for trie dumping
|
||||||
|
|
||||||
hc *HeaderChain
|
hc *HeaderChain
|
||||||
rmLogsFeed event.Feed
|
rmLogsFeed event.Feed
|
||||||
|
|
@ -140,7 +140,7 @@ type BlockChain struct {
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialises the default Ethereum Validator and
|
// available in the database. It initialises the default Ethereum Validator and
|
||||||
// Processor.
|
// 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 {
|
if cacheConfig == nil {
|
||||||
cacheConfig = &CacheConfig{
|
cacheConfig = &CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
|
|
@ -284,7 +284,7 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
||||||
defer bc.chainmu.Unlock()
|
defer bc.chainmu.Unlock()
|
||||||
|
|
||||||
// Rewind the header chain, deleting all block bodies until then
|
// 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)
|
rawdb.DeleteBody(db, hash, num)
|
||||||
}
|
}
|
||||||
bc.hc.SetHead(head, delFn)
|
bc.hc.SetHead(head, delFn)
|
||||||
|
|
@ -866,7 +866,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||||
|
|
||||||
stats.processed++
|
stats.processed++
|
||||||
|
|
||||||
if batch.ValueSize() >= ethdb.IdealBatchSize {
|
if batch.ValueSize() >= database.IdealBatchSize {
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -976,7 +976,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||||
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
|
limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024
|
||||||
)
|
)
|
||||||
if nodes > limit || imgs > 4*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
|
// Find the next state trie we need to commit
|
||||||
chosen := current - triesInMemory
|
chosen := current - triesInMemory
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -45,9 +45,9 @@ var (
|
||||||
// newCanonical creates a chain database, and injects a deterministic canonical
|
// 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
|
// chain. Depending on the full flag, if creates either a full block chain or a
|
||||||
// header only chain.
|
// 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 (
|
var (
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
genesis = new(Genesis).MustCommit(db)
|
genesis = new(Genesis).MustCommit(db)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -603,7 +603,7 @@ func testInsertNonceError(t *testing.T, full bool) {
|
||||||
func TestFastVsFullChains(t *testing.T) {
|
func TestFastVsFullChains(t *testing.T) {
|
||||||
// Configure and generate a sample block chain
|
// Configure and generate a sample block chain
|
||||||
var (
|
var (
|
||||||
gendb = ethdb.NewMemDatabase()
|
gendb = rawdb.NewMemoryDatabase()
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
|
|
@ -633,7 +633,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the chain as an archive node for the comparison baseline
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb := ethdb.NewMemDatabase()
|
archiveDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer archive.Stop()
|
defer archive.Stop()
|
||||||
|
|
@ -642,7 +642,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb := ethdb.NewMemDatabase()
|
fastDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
@ -691,7 +691,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Configure and generate a sample block chain
|
// Configure and generate a sample block chain
|
||||||
var (
|
var (
|
||||||
gendb = ethdb.NewMemDatabase()
|
gendb = rawdb.NewMemoryDatabase()
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
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
|
// Import the chain as an archive node and ensure all pointers are updated
|
||||||
archiveDb := ethdb.NewMemDatabase()
|
archiveDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
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)
|
assert(t, "archive", archive, height/2, height/2, height/2)
|
||||||
|
|
||||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb := ethdb.NewMemDatabase()
|
fastDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
@ -753,7 +753,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
assert(t, "fast", fast, height/2, height/2, 0)
|
assert(t, "fast", fast, height/2, height/2, 0)
|
||||||
|
|
||||||
// Import the chain as a light node and ensure all pointers are updated
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb := ethdb.NewMemDatabase()
|
lightDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(lightDb)
|
gspec.MustCommit(lightDb)
|
||||||
|
|
||||||
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
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)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec = &Genesis{
|
gspec = &Genesis{
|
||||||
Config: params.TestChainConfig,
|
Config: params.TestChainConfig,
|
||||||
GasLimit: 3141592,
|
GasLimit: 3141592,
|
||||||
|
|
@ -888,7 +888,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
// this code generates a log
|
// this code generates a log
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
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) {
|
func TestReorgSideEvent(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
gspec = &Genesis{
|
gspec = &Genesis{
|
||||||
|
|
@ -1060,7 +1060,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
func TestEIP155Transition(t *testing.T) {
|
func TestEIP155Transition(t *testing.T) {
|
||||||
// Configure and generate a sample block chain
|
// Configure and generate a sample block chain
|
||||||
var (
|
var (
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
|
|
@ -1163,7 +1163,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
func TestEIP161AccountRemoval(t *testing.T) {
|
func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
// Configure and generate a sample block chain
|
// Configure and generate a sample block chain
|
||||||
var (
|
var (
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
|
|
@ -1235,7 +1235,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
|
||||||
// Generate a canonical chain to act as the main dataset
|
// Generate a canonical chain to act as the main dataset
|
||||||
engine := ethash.NewFaker()
|
engine := ethash.NewFaker()
|
||||||
|
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis := new(Genesis).MustCommit(db)
|
genesis := new(Genesis).MustCommit(db)
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
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
|
// Import the canonical and fork chain side by side, verifying the current block
|
||||||
// and current header consistency
|
// and current header consistency
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
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
|
// Generate a canonical chain to act as the main dataset
|
||||||
engine := ethash.NewFaker()
|
engine := ethash.NewFaker()
|
||||||
|
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis := new(Genesis).MustCommit(db)
|
genesis := new(Genesis).MustCommit(db)
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*triesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
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]
|
forks[i] = fork[0]
|
||||||
}
|
}
|
||||||
// Import the canonical and fork chain side by side, forcing the trie cache to cache both
|
// 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)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
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
|
// Generate the original common chain segment and the two competing forks
|
||||||
engine := ethash.NewFaker()
|
engine := ethash.NewFaker()
|
||||||
|
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis := new(Genesis).MustCommit(db)
|
genesis := new(Genesis).MustCommit(db)
|
||||||
|
|
||||||
shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
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}) })
|
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
|
// Import the shared chain and the original canonical one
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
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
|
// Generate the original common chain segment and the two competing forks
|
||||||
engine := ethash.NewFaker()
|
engine := ethash.NewFaker()
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
blockGenerator := func(i int, block *BlockGen) {
|
blockGenerator := func(i int, block *BlockGen) {
|
||||||
|
|
@ -1416,7 +1416,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// Import the shared chain and the original canonical one
|
// Import the shared chain and the original canonical one
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
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) {
|
func TestLowDiffLongChain(t *testing.T) {
|
||||||
// Generate a canonical chain to act as the main dataset
|
// Generate a canonical chain to act as the main dataset
|
||||||
engine := ethash.NewFaker()
|
engine := ethash.NewFaker()
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
genesis := new(Genesis).MustCommit(db)
|
genesis := new(Genesis).MustCommit(db)
|
||||||
|
|
||||||
// We must use a pretty long chain to ensure that the fork doesn't overtake us
|
// 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
|
// Import the canonical chain
|
||||||
diskdb := ethdb.NewMemDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"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
|
// after an entire section has been finished or in case of rollbacks that might
|
||||||
// affect already finished sections.
|
// affect already finished sections.
|
||||||
type ChainIndexer struct {
|
type ChainIndexer struct {
|
||||||
chainDb ethdb.Database // Chain database to index the data from
|
chainDb database.Database // Chain database to index the data from
|
||||||
indexDb ethdb.Database // Prefixed table-view of the db to write index metadata into
|
indexDb database.Database // Prefixed table-view of the db to write index metadata into
|
||||||
backend ChainIndexerBackend // Background processor generating the index data content
|
backend ChainIndexerBackend // Background processor generating the index data content
|
||||||
children []*ChainIndexer // Child indexers to cascade chain updates to
|
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
|
// NewChainIndexer creates a new chain indexer to do background processing on
|
||||||
// chain segments of a given size after certain number of confirmations passed.
|
// chain segments of a given size after certain number of confirmations passed.
|
||||||
// The throttling parameter might be used to prevent database thrashing.
|
// 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{
|
c := &ChainIndexer{
|
||||||
chainDb: chainDb,
|
chainDb: chainDb,
|
||||||
indexDb: indexDb,
|
indexDb: indexDb,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Runs multiple tests with randomized parameters.
|
// 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
|
// multiple backends. The section size and required confirmation count parameters
|
||||||
// are randomized.
|
// are randomized.
|
||||||
func testChainIndexer(t *testing.T, count int) {
|
func testChainIndexer(t *testing.T, count int) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// Create a chain of indexers and ensure they all report empty
|
// 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))
|
confirmsReq = uint64(rand.Intn(10))
|
||||||
)
|
)
|
||||||
backends[i] = &testChainIndexBackend{t: t, processCh: make(chan uint64)}
|
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 {
|
if sections, _, _ := backends[i].indexer.Sections(); sections != 0 {
|
||||||
t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0)
|
t.Fatalf("Canonical section count mismatch: have %v, want %v", sections, 0)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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"
|
"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
|
// Blocks created by GenerateChain do not contain valid proof of work
|
||||||
// values. Inserting them into BlockChain requires use of FakePow or
|
// values. Inserting them into BlockChain requires use of FakePow or
|
||||||
// a similar non-validating proof of work implementation.
|
// 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 {
|
if config == nil {
|
||||||
config = params.TestChainConfig
|
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.
|
// 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)
|
blocks := makeBlockChain(types.NewBlockWithHeader(parent), n, engine, db, seed)
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range 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.
|
// 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) {
|
blocks, _ := GenerateChain(params.TestChainConfig, parent, engine, db, n, func(i int, b *BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
|
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,10 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ func ExampleGenerateChain() {
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ensure that key1 has some funds in the genesis block.
|
// Ensure that key1 has some funds in the genesis block.
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"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/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -32,13 +32,13 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
forkBlock := big.NewInt(32)
|
forkBlock := big.NewInt(32)
|
||||||
|
|
||||||
// Generate a common prefix for both pro-forkers and non-forkers
|
// Generate a common prefix for both pro-forkers and non-forkers
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
gspec := new(Genesis)
|
gspec := new(Genesis)
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
prefix, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
// Create the concurrent, conflicting two nodes
|
// Create the concurrent, conflicting two nodes
|
||||||
proDb := ethdb.NewMemDatabase()
|
proDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(proDb)
|
gspec.MustCommit(proDb)
|
||||||
|
|
||||||
proConf := *params.TestChainConfig
|
proConf := *params.TestChainConfig
|
||||||
|
|
@ -48,7 +48,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer proBc.Stop()
|
defer proBc.Stop()
|
||||||
|
|
||||||
conDb := ethdb.NewMemDatabase()
|
conDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(conDb)
|
gspec.MustCommit(conDb)
|
||||||
|
|
||||||
conConf := *params.TestChainConfig
|
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
|
// 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++ {
|
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
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)
|
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
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
@ -118,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
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)
|
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
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -134,7 +134,7 @@ type GenesisMismatchError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *GenesisMismatchError) Error() string {
|
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.
|
// 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.
|
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
|
||||||
//
|
//
|
||||||
// The returned chain configuration is never nil.
|
// 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)
|
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 {
|
if genesis != nil && genesis.Config == nil {
|
||||||
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
|
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
|
// ToBlock creates the genesis block and writes state of a genesis specification
|
||||||
// to the given database (or discards it if nil).
|
// 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 {
|
if db == nil {
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
}
|
}
|
||||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
|
||||||
for addr, account := range g.Alloc {
|
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.
|
// Commit writes the block and state of a genesis specification to the database.
|
||||||
// The block is committed as the canonical head block.
|
// 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)
|
block := g.ToBlock(db)
|
||||||
if block.Number().Sign() != 0 {
|
if block.Number().Sign() != 0 {
|
||||||
return nil, fmt.Errorf("can't commit genesis block with number > 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.
|
// MustCommit writes the genesis block and state to db, panicking on error.
|
||||||
// The block is committed as the canonical head block.
|
// 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)
|
block, err := g.Commit(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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.
|
// 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}}}
|
g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
|
||||||
return g.MustCommit(db)
|
return g.MustCommit(db)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -55,14 +55,14 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)}
|
oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2)}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
|
fn func(database.Database) (*params.ChainConfig, common.Hash, error)
|
||||||
wantConfig *params.ChainConfig
|
wantConfig *params.ChainConfig
|
||||||
wantHash common.Hash
|
wantHash common.Hash
|
||||||
wantErr error
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "genesis without ChainConfig",
|
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))
|
return SetupGenesisBlock(db, new(Genesis))
|
||||||
},
|
},
|
||||||
wantErr: errGenesisNoConfig,
|
wantErr: errGenesisNoConfig,
|
||||||
|
|
@ -70,7 +70,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no block in DB, genesis == nil",
|
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)
|
return SetupGenesisBlock(db, nil)
|
||||||
},
|
},
|
||||||
wantHash: params.MainnetGenesisHash,
|
wantHash: params.MainnetGenesisHash,
|
||||||
|
|
@ -78,7 +78,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "mainnet block in DB, genesis == nil",
|
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)
|
DefaultGenesisBlock().MustCommit(db)
|
||||||
return SetupGenesisBlock(db, nil)
|
return SetupGenesisBlock(db, nil)
|
||||||
},
|
},
|
||||||
|
|
@ -87,7 +87,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "custom block in DB, genesis == nil",
|
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)
|
customg.MustCommit(db)
|
||||||
return SetupGenesisBlock(db, nil)
|
return SetupGenesisBlock(db, nil)
|
||||||
},
|
},
|
||||||
|
|
@ -96,7 +96,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "custom block in DB, genesis == testnet",
|
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)
|
customg.MustCommit(db)
|
||||||
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
|
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
|
||||||
},
|
},
|
||||||
|
|
@ -106,7 +106,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "compatible config in DB",
|
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)
|
oldcustomg.MustCommit(db)
|
||||||
return SetupGenesisBlock(db, &customg)
|
return SetupGenesisBlock(db, &customg)
|
||||||
},
|
},
|
||||||
|
|
@ -115,7 +115,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "incompatible config in DB",
|
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.
|
// Commit the 'old' genesis block with Homestead transition at #2.
|
||||||
// Advance to block #4, past the homestead transition block of customg.
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
genesis := oldcustomg.MustCommit(db)
|
genesis := oldcustomg.MustCommit(db)
|
||||||
|
|
@ -141,7 +141,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
config, hash, err := test.fn(db)
|
config, hash, err := test.fn(db)
|
||||||
// Check the return values.
|
// Check the return values.
|
||||||
if !reflect.DeepEqual(err, test.wantErr) {
|
if !reflect.DeepEqual(err, test.wantErr) {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
@ -50,7 +50,7 @@ const (
|
||||||
type HeaderChain struct {
|
type HeaderChain struct {
|
||||||
config *params.ChainConfig
|
config *params.ChainConfig
|
||||||
|
|
||||||
chainDb ethdb.Database
|
chainDb database.Database
|
||||||
genesisHeader *types.Header
|
genesisHeader *types.Header
|
||||||
|
|
||||||
currentHeader atomic.Value // Current head of the header chain (may be above the block chain!)
|
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
|
// getValidator should return the parent's validator
|
||||||
// procInterrupt points to the parent's interrupt semaphore
|
// procInterrupt points to the parent's interrupt semaphore
|
||||||
// wg points to the parent's shutdown wait group
|
// 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)
|
headerCache, _ := lru.New(headerCacheLimit)
|
||||||
tdCache, _ := lru.New(tdCacheLimit)
|
tdCache, _ := lru.New(tdCacheLimit)
|
||||||
numberCache, _ := lru.New(numberCacheLimit)
|
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
|
// DeleteCallback is a callback function that is called by SetHead before
|
||||||
// each header is deleted.
|
// 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
|
// SetHead rewinds the local chain to a new head. Everything above the new head
|
||||||
// will be deleted and the new one set.
|
// will be deleted and the new one set.
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,9 @@ package core
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ type TestManager struct {
|
||||||
// stateManager *StateManager
|
// stateManager *StateManager
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
|
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
txPool *TxPool
|
txPool *TxPool
|
||||||
blockChain *BlockChain
|
blockChain *BlockChain
|
||||||
Blocks []*types.Block
|
Blocks []*types.Block
|
||||||
|
|
@ -71,14 +72,14 @@ func (tm *TestManager) EventMux() *event.TypeMux {
|
||||||
// return nil
|
// return nil
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (tm *TestManager) Db() ethdb.Database {
|
func (tm *TestManager) Db() database.Database {
|
||||||
return tm.db
|
return tm.db
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTestManager() *TestManager {
|
func NewTestManager() *TestManager {
|
||||||
testManager := &TestManager{}
|
testManager := &TestManager{}
|
||||||
testManager.eventMux = new(event.TypeMux)
|
testManager.eventMux = new(event.TypeMux)
|
||||||
testManager.db = ethdb.NewMemDatabase()
|
testManager.db = rawdb.NewMemoryDatabase()
|
||||||
// testManager.txPool = NewTxPool(testManager)
|
// testManager.txPool = NewTxPool(testManager)
|
||||||
// testManager.blockChain = NewBlockChain(testManager)
|
// testManager.blockChain = NewBlockChain(testManager)
|
||||||
// testManager.stateManager = NewStateManager(testManager)
|
// testManager.stateManager = NewStateManager(testManager)
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,17 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
|
// ReadCanonicalHash retrieves the hash assigned to a canonical block number.
|
||||||
func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
|
func ReadCanonicalHash(db database.AncientReader, number uint64) common.Hash {
|
||||||
data, _ := db.Get(headerHashKey(number))
|
data, _ := db.Ancient("hashes", number)
|
||||||
|
if len(data) == 0 {
|
||||||
|
data, _ = db.Get(headerHashKey(number))
|
||||||
|
}
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
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.
|
// 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 {
|
if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {
|
||||||
log.Crit("Failed to store number to hash mapping", "err", err)
|
log.Crit("Failed to store number to hash mapping", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCanonicalHash removes the number to hash canonical mapping.
|
// 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 {
|
if err := db.Delete(headerHashKey(number)); err != nil {
|
||||||
log.Crit("Failed to delete number to hash mapping", "err", err)
|
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.
|
// 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))
|
data, _ := db.Get(headerNumberKey(hash))
|
||||||
if len(data) != 8 {
|
if len(data) != 8 {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -61,7 +83,7 @@ func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadHeadHeaderHash retrieves the hash of the current canonical head header.
|
// 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)
|
data, _ := db.Get(headHeaderKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
|
|
@ -70,14 +92,14 @@ func ReadHeadHeaderHash(db DatabaseReader) common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteHeadHeaderHash stores the hash of the current canonical head header.
|
// 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 {
|
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
|
||||||
log.Crit("Failed to store last header's hash", "err", err)
|
log.Crit("Failed to store last header's hash", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadHeadBlockHash retrieves the hash of the current canonical head block.
|
// 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)
|
data, _ := db.Get(headBlockKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
|
|
@ -86,14 +108,14 @@ func ReadHeadBlockHash(db DatabaseReader) common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteHeadBlockHash stores the head block's 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 {
|
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
|
||||||
log.Crit("Failed to store last block's hash", "err", err)
|
log.Crit("Failed to store last block's hash", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block.
|
// 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)
|
data, _ := db.Get(headFastBlockKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
|
|
@ -102,7 +124,7 @@ func ReadHeadFastBlockHash(db DatabaseReader) common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteHeadFastBlockHash stores the hash of the current fast-sync head block.
|
// 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 {
|
if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil {
|
||||||
log.Crit("Failed to store last fast block's hash", "err", err)
|
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
|
// ReadFastTrieProgress retrieves the number of tries nodes fast synced to allow
|
||||||
// reporting correct numbers across restarts.
|
// reporting correct numbers across restarts.
|
||||||
func ReadFastTrieProgress(db DatabaseReader) uint64 {
|
func ReadFastTrieProgress(db database.Reader) uint64 {
|
||||||
data, _ := db.Get(fastTrieProgressKey)
|
data, _ := db.Get(fastTrieProgressKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -120,20 +142,26 @@ func ReadFastTrieProgress(db DatabaseReader) uint64 {
|
||||||
|
|
||||||
// WriteFastTrieProgress stores the fast sync trie process counter to support
|
// WriteFastTrieProgress stores the fast sync trie process counter to support
|
||||||
// retrieving it across restarts.
|
// 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 {
|
if err := db.Put(fastTrieProgressKey, new(big.Int).SetUint64(count).Bytes()); err != nil {
|
||||||
log.Crit("Failed to store fast sync trie progress", "err", err)
|
log.Crit("Failed to store fast sync trie progress", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
|
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
|
||||||
func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
func ReadHeaderRLP(db database.AncientReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
data, _ := db.Get(headerKey(number, hash))
|
data, _ := db.Ancient("headers", number)
|
||||||
|
if len(data) == 0 {
|
||||||
|
data, _ = db.Get(headerKey(number, hash))
|
||||||
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasHeader verifies the existence of a block header corresponding to the hash.
|
// 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 {
|
if has, err := db.Has(headerKey(number, hash)); !has || err != nil {
|
||||||
return false
|
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.
|
// 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)
|
data := ReadHeaderRLP(db, hash, number)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
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-
|
// WriteHeader stores a block header into the database and also stores the hash-
|
||||||
// to-number mapping.
|
// to-number mapping.
|
||||||
func WriteHeader(db DatabaseWriter, header *types.Header) {
|
func WriteHeader(db database.Writer, header *types.Header) {
|
||||||
// Write the hash -> number mapping
|
// Write the hash -> number mapping
|
||||||
var (
|
var (
|
||||||
hash = header.Hash()
|
hash = header.Hash()
|
||||||
|
|
@ -179,30 +207,42 @@ func WriteHeader(db DatabaseWriter, header *types.Header) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteHeader removes all block header data associated with a hash.
|
// DeleteHeader removes all block header data associated with a hash.
|
||||||
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
|
func DeleteHeader(db database.Deleter, hash common.Hash, number uint64) {
|
||||||
if err := db.Delete(headerKey(number, hash)); err != nil {
|
deleteHeaderWithoutNumber(db, hash, number)
|
||||||
log.Crit("Failed to delete header", "err", err)
|
|
||||||
}
|
|
||||||
if err := db.Delete(headerNumberKey(hash)); err != nil {
|
if err := db.Delete(headerNumberKey(hash)); err != nil {
|
||||||
log.Crit("Failed to delete hash to number mapping", "err", err)
|
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.
|
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
|
||||||
func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
func ReadBodyRLP(db database.AncientReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
data, _ := db.Get(blockBodyKey(number, hash))
|
data, _ := db.Ancient("bodies", number)
|
||||||
|
if len(data) == 0 {
|
||||||
|
data, _ = db.Get(blockBodyKey(number, hash))
|
||||||
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBodyRLP stores an RLP encoded block body into the database.
|
// 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 {
|
if err := db.Put(blockBodyKey(number, hash), rlp); err != nil {
|
||||||
log.Crit("Failed to store block body", "err", err)
|
log.Crit("Failed to store block body", "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasBody verifies the existence of a block body corresponding to the hash.
|
// 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 {
|
if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil {
|
||||||
return false
|
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.
|
// 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)
|
data := ReadBodyRLP(db, hash, number)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
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.
|
// 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)
|
data, err := rlp.EncodeToBytes(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to RLP encode body", "err", err)
|
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.
|
// 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 {
|
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
|
||||||
log.Crit("Failed to delete block body", "err", err)
|
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.
|
// ReadTd retrieves a block's total difficulty corresponding to the hash.
|
||||||
func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
|
func ReadTd(db database.AncientReader, hash common.Hash, number uint64) *big.Int {
|
||||||
data, _ := db.Get(headerTDKey(number, hash))
|
data := ReadTdRLP(db, hash, number)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
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.
|
// 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)
|
data, err := rlp.EncodeToBytes(td)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to RLP encode block total difficulty", "err", err)
|
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.
|
// 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 {
|
if err := db.Delete(headerTDKey(number, hash)); err != nil {
|
||||||
log.Crit("Failed to delete block total difficulty", "err", err)
|
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
|
// HasReceipts verifies the existence of all the transaction receipts belonging
|
||||||
// to a block.
|
// 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 {
|
if has, err := db.Has(blockReceiptsKey(number, hash)); !has || err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
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.
|
// 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
|
// Retrieve the flattened receipt slice
|
||||||
data, _ := db.Get(blockReceiptsKey(number, hash))
|
data := ReadReceiptsRLP(db, hash, number)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
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.
|
// 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
|
// Convert the receipts into their storage form and serialize them
|
||||||
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
|
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
|
||||||
for i, receipt := range 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.
|
// 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 {
|
if err := db.Delete(blockReceiptsKey(number, hash)); err != nil {
|
||||||
log.Crit("Failed to delete block receipts", "err", err)
|
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
|
// 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).
|
// 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)
|
header := ReadHeader(db, hash, number)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return 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.
|
// 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())
|
WriteBody(db, block.Hash(), block.NumberU64(), block.Body())
|
||||||
WriteHeader(db, block.Header())
|
WriteHeader(db, block.Header())
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBlock removes all block data associated with a hash.
|
// 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)
|
DeleteReceipts(db, hash, number)
|
||||||
DeleteHeader(db, hash, number)
|
DeleteHeader(db, hash, number)
|
||||||
DeleteBody(db, hash, number)
|
DeleteBody(db, hash, number)
|
||||||
DeleteTd(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
|
// 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; {
|
for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
|
||||||
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
|
a = ReadHeader(db, a.ParentHash, a.Number.Uint64()-1)
|
||||||
if a == nil {
|
if a == nil {
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,13 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests block header storage and retrieval operations.
|
// Tests block header storage and retrieval operations.
|
||||||
func TestHeaderStorage(t *testing.T) {
|
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
|
// 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")}
|
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.
|
// Tests block body storage and retrieval operations.
|
||||||
func TestBodyStorage(t *testing.T) {
|
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
|
// 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")}}}
|
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.
|
// Tests block storage and retrieval operations.
|
||||||
func TestBlockStorage(t *testing.T) {
|
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
|
// Create a test block to move around the database and make sure it's really new
|
||||||
block := types.NewBlockWithHeader(&types.Header{
|
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.
|
// Tests that partial block contents don't get reassembled into full blocks.
|
||||||
func TestPartialBlockStorage(t *testing.T) {
|
func TestPartialBlockStorage(t *testing.T) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := NewMemoryDatabase()
|
||||||
block := types.NewBlockWithHeader(&types.Header{
|
block := types.NewBlockWithHeader(&types.Header{
|
||||||
Extra: []byte("test block"),
|
Extra: []byte("test block"),
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
|
|
@ -185,7 +184,7 @@ func TestPartialBlockStorage(t *testing.T) {
|
||||||
|
|
||||||
// Tests block total difficulty storage and retrieval operations.
|
// Tests block total difficulty storage and retrieval operations.
|
||||||
func TestTdStorage(t *testing.T) {
|
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
|
// Create a test TD to move around the database and make sure it's really new
|
||||||
hash, td := common.Hash{}, big.NewInt(314)
|
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.
|
// Tests that canonical numbers can be mapped to hashes and retrieved.
|
||||||
func TestCanonicalMappingStorage(t *testing.T) {
|
func TestCanonicalMappingStorage(t *testing.T) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := NewMemoryDatabase()
|
||||||
|
|
||||||
// Create a test canonical number and assinged hash to move around
|
// Create a test canonical number and assinged hash to move around
|
||||||
hash, number := common.Hash{0: 0xff}, uint64(314)
|
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.
|
// Tests that head headers and head blocks can be assigned, individually.
|
||||||
func TestHeadStorage(t *testing.T) {
|
func TestHeadStorage(t *testing.T) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := NewMemoryDatabase()
|
||||||
|
|
||||||
blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
|
blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
|
||||||
blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")})
|
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.
|
// Tests that receipts associated with a single block can be stored and retrieved.
|
||||||
func TestBlockReceiptStorage(t *testing.T) {
|
func TestBlockReceiptStorage(t *testing.T) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := NewMemoryDatabase()
|
||||||
|
|
||||||
receipt1 := &types.Receipt{
|
receipt1 := &types.Receipt{
|
||||||
Status: types.ReceiptStatusFailed,
|
Status: types.ReceiptStatusFailed,
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,14 @@ package rawdb
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
|
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction
|
||||||
// hash to allow retrieving the transaction or receipt by hash.
|
// 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))
|
data, _ := db.Get(txLookupKey(hash))
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}, 0, 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
|
// WriteTxLookupEntries stores a positional metadata for every transaction from
|
||||||
// a block, enabling hash based transaction and receipt lookups.
|
// 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() {
|
for i, tx := range block.Transactions() {
|
||||||
entry := TxLookupEntry{
|
entry := TxLookupEntry{
|
||||||
BlockHash: block.Hash(),
|
BlockHash: block.Hash(),
|
||||||
|
|
@ -58,13 +59,13 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
// 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))
|
db.Delete(txLookupKey(hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadTransaction retrieves a specific transaction from the database, along with
|
// ReadTransaction retrieves a specific transaction from the database, along with
|
||||||
// its added positional metadata.
|
// 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)
|
blockHash, blockNumber, txIndex := ReadTxLookupEntry(db, hash)
|
||||||
if blockHash == (common.Hash{}) {
|
if blockHash == (common.Hash{}) {
|
||||||
return nil, common.Hash{}, 0, 0
|
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
|
// ReadReceipt retrieves a specific transaction receipt from the database, along with
|
||||||
// its added positional metadata.
|
// 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)
|
blockHash, blockNumber, receiptIndex := ReadTxLookupEntry(db, hash)
|
||||||
if blockHash == (common.Hash{}) {
|
if blockHash == (common.Hash{}) {
|
||||||
return nil, common.Hash{}, 0, 0
|
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
|
// ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
|
||||||
// section and bit index from the.
|
// 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))
|
return db.Get(bloomBitsKey(bit, section, head))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
|
// WriteBloomBits stores the compressed bloom bits vector belonging to the given
|
||||||
// section and bit index.
|
// 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 {
|
if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
|
||||||
log.Crit("Failed to store bloom bits", "err", err)
|
log.Crit("Failed to store bloom bits", "err", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,11 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests that positional lookup metadata can be stored and retrieved.
|
// Tests that positional lookup metadata can be stored and retrieved.
|
||||||
func TestLookupStorage(t *testing.T) {
|
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})
|
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})
|
tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,14 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadDatabaseVersion retrieves the version number of the database.
|
// ReadDatabaseVersion retrieves the version number of the database.
|
||||||
func ReadDatabaseVersion(db DatabaseReader) *uint64 {
|
func ReadDatabaseVersion(db database.Reader) *uint64 {
|
||||||
var version uint64
|
var version uint64
|
||||||
|
|
||||||
enc, _ := db.Get(databaseVerisionKey)
|
enc, _ := db.Get(databaseVerisionKey)
|
||||||
|
|
@ -41,7 +42,7 @@ func ReadDatabaseVersion(db DatabaseReader) *uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteDatabaseVersion stores the version number of the database
|
// 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)
|
enc, err := rlp.EncodeToBytes(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to encode database version", "err", err)
|
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.
|
// 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))
|
data, _ := db.Get(configKey(hash))
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -66,7 +67,7 @@ func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteChainConfig writes the chain config settings to the database.
|
// 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 {
|
if cfg == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -80,13 +81,13 @@ func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConf
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadPreimage retrieves a single preimage of the provided hash.
|
// 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))
|
data, _ := db.Get(preimageKey(hash))
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// WritePreimages writes the provided set of preimages to the database.
|
// 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 {
|
for hash, preimage := range preimages {
|
||||||
if err := db.Put(preimageKey(hash), preimage); err != nil {
|
if err := db.Put(preimageKey(hash), preimage); err != nil {
|
||||||
log.Crit("Failed to store trie preimage", "err", err)
|
log.Crit("Failed to store trie preimage", "err", err)
|
||||||
|
|
|
||||||
100
core/rawdb/database.go
Normal file
100
core/rawdb/database.go
Normal 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
276
core/rawdb/freezer.go
Normal 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
284
core/rawdb/freezer_table.go
Normal 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()
|
||||||
|
}
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -78,6 +78,11 @@ func encodeBlockNumber(number uint64) []byte {
|
||||||
return enc
|
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
|
// headerKey = headerPrefix + num (uint64 big endian) + hash
|
||||||
func headerKey(number uint64, hash common.Hash) []byte {
|
func headerKey(number uint64, hash common.Hash) []byte {
|
||||||
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
|
|
||||||
124
core/rawdb/table.go
Normal file
124
core/rawdb/table.go
Normal 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()
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
)
|
)
|
||||||
|
|
@ -68,20 +68,20 @@ type Trie interface {
|
||||||
Hash() common.Hash
|
Hash() common.Hash
|
||||||
NodeIterator(startKey []byte) trie.NodeIterator
|
NodeIterator(startKey []byte) trie.NodeIterator
|
||||||
GetKey([]byte) []byte // TODO(fjl): remove this when SecureTrie is removed
|
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
|
// 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
|
// concurrent use and retains a few recent expanded trie nodes in memory. To keep
|
||||||
// more historical state in memory, use the NewDatabaseWithCache constructor.
|
// 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)
|
return NewDatabaseWithCache(db, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabase creates a backing store for state. The returned database is safe for
|
// 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
|
// 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.
|
// 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)
|
csc, _ := lru.New(codeSizeCacheSize)
|
||||||
return &cachingDB{
|
return &cachingDB{
|
||||||
db: trie.NewDatabaseWithCache(db, cache),
|
db: trie.NewDatabaseWithCache(db, cache),
|
||||||
|
|
@ -179,6 +179,6 @@ func (m cachedTrie) Commit(onleaf trie.LeafCallback) (common.Hash, error) {
|
||||||
return root, err
|
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)
|
return m.SecureTrie.Prove(key, fromLevel, proofDb)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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.
|
// 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)
|
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-")) {
|
if bytes.HasPrefix(key, []byte("secure-key-")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -59,4 +61,5 @@ func TestNodeIteratorCoverage(t *testing.T) {
|
||||||
t.Errorf("state entry not reported %x", key)
|
t.Errorf("state entry not reported %x", key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
it.Release()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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"))
|
var addr = common.BytesToAddress([]byte("test"))
|
||||||
|
|
||||||
func create() (*ManagedState, *account) {
|
func create() (*ManagedState, *account) {
|
||||||
statedb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
|
statedb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
ms := ManageState(statedb)
|
ms := ManageState(statedb)
|
||||||
ms.StateDB.SetNonce(addr, 100)
|
ms.StateDB.SetNonce(addr, 100)
|
||||||
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
|
ms.accounts[addr] = newAccount(ms.StateDB.getStateObject(addr))
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
checker "gopkg.in/check.v1"
|
checker "gopkg.in/check.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StateSuite struct {
|
type StateSuite struct {
|
||||||
db *ethdb.MemDatabase
|
db database.Database
|
||||||
state *StateDB
|
state *StateDB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +88,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateSuite) SetUpTest(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))
|
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
|
// use testing instead of checker because checker does not support
|
||||||
// printing/logging in tests (-check.vv does not work)
|
// printing/logging in tests (-check.vv does not work)
|
||||||
func TestSnapshot2(t *testing.T) {
|
func TestSnapshot2(t *testing.T) {
|
||||||
state, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
|
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
|
|
||||||
stateobjaddr0 := toAddr([]byte("so0"))
|
stateobjaddr0 := toAddr([]byte("so0"))
|
||||||
stateobjaddr1 := toAddr([]byte("so1"))
|
stateobjaddr1 := toAddr([]byte("so1"))
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,15 @@ import (
|
||||||
check "gopkg.in/check.v1"
|
check "gopkg.in/check.v1"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests that updating a state trie does not leak any database writes prior to
|
// Tests that updating a state trie does not leak any database writes prior to
|
||||||
// actually committing the state.
|
// actually committing the state.
|
||||||
func TestUpdateLeaks(t *testing.T) {
|
func TestUpdateLeaks(t *testing.T) {
|
||||||
// Create an empty state database
|
// Create an empty state database
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
state, _ := New(common.Hash{}, NewDatabase(db))
|
state, _ := New(common.Hash{}, NewDatabase(db))
|
||||||
|
|
||||||
// Update it with some accounts
|
// Update it with some accounts
|
||||||
|
|
@ -56,18 +56,19 @@ func TestUpdateLeaks(t *testing.T) {
|
||||||
state.IntermediateRoot(false)
|
state.IntermediateRoot(false)
|
||||||
}
|
}
|
||||||
// Ensure that no data was leaked into the database
|
// Ensure that no data was leaked into the database
|
||||||
for _, key := range db.Keys() {
|
it := db.NewIterator()
|
||||||
value, _ := db.Get(key)
|
for it.Next() {
|
||||||
t.Errorf("State leaked into database: %x -> %x", key, value)
|
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,
|
// Tests that no intermediate state of an object is stored into the database,
|
||||||
// only the one right before the commit.
|
// only the one right before the commit.
|
||||||
func TestIntermediateLeaks(t *testing.T) {
|
func TestIntermediateLeaks(t *testing.T) {
|
||||||
// Create two state databases, one transitioning to the final state, the other final from the beginning
|
// Create two state databases, one transitioning to the final state, the other final from the beginning
|
||||||
transDb := ethdb.NewMemDatabase()
|
transDb := rawdb.NewMemoryDatabase()
|
||||||
finalDb := ethdb.NewMemDatabase()
|
finalDb := rawdb.NewMemoryDatabase()
|
||||||
transState, _ := New(common.Hash{}, NewDatabase(transDb))
|
transState, _ := New(common.Hash{}, NewDatabase(transDb))
|
||||||
finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
|
finalState, _ := New(common.Hash{}, NewDatabase(finalDb))
|
||||||
|
|
||||||
|
|
@ -103,16 +104,20 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
if _, err := finalState.Commit(false); err != nil {
|
if _, err := finalState.Commit(false); err != nil {
|
||||||
t.Fatalf("failed to commit final state: %v", err)
|
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 {
|
if _, err := transDb.Get(key); err != nil {
|
||||||
val, _ := finalDb.Get(key)
|
t.Errorf("entry missing from the transition database: %x -> %x", key, it.Value())
|
||||||
t.Errorf("entry missing from the transition database: %x -> %x", key, val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, key := range transDb.Keys() {
|
it.Release()
|
||||||
|
|
||||||
|
it = transDb.NewIterator()
|
||||||
|
for it.Next() {
|
||||||
|
key := it.Key()
|
||||||
if _, err := finalDb.Get(key); err != nil {
|
if _, err := finalDb.Get(key); err != nil {
|
||||||
val, _ := transDb.Get(key)
|
t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value())
|
||||||
t.Errorf("extra entry in the transition database: %x -> %x", key, val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +127,7 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
// https://github.com/ethereum/go-ethereum/pull/15549.
|
// https://github.com/ethereum/go-ethereum/pull/15549.
|
||||||
func TestCopy(t *testing.T) {
|
func TestCopy(t *testing.T) {
|
||||||
// Create a random state test to copy and modify "independently"
|
// 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++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
|
||||||
|
|
@ -342,7 +347,7 @@ func (test *snapshotTest) String() string {
|
||||||
func (test *snapshotTest) run() bool {
|
func (test *snapshotTest) run() bool {
|
||||||
// Run all actions and create snapshots.
|
// Run all actions and create snapshots.
|
||||||
var (
|
var (
|
||||||
state, _ = New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
|
state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
snapshotRevs = make([]int, len(test.snapshots))
|
snapshotRevs = make([]int, len(test.snapshots))
|
||||||
sindex = 0
|
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.
|
// 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
|
// See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512
|
||||||
func TestCopyOfCopy(t *testing.T) {
|
func TestCopyOfCopy(t *testing.T) {
|
||||||
sdb, _ := New(common.Hash{}, NewDatabase(ethdb.NewMemDatabase()))
|
sdb, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
addr := common.HexToAddress("aaaa")
|
addr := common.HexToAddress("aaaa")
|
||||||
sdb.SetBalance(addr, big.NewInt(42))
|
sdb.SetBalance(addr, big.NewInt(42))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,13 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewStateSync create a new state trie download scheduler.
|
// 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
|
var syncer *trie.Sync
|
||||||
callback := func(leaf []byte, parent common.Hash) error {
|
callback := func(leaf []byte, parent common.Hash) error {
|
||||||
var obj Account
|
var obj Account
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -38,7 +39,7 @@ type testAccount struct {
|
||||||
// makeTestState create a sample test state to test node-wise reconstruction.
|
// makeTestState create a sample test state to test node-wise reconstruction.
|
||||||
func makeTestState() (Database, common.Hash, []*testAccount) {
|
func makeTestState() (Database, common.Hash, []*testAccount) {
|
||||||
// Create an empty state
|
// Create an empty state
|
||||||
db := NewDatabase(ethdb.NewMemDatabase())
|
db := NewDatabase(rawdb.NewMemoryDatabase())
|
||||||
state, _ := New(common.Hash{}, db)
|
state, _ := New(common.Hash{}, db)
|
||||||
|
|
||||||
// Fill it with some arbitrary data
|
// 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
|
// checkStateAccounts cross references a reconstructed state with an expected
|
||||||
// account array.
|
// 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
|
// Check root availability and state contents
|
||||||
state, err := New(root, NewDatabase(db))
|
state, err := New(root, NewDatabase(db))
|
||||||
if err != nil {
|
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.
|
// 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 {
|
if v, _ := db.Get(root[:]); v == nil {
|
||||||
return nil // Consider a non existent state consistent.
|
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.
|
// 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
|
// Create and iterate a state trie rooted in a sub-node
|
||||||
if _, err := db.Get(root.Bytes()); err != nil {
|
if _, err := db.Get(root.Bytes()); err != nil {
|
||||||
return nil // Consider a non existent state consistent.
|
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.
|
// Tests that an empty state is not scheduled for syncing.
|
||||||
func TestEmptyStateSync(t *testing.T) {
|
func TestEmptyStateSync(t *testing.T) {
|
||||||
empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
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)
|
t.Errorf("content requested for empty state: %v", req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +140,7 @@ func testIterativeStateSync(t *testing.T, batch int) {
|
||||||
srcDb, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb := ethdb.NewMemDatabase()
|
dstDb := rawdb.NewMemoryDatabase()
|
||||||
sched := NewStateSync(srcRoot, dstDb)
|
sched := NewStateSync(srcRoot, dstDb)
|
||||||
|
|
||||||
queue := append([]common.Hash{}, sched.Missing(batch)...)
|
queue := append([]common.Hash{}, sched.Missing(batch)...)
|
||||||
|
|
@ -171,7 +172,7 @@ func TestIterativeDelayedStateSync(t *testing.T) {
|
||||||
srcDb, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb := ethdb.NewMemDatabase()
|
dstDb := rawdb.NewMemoryDatabase()
|
||||||
sched := NewStateSync(srcRoot, dstDb)
|
sched := NewStateSync(srcRoot, dstDb)
|
||||||
|
|
||||||
queue := append([]common.Hash{}, sched.Missing(0)...)
|
queue := append([]common.Hash{}, sched.Missing(0)...)
|
||||||
|
|
@ -208,7 +209,7 @@ func testIterativeRandomStateSync(t *testing.T, batch int) {
|
||||||
srcDb, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb := ethdb.NewMemDatabase()
|
dstDb := rawdb.NewMemoryDatabase()
|
||||||
sched := NewStateSync(srcRoot, dstDb)
|
sched := NewStateSync(srcRoot, dstDb)
|
||||||
|
|
||||||
queue := make(map[common.Hash]struct{})
|
queue := make(map[common.Hash]struct{})
|
||||||
|
|
@ -248,7 +249,7 @@ func TestIterativeRandomDelayedStateSync(t *testing.T) {
|
||||||
srcDb, srcRoot, srcAccounts := makeTestState()
|
srcDb, srcRoot, srcAccounts := makeTestState()
|
||||||
|
|
||||||
// Create a destination state and sync with the scheduler
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb := ethdb.NewMemDatabase()
|
dstDb := rawdb.NewMemoryDatabase()
|
||||||
sched := NewStateSync(srcRoot, dstDb)
|
sched := NewStateSync(srcRoot, dstDb)
|
||||||
|
|
||||||
queue := make(map[common.Hash]struct{})
|
queue := make(map[common.Hash]struct{})
|
||||||
|
|
@ -292,10 +293,10 @@ func TestIncompleteStateSync(t *testing.T) {
|
||||||
// Create a random state to copy
|
// Create a random state to copy
|
||||||
srcDb, srcRoot, srcAccounts := makeTestState()
|
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
|
// Create a destination state and sync with the scheduler
|
||||||
dstDb := ethdb.NewMemDatabase()
|
dstDb := rawdb.NewMemoryDatabase()
|
||||||
sched := NewStateSync(srcRoot, dstDb)
|
sched := NewStateSync(srcRoot, dstDb)
|
||||||
|
|
||||||
added := []common.Hash{}
|
added := []common.Hash{}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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) {
|
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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
|
|
@ -163,7 +163,7 @@ func (c *testChain) State() (*state.StateDB, error) {
|
||||||
// a state change between those fetches.
|
// a state change between those fetches.
|
||||||
stdb := c.statedb
|
stdb := c.statedb
|
||||||
if *c.trigger {
|
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
|
// simulate that the new head block included tx0 and tx1
|
||||||
c.statedb.SetNonce(c.address, 2)
|
c.statedb.SetNonce(c.address, 2)
|
||||||
c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether))
|
c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether))
|
||||||
|
|
@ -181,7 +181,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
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
|
trigger = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -335,7 +335,7 @@ func TestTransactionChainFork(t *testing.T) {
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
resetState := func() {
|
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))
|
statedb.AddBalance(addr, big.NewInt(100000000000000))
|
||||||
|
|
||||||
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
|
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
@ -364,7 +364,7 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
|
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
resetState := func() {
|
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))
|
statedb.AddBalance(addr, big.NewInt(100000000000000))
|
||||||
|
|
||||||
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
|
pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
@ -554,7 +554,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the postponing with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
|
|
@ -769,7 +769,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -857,7 +857,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) {
|
||||||
evictionInterval = time.Second
|
evictionInterval = time.Second
|
||||||
|
|
||||||
// Create the pool to test the non-expiration enforcement
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1011,7 +1011,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1057,7 +1057,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1091,7 +1091,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the limit enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1139,7 +1139,7 @@ func TestTransactionPoolRepricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
|
|
@ -1260,7 +1260,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
|
|
@ -1322,7 +1322,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1428,7 +1428,7 @@ func TestTransactionPoolStableUnderpricing(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1494,7 +1494,7 @@ func TestTransactionReplacement(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the pricing enforcement with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
|
|
@ -1588,7 +1588,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
|
||||||
os.Remove(journal)
|
os.Remove(journal)
|
||||||
|
|
||||||
// Create the original pool to inject transaction into the 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
config := testTxPoolConfig
|
config := testTxPoolConfig
|
||||||
|
|
@ -1686,7 +1686,7 @@ func TestTransactionStatusCheck(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Create the pool to test the status retrievals with
|
// 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)}
|
blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
|
||||||
|
|
||||||
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain)
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
setDefaults(cfg)
|
setDefaults(cfg)
|
||||||
|
|
||||||
if cfg.State == nil {
|
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 (
|
var (
|
||||||
address = common.BytesToAddress([]byte("contract"))
|
address = common.BytesToAddress([]byte("contract"))
|
||||||
|
|
@ -129,7 +129,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||||
setDefaults(cfg)
|
setDefaults(cfg)
|
||||||
|
|
||||||
if cfg.State == nil {
|
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 (
|
var (
|
||||||
vmenv = NewEnv(cfg)
|
vmenv = NewEnv(cfg)
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ func TestExecute(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCall(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")
|
address := common.HexToAddress("0x0a")
|
||||||
state.SetCode(address, []byte{
|
state.SetCode(address, []byte{
|
||||||
byte(vm.PUSH1), 10,
|
byte(vm.PUSH1), 10,
|
||||||
|
|
@ -151,7 +151,7 @@ func BenchmarkCall(b *testing.B) {
|
||||||
}
|
}
|
||||||
func benchmarkEVM_Create(bench *testing.B, code string) {
|
func benchmarkEVM_Create(bench *testing.B, code string) {
|
||||||
var (
|
var (
|
||||||
statedb, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
|
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
sender = common.BytesToAddress([]byte("sender"))
|
sender = common.BytesToAddress([]byte("sender"))
|
||||||
receiver = common.BytesToAddress([]byte("receiver"))
|
receiver = common.BytesToAddress([]byte("receiver"))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// 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
|
// 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/>.
|
// 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.
|
// IdealBatchSize defines the size of the data batches should ideally add in one
|
||||||
// The value was determined empirically.
|
// write.
|
||||||
const IdealBatchSize = 100 * 1024
|
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
|
// 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 {
|
type Batch interface {
|
||||||
Putter
|
Writer
|
||||||
Deleter
|
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
|
Write() error
|
||||||
|
|
||||||
// Reset resets the batch for reuse
|
// Reset resets the batch for reuse
|
||||||
Reset()
|
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
84
database/database.go
Normal 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
57
database/iterator.go
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -28,9 +28,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"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)
|
return b.gpo.SuggestPrice(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) ChainDb() ethdb.Database {
|
func (b *EthAPIBackend) ChainDb() database.Database {
|
||||||
return b.eth.ChainDb()
|
return b.eth.ChainDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ import (
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var dumper = spew.ConfigState{Indent: " "}
|
var dumper = spew.ConfigState{Indent: " "}
|
||||||
|
|
@ -31,7 +31,7 @@ var dumper = spew.ConfigState{Indent: " "}
|
||||||
func TestStorageRangeAt(t *testing.T) {
|
func TestStorageRangeAt(t *testing.T) {
|
||||||
// Create a state where account 0x010000... has a few storage entries.
|
// Create a state where account 0x010000... has a few storage entries.
|
||||||
var (
|
var (
|
||||||
state, _ = state.New(common.Hash{}, state.NewDatabase(ethdb.NewMemDatabase()))
|
state, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
addr = common.Address{0x01}
|
addr = common.Address{0x01}
|
||||||
keys = []common.Hash{ // hashes of Keys of storage
|
keys = []common.Hash{ // hashes of Keys of storage
|
||||||
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
|
common.HexToHash("340dd630ad21bf010b4e676dbfa9ba9a02175262d1fa356232cfde6cb5b47ef2"),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -37,12 +36,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/freezer"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
|
|
@ -71,12 +69,11 @@ type Ethereum struct {
|
||||||
// Handlers
|
// Handlers
|
||||||
txPool *core.TxPool
|
txPool *core.TxPool
|
||||||
blockchain *core.BlockChain
|
blockchain *core.BlockChain
|
||||||
freezer *freezer.Freezer
|
|
||||||
protocolManager *ProtocolManager
|
protocolManager *ProtocolManager
|
||||||
lesServer LesServer
|
lesServer LesServer
|
||||||
|
|
||||||
// DB interfaces
|
// DB interfaces
|
||||||
chainDb ethdb.Database // Block chain database
|
chainDb database.Database // Block chain database
|
||||||
|
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
engine consensus.Engine
|
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)
|
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
|
||||||
|
|
||||||
// Assemble the Ethereum object
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -171,12 +168,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// Rewind the chain in case of an incompatible config upgrade.
|
||||||
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
|
||||||
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
|
||||||
|
|
@ -224,20 +215,8 @@ func makeExtraData(extra []byte) []byte {
|
||||||
return extra
|
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
|
// 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 proof-of-authority is requested, set it up
|
||||||
if chainConfig.Clique != nil {
|
if chainConfig.Clique != nil {
|
||||||
return clique.New(chainConfig.Clique, db)
|
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) TxPool() *core.TxPool { return s.txPool }
|
||||||
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux }
|
||||||
func (s *Ethereum) Engine() consensus.Engine { return s.engine }
|
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) IsListening() bool { return true } // Always listening
|
||||||
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
|
||||||
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
func (s *Ethereum) NetVersion() uint64 { return s.networkID }
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -89,7 +89,7 @@ const (
|
||||||
// for the Ethereum header bloom filters, permitting blazing fast filtering.
|
// for the Ethereum header bloom filters, permitting blazing fast filtering.
|
||||||
type BloomIndexer struct {
|
type BloomIndexer struct {
|
||||||
size uint64 // section size to generate bloombits for
|
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
|
gen *bloombits.Generator // generator to rotate the bloom bits crating the bloom index
|
||||||
section uint64 // Section is the section number being processed currently
|
section uint64 // Section is the section number being processed currently
|
||||||
head common.Hash // Head is the hash of the last header processed
|
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
|
// NewBloomIndexer returns a chain indexer that generates bloom bits data for the
|
||||||
// canonical chain for fast logs filtering.
|
// 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{
|
backend := &BloomIndexer{
|
||||||
db: db,
|
db: db,
|
||||||
size: size,
|
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")
|
return core.NewChainIndexer(db, table, backend, size, confirms, bloomThrottling, "bloombits")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,11 @@ type Config struct {
|
||||||
SkipBcVersionCheck bool `toml:"-"`
|
SkipBcVersionCheck bool `toml:"-"`
|
||||||
DatabaseHandles int `toml:"-"`
|
DatabaseHandles int `toml:"-"`
|
||||||
DatabaseCache int
|
DatabaseCache int
|
||||||
TrieCleanCache int
|
DatabaseFreezer string
|
||||||
TrieDirtyCache int
|
|
||||||
TrieTimeout time.Duration
|
TrieCleanCache int
|
||||||
|
TrieDirtyCache int
|
||||||
|
TrieTimeout time.Duration
|
||||||
|
|
||||||
// Mining-related options
|
// Mining-related options
|
||||||
Etherbase common.Address `toml:",omitempty"`
|
Etherbase common.Address `toml:",omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"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)
|
genesis uint64 // Genesis block number to limit sync to (e.g. light client CHT)
|
||||||
queue *queue // Scheduler for selecting the hashes to download
|
queue *queue // Scheduler for selecting the hashes to download
|
||||||
peers *peerSet // Set of active peers from which download can proceed
|
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
|
rttEstimate uint64 // Round trip time to target for download requests
|
||||||
rttConfidence uint64 // Confidence in the estimated RTT (unit: millionths to allow atomic ops)
|
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.
|
// 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 {
|
if lightchain == nil {
|
||||||
lightchain = chain
|
lightchain = chain
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,9 @@ import (
|
||||||
|
|
||||||
ethereum "github.com/ethereum/go-ethereum"
|
ethereum "github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/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/event"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
@ -45,9 +46,9 @@ func init() {
|
||||||
type downloadTester struct {
|
type downloadTester struct {
|
||||||
downloader *Downloader
|
downloader *Downloader
|
||||||
|
|
||||||
genesis *types.Block // Genesis blocks used by the tester and peers
|
genesis *types.Block // Genesis blocks used by the tester and peers
|
||||||
stateDb ethdb.Database // Database used by the tester for syncing from peers
|
stateDb database.Database // Database used by the tester for syncing from peers
|
||||||
peerDb ethdb.Database // Database of the peers containing all data
|
peerDb database.Database // Database of the peers containing all data
|
||||||
peers map[string]*downloadTesterPeer
|
peers map[string]*downloadTesterPeer
|
||||||
|
|
||||||
ownHashes []common.Hash // Hash chain belonging to the tester
|
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},
|
ownReceipts: map[common.Hash]types.Receipts{testGenesis.Hash(): nil},
|
||||||
ownChainTd: map[common.Hash]*big.Int{testGenesis.Hash(): testGenesis.Difficulty()},
|
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.stateDb.Put(testGenesis.Root().Bytes(), []byte{0x00})
|
||||||
|
|
||||||
tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer)
|
tester.downloader = New(FullSync, tester.stateDb, new(event.TypeMux), tester, nil, tester.dropPeer)
|
||||||
return tester
|
return tester
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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
|
// 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.
|
// sync commands from an existing local database.
|
||||||
type FakePeer struct {
|
type FakePeer struct {
|
||||||
id string
|
id string
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
hc *core.HeaderChain
|
hc *core.HeaderChain
|
||||||
dl *Downloader
|
dl *Downloader
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFakePeer creates a new mock downloader peer with the given data sources.
|
// 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}
|
return &FakePeer{id: id, db: db, hc: hc, dl: dl}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
@ -325,7 +325,7 @@ func (s *stateSync) loop() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateSync) commit(force bool) error {
|
func (s *stateSync) commit(force bool) error {
|
||||||
if !force && s.bytesUncommitted < ethdb.IdealBatchSize {
|
if !force && s.bytesUncommitted < database.IdealBatchSize {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -34,7 +34,7 @@ import (
|
||||||
var (
|
var (
|
||||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
testDB = ethdb.NewMemDatabase()
|
testDB = rawdb.NewMemoryDatabase()
|
||||||
testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000))
|
testGenesis = core.GenesisBlockForTesting(testDB, testAddress, big.NewInt(1000000000))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testdb = ethdb.NewMemDatabase()
|
testdb = rawdb.NewMemoryDatabase()
|
||||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
|
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
|
||||||
genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))
|
genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
@ -55,7 +55,7 @@ type PublicFilterAPI struct {
|
||||||
backend Backend
|
backend Backend
|
||||||
mux *event.TypeMux
|
mux *event.TypeMux
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
chainDb ethdb.Database
|
chainDb database.Database
|
||||||
events *EventSystem
|
events *EventSystem
|
||||||
filtersMu sync.Mutex
|
filtersMu sync.Mutex
|
||||||
filters map[rpc.ID]*filter
|
filters map[rpc.ID]*filter
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package filters
|
package filters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -28,7 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
)
|
)
|
||||||
|
|
@ -67,7 +66,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
||||||
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
||||||
fmt.Println("Running bloombits benchmark section size:", sectionSize)
|
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 {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
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++ {
|
for i := 0; i < benchFilterCnt; i++ {
|
||||||
if i%20 == 0 {
|
if i%20 == 0 {
|
||||||
db.Close()
|
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)}
|
backend = &testBackend{mux, db, cnt, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)}
|
||||||
}
|
}
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
|
|
@ -146,37 +145,21 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
||||||
db.Close()
|
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-")
|
var bloomBitsPrefix = []byte("bloomBits-")
|
||||||
|
|
||||||
func clearBloomBits(db ethdb.Database) {
|
func clearBloomBits(db database.Database) {
|
||||||
fmt.Println("Clearing bloombits data...")
|
fmt.Println("Clearing bloombits data...")
|
||||||
forEachKey(db, bloomBitsPrefix, bloomBitsPrefix, func(key []byte) {
|
it := db.NewIteratorWithPrefix(bloomBitsPrefix)
|
||||||
db.Delete(key)
|
for it.Next() {
|
||||||
})
|
db.Delete(it.Key())
|
||||||
|
}
|
||||||
|
it.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkNoBloomBits(b *testing.B) {
|
func BenchmarkNoBloomBits(b *testing.B) {
|
||||||
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
benchDataDir := node.DefaultDataDir() + "/geth/chaindata"
|
||||||
fmt.Println("Running benchmark without bloombits")
|
fmt.Println("Running benchmark without bloombits")
|
||||||
db, err := ethdb.NewLDBDatabase(benchDataDir, 128, 1024)
|
db, err := rawdb.NewLeveldbDatabase(benchDataDir, 128, 1024, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
b.Fatalf("error opening database at %v: %v", benchDataDir, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Backend interface {
|
type Backend interface {
|
||||||
ChainDb() ethdb.Database
|
ChainDb() database.Database
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
|
||||||
HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
|
HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
|
||||||
|
|
@ -51,7 +51,7 @@ type Backend interface {
|
||||||
type Filter struct {
|
type Filter struct {
|
||||||
backend Backend
|
backend Backend
|
||||||
|
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
addresses []common.Address
|
addresses []common.Address
|
||||||
topics [][]common.Hash
|
topics [][]common.Hash
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
@ -40,7 +40,7 @@ import (
|
||||||
|
|
||||||
type testBackend struct {
|
type testBackend struct {
|
||||||
mux *event.TypeMux
|
mux *event.TypeMux
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
sections uint64
|
sections uint64
|
||||||
txFeed *event.Feed
|
txFeed *event.Feed
|
||||||
rmLogsFeed *event.Feed
|
rmLogsFeed *event.Feed
|
||||||
|
|
@ -48,7 +48,7 @@ type testBackend struct {
|
||||||
chainFeed *event.Feed
|
chainFeed *event.Feed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) ChainDb() ethdb.Database {
|
func (b *testBackend) ChainDb() database.Database {
|
||||||
return b.db
|
return b.db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +161,7 @@ func TestBlockSubscription(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
@ -218,7 +218,7 @@ func TestPendingTxFilter(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
@ -278,7 +278,7 @@ func TestPendingTxFilter(t *testing.T) {
|
||||||
func TestLogFilterCreation(t *testing.T) {
|
func TestLogFilterCreation(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
@ -327,7 +327,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
@ -354,7 +354,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
|
||||||
func TestInvalidGetLogsRequest(t *testing.T) {
|
func TestInvalidGetLogsRequest(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
@ -384,7 +384,7 @@ func TestLogFilter(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
@ -503,7 +503,7 @@ func TestPendingLogsSubscription(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
logsFeed = new(event.Feed)
|
logsFeed = new(event.Feed)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
@ -51,7 +50,7 @@ func BenchmarkFilters(b *testing.B) {
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db, _ = ethdb.NewLDBDatabase(dir, 0, 0)
|
db, _ = rawdb.NewLeveldbDatabase(dir, 0, 0, "")
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
|
|
@ -110,7 +109,7 @@ func TestFilters(t *testing.T) {
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db, _ = ethdb.NewLDBDatabase(dir, 0, 0)
|
db, _ = rawdb.NewLeveldbDatabase(dir, 0, 0, "")
|
||||||
mux = new(event.TypeMux)
|
mux = new(event.TypeMux)
|
||||||
txFeed = new(event.Feed)
|
txFeed = new(event.Feed)
|
||||||
rmLogsFeed = new(event.Feed)
|
rmLogsFeed = new(event.Feed)
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/fetcher"
|
"github.com/ethereum/go-ethereum/eth/fetcher"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"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
|
// NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||||
// with the Ethereum network.
|
// 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
|
// Create the protocol manager with the base fields
|
||||||
manager := &ProtocolManager{
|
manager := &ProtocolManager{
|
||||||
networkID: networkID,
|
networkID: networkID,
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -344,11 +344,15 @@ func testGetNodeData(t *testing.T, protocol int) {
|
||||||
|
|
||||||
// Fetch for now the entire chain db
|
// Fetch for now the entire chain db
|
||||||
hashes := []common.Hash{}
|
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))
|
hashes = append(hashes, common.BytesToHash(key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
it.Release()
|
||||||
|
|
||||||
p2p.Send(peer.app, 0x0d, hashes)
|
p2p.Send(peer.app, 0x0d, hashes)
|
||||||
msg, err := peer.app.ReadMsg()
|
msg, err := peer.app.ReadMsg()
|
||||||
if err != nil {
|
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)
|
t.Errorf("data hash mismatch: have %x, want %x", hash, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statedb := ethdb.NewMemDatabase()
|
statedb := rawdb.NewMemoryDatabase()
|
||||||
for i := 0; i < len(data); i++ {
|
for i := 0; i < len(data); i++ {
|
||||||
statedb.Put(hashes[i].Bytes(), data[i])
|
statedb.Put(hashes[i].Bytes(), data[i])
|
||||||
}
|
}
|
||||||
|
|
@ -469,7 +473,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
||||||
var (
|
var (
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
pow = ethash.NewFaker()
|
pow = ethash.NewFaker()
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
||||||
gspec = &core.Genesis{Config: config}
|
gspec = &core.Genesis{Config: config}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
|
|
@ -550,7 +554,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
|
||||||
var (
|
var (
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
pow = ethash.NewFaker()
|
pow = ethash.NewFaker()
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
config = ¶ms.ChainConfig{}
|
config = ¶ms.ChainConfig{}
|
||||||
gspec = &core.Genesis{Config: config}
|
gspec = &core.Genesis{Config: config}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
|
@ -49,11 +50,11 @@ var (
|
||||||
// newTestProtocolManager creates a new protocol manager for testing purposes,
|
// newTestProtocolManager creates a new protocol manager for testing purposes,
|
||||||
// with the given number of blocks already known, and potential notification
|
// with the given number of blocks already known, and potential notification
|
||||||
// channels for different events.
|
// 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 (
|
var (
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
engine = ethash.NewFaker()
|
engine = ethash.NewFaker()
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec = &core.Genesis{
|
gspec = &core.Genesis{
|
||||||
Config: params.TestChainConfig,
|
Config: params.TestChainConfig,
|
||||||
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
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
|
// with the given number of blocks already known, and potential notification
|
||||||
// channels for different events. In case of an error, the constructor force-
|
// channels for different events. In case of an error, the constructor force-
|
||||||
// fails the test.
|
// 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)
|
pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create protocol manager: %v", err)
|
t.Fatalf("Failed to create protocol manager: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
|
|
@ -155,6 +155,7 @@ func TestPrestateTracerCreate2(t *testing.T) {
|
||||||
GasPrice: big.NewInt(1),
|
GasPrice: big.NewInt(1),
|
||||||
}
|
}
|
||||||
alloc := core.GenesisAlloc{}
|
alloc := core.GenesisAlloc{}
|
||||||
|
|
||||||
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
|
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
|
||||||
// the address
|
// the address
|
||||||
alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{
|
alloc[common.HexToAddress("0x00000000000000000000000000000000deadbeef")] = core.GenesisAccount{
|
||||||
|
|
@ -167,7 +168,8 @@ func TestPrestateTracerCreate2(t *testing.T) {
|
||||||
Code: []byte{},
|
Code: []byte{},
|
||||||
Balance: big.NewInt(500000000000000),
|
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
|
// Create the tracer, the EVM environment and run it
|
||||||
tracer, err := New("prestateTracer")
|
tracer, err := New("prestateTracer")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -240,7 +242,7 @@ func TestCallTracer(t *testing.T) {
|
||||||
GasLimit: uint64(test.Context.GasLimit),
|
GasLimit: uint64(test.Context.GasLimit),
|
||||||
GasPrice: tx.GasPrice(),
|
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
|
// Create the tracer, the EVM environment and run it
|
||||||
tracer, err := New("callTracer")
|
tracer, err := New("callTracer")
|
||||||
|
|
|
||||||
12
ethdb/.gitignore
vendored
12
ethdb/.gitignore
vendored
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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 = ðdb.LDBDatabase{}
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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.
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
290
freezer/table.go
290
freezer/table.go
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -27,8 +27,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
@ -41,7 +41,7 @@ type Backend interface {
|
||||||
Downloader() *downloader.Downloader
|
Downloader() *downloader.Downloader
|
||||||
ProtocolVersion() int
|
ProtocolVersion() int
|
||||||
SuggestPrice(ctx context.Context) (*big.Int, error)
|
SuggestPrice(ctx context.Context) (*big.Int, error)
|
||||||
ChainDb() ethdb.Database
|
ChainDb() database.Database
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
AccountManager() *accounts.Manager
|
AccountManager() *accounts.Manager
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
// +build !js
|
// +build !js
|
||||||
|
|
||||||
package ethdb
|
package keyvalue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -26,23 +26,38 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||||
"github.com/syndtr/goleveldb/leveldb/filter"
|
"github.com/syndtr/goleveldb/leveldb/filter"
|
||||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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
|
// LeveldbDatabase is a persistent key-value store. Apart from basic data storage
|
||||||
|
// functionality it also supports batch writes and iterating over the keyspace in
|
||||||
type LDBDatabase struct {
|
// binary-alphabetical order.
|
||||||
|
type LeveldbDatabase struct {
|
||||||
fn string // filename for reporting
|
fn string // filename for reporting
|
||||||
db *leveldb.DB // LevelDB instance
|
db *leveldb.DB // LevelDB instance
|
||||||
|
|
||||||
|
|
@ -60,17 +75,16 @@ type LDBDatabase struct {
|
||||||
log log.Logger // Contextual logger tracking the database path
|
log log.Logger // Contextual logger tracking the database path
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLDBDatabase returns a LevelDB wrapped object.
|
// NewLeveldbDatabase returns a wrapped LevelDB object.
|
||||||
func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
|
func NewLeveldbDatabase(file string, cache int, handles int, namespace string) (database.KeyValueStore, error) {
|
||||||
logger := log.New("database", file)
|
|
||||||
|
|
||||||
// Ensure we have some minimal caching and file guarantees
|
// Ensure we have some minimal caching and file guarantees
|
||||||
if cache < 16 {
|
if cache < leveldbMinCache {
|
||||||
cache = 16
|
cache = leveldbMinCache
|
||||||
}
|
}
|
||||||
if handles < 16 {
|
if handles < leveldbMinHandles {
|
||||||
handles = 16
|
handles = leveldbMinHandles
|
||||||
}
|
}
|
||||||
|
logger := log.New("database", file)
|
||||||
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles)
|
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles)
|
||||||
|
|
||||||
// Open the db and recover any potential corruptions
|
// 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 {
|
if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
|
||||||
db, err = leveldb.RecoverFile(file, nil)
|
db, err = leveldb.RecoverFile(file, nil)
|
||||||
}
|
}
|
||||||
// (Re)check for errors and abort if opening of the db failed
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &LDBDatabase{
|
// Assemble the wrapper with all the registered metrics
|
||||||
fn: file,
|
ldb := &LeveldbDatabase{
|
||||||
db: db,
|
fn: file,
|
||||||
log: logger,
|
db: db,
|
||||||
}, nil
|
log: logger,
|
||||||
}
|
quitChan: make(chan chan error),
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
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
|
// Close stops th emetrics collection, flushes any pending data to disk and closes
|
||||||
func (db *LDBDatabase) Delete(key []byte) error {
|
// all io access to the underlying key-value store.
|
||||||
return db.db.Delete(key, nil)
|
func (db *LeveldbDatabase) Close() error {
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
db.quitLock.Lock()
|
db.quitLock.Lock()
|
||||||
defer db.quitLock.Unlock()
|
defer db.quitLock.Unlock()
|
||||||
|
|
||||||
|
|
@ -144,41 +134,68 @@ func (db *LDBDatabase) Close() {
|
||||||
}
|
}
|
||||||
db.quitChan = nil
|
db.quitChan = nil
|
||||||
}
|
}
|
||||||
err := db.db.Close()
|
return db.db.Close()
|
||||||
if err == nil {
|
}
|
||||||
db.log.Info("Database closed")
|
|
||||||
} else {
|
// Has retrieves if a key is present in the key-value store.
|
||||||
db.log.Error("Failed to close database", "err", err)
|
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 {
|
// NewIterator creates a binary-alphabetical iterator over the entire keyspace
|
||||||
return db.db
|
// contained within the leveldb database.
|
||||||
|
func (db *LeveldbDatabase) NewIterator() database.Iterator {
|
||||||
|
return db.NewIteratorWithPrefix(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meter configures the database metrics collectors and
|
// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
|
||||||
func (db *LDBDatabase) Meter(prefix string) {
|
// of database content with a particular key prefix.
|
||||||
// Initialize all the metrics collector at the requested prefix
|
func (db *LeveldbDatabase) NewIteratorWithPrefix(prefix []byte) database.Iterator {
|
||||||
db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
|
return db.db.NewIterator(util.BytesPrefix(prefix), 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)
|
|
||||||
|
|
||||||
// Create a quit channel for the periodic collector and run it
|
// Stat returns a particular internal stat of the database.
|
||||||
db.quitLock.Lock()
|
func (db *LeveldbDatabase) Stat(property string) (string, error) {
|
||||||
db.quitChan = make(chan chan error)
|
return db.db.GetProperty(property)
|
||||||
db.quitLock.Unlock()
|
}
|
||||||
|
|
||||||
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
|
// meter periodically retrieves internal leveldb counters and reports them to
|
||||||
// the metrics subsystem.
|
// the metrics subsystem.
|
||||||
//
|
//
|
||||||
// This is how a stats table look like (currently):
|
// This is how a stats leveldbTable look like (currently):
|
||||||
// Compactions
|
// Compactions
|
||||||
// Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)
|
// 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):
|
// This is how the iostats look like (currently):
|
||||||
// Read(MB):3895.04860 Write(MB):3654.64712
|
// 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
|
// Create the counters to store current and previous compaction values
|
||||||
compactions := make([][]float64, 2)
|
compactions := make([][]float64, 2)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
|
|
@ -221,19 +238,19 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
merr = err
|
merr = err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Find the compaction table, skip the header
|
// Find the compaction leveldbTable, skip the header
|
||||||
lines := strings.Split(stats, "\n")
|
lines := strings.Split(stats, "\n")
|
||||||
for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" {
|
for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" {
|
||||||
lines = lines[1:]
|
lines = lines[1:]
|
||||||
}
|
}
|
||||||
if len(lines) <= 3 {
|
if len(lines) <= 3 {
|
||||||
db.log.Error("Compaction table not found")
|
db.log.Error("Compaction leveldbTable not found")
|
||||||
merr = errors.New("compaction table not found")
|
merr = errors.New("compaction leveldbTable not found")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lines = lines[3:]
|
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++ {
|
for j := 0; j < len(compactions[i%2]); j++ {
|
||||||
compactions[i%2][j] = 0
|
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
|
// 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.
|
// warnings will be withheld for one minute not to overwhelm the user.
|
||||||
if paused && delayN-delaystats[0] == 0 && duration.Nanoseconds()-delaystats[1] == 0 &&
|
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")
|
db.log.Warn("Database compacting, degraded performance")
|
||||||
lastWritePaused = time.Now()
|
lastWritePaused = time.Now()
|
||||||
}
|
}
|
||||||
|
|
@ -349,37 +366,40 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
|
||||||
errc <- merr
|
errc <- merr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *LDBDatabase) NewBatch() Batch {
|
// leveldbBatch is a write-only leveldb batch that commits changes to its host
|
||||||
return &ldbBatch{db: db.db, b: new(leveldb.Batch)}
|
// database when Write is called. A batch cannot be used concurrently.
|
||||||
}
|
type leveldbBatch struct {
|
||||||
|
|
||||||
type ldbBatch struct {
|
|
||||||
db *leveldb.DB
|
db *leveldb.DB
|
||||||
b *leveldb.Batch
|
b *leveldb.Batch
|
||||||
size int
|
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.b.Put(key, value)
|
||||||
b.size += len(value)
|
b.size += len(value)
|
||||||
return nil
|
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.b.Delete(key)
|
||||||
b.size += 1
|
b.size += 1
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *ldbBatch) Write() error {
|
// ValueSize retrieves the amount of data queued up for writing.
|
||||||
return b.db.Write(b.b, nil)
|
func (b *leveldbBatch) ValueSize() int {
|
||||||
}
|
|
||||||
|
|
||||||
func (b *ldbBatch) ValueSize() int {
|
|
||||||
return b.size
|
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.b.Reset()
|
||||||
b.size = 0
|
b.size = 0
|
||||||
}
|
}
|
||||||
295
internal/keyvalue/memorydb.go
Normal file
295
internal/keyvalue/memorydb.go
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -29,9 +29,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"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)
|
return b.gpo.SuggestPrice(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) ChainDb() ethdb.Database {
|
func (b *LesApiBackend) ChainDb() database.Database {
|
||||||
return b.eth.chainDb
|
return b.eth.chainDb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ type LightEthereum struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
|
@ -34,7 +34,7 @@ import (
|
||||||
type lesCommons struct {
|
type lesCommons struct {
|
||||||
config *eth.Config
|
config *eth.Config
|
||||||
iConfig *light.IndexerConfig
|
iConfig *light.IndexerConfig
|
||||||
chainDb ethdb.Database
|
chainDb database.Database
|
||||||
protocolManager *ProtocolManager
|
protocolManager *ProtocolManager
|
||||||
chtIndexer, bloomTrieIndexer *core.ChainIndexer
|
chtIndexer, bloomTrieIndexer *core.ChainIndexer
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
@ -44,7 +44,7 @@ import (
|
||||||
// value for the client. Currently the LES protocol manager uses IP addresses
|
// value for the client. Currently the LES protocol manager uses IP addresses
|
||||||
// (without port address) to identify clients.
|
// (without port address) to identify clients.
|
||||||
type freeClientPool struct {
|
type freeClientPool struct {
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
clock mclock.Clock
|
clock mclock.Clock
|
||||||
closed bool
|
closed bool
|
||||||
|
|
@ -64,7 +64,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// newFreeClientPool creates a new free client pool
|
// 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{
|
pool := &freeClientPool{
|
||||||
db: db,
|
db: db,
|
||||||
clock: clock,
|
clock: clock,
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"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) {
|
func TestFreeClientPoolL10C100(t *testing.T) {
|
||||||
|
|
@ -45,7 +45,7 @@ const testFreeClientPoolTicks = 500000
|
||||||
func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
|
func testFreeClientPool(t *testing.T, connLimit, clientCount int) {
|
||||||
var (
|
var (
|
||||||
clock mclock.Simulated
|
clock mclock.Simulated
|
||||||
db = ethdb.NewMemDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
pool = newFreeClientPool(db, connLimit, 10000, &clock)
|
pool = newFreeClientPool(db, connLimit, 10000, &clock)
|
||||||
connected = make([]bool, clientCount)
|
connected = make([]bool, clientCount)
|
||||||
connTicks = make([]int, clientCount)
|
connTicks = make([]int, clientCount)
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -97,7 +97,7 @@ type ProtocolManager struct {
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
iConfig *light.IndexerConfig
|
iConfig *light.IndexerConfig
|
||||||
blockchain BlockChain
|
blockchain BlockChain
|
||||||
chainDb ethdb.Database
|
chainDb database.Database
|
||||||
odr *LesOdr
|
odr *LesOdr
|
||||||
server *LesServer
|
server *LesServer
|
||||||
serverPool *serverPool
|
serverPool *serverPool
|
||||||
|
|
@ -136,7 +136,7 @@ func NewProtocolManager(
|
||||||
peers *peerSet,
|
peers *peerSet,
|
||||||
blockchain BlockChain,
|
blockchain BlockChain,
|
||||||
txpool txPool,
|
txpool txPool,
|
||||||
chainDb ethdb.Database,
|
chainDb database.Database,
|
||||||
odr *LesOdr,
|
odr *LesOdr,
|
||||||
txrelay *LesTxRelay,
|
txrelay *LesTxRelay,
|
||||||
serverPool *serverPool,
|
serverPool *serverPool,
|
||||||
|
|
@ -907,7 +907,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
if reject(uint64(reqCnt), MaxHelperTrieProofsFetch) {
|
if reject(uint64(reqCnt), MaxHelperTrieProofsFetch) {
|
||||||
return errResp(ErrRequestRejected, "")
|
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 {
|
for _, req := range req.Reqs {
|
||||||
if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil {
|
if header := pm.blockchain.GetHeaderByNumber(req.BlockNum); header != nil {
|
||||||
sectionHead := rawdb.ReadCanonicalHash(pm.chainDb, req.ChtNum*pm.iConfig.ChtSize-1)
|
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
|
var prefix string
|
||||||
if root, prefix = pm.getHelperTrie(req.Type, req.TrieIdx); root != (common.Hash{}) {
|
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 {
|
if req.AuxReq == auxRoot {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -405,7 +404,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case 1:
|
case 1:
|
||||||
root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(frequency-1).Hash())
|
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
|
var proof light.NodeList
|
||||||
trie.Prove(key, 0, &proof)
|
trie.Prove(key, 0, &proof)
|
||||||
|
|
@ -413,7 +412,7 @@ func testGetCHTProofs(t *testing.T, protocol int) {
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
root := light.GetChtRoot(server.db, (frequency/config.ChtSize)-1, bc.GetHeaderByNumber(frequency-1).Hash())
|
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)
|
trie.Prove(key, 0, &proofsV2.Proofs)
|
||||||
}
|
}
|
||||||
// Assemble the requests for the different protocols
|
// Assemble the requests for the different protocols
|
||||||
|
|
@ -480,7 +479,7 @@ func TestGetBloombitsProofs(t *testing.T) {
|
||||||
var proofs HelperTrieResps
|
var proofs HelperTrieResps
|
||||||
|
|
||||||
root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash())
|
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)
|
trie.Prove(key, 0, &proofs.Proofs)
|
||||||
|
|
||||||
// Send the proof request and verify the response
|
// Send the proof request and verify the response
|
||||||
|
|
@ -493,7 +492,7 @@ func TestGetBloombitsProofs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransactionStatusLes2(t *testing.T) {
|
func TestTransactionStatusLes2(t *testing.T) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db, nil)
|
pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db, nil)
|
||||||
chain := pm.blockchain.(*core.BlockChain)
|
chain := pm.blockchain.(*core.BlockChain)
|
||||||
config := core.DefaultTxPoolConfig
|
config := core.DefaultTxPoolConfig
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/les/flowcontrol"
|
"github.com/ethereum/go-ethereum/les/flowcontrol"
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"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.
|
// 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)
|
chtIndexer := light.NewChtIndexer(db, odr, iConfig.ChtSize, iConfig.ChtConfirms)
|
||||||
bloomIndexer := eth.NewBloomIndexer(db, iConfig.BloomSize, iConfig.BloomConfirms)
|
bloomIndexer := eth.NewBloomIndexer(db, iConfig.BloomSize, iConfig.BloomConfirms)
|
||||||
bloomTrieIndexer := light.NewBloomTrieIndexer(db, odr, iConfig.BloomSize, iConfig.BloomTrieSize)
|
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,
|
// newTestProtocolManager creates a new protocol manager for testing purposes,
|
||||||
// with the given number of blocks already known, potential notification
|
// with the given number of blocks already known, potential notification
|
||||||
// channels for different events and relative chain indexers array.
|
// 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 (
|
var (
|
||||||
evmux = new(event.TypeMux)
|
evmux = new(event.TypeMux)
|
||||||
engine = ethash.NewFaker()
|
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
|
// 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-
|
// channels for different events and relative chain indexers array. In case of an error, the constructor force-
|
||||||
// fails the test.
|
// 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)
|
pm, err := newTestProtocolManager(lightSync, blocks, generator, odr, peers, db, ulcConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create protocol manager: %v", err)
|
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.
|
// TestEntity represents a network entity for testing with necessary auxiliary fields.
|
||||||
type TestEntity struct {
|
type TestEntity struct {
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
rPeer *peer
|
rPeer *peer
|
||||||
tPeer *testPeer
|
tPeer *testPeer
|
||||||
peers *peerSet
|
peers *peerSet
|
||||||
|
|
@ -340,7 +341,7 @@ type TestEntity struct {
|
||||||
|
|
||||||
// newServerEnv creates a server testing environment with a connected test peer for testing purpose.
|
// 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()) {
|
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)
|
cIndexer, bIndexer, btIndexer := testIndexers(db, nil, light.TestServerIndexerConfig)
|
||||||
|
|
||||||
pm := newTestProtocolManagerMust(t, false, blocks, testChainGen, nil, nil, db, nil)
|
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
|
// newClientServerEnv creates a client/server arch environment with a connected les server and light client pair
|
||||||
// for testing purpose.
|
// 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()) {
|
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()
|
peers, lPeers := newPeerSet(), newPeerSet()
|
||||||
|
|
||||||
dist := newRequestDistributor(lPeers, make(chan struct{}))
|
dist := newRequestDistributor(lPeers, make(chan struct{}))
|
||||||
|
|
|
||||||
|
|
@ -20,21 +20,21 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/light"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LesOdr implements light.OdrBackend
|
// LesOdr implements light.OdrBackend
|
||||||
type LesOdr struct {
|
type LesOdr struct {
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
indexerConfig *light.IndexerConfig
|
indexerConfig *light.IndexerConfig
|
||||||
chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer
|
chtIndexer, bloomTrieIndexer, bloomIndexer *core.ChainIndexer
|
||||||
retriever *retrieveManager
|
retriever *retrieveManager
|
||||||
stop chan struct{}
|
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{
|
return &LesOdr{
|
||||||
db: db,
|
db: db,
|
||||||
indexerConfig: config,
|
indexerConfig: config,
|
||||||
|
|
@ -49,7 +49,7 @@ func (odr *LesOdr) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database returns the backing database
|
// Database returns the backing database
|
||||||
func (odr *LesOdr) Database() ethdb.Database {
|
func (odr *LesOdr) Database() database.Database {
|
||||||
return odr.db
|
return odr.db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"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/light"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -51,7 +51,7 @@ type LesOdrRequest interface {
|
||||||
GetCost(*peer) uint64
|
GetCost(*peer) uint64
|
||||||
CanSend(*peer) bool
|
CanSend(*peer) bool
|
||||||
Request(uint64, *peer) error
|
Request(uint64, *peer) error
|
||||||
Validate(ethdb.Database, *Msg) error
|
Validate(database.Database, *Msg) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func LesRequest(req light.OdrRequest) LesOdrRequest {
|
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
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// 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)
|
log.Debug("Validating block body", "hash", r.Hash)
|
||||||
|
|
||||||
// Ensure we have a correct message with a single block body
|
// 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
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// 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)
|
log.Debug("Validating block receipts", "hash", r.Hash)
|
||||||
|
|
||||||
// Ensure we have a correct message with a single block receipt
|
// 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
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// 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)
|
log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key)
|
||||||
|
|
||||||
switch msg.MsgType {
|
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
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// 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)
|
log.Debug("Validating code data", "hash", r.Hash)
|
||||||
|
|
||||||
// Ensure we have a correct message with a single code element
|
// 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
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// 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)
|
log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum)
|
||||||
|
|
||||||
switch msg.MsgType {
|
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
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// 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)
|
log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList)
|
||||||
|
|
||||||
// Ensure we have a correct message with a single proof element
|
// 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
|
// 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.
|
// sets contain only the trie nodes necessary to make proofs pass.
|
||||||
type readTraceDB struct {
|
type readTraceDB struct {
|
||||||
db trie.DatabaseReader
|
db database.Reader
|
||||||
reads map[string]struct{}
|
reads map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,19 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"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/light"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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 TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) }
|
||||||
|
|
||||||
func TestOdrGetBlockLes2(t *testing.T) { testOdr(t, 2, 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
|
var block *types.Block
|
||||||
if bc != nil {
|
if bc != nil {
|
||||||
block = bc.GetBlockByHash(bhash)
|
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 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
|
var receipts types.Receipts
|
||||||
if bc != nil {
|
if bc != nil {
|
||||||
if number := rawdb.ReadHeaderNumber(db, bhash); number != 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 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")
|
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
|
||||||
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
|
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ type callmsg struct {
|
||||||
|
|
||||||
func (callmsg) CheckNonce() bool { return false }
|
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")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
|
||||||
var res []byte
|
var res []byte
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"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/light"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -34,13 +34,13 @@ func secAddr(addr common.Address) []byte {
|
||||||
return crypto.Keccak256(addr[:])
|
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 TestBlockAccessLes1(t *testing.T) { testAccess(t, 1, tfBlockAccess) }
|
||||||
|
|
||||||
func TestBlockAccessLes2(t *testing.T) { testAccess(t, 2, 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}
|
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 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}
|
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 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 {
|
if number := rawdb.ReadHeaderNumber(db, bhash); number != nil {
|
||||||
return &light.TrieRequest{Id: light.StateTrieID(rawdb.ReadHeader(db, bhash, *number)), Key: testBankSecureTrieKey}
|
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 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)
|
number := rawdb.ReadHeaderNumber(db, bhash)
|
||||||
if number != nil {
|
if number != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/les/flowcontrol"
|
"github.com/ethereum/go-ethereum/les/flowcontrol"
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -247,7 +247,7 @@ func linRegFromBytes(data []byte) *linReg {
|
||||||
|
|
||||||
type requestCostStats struct {
|
type requestCostStats struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
stats map[uint64]*linReg
|
stats map[uint64]*linReg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,7 +258,7 @@ type requestCostStatsRlp []struct {
|
||||||
|
|
||||||
var rcStatsKey = []byte("_requestCostStats")
|
var rcStatsKey = []byte("_requestCostStats")
|
||||||
|
|
||||||
func newCostStats(db ethdb.Database) *requestCostStats {
|
func newCostStats(db database.Database) *requestCostStats {
|
||||||
stats := make(map[uint64]*linReg)
|
stats := make(map[uint64]*linReg)
|
||||||
for _, code := range reqList {
|
for _, code := range reqList {
|
||||||
stats[code] = &linReg{cnt: 100}
|
stats[code] = &linReg{cnt: 100}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
"github.com/ethereum/go-ethereum/common/mclock"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"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/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"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 light server nodes. It received discovered nodes, stores statistics about
|
||||||
// known nodes and takes care of always having enough good quality servers connected.
|
// known nodes and takes care of always having enough good quality servers connected.
|
||||||
type serverPool struct {
|
type serverPool struct {
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
dbKey []byte
|
dbKey []byte
|
||||||
server *p2p.Server
|
server *p2p.Server
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
|
|
@ -141,7 +141,7 @@ type serverPool struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newServerPool creates a new serverPool instance
|
// 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{
|
pool := &serverPool{
|
||||||
db: db,
|
db: db,
|
||||||
quit: quit,
|
quit: quit,
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
package les
|
package les
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"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
|
// newFullPeerPair creates node with full sync mode
|
||||||
func newFullPeerPair(t *testing.T, index int, numberOfblocks int, chainGen func(int, *core.BlockGen)) pairPeer {
|
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)
|
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()
|
peers := newPeerSet()
|
||||||
dist := newRequestDistributor(peers, make(chan struct{}))
|
dist := newRequestDistributor(peers, make(chan struct{}))
|
||||||
rm := newRetrieveManager(peers, dist, nil)
|
rm := newRetrieveManager(peers, dist, nil)
|
||||||
ldb := ethdb.NewMemDatabase()
|
ldb := rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm)
|
odr := NewLesOdr(ldb, light.DefaultClientIndexerConfig, rm)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -49,7 +49,7 @@ var (
|
||||||
type LightChain struct {
|
type LightChain struct {
|
||||||
hc *core.HeaderChain
|
hc *core.HeaderChain
|
||||||
indexerConfig *IndexerConfig
|
indexerConfig *IndexerConfig
|
||||||
chainDb ethdb.Database
|
chainDb database.Database
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
odr OdrBackend
|
odr OdrBackend
|
||||||
chainFeed event.Feed
|
chainFeed event.Feed
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
|
// 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) {
|
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)})
|
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
|
// 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
|
// chain. Depending on the full flag, if creates either a full block chain or a
|
||||||
// header only chain.
|
// header only chain.
|
||||||
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
func newCanonical(n int) (database.Database, *LightChain, error) {
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
gspec := core.Genesis{Config: params.TestChainConfig}
|
gspec := core.Genesis{Config: params.TestChainConfig}
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker())
|
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.
|
// newTestLightChain creates a LightChain that doesn't validate anything.
|
||||||
func newTestLightChain() *LightChain {
|
func newTestLightChain() *LightChain {
|
||||||
db := ethdb.NewMemDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
gspec := &core.Genesis{
|
gspec := &core.Genesis{
|
||||||
Difficulty: big.NewInt(1),
|
Difficulty: big.NewInt(1),
|
||||||
Config: params.TestChainConfig,
|
Config: params.TestChainConfig,
|
||||||
|
|
@ -265,11 +265,11 @@ func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.
|
||||||
|
|
||||||
type dummyOdr struct {
|
type dummyOdr struct {
|
||||||
OdrBackend
|
OdrBackend
|
||||||
db ethdb.Database
|
db database.Database
|
||||||
indexerConfig *IndexerConfig
|
indexerConfig *IndexerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (odr *dummyOdr) Database() ethdb.Database {
|
func (odr *dummyOdr) Database() database.Database {
|
||||||
return odr.db
|
return odr.db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/database"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"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
|
// 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()
|
db.lock.RLock()
|
||||||
defer db.lock.RUnlock()
|
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
|
type NodeList []rlp.RawValue
|
||||||
|
|
||||||
// Store writes the contents of the list to the given database
|
// 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 {
|
for _, node := range n {
|
||||||
db.Put(crypto.Keccak256(node), node)
|
db.Put(crypto.Keccak256(node), node)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
light/odr.go
18
light/odr.go
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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
|
// 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
|
// OdrBackend is an interface to a backend service that handles ODR retrievals type
|
||||||
type OdrBackend interface {
|
type OdrBackend interface {
|
||||||
Database() ethdb.Database
|
Database() database.Database
|
||||||
ChtIndexer() *core.ChainIndexer
|
ChtIndexer() *core.ChainIndexer
|
||||||
BloomTrieIndexer() *core.ChainIndexer
|
BloomTrieIndexer() *core.ChainIndexer
|
||||||
BloomIndexer() *core.ChainIndexer
|
BloomIndexer() *core.ChainIndexer
|
||||||
|
|
@ -49,7 +49,7 @@ type OdrBackend interface {
|
||||||
|
|
||||||
// OdrRequest is an interface for retrieval requests
|
// OdrRequest is an interface for retrieval requests
|
||||||
type OdrRequest interface {
|
type OdrRequest interface {
|
||||||
StoreResult(db ethdb.Database)
|
StoreResult(db database.Database)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrieID identifies a state or account storage trie
|
// TrieID identifies a state or account storage trie
|
||||||
|
|
@ -91,7 +91,7 @@ type TrieRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// 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)
|
req.Proof.Store(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ type CodeRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// 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)
|
db.Put(req.Hash[:], req.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +117,7 @@ type BlockRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// 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)
|
rawdb.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ type ReceiptsRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// 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)
|
rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -146,7 +146,7 @@ type ChtRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// 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()
|
hash, num := req.Header.Hash(), req.Header.Number.Uint64()
|
||||||
|
|
||||||
rawdb.WriteHeader(db, req.Header)
|
rawdb.WriteHeader(db, req.Header)
|
||||||
|
|
@ -167,7 +167,7 @@ type BloomRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// 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 {
|
for i, sectionIdx := range req.SectionIndexList {
|
||||||
sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1)
|
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
|
// 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
Loading…
Reference in a new issue