diff options
Diffstat (limited to 'chain/chain_manager.go')
-rw-r--r-- | chain/chain_manager.go | 106 |
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 +} |