core: fix block canonical mark / content write race

This commit is contained in:
Péter Szilágyi 2015-09-29 14:24:28 +03:00
parent f186b39018
commit b99fe27f8b

View File

@ -601,7 +601,7 @@ func (self *BlockChain) writeHeader(header *types.Header) error {
} }
// InsertHeaderChain will attempt to insert the given header chain in to the // InsertHeaderChain will attempt to insert the given header chain in to the
// local chain, possibly creating a dork. If an error is returned, it will // local chain, possibly creating a fork. If an error is returned, it will
// return the index number of the failing header as well an error describing // return the index number of the failing header as well an error describing
// what went wrong. // what went wrong.
// //
@ -686,37 +686,31 @@ func (self *BlockChain) WriteBlock(block *types.Block) (status writeStatus, err
} }
td := new(big.Int).Add(block.Difficulty(), ptd) td := new(big.Int).Add(block.Difficulty(), ptd)
self.mu.RLock() // Make sure no inconsistent state is leaked during insertion
cblock := self.currentBlock self.mu.Lock()
self.mu.RUnlock() defer self.mu.Unlock()
// Compare the TD of the last known block in the canonical chain to make sure it's greater. // If the total difficulty is higher than our known, add it to the canonical chain
// At this point it's possible that a different chain (fork) becomes the new canonical chain.
if td.Cmp(self.GetTd(self.currentBlock.Hash())) > 0 { if td.Cmp(self.GetTd(self.currentBlock.Hash())) > 0 {
// chain fork // Reorganize the chain if the parent is not the head block
if block.ParentHash() != cblock.Hash() { if block.ParentHash() != self.currentBlock.Hash() {
// during split we merge two different chains and create the new canonical chain if err := self.reorg(self.currentBlock, block); err != nil {
err := self.reorg(cblock, block)
if err != nil {
return NonStatTy, err return NonStatTy, err
} }
} }
status = CanonStatTy // Insert the block as the new head of the chain
self.mu.Lock()
self.insert(block) self.insert(block)
self.mu.Unlock() status = CanonStatTy
} else { } else {
status = SideStatTy status = SideStatTy
} }
// Irrelevant of the canonical status, write the block itself to the database
if err := WriteTd(self.chainDb, block.Hash(), td); err != nil { if err := WriteTd(self.chainDb, block.Hash(), td); err != nil {
glog.Fatalf("failed to write block total difficulty: %v", err) glog.Fatalf("failed to write block total difficulty: %v", err)
} }
if err := WriteBlock(self.chainDb, block); err != nil { if err := WriteBlock(self.chainDb, block); err != nil {
glog.Fatalf("filed to write block contents: %v", err) glog.Fatalf("filed to write block contents: %v", err)
} }
// Delete from future blocks
self.futureBlocks.Remove(block.Hash()) self.futureBlocks.Remove(block.Hash())
return return
@ -860,9 +854,6 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// to be part of the new canonical chain and accumulates potential missing transactions and post an // to be part of the new canonical chain and accumulates potential missing transactions and post an
// event about them // event about them
func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error { func (self *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
self.mu.Lock()
defer self.mu.Unlock()
var ( var (
newChain types.Blocks newChain types.Blocks
commonBlock *types.Block commonBlock *types.Block