7 log "github.com/sirupsen/logrus"
9 "github.com/bytom/protocol/bc"
10 "github.com/bytom/protocol/bc/types"
11 "github.com/bytom/testutil"
15 orphanBlockTTL = 60 * time.Minute
16 orphanExpireWorkInterval = 3 * time.Minute
17 numOrphanBlockLimit = 256
20 type OrphanBlock struct {
25 func NewOrphanBlock(block *types.Block, expiration time.Time) *OrphanBlock {
28 expiration: expiration,
32 func (o *OrphanBlock) Equals(o1 *OrphanBlock) bool {
33 return testutil.DeepEqual(o.Block, o1.Block)
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
43 // NewOrphanManage return a new orphan block
44 func NewOrphanManage() *OrphanManage {
46 orphan: make(map[bc.Hash]*OrphanBlock),
47 prevOrphans: make(map[bc.Hash][]*bc.Hash),
50 go o.orphanExpireWorker()
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 {
58 prevOrphans: prevOrphans,
62 // Add will add the block to OrphanManage
63 func (o *OrphanManage) Add(block *types.Block) {
64 blockHash := block.Hash()
68 if _, ok := o.orphan[blockHash]; ok {
72 if len(o.orphan) >= numOrphanBlockLimit {
74 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("the number of orphan blocks exceeds the limit")
77 o.orphan[blockHash] = &OrphanBlock{block, time.Now().Add(orphanBlockTTL)}
78 o.prevOrphans[block.PreviousBlockHash] = append(o.prevOrphans[block.PreviousBlockHash], &blockHash)
80 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("add block to orphan")
83 // BlockExist check is the block in OrphanManage
84 func (o *OrphanManage) BlockExist(hash *bc.Hash) bool {
86 _, ok := o.orphan[*hash]
91 // Delete will delete the block from OrphanManage
92 func (o *OrphanManage) Delete(hash *bc.Hash) {
98 func (o *OrphanManage) Equals(o1 *OrphanManage) bool {
102 for hash, block := range o.orphan {
103 if block1, ok := o1.orphan[hash]; !ok || !block.Equals(block1) {
107 return testutil.DeepEqual(o.prevOrphans, o1.prevOrphans)
110 // Get return the orphan block by hash
111 func (o *OrphanManage) Get(hash *bc.Hash) (*types.Block, bool) {
113 block, ok := o.orphan[*hash]
115 return block.Block, ok
118 // GetPrevOrphans return the list of child orphans
119 func (o *OrphanManage) GetPrevOrphans(hash *bc.Hash) ([]*bc.Hash, bool) {
121 prevOrphans, ok := o.prevOrphans[*hash]
123 return prevOrphans, ok
126 func (o *OrphanManage) delete(hash *bc.Hash) {
127 block, ok := o.orphan[*hash]
131 delete(o.orphan, *hash)
133 prevOrphans, ok := o.prevOrphans[block.Block.PreviousBlockHash]
134 if !ok || len(prevOrphans) == 1 {
135 delete(o.prevOrphans, block.Block.PreviousBlockHash)
139 for i, preOrphan := range prevOrphans {
140 if *preOrphan == *hash {
141 o.prevOrphans[block.Block.PreviousBlockHash] = append(prevOrphans[:i], prevOrphans[i+1:]...)
147 func (o *OrphanManage) deleteLRU() {
148 var deleteBlock *OrphanBlock
149 for _, orphan := range o.orphan {
150 if deleteBlock == nil || orphan.expiration.Before(deleteBlock.expiration) {
155 if deleteBlock != nil {
156 blockHash := deleteBlock.Block.Hash()
161 func (o *OrphanManage) orphanExpireWorker() {
162 ticker := time.NewTicker(orphanExpireWorkInterval)
163 for now := range ticker.C {
169 func (o *OrphanManage) orphanExpire(now time.Time) {
172 for hash, orphan := range o.orphan {
173 if orphan.expiration.Before(now) {