aboutsummaryrefslogtreecommitdiffstats
path: root/chain/chain_manager.go
diff options
context:
space:
mode:
Diffstat (limited to 'chain/chain_manager.go')
-rw-r--r--chain/chain_manager.go106
1 files changed, 101 insertions, 5 deletions
diff --git a/chain/chain_manager.go b/chain/chain_manager.go
index 8ee7a85cc..df390a4c0 100644
--- a/chain/chain_manager.go
+++ b/chain/chain_manager.go
@@ -2,11 +2,13 @@ package chain
import (
"bytes"
+ "container/list"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/state"
)
var chainlogger = logger.NewLogger("CHAIN")
@@ -22,6 +24,8 @@ type ChainManager struct {
CurrentBlock *Block
LastBlockHash []byte
+
+ workingChain *BlockChain
}
func NewChainManager(ethereum EthManager) *ChainManager {
@@ -43,7 +47,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *Block {
hash := ZeroHash256
if bc.CurrentBlock != nil {
- root = bc.CurrentBlock.state.Trie.Root
+ root = bc.CurrentBlock.Root()
hash = bc.LastBlockHash
}
@@ -86,7 +90,7 @@ func (bc *ChainManager) Reset() {
bc.genesisBlock.state.Trie.Sync()
// Prepare the genesis block
- bc.Add(bc.genesisBlock)
+ bc.add(bc.genesisBlock)
bc.CurrentBlock = bc.genesisBlock
bc.SetTotalDifficulty(ethutil.Big("0"))
@@ -135,6 +139,7 @@ func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
for i := uint64(0); i < max; i++ {
+
chain = append(chain, block.Hash())
if block.Number.Cmp(ethutil.Big0) <= 0 {
@@ -191,9 +196,8 @@ func (bc *ChainManager) SetTotalDifficulty(td *big.Int) {
}
// Add a block to the chain and record addition information
-func (bc *ChainManager) Add(block *Block) {
+func (bc *ChainManager) add(block *Block) {
bc.writeBlockInfo(block)
- // Prepare the genesis block
bc.CurrentBlock = block
bc.LastBlockHash = block.Hash()
@@ -201,6 +205,8 @@ func (bc *ChainManager) Add(block *Block) {
encodedBlock := block.RlpEncode()
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
+
+ //chainlogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4])
}
func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) {
@@ -223,9 +229,18 @@ func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) {
return td, nil
}
-func (bc *ChainManager) GetBlock(hash []byte) *Block {
+func (self *ChainManager) GetBlock(hash []byte) *Block {
data, _ := ethutil.Config.Db.Get(hash)
if len(data) == 0 {
+ if self.workingChain != nil {
+ // Check the temp chain
+ for e := self.workingChain.Front(); e != nil; e = e.Next() {
+ if bytes.Compare(e.Value.(*link).block.Hash(), hash) == 0 {
+ return e.Value.(*link).block
+ }
+ }
+ }
+
return nil
}
@@ -287,3 +302,84 @@ func (bc *ChainManager) Stop() {
chainlogger.Infoln("Stopped")
}
}
+
+type link struct {
+ block *Block
+ messages state.Messages
+ td *big.Int
+}
+
+type BlockChain struct {
+ *list.List
+}
+
+func NewChain(blocks Blocks) *BlockChain {
+ chain := &BlockChain{list.New()}
+
+ for _, block := range blocks {
+ chain.PushBack(&link{block, nil, nil})
+ }
+
+ return chain
+}
+
+// This function assumes you've done your checking. No checking is done at this stage anymore
+func (self *ChainManager) InsertChain(chain *BlockChain) {
+ for e := chain.Front(); e != nil; e = e.Next() {
+ link := e.Value.(*link)
+
+ self.add(link.block)
+ self.SetTotalDifficulty(link.td)
+ self.Ethereum.EventMux().Post(NewBlockEvent{link.block})
+ self.Ethereum.EventMux().Post(link.messages)
+ }
+
+ b, e := chain.Front(), chain.Back()
+ if b != nil && e != nil {
+ front, back := b.Value.(*link).block, e.Value.(*link).block
+ chainlogger.Infof("Imported %d blocks. #%v (%x) / %#v (%x)", chain.Len(), front.Number, front.Hash()[0:4], back.Number, back.Hash()[0:4])
+ }
+}
+
+func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) {
+ self.workingChain = chain
+ defer func() { self.workingChain = nil }()
+
+ for e := chain.Front(); e != nil; e = e.Next() {
+ var (
+ l = e.Value.(*link)
+ block = l.block
+ parent = self.GetBlock(block.PrevHash)
+ )
+
+ //fmt.Println("parent", parent)
+ //fmt.Println("current", block)
+
+ if parent == nil {
+ err = fmt.Errorf("incoming chain broken on hash %x\n", block.PrevHash[0:4])
+ return
+ }
+
+ var messages state.Messages
+ td, messages, err = self.Ethereum.BlockManager().ProcessWithParent(block, parent)
+ if err != nil {
+ chainlogger.Infoln(err)
+ chainlogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4])
+ chainlogger.Debugln(block)
+
+ err = fmt.Errorf("incoming chain failed %v\n", err)
+ return
+ }
+ l.td = td
+ l.messages = messages
+ }
+
+ if td.Cmp(self.TD) <= 0 {
+ err = &TDError{td, self.TD}
+ return
+ }
+
+ self.workingChain = nil
+
+ return
+}