github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/evidence/reactor.go (about)

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