github.com/DFWallet/tendermint-cosmos@v0.0.2/evidence/reactor.go (about)

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