github.com/devwanda/aphelion-staking@v0.33.9/evidence/reactor.go (about)

     1  package evidence
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"time"
     7  
     8  	amino "github.com/evdatsion/go-amino"
     9  
    10  	clist "github.com/devwanda/aphelion-staking/libs/clist"
    11  	"github.com/devwanda/aphelion-staking/libs/log"
    12  	"github.com/devwanda/aphelion-staking/p2p"
    13  	"github.com/devwanda/aphelion-staking/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  	for {
   118  		// This happens because the CElement we were looking at got garbage
   119  		// collected (removed). That is, .NextWait() returned nil. Go ahead and
   120  		// start from the beginning.
   121  		if next == nil {
   122  			select {
   123  			case <-evR.evpool.EvidenceWaitChan(): // Wait until evidence is available
   124  				if next = evR.evpool.EvidenceFront(); next == nil {
   125  					continue
   126  				}
   127  			case <-peer.Quit():
   128  				return
   129  			case <-evR.Quit():
   130  				return
   131  			}
   132  		}
   133  
   134  		ev := next.Value.(types.Evidence)
   135  		msg, retry := evR.checkSendEvidenceMessage(peer, ev)
   136  		if msg != nil {
   137  			success := peer.Send(EvidenceChannel, cdc.MustMarshalBinaryBare(msg))
   138  			retry = !success
   139  		}
   140  
   141  		if retry {
   142  			time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond)
   143  			continue
   144  		}
   145  
   146  		afterCh := time.After(time.Second * broadcastEvidenceIntervalS)
   147  		select {
   148  		case <-afterCh:
   149  			// start from the beginning every tick.
   150  			// TODO: only do this if we're at the end of the list!
   151  			next = nil
   152  		case <-next.NextWaitChan():
   153  			// see the start of the for loop for nil check
   154  			next = next.Next()
   155  		case <-peer.Quit():
   156  			return
   157  		case <-evR.Quit():
   158  			return
   159  		}
   160  	}
   161  }
   162  
   163  // Returns the message to send the peer, or nil if the evidence is invalid for the peer.
   164  // If message is nil, return true if we should sleep and try again.
   165  func (evR Reactor) checkSendEvidenceMessage(
   166  	peer p2p.Peer,
   167  	ev types.Evidence,
   168  ) (msg Message, retry bool) {
   169  
   170  	// make sure the peer is up to date
   171  	evHeight := ev.Height()
   172  	peerState, ok := peer.Get(types.PeerStateKey).(PeerState)
   173  	if !ok {
   174  		// Peer does not have a state yet. We set it in the consensus reactor, but
   175  		// when we add peer in Switch, the order we call reactors#AddPeer is
   176  		// different every time due to us using a map. Sometimes other reactors
   177  		// will be initialized before the consensus reactor. We should wait a few
   178  		// milliseconds and retry.
   179  		return nil, true
   180  	}
   181  
   182  	// NOTE: We only send evidence to peers where
   183  	// peerHeight - maxAge < evidenceHeight < peerHeight
   184  	// and
   185  	// lastBlockTime - maxDuration < evidenceTime
   186  	var (
   187  		peerHeight = peerState.GetHeight()
   188  
   189  		params = evR.evpool.State().ConsensusParams.Evidence
   190  
   191  		ageDuration  = evR.evpool.State().LastBlockTime.Sub(ev.Time())
   192  		ageNumBlocks = peerHeight - evHeight
   193  	)
   194  
   195  	if peerHeight < evHeight { // peer is behind. sleep while he catches up
   196  		return nil, true
   197  	} else if ageNumBlocks > params.MaxAgeNumBlocks &&
   198  		ageDuration > params.MaxAgeDuration { // evidence is too old, skip
   199  
   200  		// NOTE: if evidence is too old for an honest peer, then we're behind and
   201  		// either it already got committed or it never will!
   202  		evR.Logger.Info("Not sending peer old evidence",
   203  			"peerHeight", peerHeight,
   204  			"evHeight", evHeight,
   205  			"maxAgeNumBlocks", params.MaxAgeNumBlocks,
   206  			"lastBlockTime", evR.evpool.State().LastBlockTime,
   207  			"evTime", ev.Time(),
   208  			"maxAgeDuration", params.MaxAgeDuration,
   209  			"peer", peer,
   210  		)
   211  
   212  		return nil, false
   213  	}
   214  
   215  	// send evidence
   216  	msg = &ListMessage{[]types.Evidence{ev}}
   217  	return msg, false
   218  }
   219  
   220  // PeerState describes the state of a peer.
   221  type PeerState interface {
   222  	GetHeight() int64
   223  }
   224  
   225  //-----------------------------------------------------------------------------
   226  // Messages
   227  
   228  // Message is a message sent or received by the Reactor.
   229  type Message interface {
   230  	ValidateBasic() error
   231  }
   232  
   233  func RegisterMessages(cdc *amino.Codec) {
   234  	cdc.RegisterInterface((*Message)(nil), nil)
   235  	cdc.RegisterConcrete(&ListMessage{},
   236  		"tendermint/evidence/ListMessage", nil)
   237  }
   238  
   239  func decodeMsg(bz []byte) (msg Message, err error) {
   240  	if len(bz) > maxMsgSize {
   241  		return msg, fmt.Errorf("msg exceeds max size (%d > %d)", len(bz), maxMsgSize)
   242  	}
   243  	err = cdc.UnmarshalBinaryBare(bz, &msg)
   244  	return
   245  }
   246  
   247  //-------------------------------------
   248  
   249  // ListMessage contains a list of evidence.
   250  type ListMessage struct {
   251  	Evidence []types.Evidence
   252  }
   253  
   254  // ValidateBasic performs basic validation.
   255  func (m *ListMessage) ValidateBasic() error {
   256  	for i, ev := range m.Evidence {
   257  		if err := ev.ValidateBasic(); err != nil {
   258  			return fmt.Errorf("invalid evidence (#%d): %v", i, err)
   259  		}
   260  	}
   261  	return nil
   262  }
   263  
   264  // String returns a string representation of the ListMessage.
   265  func (m *ListMessage) String() string {
   266  	return fmt.Sprintf("[ListMessage %v]", m.Evidence)
   267  }