mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-08 22:14:29 +00:00
Merge pull request #841 from gzliudan/clean_db
all: clean up and properly abstract database accesses
This commit is contained in:
commit
4602e23933
11 changed files with 53 additions and 33 deletions
|
|
@ -195,6 +195,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
|
||||||
|
|
@ -322,11 +323,11 @@ func importPreimages(ctx *cli.Context) error {
|
||||||
stack, _ := makeFullNode(ctx)
|
stack, _ := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
diskdb := utils.MakeChainDatabase(ctx, stack, false)
|
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||||
defer diskdb.Close()
|
defer db.Close()
|
||||||
|
|
||||||
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("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))
|
||||||
|
|
@ -341,11 +342,11 @@ func exportPreimages(ctx *cli.Context) error {
|
||||||
stack, _ := makeFullNode(ctx)
|
stack, _ := makeFullNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
diskdb := utils.MakeChainDatabase(ctx, stack, true)
|
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||||
defer diskdb.Close()
|
defer db.Close()
|
||||||
|
|
||||||
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))
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,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.
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ func DeleteHeaderNumber(db ethdb.KeyValueWriter, hash common.Hash) {
|
||||||
// last block hash is only updated upon a full block import, the last header
|
// last block hash is only updated upon a full block import, the last header
|
||||||
// hash is updated already at header import, allowing head tracking for the
|
// hash is updated already at header import, allowing head tracking for the
|
||||||
// light synchronization mechanism.
|
// light synchronization mechanism.
|
||||||
func ReadHeadHeaderHash(db ethdb.Reader) common.Hash {
|
func ReadHeadHeaderHash(db ethdb.KeyValueReader) common.Hash {
|
||||||
data, _ := db.Get(headHeaderKey)
|
data, _ := db.Get(headHeaderKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
|
|
@ -331,10 +331,16 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding.
|
||||||
|
func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
|
data, _ := db.Get(headerTDKey(number, hash))
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
// ReadTd retrieves a block's total difficulty corresponding to the hash, nil if
|
// ReadTd retrieves a block's total difficulty corresponding to the hash, nil if
|
||||||
// none found.
|
// none found.
|
||||||
func ReadTd(db ethdb.Reader, hash common.Hash, number uint64) *big.Int {
|
func ReadTd(db ethdb.Reader, 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
|
||||||
}
|
}
|
||||||
|
|
@ -572,3 +578,12 @@ func DeleteBlock(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||||
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 ethdb.KeyValueWriter, hash common.Hash, number uint64) {
|
||||||
|
DeleteReceipts(db, hash, number)
|
||||||
|
deleteHeaderWithoutNumber(db, hash, number)
|
||||||
|
DeleteBody(db, hash, number)
|
||||||
|
DeleteTd(db, hash, number)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,13 @@ func NewMemoryDatabase() ethdb.Database {
|
||||||
return NewDatabase(memorydb.New())
|
return NewDatabase(memorydb.New())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) ethdb.Database {
|
||||||
|
return NewDatabase(memorydb.NewWithCap(size))
|
||||||
|
}
|
||||||
|
|
||||||
// NewLevelDBDatabase creates a persistent key-value database without a freezer
|
// NewLevelDBDatabase creates a persistent key-value database without a freezer
|
||||||
// moving immutable chain segments into cold storage.
|
// moving immutable chain segments into cold storage.
|
||||||
func NewLevelDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
func NewLevelDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,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()...)
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"testing/quick"
|
"testing/quick"
|
||||||
|
|
||||||
check "gopkg.in/check.v1"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
check "gopkg.in/check.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
|
|
@ -57,10 +57,9 @@ func TestUpdateLeaks(t *testing.T) {
|
||||||
// Ensure that no data was leaked into the database
|
// Ensure that no data was leaked into the database
|
||||||
it := db.NewIterator(nil, nil)
|
it := db.NewIterator(nil, nil)
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
key := it.Key()
|
t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value())
|
||||||
value := it.Value()
|
|
||||||
t.Errorf("State leaked into database: %x -> %x", key, 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,
|
||||||
|
|
@ -108,16 +107,16 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
key := it.Key()
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
it.Release()
|
||||||
|
|
||||||
it = transDb.NewIterator(nil, nil)
|
it = transDb.NewIterator(nil, nil)
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
key := it.Key()
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,9 @@ func New(ctx *node.ServiceContext, config *ethconfig.Config, XDCXServ *XDCx.XDCX
|
||||||
if !config.SyncMode.IsValid() {
|
if !config.SyncMode.IsValid() {
|
||||||
return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
|
return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
|
||||||
}
|
}
|
||||||
chainDb, err := CreateDB(ctx, config, "chaindata")
|
|
||||||
|
// Assemble the Ethereum object
|
||||||
|
chainDb, err := ctx.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -341,15 +343,6 @@ func makeExtraData(extra []byte) []byte {
|
||||||
return extra
|
return extra
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateDB creates the chain database.
|
|
||||||
func CreateDB(ctx *node.ServiceContext, config *ethconfig.Config, name string) (ethdb.Database, error) {
|
|
||||||
db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
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, config *ethash.Config, chainConfig *params.ChainConfig, db ethdb.Database) consensus.Engine {
|
func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chainConfig *params.ChainConfig, db ethdb.Database) consensus.Engine {
|
||||||
// If delegated-proof-of-stake is requested, set it up
|
// If delegated-proof-of-stake is requested, set it up
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ type LightEthereum struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx *node.ServiceContext, config *ethconfig.Config) (*LightEthereum, error) {
|
func New(ctx *node.ServiceContext, config *ethconfig.Config) (*LightEthereum, error) {
|
||||||
chainDb, err := eth.CreateDB(ctx, config, "lightchaindata")
|
chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ func (db *NodeSet) Store(target ethdb.KeyValueWriter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeList stores an ordered list of trie nodes. It implements ethdb.Putter.
|
// NodeList stores an ordered list of trie nodes. It implements ethdb.Writer.
|
||||||
type NodeList []rlp.RawValue
|
type NodeList []rlp.RawValue
|
||||||
|
|
||||||
func (n NodeList) Delete(key []byte) error {
|
func (n NodeList) Delete(key []byte) error {
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,11 @@ type ServiceContext struct {
|
||||||
// OpenDatabase opens an existing database with the given name (or creates one
|
// OpenDatabase opens an existing database with the given name (or creates one
|
||||||
// if no previous can be found) from within the node's data directory. If the
|
// if no previous can be found) from within the node's data directory. If the
|
||||||
// node is an ephemeral one, a memory database is returned.
|
// node is an ephemeral one, a memory database is returned.
|
||||||
func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, readonly bool) (ethdb.Database, error) {
|
func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||||
if ctx.config.DataDir == "" {
|
if ctx.config.DataDir == "" {
|
||||||
return rawdb.NewMemoryDatabase(), nil
|
return rawdb.NewMemoryDatabase(), nil
|
||||||
}
|
}
|
||||||
db, err := rawdb.NewLevelDBDatabase(ctx.config.resolvePath(name), cache, handles, "", readonly)
|
db, err := rawdb.NewLevelDBDatabase(ctx.config.resolvePath(name), cache, handles, namespace, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func TestContextDatabases(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Request the opening/creation of a database and ensure it persists to disk
|
// Request the opening/creation of a database and ensure it persists to disk
|
||||||
ctx := &ServiceContext{config: &Config{Name: "unit-test", DataDir: dir}}
|
ctx := &ServiceContext{config: &Config{Name: "unit-test", DataDir: dir}}
|
||||||
db, err := ctx.OpenDatabase("persistent", 0, 0, false)
|
db, err := ctx.OpenDatabase("persistent", 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to open persistent database: %v", err)
|
t.Fatalf("failed to open persistent database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +46,7 @@ func TestContextDatabases(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Request th opening/creation of an ephemeral database and ensure it's not persisted
|
// Request th opening/creation of an ephemeral database and ensure it's not persisted
|
||||||
ctx = &ServiceContext{config: &Config{DataDir: ""}}
|
ctx = &ServiceContext{config: &Config{DataDir: ""}}
|
||||||
db, err = ctx.OpenDatabase("ephemeral", 0, 0, false)
|
db, err = ctx.OpenDatabase("ephemeral", 0, 0, "", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to open ephemeral database: %v", err)
|
t.Fatalf("failed to open ephemeral database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue