cmd: implement preimage dump and import cmds

This commit is contained in:
rjl493456442 2018-03-14 20:15:30 +08:00 committed by Péter Szilágyi
parent 933972d139
commit b6b6f52ec8
No known key found for this signature in database
GPG Key ID: E9AE538CEDF8293D
3 changed files with 121 additions and 0 deletions

@ -40,6 +40,11 @@ import (
"gopkg.in/urfave/cli.v1"
)
var (
// secureKeyPrefix is the database key prefix used to store trie node preimages.
secureKeyPrefix = []byte("secure-key-")
)
var (
initCommand = cli.Command{
Action: utils.MigrateFlags(initGenesis),
@ -141,6 +146,34 @@ Remove blockchain and state databases`,
The arguments are interpreted as block numbers or hashes.
Use "ethereum dump 0" to dump the genesis block.`,
}
preimageDumpCommand = cli.Command{
Action: utils.MigrateFlags(dumpPreimage),
Name: "preimagedump",
Usage: "Dump the preimage database in json format",
ArgsUsage: "<dumpfile>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
Dump the preimage database in json format`,
}
preimageImportCommand = cli.Command{
Action: utils.MigrateFlags(importPreimage),
Name: "preimageimport",
Usage: "Import the preimage data from the specified file",
ArgsUsage: "<datafile>",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.CacheFlag,
utils.LightModeFlag,
},
Category: "BLOCKCHAIN COMMANDS",
Description: `
Import the preimage data from the specified file`,
}
)
// initGenesis will initialise the given JSON format genesis file and writes it as
@ -406,6 +439,86 @@ func dump(ctx *cli.Context) error {
return nil
}
// PreimageEntry represents a map between preimage and hash.
type PreimageEntry struct {
Hash string `json:"hash"`
Preimage string `json:"preimage"`
}
// dumpPreimage dumps the preimage data to specified json file in streaming way.
func dumpPreimage(ctx *cli.Context) error {
// Make sure the export json file has been specified.
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
// Encode preimage data to json file in streaming way.
file, err := os.Create(ctx.Args().First())
if err != nil {
return err
}
encoder := json.NewEncoder(file)
stack := makeFullNode(ctx)
db := utils.MakeChainDatabase(ctx, stack)
// Dump all preimage entries.
it := db.(*ethdb.LDBDatabase).NewIteratorByPrefix(secureKeyPrefix)
for it.Next() {
hash := it.Key()[len(secureKeyPrefix):]
if err := encoder.Encode(PreimageEntry{common.Bytes2Hex(hash), common.Bytes2Hex(it.Value())}); err != nil {
return err
}
}
return nil
}
// importPreimages imports preimage data from the specified file.
func importPreimage(ctx *cli.Context) error {
// Make sure the export json file has been specified.
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
// Decode the preimage data in streaming way.
file, err := os.Open(ctx.Args().First())
if err != nil {
return err
}
decoder := json.NewDecoder(file)
stack := makeFullNode(ctx)
db := utils.MakeChainDatabase(ctx, stack)
var (
entry PreimageEntry
preimages = make(map[common.Hash][]byte)
)
for decoder.More() {
if err := decoder.Decode(&entry); err != nil {
return err
}
preimages[common.HexToHash(entry.Hash)] = common.Hex2Bytes(entry.Preimage)
// Flush to database in batch
if len(preimages) > 1024 {
err := core.WritePreimages(db, 0, preimages)
if err != nil {
return err
}
preimages = make(map[common.Hash][]byte)
}
}
// Flush the last batch preimage data
if len(preimages) > 0 {
err := core.WritePreimages(db, 0, preimages)
if err != nil {
return err
}
}
return nil
}
// hashish returns true for strings that look like hashes.
func hashish(x string) bool {
_, err := strconv.Atoi(x)

@ -158,6 +158,8 @@ func init() {
copydbCommand,
removedbCommand,
dumpCommand,
preimageDumpCommand,
preimageImportCommand,
// See monitorcmd.go:
monitorCommand,
// See accountcmd.go:

@ -29,6 +29,7 @@ import (
"github.com/syndtr/goleveldb/leveldb/filter"
"github.com/syndtr/goleveldb/leveldb/iterator"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/util"
)
var OpenFileLimit = 64
@ -121,6 +122,11 @@ func (db *LDBDatabase) NewIterator() iterator.Iterator {
return db.db.NewIterator(nil, nil)
}
// NewIteratorByPrefix returns a iterator to iterate over subset of database content with a particular prefix.
func (db *LDBDatabase) NewIteratorByPrefix(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()