github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/ibft/core/backlog.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "github.com/kisexp/xdchain/consensus/istanbul" 21 istanbulcommon "github.com/kisexp/xdchain/consensus/istanbul/common" 22 ibfttypes "github.com/kisexp/xdchain/consensus/istanbul/ibft/types" 23 "gopkg.in/karalabe/cookiejar.v2/collections/prque" 24 ) 25 26 var ( 27 // msgPriority is defined for calculating processing priority to speedup consensus 28 // msgPreprepare > msgCommit > msgPrepare 29 msgPriority = map[uint64]int{ 30 ibfttypes.MsgPreprepare: 1, 31 ibfttypes.MsgCommit: 2, 32 ibfttypes.MsgPrepare: 3, 33 } 34 ) 35 36 // checkMessage checks the message state 37 // return errInvalidMessage if the message is invalid 38 // return errFutureMessage if the message view is larger than current view 39 // return errOldMessage if the message view is smaller than current view 40 func (c *core) checkMessage(msgCode uint64, view *istanbul.View) error { 41 if view == nil || view.Sequence == nil || view.Round == nil { 42 return istanbulcommon.ErrInvalidMessage 43 } 44 45 if msgCode == ibfttypes.MsgRoundChange { 46 if view.Sequence.Cmp(c.currentView().Sequence) > 0 { 47 return istanbulcommon.ErrFutureMessage 48 } else if view.Cmp(c.currentView()) < 0 { 49 return istanbulcommon.ErrOldMessage 50 } 51 return nil 52 } 53 54 if view.Cmp(c.currentView()) > 0 { 55 return istanbulcommon.ErrFutureMessage 56 } 57 58 if view.Cmp(c.currentView()) < 0 { 59 return istanbulcommon.ErrOldMessage 60 } 61 62 if c.waitingForRoundChange { 63 return istanbulcommon.ErrFutureMessage 64 } 65 66 // StateAcceptRequest only accepts msgPreprepare 67 // other messages are future messages 68 if c.state == ibfttypes.StateAcceptRequest { 69 if msgCode > ibfttypes.MsgPreprepare { 70 return istanbulcommon.ErrFutureMessage 71 } 72 return nil 73 } 74 75 // For states(StatePreprepared, StatePrepared, StateCommitted), 76 // can accept all message types if processing with same view 77 return nil 78 } 79 80 func (c *core) storeBacklog(msg *ibfttypes.Message, src istanbul.Validator) { 81 logger := c.logger.New("from", src, "state", c.state) 82 83 if src.Address() == c.Address() { 84 logger.Warn("Backlog from self") 85 return 86 } 87 88 logger.Trace("Store future message") 89 90 c.backlogsMu.Lock() 91 defer c.backlogsMu.Unlock() 92 93 logger.Debug("Retrieving backlog queue", "for", src.Address(), "backlogs_size", len(c.backlogs)) 94 backlog := c.backlogs[src.Address()] 95 if backlog == nil { 96 backlog = prque.New() 97 } 98 switch msg.Code { 99 case ibfttypes.MsgPreprepare: 100 var p *istanbul.Preprepare 101 err := msg.Decode(&p) 102 if err == nil { 103 backlog.Push(msg, toPriority(msg.Code, p.View)) 104 } 105 // for msgRoundChange, msgPrepare and msgCommit cases 106 default: 107 var p *istanbul.Subject 108 err := msg.Decode(&p) 109 if err == nil { 110 backlog.Push(msg, toPriority(msg.Code, p.View)) 111 } 112 } 113 c.backlogs[src.Address()] = backlog 114 } 115 116 func (c *core) processBacklog() { 117 c.backlogsMu.Lock() 118 defer c.backlogsMu.Unlock() 119 120 for srcAddress, backlog := range c.backlogs { 121 if backlog == nil { 122 continue 123 } 124 _, src := c.valSet.GetByAddress(srcAddress) 125 if src == nil { 126 // validator is not available 127 delete(c.backlogs, srcAddress) 128 continue 129 } 130 logger := c.logger.New("from", src, "state", c.state) 131 isFuture := false 132 133 // We stop processing if 134 // 1. backlog is empty 135 // 2. The first message in queue is a future message 136 for !(backlog.Empty() || isFuture) { 137 m, prio := backlog.Pop() 138 msg := m.(*ibfttypes.Message) 139 var view *istanbul.View 140 switch msg.Code { 141 case ibfttypes.MsgPreprepare: 142 var m *istanbul.Preprepare 143 err := msg.Decode(&m) 144 if err == nil { 145 view = m.View 146 } 147 // for msgRoundChange, msgPrepare and msgCommit cases 148 default: 149 var sub *istanbul.Subject 150 err := msg.Decode(&sub) 151 if err == nil { 152 view = sub.View 153 } 154 } 155 if view == nil { 156 logger.Debug("Nil view", "msg", msg) 157 continue 158 } 159 // Push back if it's a future message 160 err := c.checkMessage(msg.Code, view) 161 if err != nil { 162 if err == istanbulcommon.ErrFutureMessage { 163 logger.Trace("Stop processing backlog", "msg", msg) 164 backlog.Push(msg, prio) 165 isFuture = true 166 break 167 } 168 logger.Trace("Skip the backlog event", "msg", msg, "err", err) 169 continue 170 } 171 logger.Trace("Post backlog event", "msg", msg) 172 173 go c.sendEvent(backlogEvent{ 174 src: src, 175 msg: msg, 176 }) 177 } 178 } 179 } 180 181 func toPriority(msgCode uint64, view *istanbul.View) float32 { 182 if msgCode == ibfttypes.MsgRoundChange { 183 // For msgRoundChange, set the message priority based on its sequence 184 return -float32(view.Sequence.Uint64() * 1000) 185 } 186 // FIXME: round will be reset as 0 while new sequence 187 // 10 * Round limits the range of message code is from 0 to 9 188 // 1000 * Sequence limits the range of round is from 0 to 99 189 return -float32(view.Sequence.Uint64()*1000 + view.Round.Uint64()*10 + uint64(msgPriority[msgCode])) 190 }