Bläddra i källkod

core: use package rlp to encode blocks

This also changes the chain export format so there is no
enclosing list around the blocks, which enables streaming export.
Felix Lange 10 år sedan
förälder
incheckning
b5b83db450
2 ändrade filer med 34 tillägg och 30 borttagningar
  1. 22 15
      cmd/utils/cmd.go
  2. 12 15
      core/chain_manager.go

+ 22 - 15
cmd/utils/cmd.go

@@ -23,14 +23,15 @@ package utils
 
 import (
 	"fmt"
+	"io"
 	"os"
 	"os/signal"
 	"regexp"
 
+	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/logger"
 	"github.com/ethereum/go-ethereum/rlp"
 )
@@ -152,29 +153,35 @@ func ImportChain(chainmgr *core.ChainManager, fn string) error {
 	}
 	defer fh.Close()
 
-	var blocks types.Blocks
-	if err := rlp.Decode(fh, &blocks); err != nil {
-		return err
-	}
-
 	chainmgr.Reset()
-	if err := chainmgr.InsertChain(blocks); err != nil {
-		return err
+	stream := rlp.NewStream(fh)
+	var i int
+	for ; ; i++ {
+		var b types.Block
+		err := stream.Decode(&b)
+		if err == io.EOF {
+			break
+		} else if err != nil {
+			return fmt.Errorf("at block %d: %v", i, err)
+		}
+		if err := chainmgr.InsertChain(types.Blocks{b}); err != nil {
+			return fmt.Errorf("invalid block %d: %v", i, err)
+		}
 	}
-	fmt.Printf("imported %d blocks\n", len(blocks))
-
+	fmt.Printf("imported %d blocks\n", i)
 	return nil
 }
 
 func ExportChain(chainmgr *core.ChainManager, fn string) error {
 	fmt.Printf("exporting blockchain '%s'\n", fn)
-
-	data := chainmgr.Export()
-
-	if err := common.WriteFile(fn, data); err != nil {
+	fh, err := os.OpenFile(fn, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
+	if err != nil {
+		return err
+	}
+	defer fh.Close()
+	if err := chainmgr.Export(fh); err != nil {
 		return err
 	}
 	fmt.Printf("exported blockchain\n")
-
 	return nil
 }

+ 12 - 15
core/chain_manager.go

@@ -3,6 +3,7 @@ package core
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"math/big"
 	"sync"
 
@@ -254,22 +255,20 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
 	bc.currentBlock = bc.genesisBlock
 }
 
-func (self *ChainManager) Export() []byte {
+// Export writes the active chain to the given writer.
+func (self *ChainManager) Export(w io.Writer) error {
 	self.mu.RLock()
 	defer self.mu.RUnlock()
-
 	chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
-
-	blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
 	for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
-		blocks[block.NumberU64()] = block
+		if err := block.EncodeRLP(w); err != nil {
+			return err
+		}
 	}
-
-	return common.Encode(blocks)
+	return nil
 }
 
 func (bc *ChainManager) insert(block *types.Block) {
-	//encodedBlock := common.Encode(block)
 	bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes())
 	bc.currentBlock = block
 	bc.lastBlockHash = block.Hash()
@@ -279,10 +278,9 @@ func (bc *ChainManager) insert(block *types.Block) {
 }
 
 func (bc *ChainManager) write(block *types.Block) {
-	encodedBlock := common.Encode(block.RlpDataForStorage())
-
+	enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block))
 	key := append(blockHashPre, block.Hash().Bytes()...)
-	bc.blockDb.Put(key, encodedBlock)
+	bc.blockDb.Put(key, enc)
 }
 
 // Accessors
@@ -324,13 +322,12 @@ func (self *ChainManager) GetBlock(hash common.Hash) *types.Block {
 	if len(data) == 0 {
 		return nil
 	}
-	var block types.Block
+	var block types.StorageBlock
 	if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
-		fmt.Println(err)
+		chainlogger.Errorf("invalid block RLP for hash %x: %v", hash, err)
 		return nil
 	}
-
-	return &block
+	return (*types.Block)(&block)
 }
 
 func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {