continue
}
- if err := bk.peers.BroadcastNewStatus(bk.chain.BestBlockHeader(), bk.chain.BestIrreversibleHeader()); err != nil {
+ if err := bk.peers.BroadcastNewStatus(bk.chain.BestBlockHeader(), bk.chain.LastIrreversibleHeader()); err != nil {
log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on syncWorker broadcast new status")
}
case <-bk.quit:
// Chain is the interface for Bytom core
type Chain interface {
BestBlockHeader() *types.BlockHeader
- BestIrreversibleHeader() *types.BlockHeader
+ LastIrreversibleHeader() *types.BlockHeader
BestBlockHeight() uint64
GetBlockByHash(*bc.Hash) (*types.Block, error)
GetBlockByHeight(uint64) (*types.Block, error)
return errors.New("invalid peer")
}
- if err := p.SendStatus(m.chain.BestBlockHeader(), m.chain.BestIrreversibleHeader()); err != nil {
+ if err := p.SendStatus(m.chain.BestBlockHeader(), m.chain.LastIrreversibleHeader()); err != nil {
m.peers.RemovePeer(p.ID())
return err
}
// validateSign verify the signatures of block, and return the number of correct signature
// if some signature is invalid, they will be reset to nil
-// if the block has not the signature of blocker, it will return error
+// if the block does not have the signature of blocker, it will return error
func (c *Chain) validateSign(block *types.Block) error {
consensusNodeMap, err := c.getConsensusNodes(&block.PreviousBlockHash)
if err != nil {
return err
}
- if c.isIrreversible(blockHeader) && blockHeader.Height > c.bestIrrBlockHeader.Height {
+ if !c.isIrreversible(blockHeader) || blockHeader.Height <= c.lastIrrBlockHeader.Height {
+ return nil
+ }
+
+ if c.InMainChain(blockHeader.Hash()) {
if err := c.store.SaveChainStatus(c.bestBlockHeader, blockHeader, []*types.BlockHeader{}, state.NewUtxoViewpoint(), []*state.ConsensusResult{}); err != nil {
return err
}
- c.bestIrrBlockHeader = blockHeader
+
+ c.lastIrrBlockHeader = blockHeader
+ } else {
+ // block is on a forked chain
+ log.WithFields(log.Fields{"module": logModule}).Info("majority votes received on forked chain")
+ tail, err := c.traceLongestChainTail(blockHeader)
+ if err != nil {
+ return err
+ }
+
+ return c.reorganizeChain(tail)
}
return nil
}
return err
}
- irrBlockHeader := c.bestIrrBlockHeader
+ irrBlockHeader := c.lastIrrBlockHeader
if c.isIrreversible(&block.BlockHeader) && block.Height > irrBlockHeader.Height {
irrBlockHeader = &block.BlockHeader
}
log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("detach from mainchain")
}
- irrBlockHeader := c.bestIrrBlockHeader
+ irrBlockHeader := c.lastIrrBlockHeader
for _, attachBlockHeader := range attachBlockHeaders {
attachHash := attachBlockHeader.Hash()
b, err := c.store.GetBlock(&attachHash)
log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("attach from mainchain")
}
- if len(detachBlockHeaders) > 0 && detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.bestIrrBlockHeader.Height && irrBlockHeader.Height <= c.bestIrrBlockHeader.Height {
+ if len(detachBlockHeaders) > 0 &&
+ detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.lastIrrBlockHeader.Height &&
+ irrBlockHeader.Height <= c.lastIrrBlockHeader.Height {
return errors.New("rollback block below the height of irreversible block")
}
consensusResults = append(consensusResults, consensusResult.Fork())
eventDispatcher *event.Dispatcher
cond sync.Cond
- bestBlockHeader *types.BlockHeader
- bestIrrBlockHeader *types.BlockHeader
+ bestBlockHeader *types.BlockHeader // the last block on current main chain
+ lastIrrBlockHeader *types.BlockHeader // the last irreversible block
}
// NewChain returns a new Chain using store as the underlying storage.
return nil, err
}
- c.bestIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
+ c.lastIrrBlockHeader, err = c.store.GetBlockHeader(storeStatus.IrreversibleHash)
if err != nil {
return nil, err
}
return c.bestBlockHeader.Height
}
-// BestBlockHash return the hash of the chain tail block
+// BestBlockHash return the hash of the main chain tail block
func (c *Chain) BestBlockHash() *bc.Hash {
c.cond.L.Lock()
defer c.cond.L.Unlock()
return &bestHash
}
-// BestIrreversibleHeader returns the chain best irreversible block header
-func (c *Chain) BestIrreversibleHeader() *types.BlockHeader {
+// LastIrreversibleHeader returns the chain last irreversible block header
+func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
c.cond.L.Lock()
defer c.cond.L.Unlock()
- return c.bestIrrBlockHeader
+ return c.lastIrrBlockHeader
}
// BestBlockHeader returns the chain best block header
return *blockHash == hash
}
+// trace back to the tail of the chain from the given block header
+func (c *Chain) traceLongestChainTail(blockHeader *types.BlockHeader) (*types.BlockHeader, error) {
+ longestTail, workQueue := blockHeader, []*types.BlockHeader{blockHeader}
+
+ for len(workQueue) > 0 {
+ currentHeader := workQueue[0]
+ currentHash := currentHeader.Hash()
+ workQueue = workQueue[1:]
+ hashes, err := c.store.GetBlockHashesByHeight(currentHeader.Height + 1)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, h := range hashes {
+ if header, err := c.store.GetBlockHeader(h); err != nil {
+ return nil, err
+ } else if header.PreviousBlockHash == currentHash {
+ if longestTail.Height < header.Height {
+ longestTail = header
+ }
+ workQueue = append(workQueue, header)
+ }
+ }
+ }
+ return longestTail, nil
+}
+
// This function must be called with mu lock in above level
func (c *Chain) setState(blockHeader, irrBlockHeader *types.BlockHeader, mainBlockHeaders []*types.BlockHeader, view *state.UtxoViewpoint, consensusResults []*state.ConsensusResult) error {
if err := c.store.SaveChainStatus(blockHeader, irrBlockHeader, mainBlockHeaders, view, consensusResults); err != nil {
}
c.bestBlockHeader = blockHeader
- c.bestIrrBlockHeader = irrBlockHeader
+ c.lastIrrBlockHeader = irrBlockHeader
blockHash := blockHeader.Hash()
log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("chain best status has been update")
return c.bestBlockHeader.Height
}
-func (c *Chain) BestIrreversibleHeader() *types.BlockHeader {
+func (c *Chain) LastIrreversibleHeader() *types.BlockHeader {
return c.bestBlockHeader
}