From 04a09b7e2d09d61a7bedd5eeeeabb57e1be99d83 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Apr 2015 17:13:51 +0200 Subject: [PATCH 1/9] core: set min gas price at startup --- core/chain_manager.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index fb2af0280..d9ab04a02 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -92,15 +92,14 @@ 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), - currentGasLimit: new(big.Int), + blockDb: blockDb, + stateDb: stateDb, + genesisBlock: GenesisBlock(stateDb), + eventMux: mux, + quit: make(chan struct{}), + cache: NewBlockCache(blockCacheLimit), } - bc.setLastBlock() + bc.setLastState() // 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 { @@ -145,7 +144,7 @@ func (bc *ChainManager) SetHead(head *types.Block) { bc.transState = statedb.Copy() bc.setTotalDifficulty(head.Td) bc.insert(head) - bc.setLastBlock() + bc.setLastState() } func (self *ChainManager) Td() *big.Int { @@ -212,7 +211,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) { self.transState = statedb } -func (bc *ChainManager) setLastBlock() { +func (bc *ChainManager) setLastState() { data, _ := bc.blockDb.Get([]byte("LastBlock")) if len(data) != 0 { block := bc.GetBlock(common.BytesToHash(data)) @@ -224,6 +223,7 @@ func (bc *ChainManager) setLastBlock() { } else { bc.Reset() } + bc.currentGasLimit = CalcGasLimit(bc.currentBlock) if glog.V(logger.Info) { glog.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td) From a4b79f1dac2143b5fb9eb5745077ea245050a7ed Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Apr 2015 17:26:29 +0200 Subject: [PATCH 2/9] core: moved mutex locks in insert blocks to start of function Insert blocks will no longer allow processing of multiple chains at the same time. The block lock has been moved to start of the function. --- core/chain_manager.go | 81 +++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index d9ab04a02..9bb14b0cd 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -496,6 +496,9 @@ func (self *ChainManager) procFutureBlocks() { } func (self *ChainManager) InsertChain(chain types.Blocks) error { + self.mu.Lock() + defer self.mu.Unlock() + // A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring. var ( queue = make([]interface{}, len(chain)) @@ -543,55 +546,51 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { block.Td = new(big.Int).Set(CalculateTD(block, self.GetBlock(block.ParentHash()))) - self.mu.Lock() - { - cblock := self.currentBlock - // Write block to database. Eventually we'll have to improve on this and throw away blocks that are - // not in the canonical chain. - 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 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], 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) - - queue[i] = ChainSplitEvent{block, logs} - queueEvent.splitCount++ + cblock := self.currentBlock + // Write block to database. Eventually we'll have to improve on this and throw away blocks that are + // not in the canonical chain. + 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 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], 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) - self.setTotalDifficulty(block.Td) - self.insert(block) + queue[i] = ChainSplitEvent{block, logs} + queueEvent.splitCount++ + } - jsonlogger.LogJson(&logger.EthChainNewHead{ - BlockHash: block.Hash().Hex(), - BlockNumber: block.Number(), - ChainHeadHash: cblock.Hash().Hex(), - BlockPrevHash: block.ParentHash().Hex(), - }) + self.setTotalDifficulty(block.Td) + self.insert(block) - self.setTransState(state.New(block.Root(), self.stateDb)) - self.txState.SetState(state.New(block.Root(), self.stateDb)) + jsonlogger.LogJson(&logger.EthChainNewHead{ + BlockHash: block.Hash().Hex(), + BlockNumber: block.Number(), + ChainHeadHash: cblock.Hash().Hex(), + BlockPrevHash: block.ParentHash().Hex(), + }) - queue[i] = ChainEvent{block, logs} - queueEvent.canonicalCount++ + self.setTransState(state.New(block.Root(), self.stateDb)) + self.txState.SetState(state.New(block.Root(), self.stateDb)) - if glog.V(logger.Debug) { - glog.Infof("inserted block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4]) - } - } else { - queue[i] = ChainSideEvent{block, logs} - queueEvent.sideCount++ + queue[i] = ChainEvent{block, logs} + queueEvent.canonicalCount++ + + if glog.V(logger.Debug) { + glog.Infof("inserted block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4]) } + } else { + queue[i] = ChainSideEvent{block, logs} + queueEvent.sideCount++ } - self.mu.Unlock() stats.processed++ From 9f32117457505f49001c324658f00833ab724667 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Apr 2015 17:32:51 +0200 Subject: [PATCH 3/9] core: bump database version --- core/block_processor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/block_processor.go b/core/block_processor.go index af47069ad..9f26ab8b5 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -21,7 +21,7 @@ import ( const ( // must be bumped when consensus algorithm is changed, this forces the upgradedb // command to be run (forces the blocks to be imported again using the new algorithm) - BlockChainVersion = 2 + BlockChainVersion = 3 ) var statelogger = logger.NewLogger("BLOCK") From 7ac24d551bf41bca4deec9f47239c4c0d052e721 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Apr 2015 17:48:46 +0200 Subject: [PATCH 4/9] core: seperated proccing mutex and getting mutex --- core/block_processor.go | 2 +- core/chain_manager.go | 88 ++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/core/block_processor.go b/core/block_processor.go index 9f26ab8b5..af47069ad 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -21,7 +21,7 @@ import ( const ( // must be bumped when consensus algorithm is changed, this forces the upgradedb // command to be run (forces the blocks to be imported again using the new algorithm) - BlockChainVersion = 3 + BlockChainVersion = 2 ) var statelogger = logger.NewLogger("BLOCK") diff --git a/core/chain_manager.go b/core/chain_manager.go index 9bb14b0cd..56895b73e 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -74,8 +74,10 @@ type ChainManager struct { eventMux *event.TypeMux genesisBlock *types.Block // Last known total difficulty - mu sync.RWMutex - tsmu sync.RWMutex + mu sync.RWMutex + tsmu sync.RWMutex + insertMu sync.Mutex + td *big.Int currentBlock *types.Block lastBlockHash common.Hash @@ -496,8 +498,8 @@ func (self *ChainManager) procFutureBlocks() { } func (self *ChainManager) InsertChain(chain types.Blocks) error { - self.mu.Lock() - defer self.mu.Unlock() + self.insertMu.Lock() + defer self.insertMu.Unlock() // A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring. var ( @@ -546,51 +548,55 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { block.Td = new(big.Int).Set(CalculateTD(block, self.GetBlock(block.ParentHash()))) - cblock := self.currentBlock - // Write block to database. Eventually we'll have to improve on this and throw away blocks that are - // not in the canonical chain. - 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 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], 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) + self.mu.Lock() + { + cblock := self.currentBlock + // Write block to database. Eventually we'll have to improve on this and throw away blocks that are + // not in the canonical chain. + 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 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], 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) - queue[i] = ChainSplitEvent{block, logs} - queueEvent.splitCount++ - } + queue[i] = ChainSplitEvent{block, logs} + queueEvent.splitCount++ + } - self.setTotalDifficulty(block.Td) - self.insert(block) + self.setTotalDifficulty(block.Td) + self.insert(block) - jsonlogger.LogJson(&logger.EthChainNewHead{ - BlockHash: block.Hash().Hex(), - BlockNumber: block.Number(), - ChainHeadHash: cblock.Hash().Hex(), - BlockPrevHash: block.ParentHash().Hex(), - }) + jsonlogger.LogJson(&logger.EthChainNewHead{ + BlockHash: block.Hash().Hex(), + BlockNumber: block.Number(), + ChainHeadHash: cblock.Hash().Hex(), + BlockPrevHash: block.ParentHash().Hex(), + }) - self.setTransState(state.New(block.Root(), self.stateDb)) - self.txState.SetState(state.New(block.Root(), self.stateDb)) + self.setTransState(state.New(block.Root(), self.stateDb)) + self.txState.SetState(state.New(block.Root(), self.stateDb)) - queue[i] = ChainEvent{block, logs} - queueEvent.canonicalCount++ + queue[i] = ChainEvent{block, logs} + queueEvent.canonicalCount++ - if glog.V(logger.Debug) { - glog.Infof("inserted block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4]) + if glog.V(logger.Debug) { + glog.Infof("inserted block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4]) + } + } else { + queue[i] = ChainSideEvent{block, logs} + queueEvent.sideCount++ } - } else { - queue[i] = ChainSideEvent{block, logs} - queueEvent.sideCount++ } + self.mu.Unlock() stats.processed++ From 4b7bdc3766e1e06ebd6f865f0fdda26f9b331932 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 28 Apr 2015 21:18:08 +0200 Subject: [PATCH 5/9] eth: check if downloader is busy before showing log message --- eth/downloader/downloader.go | 4 ++++ eth/handler.go | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 60d908758..63d202a7f 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -472,3 +472,7 @@ func (d *Downloader) isProcessing() bool { func (d *Downloader) isBusy() bool { return d.isFetchingHashes() || d.isDownloadingBlocks() || d.isProcessing() } + +func (d *Downloader) IsBusy() bool { + return d.isBusy() +} diff --git a/eth/handler.go b/eth/handler.go index d00d00f23..61149049e 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -163,6 +163,11 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if peer.td.Cmp(pm.chainman.Td()) <= 0 { return } + // Check downloader if it's busy so it doesn't show the sync message + // for every attempty + if pm.downloader.IsBusy() { + return + } glog.V(logger.Info).Infof("Synchronisation attempt using %s TD=%v\n", peer.id, peer.td) // Get the hashes from the peer (synchronously) From af73d1d6823565c5bf8cc02d6f110bcc1edb2d99 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 29 Apr 2015 12:40:05 +0200 Subject: [PATCH 6/9] core/types: added fake parent hash / hash to String() output --- core/types/block.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/types/block.go b/core/types/block.go index fa83fc8e8..19cf49c12 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -351,7 +351,7 @@ func (self *Block) Copy() *Block { } func (self *Block) String() string { - return fmt.Sprintf(`Block(#%v): Size: %v TD: %v { + str := fmt.Sprintf(`Block(#%v): Size: %v TD: %v { MinerHash: %x %v Transactions: @@ -360,6 +360,16 @@ Uncles: %v } `, self.Number(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles) + + if (self.HeaderHash != common.Hash{}) { + str += fmt.Sprintf("\nFake hash = %x", self.HeaderHash) + } + + if (self.ParentHeaderHash != common.Hash{}) { + str += fmt.Sprintf("\nFake parent hash = %x", self.ParentHeaderHash) + } + + return str } func (self *Header) String() string { From 4e0796771190b6f8a976d931540d5f21789a882f Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 29 Apr 2015 12:43:24 +0200 Subject: [PATCH 7/9] core: fixed chain reorg during splits Chain reorgs weren't properly handled when a chain was further ahead. Previously we'd end up with mixed chains in our canonical numbering sequence. Added test for this type of forking. ``` /-o-o-o A o-C-+ \-o-o-o-o B ``` Ends up with with C A1, A2, A3, B4 --- core/chain_manager.go | 58 +++++++++++++++++++++----------------- core/chain_manager_test.go | 52 +++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 27 deletions(-) diff --git a/core/chain_manager.go b/core/chain_manager.go index 56895b73e..32ad4a2ba 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -74,9 +74,8 @@ type ChainManager struct { eventMux *event.TypeMux genesisBlock *types.Block // Last known total difficulty - mu sync.RWMutex - tsmu sync.RWMutex - insertMu sync.Mutex + mu sync.RWMutex + tsmu sync.RWMutex td *big.Int currentBlock *types.Block @@ -321,6 +320,7 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { bc.insert(bc.genesisBlock) bc.currentBlock = bc.genesisBlock bc.makeCache() + bc.td = gb.Difficulty() } // Export writes the active chain to the given writer. @@ -348,8 +348,6 @@ func (self *ChainManager) Export(w io.Writer) error { func (bc *ChainManager) insert(block *types.Block) { key := append(blockNumPre, block.Number().Bytes()...) bc.blockDb.Put(key, block.Hash().Bytes()) - // Push block to cache - bc.cache.Push(block) bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes()) bc.currentBlock = block @@ -360,6 +358,8 @@ func (bc *ChainManager) write(block *types.Block) { enc, _ := rlp.EncodeToBytes((*types.StorageBlock)(block)) key := append(blockHashPre, block.Hash().Bytes()...) bc.blockDb.Put(key, enc) + // Push block to cache + bc.cache.Push(block) } // Accessors @@ -498,9 +498,6 @@ func (self *ChainManager) procFutureBlocks() { } func (self *ChainManager) InsertChain(chain types.Blocks) error { - self.insertMu.Lock() - defer self.insertMu.Unlock() - // A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring. var ( queue = make([]interface{}, len(chain)) @@ -557,16 +554,17 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { // 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 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 { + // Check for chain forks. If H(block.num - 1) != block.parent, we're on a fork and need to do some merging + if previous := self.getBlockByNumber(block.NumberU64() - 1); previous.Hash() != block.ParentHash() { 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], 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) + self.merge(previous, block) queue[i] = ChainSplitEvent{block, logs} queueEvent.splitCount++ @@ -592,16 +590,19 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { glog.Infof("inserted block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4]) } } else { + if glog.V(logger.Detail) { + glog.Infof("inserted forked block #%d (%d TXs %d UNCs) (%x...)\n", block.Number(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4]) + } + queue[i] = ChainSideEvent{block, logs} queueEvent.sideCount++ } + self.futureBlocks.Delete(block.Hash()) } self.mu.Unlock() stats.processed++ - self.futureBlocks.Delete(block.Hash()) - } if (stats.queued > 0 || stats.processed > 0) && bool(glog.V(logger.Info)) { @@ -615,33 +616,38 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { return nil } -// merge takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them +// diff takes two blocks, an old chain and a new chain and will reconstruct the blocks and inserts them // to be part of the new canonical chain. -func (self *ChainManager) merge(oldBlock, newBlock *types.Block) { +func (self *ChainManager) diff(oldBlock, newBlock *types.Block) types.Blocks { glog.V(logger.Debug).Infof("Applying diff to %x & %x\n", oldBlock.Hash().Bytes()[:4], newBlock.Hash().Bytes()[:4]) - var oldChain, newChain types.Blocks - // First find the split (common ancestor) so we can perform an adequate merge + var newChain types.Blocks + // first find common number + for newBlock = newBlock; newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = self.GetBlock(newBlock.ParentHash()) { + newChain = append(newChain, newBlock) + } + + glog.V(logger.Debug).Infoln("Found common number", newBlock.Number()) for { - oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) if oldBlock.Hash() == newBlock.Hash() { break } - oldChain = append(oldChain, oldBlock) newChain = append(newChain, newBlock) + + oldBlock, newBlock = self.GetBlock(oldBlock.ParentHash()), self.GetBlock(newBlock.ParentHash()) } + return newChain +} + +// merge merges two different chain to the new canonical chain +func (self *ChainManager) merge(oldBlock, newBlock *types.Block) { + newChain := self.diff(oldBlock, newBlock) + // insert blocks for _, block := range newChain { self.insert(block) } - - if glog.V(logger.Detail) { - for i, oldBlock := range oldChain { - glog.Infof("- %.10v = %x\n", oldBlock.Number(), oldBlock.Hash()) - glog.Infof("+ %.10v = %x\n", newChain[i].Number(), newChain[i].Hash()) - } - } } func (self *ChainManager) update() { diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index c2911150a..a88afd7c8 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -9,6 +9,7 @@ import ( "strconv" "testing" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -56,12 +57,14 @@ func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big } // Compare difficulties f(tdpre, td) + + // Loop over parents making sure reconstruction is done properly } func printChain(bc *ChainManager) { for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- { b := bc.GetBlockByNumber(uint64(i)) - fmt.Printf("\t%x\n", b.Hash()) + fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty()) } } @@ -344,3 +347,50 @@ func TestGetAncestors(t *testing.T) { ancestors := chainMan.GetAncestors(chain[len(chain)-1], 4) fmt.Println(ancestors) } + +type bproc struct{} + +func (bproc) Process(*types.Block) (state.Logs, error) { return nil, nil } + +func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { + var chain []*types.Block + for i, difficulty := range d { + header := &types.Header{Number: big.NewInt(int64(i + 1)), Difficulty: big.NewInt(int64(difficulty))} + block := types.NewBlockWithHeader(header) + copy(block.HeaderHash[:2], []byte{byte(i + 1), seed}) + if i == 0 { + block.ParentHeaderHash = genesis.Hash() + } else { + copy(block.ParentHeaderHash[:2], []byte{byte(i), seed}) + } + + chain = append(chain, block) + } + return chain +} + +func TestReorg(t *testing.T) { + db, _ := ethdb.NewMemDatabase() + var eventMux event.TypeMux + + genesis := GenesisBlock(db) + bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: &eventMux} + bc.cache = NewBlockCache(100) + bc.futureBlocks = NewBlockCache(100) + bc.processor = bproc{} + bc.ResetWithGenesisBlock(genesis) + bc.txState = state.ManageState(bc.State()) + + chain1 := makeChainWithDiff(genesis, []int{1, 2, 4}, 10) + chain2 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 11) + + bc.InsertChain(chain1) + bc.InsertChain(chain2) + + prev := bc.CurrentBlock() + for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) { + if prev.ParentHash() != block.Hash() { + t.Errorf("parent hash mismatch %x - %x", prev.ParentHash(), block.Hash()) + } + } +} From 745c368987a08d1b8ae669f38ce04de443ff6064 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 29 Apr 2015 12:54:41 +0200 Subject: [PATCH 8/9] cmd/geth: bump version number --- cmd/geth/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 6ffc3c4a0..4e5f4c93c 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -47,7 +47,7 @@ import _ "net/http/pprof" const ( ClientIdentifier = "Geth" - Version = "0.9.12" + Version = "0.9.13" ) var app = utils.NewApp(Version, "the go-ethereum command line interface") From 13364a2dcf08924605408ae0e9233ea8e51d37fb Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 29 Apr 2015 13:40:39 +0200 Subject: [PATCH 9/9] eth/downloader: reset the chain when parent is missing during processing --- eth/downloader/downloader.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 63d202a7f..a3917854f 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -436,6 +436,8 @@ func (d *Downloader) process(peer *peer) error { if err != nil && core.IsParentErr(err) { glog.V(logger.Debug).Infoln("Aborting process due to missing parent.") + // XXX this needs a lot of attention + blocks = nil break } else if err != nil { // immediatly unregister the false peer but do not disconnect