github.com/okex/exchain@v1.8.0/libs/tendermint/evidence/reactor.go (about) 1 package evidence 2 3 import ( 4 "fmt" 5 "reflect" 6 "time" 7 8 amino "github.com/tendermint/go-amino" 9 10 clist "github.com/okex/exchain/libs/tendermint/libs/clist" 11 "github.com/okex/exchain/libs/tendermint/libs/log" 12 "github.com/okex/exchain/libs/tendermint/p2p" 13 "github.com/okex/exchain/libs/tendermint/types" 14 ) 15 16 const ( 17 EvidenceChannel = byte(0x38) 18 19 maxMsgSize = 1048576 // 1MB TODO make it configurable 20 21 broadcastEvidenceIntervalS = 60 // broadcast uncommitted evidence this often 22 peerCatchupSleepIntervalMS = 100 // If peer is behind, sleep this amount 23 ) 24 25 // Reactor handles evpool evidence broadcasting amongst peers. 26 type Reactor struct { 27 p2p.BaseReactor 28 evpool *Pool 29 eventBus *types.EventBus 30 } 31 32 // NewReactor returns a new Reactor with the given config and evpool. 33 func NewReactor(evpool *Pool) *Reactor { 34 evR := &Reactor{ 35 evpool: evpool, 36 } 37 evR.BaseReactor = *p2p.NewBaseReactor("Evidence", evR) 38 return evR 39 } 40 41 // SetLogger sets the Logger on the reactor and the underlying Evidence. 42 func (evR *Reactor) SetLogger(l log.Logger) { 43 evR.Logger = l 44 evR.evpool.SetLogger(l) 45 } 46 47 // GetChannels implements Reactor. 48 // It returns the list of channels for this reactor. 49 func (evR *Reactor) GetChannels() []*p2p.ChannelDescriptor { 50 return []*p2p.ChannelDescriptor{ 51 { 52 ID: EvidenceChannel, 53 Priority: 5, 54 }, 55 } 56 } 57 58 // AddPeer implements Reactor. 59 func (evR *Reactor) AddPeer(peer p2p.Peer) { 60 go evR.broadcastEvidenceRoutine(peer) 61 } 62 63 // Receive implements Reactor. 64 // It adds any received evidence to the evpool. 65 func (evR *Reactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { 66 msg, err := decodeMsg(msgBytes) 67 if err != nil { 68 evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes) 69 evR.Switch.StopPeerForError(src, err) 70 return 71 } 72 73 if err = msg.ValidateBasic(); err != nil { 74 evR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err) 75 evR.Switch.StopPeerForError(src, err) 76 return 77 } 78 79 evR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg) 80 81 switch msg := msg.(type) { 82 case *ListMessage: 83 for _, ev := range msg.Evidence { 84 err := evR.evpool.AddEvidence(ev) 85 switch err.(type) { 86 case ErrInvalidEvidence: 87 evR.Logger.Error("Evidence is not valid", "evidence", msg.Evidence, "err", err) 88 // punish peer 89 evR.Switch.StopPeerForError(src, err) 90 return 91 case ErrEvidenceAlreadyStored: 92 evR.Logger.Debug("Evidence already exists", "evidence", msg.Evidence) 93 case nil: 94 default: 95 evR.Logger.Error("Evidence has not been added", "evidence", msg.Evidence, "err", err) 96 return 97 } 98 } 99 default: 100 evR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) 101 } 102 } 103 104 // SetEventBus implements events.Eventable. 105 func (evR *Reactor) SetEventBus(b *types.EventBus) { 106 evR.eventBus = b 107 } 108 109 // Modeled after the mempool routine. 110 // - Evidence accumulates in a clist. 111 // - Each peer has a routine that iterates through the clist, 112 // sending available evidence to the peer. 113 // - If we're waiting for new evidence and the list is not empty, 114 // start iterating from the beginning again. 115 func (evR *Reactor) broadcastEvidenceRoutine(peer p2p.Peer) { 116 var next *clist.CElement 117 var retryByte []byte 118 for { 119 // This happens because the CElement we were looking at got garbage 120 // collected (removed). That is, .NextWait() returned nil. Go ahead and 121 // start from the beginning. 122 if next == nil { 123 select { 124 case <-evR.evpool.EvidenceWaitChan(): // Wait until evidence is available 125 if next = evR.evpool.EvidenceFront(); next == nil { 126 continue 127 } 128 case <-peer.Quit(): 129 return 130 case <-evR.Quit(): 131 return 132 } 133 } 134 135 var retry bool 136 var msg Message 137 138 //try to get msg from evidence 139 if retryByte == nil { 140 ev := next.Value.(types.Evidence) 141 msg, retry = evR.checkSendEvidenceMessage(peer, ev) 142 if msg != nil { 143 //cache retry byte 144 retryByte = cdc.MustMarshalBinaryBare(msg) 145 } 146 } 147 148 // send out evidence 149 if !retry && retryByte != nil { 150 success := peer.Send(EvidenceChannel, retryByte) 151 retry = !success 152 } 153 154 if retry { 155 time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond) 156 continue 157 } 158 159 //clean retry byte 160 retryByte = nil 161 162 afterCh := time.After(time.Second * broadcastEvidenceIntervalS) 163 select { 164 case <-afterCh: 165 // start from the beginning every tick. 166 // TODO: only do this if we're at the end of the list! 167 next = nil 168 case <-next.NextWaitChan(): 169 // see the start of the for loop for nil check 170 next = next.Next() 171 case <-peer.Quit(): 172 return 173 case <-evR.Quit(): 174 return 175 } 176 } 177 } 178 179 // Returns the message to send the peer, or nil if the evidence is invalid for the peer. 180 // If message is nil, return true if we should sleep and try again. 181 func (evR Reactor) checkSendEvidenceMessage( 182 peer p2p.Peer, 183 ev types.Evidence, 184 ) (msg Message, retry bool) { 185 186 // make sure the peer is up to date 187 evHeight := ev.Height() 188 peerState, ok := peer.Get(types.PeerStateKey).(PeerState) 189 if !ok { 190 // Peer does not have a state yet. We set it in the consensus reactor, but 191 // when we add peer in Switch, the order we call reactors#AddPeer is 192 // different every time due to us using a map. Sometimes other reactors 193 // will be initialized before the consensus reactor. We should wait a few 194 // milliseconds and retry. 195 return nil, true 196 } 197 198 // NOTE: We only send evidence to peers where 199 // peerHeight - maxAge < evidenceHeight < peerHeight 200 // and 201 // lastBlockTime - maxDuration < evidenceTime 202 var ( 203 peerHeight = peerState.GetHeight() 204 205 params = evR.evpool.State().ConsensusParams.Evidence 206 207 ageDuration = evR.evpool.State().LastBlockTime.Sub(ev.Time()) 208 ageNumBlocks = peerHeight - evHeight 209 ) 210 211 if peerHeight < evHeight { // peer is behind. sleep while he catches up 212 return nil, true 213 } else if ageNumBlocks > params.MaxAgeNumBlocks && 214 ageDuration > params.MaxAgeDuration { // evidence is too old, skip 215 216 // NOTE: if evidence is too old for an honest peer, then we're behind and 217 // either it already got committed or it never will! 218 evR.Logger.Info("Not sending peer old evidence", 219 "peerHeight", peerHeight, 220 "evHeight", evHeight, 221 "maxAgeNumBlocks", params.MaxAgeNumBlocks, 222 "lastBlockTime", evR.evpool.State().LastBlockTime, 223 "evTime", ev.Time(), 224 "maxAgeDuration", params.MaxAgeDuration, 225 "peer", peer, 226 ) 227 228 return nil, false 229 } 230 231 // send evidence 232 msg = &ListMessage{[]types.Evidence{ev}} 233 return msg, false 234 } 235 236 // PeerState describes the state of a peer. 237 type PeerState interface { 238 GetHeight() int64 239 } 240 241 //----------------------------------------------------------------------------- 242 // Messages 243 244 // Message is a message sent or received by the Reactor. 245 type Message interface { 246 ValidateBasic() error 247 } 248 249 func RegisterMessages(cdc *amino.Codec) { 250 cdc.RegisterInterface((*Message)(nil), nil) 251 cdc.RegisterConcrete(&ListMessage{}, 252 "tendermint/evidence/ListMessage", nil) 253 } 254 255 func decodeMsg(bz []byte) (msg Message, err error) { 256 if len(bz) > maxMsgSize { 257 return msg, fmt.Errorf("msg exceeds max size (%d > %d)", len(bz), maxMsgSize) 258 } 259 err = cdc.UnmarshalBinaryBare(bz, &msg) 260 return 261 } 262 263 //------------------------------------- 264 265 // ListMessage contains a list of evidence. 266 type ListMessage struct { 267 Evidence []types.Evidence 268 } 269 270 // ValidateBasic performs basic validation. 271 func (m *ListMessage) ValidateBasic() error { 272 for i, ev := range m.Evidence { 273 if err := ev.ValidateBasic(); err != nil { 274 return fmt.Errorf("invalid evidence (#%d): %v", i, err) 275 } 276 } 277 return nil 278 } 279 280 // String returns a string representation of the ListMessage. 281 func (m *ListMessage) String() string { 282 return fmt.Sprintf("[ListMessage %v]", m.Evidence) 283 }