Browse Source

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 năm trước cách đây
mục cha
commit
b5b83db450
2 tập tin đã thay đổi với 34 bổ sung30 xóa
  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 {