OSDN Git Service

fix the orphan issue
[bytom/bytom.git] / protocol / orphan_manage.go
index de15989..fad633a 100644 (file)
@@ -17,14 +17,25 @@ var (
        numOrphanBlockLimit      = 256
 )
 
-type orphanBlock struct {
+type OrphanBlock struct {
        *types.Block
        expiration time.Time
 }
 
+func NewOrphanBlock(block *types.Block, expiration time.Time) *OrphanBlock {
+       return &OrphanBlock{
+               Block:      block,
+               expiration: expiration,
+       }
+}
+
+func (o *OrphanBlock) Equals(o1 *OrphanBlock) bool {
+       return testutil.DeepEqual(o.Block, o1.Block)
+}
+
 // OrphanManage is use to handle all the orphan block
 type OrphanManage struct {
-       orphan      map[bc.Hash]*orphanBlock
+       orphan      map[bc.Hash]*OrphanBlock
        prevOrphans map[bc.Hash][]*bc.Hash
        mtx         sync.RWMutex
 }
@@ -32,7 +43,7 @@ type OrphanManage struct {
 // NewOrphanManage return a new orphan block
 func NewOrphanManage() *OrphanManage {
        o := &OrphanManage{
-               orphan:      make(map[bc.Hash]*orphanBlock),
+               orphan:      make(map[bc.Hash]*OrphanBlock),
                prevOrphans: make(map[bc.Hash][]*bc.Hash),
        }
 
@@ -40,6 +51,14 @@ func NewOrphanManage() *OrphanManage {
        return o
 }
 
+// NewOrphanManageWithData return a new orphan manage with specify data
+func NewOrphanManageWithData(orphan map[bc.Hash]*OrphanBlock, prevOrphans map[bc.Hash][]*bc.Hash) *OrphanManage {
+       return &OrphanManage{
+               orphan:      orphan,
+               prevOrphans: prevOrphans,
+       }
+}
+
 // Add will add the block to OrphanManage
 func (o *OrphanManage) Add(block *types.Block) {
        blockHash := block.Hash()
@@ -51,11 +70,11 @@ func (o *OrphanManage) Add(block *types.Block) {
        }
 
        if len(o.orphan) >= numOrphanBlockLimit {
+               o.deleteLRU()
                log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("the number of orphan blocks exceeds the limit")
-               return
        }
 
-       o.orphan[blockHash] = &orphanBlock{block, time.Now().Add(orphanBlockTTL)}
+       o.orphan[blockHash] = &OrphanBlock{block, time.Now().Add(orphanBlockTTL)}
        o.prevOrphans[block.PreviousBlockHash] = append(o.prevOrphans[block.PreviousBlockHash], &blockHash)
 
        log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("add block to orphan")
@@ -80,7 +99,12 @@ func (o *OrphanManage) Equals(o1 *OrphanManage) bool {
        if o1 == nil {
                return false
        }
-       return testutil.DeepEqual(o.orphan, o1.orphan) && testutil.DeepEqual(o.prevOrphans, o1.prevOrphans)
+       for hash, block := range o.orphan {
+               if block1, ok := o1.orphan[hash]; !ok || !block.Equals(block1) {
+                       return false
+               }
+       }
+       return testutil.DeepEqual(o.prevOrphans, o1.prevOrphans)
 }
 
 // Get return the orphan block by hash
@@ -113,13 +137,27 @@ func (o *OrphanManage) delete(hash *bc.Hash) {
        }
 
        for i, preOrphan := range prevOrphans {
-               if preOrphan == hash {
+               if *preOrphan == *hash {
                        o.prevOrphans[block.Block.PreviousBlockHash] = append(prevOrphans[:i], prevOrphans[i+1:]...)
                        return
                }
        }
 }
 
+func (o *OrphanManage) deleteLRU() {
+       var deleteBlock *OrphanBlock
+       for _, orphan := range o.orphan {
+               if deleteBlock == nil || orphan.expiration.Before(deleteBlock.expiration) {
+                       deleteBlock = orphan
+               }
+       }
+
+       if deleteBlock != nil {
+               blockHash := deleteBlock.Block.Hash()
+               o.delete(&blockHash)
+       }
+}
+
 func (o *OrphanManage) orphanExpireWorker() {
        ticker := time.NewTicker(orphanExpireWorkInterval)
        for now := range ticker.C {