github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/orphan_manage.go (about) 1 package protocol 2 3 import ( 4 "sync" 5 "time" 6 7 log "github.com/sirupsen/logrus" 8 9 "github.com/bytom/bytom/protocol/bc" 10 "github.com/bytom/bytom/protocol/bc/types" 11 "github.com/bytom/bytom/testutil" 12 ) 13 14 var ( 15 orphanBlockTTL = 60 * time.Minute 16 orphanExpireWorkInterval = 3 * time.Minute 17 numOrphanBlockLimit = 256 18 ) 19 20 type OrphanBlock struct { 21 *types.Block 22 expiration time.Time 23 } 24 25 func NewOrphanBlock(block *types.Block, expiration time.Time) *OrphanBlock { 26 return &OrphanBlock{ 27 Block: block, 28 expiration: expiration, 29 } 30 } 31 32 func (o *OrphanBlock) Equals(o1 *OrphanBlock) bool { 33 return testutil.DeepEqual(o.Block, o1.Block) 34 } 35 36 // OrphanManage is use to handle all the orphan block 37 type OrphanManage struct { 38 orphan map[bc.Hash]*OrphanBlock 39 prevOrphans map[bc.Hash][]*bc.Hash 40 mtx sync.RWMutex 41 } 42 43 // NewOrphanManage return a new orphan block 44 func NewOrphanManage() *OrphanManage { 45 o := &OrphanManage{ 46 orphan: make(map[bc.Hash]*OrphanBlock), 47 prevOrphans: make(map[bc.Hash][]*bc.Hash), 48 } 49 50 go o.orphanExpireWorker() 51 return o 52 } 53 54 // NewOrphanManageWithData return a new orphan manage with specify data 55 func NewOrphanManageWithData(orphan map[bc.Hash]*OrphanBlock, prevOrphans map[bc.Hash][]*bc.Hash) *OrphanManage { 56 return &OrphanManage{ 57 orphan: orphan, 58 prevOrphans: prevOrphans, 59 } 60 } 61 62 // Add will add the block to OrphanManage 63 func (o *OrphanManage) Add(block *types.Block) { 64 blockHash := block.Hash() 65 o.mtx.Lock() 66 defer o.mtx.Unlock() 67 68 if _, ok := o.orphan[blockHash]; ok { 69 return 70 } 71 72 if len(o.orphan) >= numOrphanBlockLimit { 73 o.deleteLRU() 74 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("the number of orphan blocks exceeds the limit") 75 } 76 77 o.orphan[blockHash] = &OrphanBlock{block, time.Now().Add(orphanBlockTTL)} 78 o.prevOrphans[block.PreviousBlockHash] = append(o.prevOrphans[block.PreviousBlockHash], &blockHash) 79 80 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("add block to orphan") 81 } 82 83 // BlockExist check is the block in OrphanManage 84 func (o *OrphanManage) BlockExist(hash *bc.Hash) bool { 85 o.mtx.RLock() 86 _, ok := o.orphan[*hash] 87 o.mtx.RUnlock() 88 return ok 89 } 90 91 // Delete will delete the block from OrphanManage 92 func (o *OrphanManage) Delete(hash *bc.Hash) { 93 o.mtx.Lock() 94 defer o.mtx.Unlock() 95 o.delete(hash) 96 } 97 98 func (o *OrphanManage) Equals(o1 *OrphanManage) bool { 99 if o1 == nil { 100 return false 101 } 102 for hash, block := range o.orphan { 103 if block1, ok := o1.orphan[hash]; !ok || !block.Equals(block1) { 104 return false 105 } 106 } 107 return testutil.DeepEqual(o.prevOrphans, o1.prevOrphans) 108 } 109 110 // Get return the orphan block by hash 111 func (o *OrphanManage) Get(hash *bc.Hash) (*types.Block, bool) { 112 o.mtx.RLock() 113 block, ok := o.orphan[*hash] 114 o.mtx.RUnlock() 115 return block.Block, ok 116 } 117 118 // GetPrevOrphans return the list of child orphans 119 func (o *OrphanManage) GetPrevOrphans(hash *bc.Hash) ([]*bc.Hash, bool) { 120 o.mtx.RLock() 121 prevOrphans, ok := o.prevOrphans[*hash] 122 o.mtx.RUnlock() 123 return prevOrphans, ok 124 } 125 126 func (o *OrphanManage) delete(hash *bc.Hash) { 127 block, ok := o.orphan[*hash] 128 if !ok { 129 return 130 } 131 delete(o.orphan, *hash) 132 133 prevOrphans, ok := o.prevOrphans[block.Block.PreviousBlockHash] 134 if !ok || len(prevOrphans) == 1 { 135 delete(o.prevOrphans, block.Block.PreviousBlockHash) 136 return 137 } 138 139 for i, preOrphan := range prevOrphans { 140 if *preOrphan == *hash { 141 o.prevOrphans[block.Block.PreviousBlockHash] = append(prevOrphans[:i], prevOrphans[i+1:]...) 142 return 143 } 144 } 145 } 146 147 func (o *OrphanManage) deleteLRU() { 148 var deleteBlock *OrphanBlock 149 for _, orphan := range o.orphan { 150 if deleteBlock == nil || orphan.expiration.Before(deleteBlock.expiration) { 151 deleteBlock = orphan 152 } 153 } 154 155 if deleteBlock != nil { 156 blockHash := deleteBlock.Block.Hash() 157 o.delete(&blockHash) 158 } 159 } 160 161 func (o *OrphanManage) orphanExpireWorker() { 162 ticker := time.NewTicker(orphanExpireWorkInterval) 163 for now := range ticker.C { 164 o.orphanExpire(now) 165 } 166 ticker.Stop() 167 } 168 169 func (o *OrphanManage) orphanExpire(now time.Time) { 170 o.mtx.Lock() 171 defer o.mtx.Unlock() 172 for hash, orphan := range o.orphan { 173 if orphan.expiration.Before(now) { 174 o.delete(&hash) 175 } 176 } 177 }