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