Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
b5b83db450
2 değiştirilmiş dosya ile 34 ekleme ve 30 silme
  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 {