github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/backlog.go (about) 1 package core 2 3 import ( 4 bft "github.com/quickchainproject/quickchain/consensus/dbft" 5 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 6 ) 7 8 var ( 9 // msgPriority is defined for calculating processing priority to speedup consensus 10 // msgPreprepare > msgCommit > msgPrepare 11 msgPriority = map[uint64]int{ 12 msgPreprepare: 1, 13 msgCommit: 2, 14 msgPrepare: 3, 15 } 16 ) 17 18 // checkMessage checks the message state 19 // return errInvalidMessage if the message is invalid 20 // return errFutureMessage if the message view is larger than current view 21 // return errOldMessage if the message view is smaller than current view 22 func (c *core) checkMessage(msgCode uint64, view *bft.View) error { 23 if view == nil || view.Sequence == nil || view.Round == nil { 24 return errInvalidMessage 25 } 26 27 if msgCode == msgRoundChange { 28 if view.Sequence.Cmp(c.currentView().Sequence) > 0 { 29 return errFutureMessage 30 } else if view.Cmp(c.currentView()) < 0 { 31 return errOldMessage 32 } 33 return nil 34 } 35 36 if view.Cmp(c.currentView()) > 0 { 37 return errFutureMessage 38 } 39 40 if view.Cmp(c.currentView()) < 0 { 41 return errOldMessage 42 } 43 44 if c.waitingForRoundChange { 45 return errFutureMessage 46 } 47 48 // StateAcceptRequest only accepts msgPreprepare 49 // other messages are future messages 50 if c.state == StateAcceptRequest { 51 if msgCode > msgPreprepare { 52 return errFutureMessage 53 } 54 return nil 55 } 56 57 // For states(StatePreprepared, StatePrepared, StateCommitted), 58 // can accept all message types if processing with same view 59 return nil 60 } 61 62 func (c *core) storeBacklog(msg *message, src bft.Validator) { 63 logger := c.logger.New("from", src, "state", c.state) 64 65 if src.Address() == c.Address() { 66 logger.Warn("Backlog from self") 67 return 68 } 69 70 logger.Trace("Store future message") 71 72 c.backlogsMu.Lock() 73 defer c.backlogsMu.Unlock() 74 75 backlog := c.backlogs[src] 76 if backlog == nil { 77 backlog = prque.New() 78 } 79 switch msg.Code { 80 case msgPreprepare: 81 var p *bft.Preprepare 82 err := msg.Decode(&p) 83 if err == nil { 84 backlog.Push(msg, toPriority(msg.Code, p.View)) 85 } 86 // for msgRoundChange, msgPrepare and msgCommit cases 87 default: 88 var p *bft.Subject 89 err := msg.Decode(&p) 90 if err == nil { 91 backlog.Push(msg, toPriority(msg.Code, p.View)) 92 } 93 } 94 c.backlogs[src] = backlog 95 } 96 97 func (c *core) processBacklog() { 98 c.backlogsMu.Lock() 99 defer c.backlogsMu.Unlock() 100 101 for src, backlog := range c.backlogs { 102 if backlog == nil { 103 continue 104 } 105 106 logger := c.logger.New("from", src, "state", c.state) 107 isFuture := false 108 109 // We stop processing if 110 // 1. backlog is empty 111 // 2. The first message in queue is a future message 112 for !(backlog.Empty() || isFuture) { 113 m, prio := backlog.Pop() 114 msg := m.(*message) 115 var view *bft.View 116 switch msg.Code { 117 case msgPreprepare: 118 var m *bft.Preprepare 119 err := msg.Decode(&m) 120 if err == nil { 121 view = m.View 122 } 123 // for msgRoundChange, msgPrepare and msgCommit cases 124 default: 125 var sub *bft.Subject 126 err := msg.Decode(&sub) 127 if err == nil { 128 view = sub.View 129 } 130 } 131 if view == nil { 132 logger.Debug("Nil view", "msg", msg) 133 continue 134 } 135 // Push back if it's a future message 136 err := c.checkMessage(msg.Code, view) 137 if err != nil { 138 if err == errFutureMessage { 139 logger.Trace("Stop processing backlog", "msg", msg) 140 backlog.Push(msg, prio) 141 isFuture = true 142 break 143 } 144 logger.Trace("Skip the backlog event", "msg", msg, "err", err) 145 continue 146 } 147 logger.Trace("Post backlog event", "msg", msg) 148 149 go c.sendEvent(backlogEvent{ 150 src: src, 151 msg: msg, 152 }) 153 } 154 } 155 } 156 157 func toPriority(msgCode uint64, view *bft.View) float32 { 158 if msgCode == msgRoundChange { 159 // For msgRoundChange, set the message priority based on its sequence 160 return -float32(view.Sequence.Uint64() * 1000) 161 } 162 // FIXME: round will be reset as 0 while new sequence 163 // 10 * Round limits the range of message code is from 0 to 9 164 // 1000 * Sequence limits the range of round is from 0 to 99 165 return -float32(view.Sequence.Uint64()*1000 + view.Round.Uint64()*10 + uint64(msgPriority[msgCode])) 166 }