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