diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/block_processor.go | 28 | ||||
-rw-r--r-- | core/blocks.go | 7 | ||||
-rw-r--r-- | core/chain_makers.go | 4 | ||||
-rw-r--r-- | core/chain_manager.go | 55 | ||||
-rw-r--r-- | core/chain_manager_test.go | 7 | ||||
-rw-r--r-- | core/genesis.go | 1 | ||||
-rw-r--r-- | core/types/block.go | 16 | ||||
-rw-r--r-- | core/types/common.go | 2 |
8 files changed, 91 insertions, 29 deletions
diff --git a/core/block_processor.go b/core/block_processor.go index e3c284979..3030af27d 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -149,28 +149,42 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state return receipts, err } +func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs state.Logs, err error) { + // Processing a blocks may never happen simultaneously + sm.mutex.Lock() + defer sm.mutex.Unlock() + + header := block.Header() + if !sm.bc.HasBlock(header.ParentHash) { + return nil, ParentError(header.ParentHash) + } + parent := sm.bc.GetBlock(header.ParentHash) + + return sm.processWithParent(block, parent) +} + // Process block will attempt to process the given block's transactions and applies them // on top of the block's parent state (given it exists) and will return wether it was // successful or not. -func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, logs state.Logs, err error) { +func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() header := block.Header() if sm.bc.HasBlock(header.Hash()) { - return nil, nil, &KnownBlockError{header.Number, header.Hash()} + return nil, &KnownBlockError{header.Number, header.Hash()} } if !sm.bc.HasBlock(header.ParentHash) { - return nil, nil, ParentError(header.ParentHash) + return nil, ParentError(header.ParentHash) } parent := sm.bc.GetBlock(header.ParentHash) return sm.processWithParent(block, parent) } -func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big.Int, logs state.Logs, err error) { +func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, err error) { sm.lastAttemptedBlock = block // Create a new state based on the parent's root (e.g., create copy) @@ -183,7 +197,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big // There can be at most two uncles if len(block.Uncles()) > 2 { - return nil, nil, ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles())) + return nil, ValidationError("Block can only contain one uncle (contained %v)", len(block.Uncles())) } receipts, err := sm.TransitionState(state, parent, block, false) @@ -232,7 +246,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big } // Calculate the td for this block - td = CalculateTD(block, parent) + //td = CalculateTD(block, parent) // Sync the current block's state to the database state.Sync() @@ -244,7 +258,7 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big putTx(sm.extraDb, tx, block, uint64(i)) } - return td, state.Logs(), nil + return state.Logs(), nil } // Validates the current block. Returns an error if the block was invalid, diff --git a/core/blocks.go b/core/blocks.go new file mode 100644 index 000000000..b26e8f6ee --- /dev/null +++ b/core/blocks.go @@ -0,0 +1,7 @@ +package core + +import "github.com/ethereum/go-ethereum/common" + +var badHashes = []common.Hash{ + common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"), +} diff --git a/core/chain_makers.go b/core/chain_makers.go index 810741820..250671ef8 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -93,12 +93,12 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db common.Dat blocks := make(types.Blocks, max) for i := 0; i < max; i++ { block := makeBlock(bman, parent, i, db, seed) - td, _, err := bman.processWithParent(block, parent) + _, err := bman.processWithParent(block, parent) if err != nil { fmt.Println("process with parent failed", err) panic(err) } - block.Td = td + block.Td = CalculateTD(block, parent) blocks[i] = block parent = block } diff --git a/core/chain_manager.go b/core/chain_manager.go index 4f1e1e68a..3f2b3a26a 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -97,6 +97,21 @@ type ChainManager struct { func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *ChainManager { bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{}), cache: NewBlockCache(blockCacheLimit)} bc.setLastBlock() + + // Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain + for _, hash := range badHashes { + if block := bc.GetBlock(hash); block != nil { + glog.V(logger.Error).Infof("Found bad hash. Reorganising chain to state %x\n", block.ParentHash().Bytes()[:4]) + block = bc.GetBlock(block.ParentHash()) + if block == nil { + glog.Fatal("Unable to complete. Parent block not found. Corrupted DB?") + } + bc.SetHead(block) + + glog.V(logger.Error).Infoln("Chain reorg was successfull. Resuming normal operation") + } + } + bc.transState = bc.State().Copy() // Take ownership of this particular state bc.txState = state.ManageState(bc.State().Copy()) @@ -109,6 +124,26 @@ func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *Chai return bc } +func (bc *ChainManager) SetHead(head *types.Block) { + bc.mu.Lock() + defer bc.mu.Unlock() + + for block := bc.currentBlock; block != nil && block.Hash() != head.Hash(); block = bc.GetBlock(block.Header().ParentHash) { + bc.removeBlock(block) + } + + bc.cache = NewBlockCache(blockCacheLimit) + bc.currentBlock = head + bc.makeCache() + + statedb := state.New(head.Root(), bc.stateDb) + bc.txState = state.ManageState(statedb) + bc.transState = statedb.Copy() + bc.setTotalDifficulty(head.Td) + bc.insert(head) + bc.setLastBlock() +} + func (self *ChainManager) Td() *big.Int { self.mu.RLock() defer self.mu.RUnlock() @@ -287,7 +322,12 @@ func (self *ChainManager) Export(w io.Writer) error { last := self.currentBlock.NumberU64() for nr := uint64(0); nr <= last; nr++ { - if err := self.GetBlockByNumber(nr).EncodeRLP(w); err != nil { + block := self.GetBlockByNumber(nr) + if block == nil { + return fmt.Errorf("export failed on #%d: not found", nr) + } + + if err := block.EncodeRLP(w); err != nil { return err } } @@ -461,7 +501,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { } // Call in to the block processor and check for errors. It's likely that if one block fails // all others will fail too (unless a known block is returned). - td, logs, err := self.processor.Process(block) + logs, err := self.processor.Process(block) if err != nil { if IsKnownBlockErr(err) { continue @@ -486,13 +526,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { h := block.Header() - glog.V(logger.Error).Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()[:4]) + glog.V(logger.Error).Infof("INVALID block #%v (%x)\n", h.Number, h.Hash().Bytes()) glog.V(logger.Error).Infoln(err) glog.V(logger.Debug).Infoln(block) return err } - block.Td = td + + block.Td = new(big.Int).Set(CalculateTD(block, self.GetBlock(block.ParentHash()))) self.mu.Lock() { @@ -502,14 +543,14 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { self.write(block) // Compare the TD of the last known block in the canonical chain to make sure it's greater. // At this point it's possible that a different chain (fork) becomes the new canonical chain. - if td.Cmp(self.td) > 0 { + if block.Td.Cmp(self.td) > 0 { //if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, common.Big1)) < 0 { if block.Number().Cmp(cblock.Number()) <= 0 { chash := cblock.Hash() hash := block.Hash() if glog.V(logger.Info) { - glog.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], td, cblock.Header().Number, chash[:4], self.td) + glog.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, hash[:4], block.Td, cblock.Header().Number, chash[:4], self.td) } // during split we merge two different chains and create the new canonical chain self.merge(self.getBlockByNumber(block.NumberU64()), block) @@ -518,7 +559,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { queueEvent.splitCount++ } - self.setTotalDifficulty(td) + self.setTotalDifficulty(block.Td) self.insert(block) jsonlogger.LogJson(&logger.EthChainNewHead{ diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index 19afe0d5c..f16c0f0c3 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -69,15 +69,16 @@ func printChain(bc *ChainManager) { func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) { td := new(big.Int) for _, block := range chainB { - td2, _, err := bman.bc.processor.Process(block) + _, err := bman.bc.processor.Process(block) if err != nil { if IsKnownBlockErr(err) { continue } return nil, err } - block.Td = td2 - td = td2 + parent := bman.bc.GetBlock(block.ParentHash()) + block.Td = CalculateTD(block, parent) + td = block.Td bman.bc.mu.Lock() { diff --git a/core/genesis.go b/core/genesis.go index 0ce60054e..e72834822 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -52,6 +52,7 @@ func GenesisBlock(db common.Database) *types.Block { } statedb.Sync() genesis.Header().Root = statedb.Root() + genesis.Td = params.GenesisDifficulty return genesis } diff --git a/core/types/block.go b/core/types/block.go index c47b555ed..f9206ec76 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -347,22 +347,20 @@ func (self *Block) Copy() *Block { } func (self *Block) String() string { - return fmt.Sprintf(`BLOCK(%x): Size: %v TD: %v { -NoNonce: %x -Header: -[ + return fmt.Sprintf(`Block(#%v): Size: %v TD: %v { +MinerHash: %x %v -] Transactions: %v Uncles: %v } -`, self.header.Hash(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) +`, self.Number(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) } func (self *Header) String() string { - return fmt.Sprintf(` + return fmt.Sprintf(`Header(%x): +[ ParentHash: %x UncleHash: %x Coinbase: %x @@ -377,8 +375,8 @@ func (self *Header) String() string { Time: %v Extra: %s MixDigest: %x - Nonce: %x`, - self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce) + Nonce: %x +]`, self.Hash(), self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.MixDigest, self.Nonce) } type Blocks []*Block diff --git a/core/types/common.go b/core/types/common.go index 4397d4938..dbdaaba0c 100644 --- a/core/types/common.go +++ b/core/types/common.go @@ -10,7 +10,7 @@ import ( ) type BlockProcessor interface { - Process(*Block) (*big.Int, state.Logs, error) + Process(*Block) (state.Logs, error) } const bloomLength = 256 |