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  }