aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/geth/chaincmd.go28
-rw-r--r--cmd/utils/cmd.go15
-rw-r--r--core/chain_manager.go17
3 files changed, 55 insertions, 5 deletions
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 947532f40..8586e3b81 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -26,6 +26,12 @@ var (
Action: exportChain,
Name: "export",
Usage: `export blockchain into file`,
+ Description: `
+Requires a first argument of the file to write to.
+Optional second and third arguments control the first and
+last block to write. In this mode, the file will be appended
+if already existing.
+ `,
}
upgradedbCommand = cli.Command{
Action: upgradeDB,
@@ -63,12 +69,30 @@ func importChain(ctx *cli.Context) {
}
func exportChain(ctx *cli.Context) {
- if len(ctx.Args()) != 1 {
+ if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
chain, _, _, _ := utils.MakeChain(ctx)
start := time.Now()
- if err := utils.ExportChain(chain, ctx.Args().First()); err != nil {
+
+ var err error
+ fp := ctx.Args().First()
+ if len(ctx.Args()) < 3 {
+ err = utils.ExportChain(chain, fp)
+ } else {
+ // This can be improved to allow for numbers larger than 9223372036854775807
+ first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64)
+ last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
+ if ferr != nil || lerr != nil {
+ utils.Fatalf("Export error in parsing parameters: block number not an integer\n")
+ }
+ if first < 0 || last < 0 {
+ utils.Fatalf("Export error: block number must be greater than 0\n")
+ }
+ err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
+ }
+
+ if err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v", time.Since(start))
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index e5413973d..f7520a8e4 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -268,3 +268,18 @@ func ExportChain(chainmgr *core.ChainManager, fn string) error {
glog.Infoln("Exported blockchain to", fn)
return nil
}
+
+func ExportAppendChain(chainmgr *core.ChainManager, fn string, first uint64, last uint64) error {
+ glog.Infoln("Exporting blockchain to", fn)
+ // TODO verify mode perms
+ fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ if err := chainmgr.ExportN(fh, first, last); err != nil {
+ return err
+ }
+ glog.Infoln("Exported blockchain to", fn)
+ return nil
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index edd1cc742..e87253304 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -347,13 +347,24 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
// Export writes the active chain to the given writer.
func (self *ChainManager) Export(w io.Writer) error {
+ if err := self.ExportN(w, uint64(0), self.currentBlock.NumberU64()); err != nil {
+ return err
+ }
+ return nil
+}
+
+// ExportN writes a subset of the active chain to the given writer.
+func (self *ChainManager) ExportN(w io.Writer, first uint64, last uint64) error {
self.mu.RLock()
defer self.mu.RUnlock()
- glog.V(logger.Info).Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
- last := self.currentBlock.NumberU64()
+ if first > last {
+ return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last)
+ }
+
+ glog.V(logger.Info).Infof("exporting %d blocks...\n", last-first+1)
- for nr := uint64(1); nr <= last; nr++ {
+ for nr := first; nr <= last; nr++ {
block := self.GetBlockByNumber(nr)
if block == nil {
return fmt.Errorf("export failed on #%d: not found", nr)