github.com/MagHErmit/tendermint@v0.282.1/evidence/reactor_test.go (about)

     1  package evidence_test
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/fortytw2/leaktest"
    11  	"github.com/go-kit/log/term"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	dbm "github.com/tendermint/tm-db"
    17  
    18  	cfg "github.com/MagHErmit/tendermint/config"
    19  	"github.com/MagHErmit/tendermint/crypto"
    20  	"github.com/MagHErmit/tendermint/crypto/tmhash"
    21  	"github.com/MagHErmit/tendermint/evidence"
    22  	"github.com/MagHErmit/tendermint/evidence/mocks"
    23  	"github.com/MagHErmit/tendermint/libs/log"
    24  	"github.com/MagHErmit/tendermint/p2p"
    25  	p2pmocks "github.com/MagHErmit/tendermint/p2p/mocks"
    26  	tmproto "github.com/MagHErmit/tendermint/proto/tendermint/types"
    27  	sm "github.com/MagHErmit/tendermint/state"
    28  	"github.com/MagHErmit/tendermint/types"
    29  )
    30  
    31  var (
    32  	numEvidence = 10
    33  	timeout     = 120 * time.Second // ridiculously high because CircleCI is slow
    34  )
    35  
    36  // We have N evidence reactors connected to one another. The first reactor
    37  // receives a number of evidence at varying heights. We test that all
    38  // other reactors receive the evidence and add it to their own respective
    39  // evidence pools.
    40  func TestReactorBroadcastEvidence(t *testing.T) {
    41  	config := cfg.TestConfig()
    42  	N := 7
    43  
    44  	// create statedb for everyone
    45  	stateDBs := make([]sm.Store, N)
    46  	val := types.NewMockPV()
    47  	// we need validators saved for heights at least as high as we have evidence for
    48  	height := int64(numEvidence) + 10
    49  	for i := 0; i < N; i++ {
    50  		stateDBs[i] = initializeValidatorState(val, height)
    51  	}
    52  
    53  	// make reactors from statedb
    54  	reactors, pools := makeAndConnectReactorsAndPools(config, stateDBs)
    55  
    56  	// set the peer height on each reactor
    57  	for _, r := range reactors {
    58  		for _, peer := range r.Switch.Peers().List() {
    59  			ps := peerState{height}
    60  			peer.Set(types.PeerStateKey, ps)
    61  		}
    62  	}
    63  
    64  	// send a bunch of valid evidence to the first reactor's evpool
    65  	// and wait for them all to be received in the others
    66  	evList := sendEvidence(t, pools[0], val, numEvidence)
    67  	waitForEvidence(t, evList, pools)
    68  }
    69  
    70  // We have two evidence reactors connected to one another but are at different heights.
    71  // Reactor 1 which is ahead receives a number of evidence. It should only send the evidence
    72  // that is below the height of the peer to that peer.
    73  func TestReactorSelectiveBroadcast(t *testing.T) {
    74  	config := cfg.TestConfig()
    75  
    76  	val := types.NewMockPV()
    77  	height1 := int64(numEvidence) + 10
    78  	height2 := int64(numEvidence) / 2
    79  
    80  	// DB1 is ahead of DB2
    81  	stateDB1 := initializeValidatorState(val, height1)
    82  	stateDB2 := initializeValidatorState(val, height2)
    83  
    84  	// make reactors from statedb
    85  	reactors, pools := makeAndConnectReactorsAndPools(config, []sm.Store{stateDB1, stateDB2})
    86  
    87  	// set the peer height on each reactor
    88  	for _, r := range reactors {
    89  		for _, peer := range r.Switch.Peers().List() {
    90  			ps := peerState{height1}
    91  			peer.Set(types.PeerStateKey, ps)
    92  		}
    93  	}
    94  
    95  	// update the first reactor peer's height to be very small
    96  	peer := reactors[0].Switch.Peers().List()[0]
    97  	ps := peerState{height2}
    98  	peer.Set(types.PeerStateKey, ps)
    99  
   100  	// send a bunch of valid evidence to the first reactor's evpool
   101  	evList := sendEvidence(t, pools[0], val, numEvidence)
   102  
   103  	// only ones less than the peers height should make it through
   104  	waitForEvidence(t, evList[:numEvidence/2-1], []*evidence.Pool{pools[1]})
   105  
   106  	// peers should still be connected
   107  	peers := reactors[1].Switch.Peers().List()
   108  	assert.Equal(t, 1, len(peers))
   109  }
   110  
   111  // This tests aims to ensure that reactors don't send evidence that they have committed or that ar
   112  // not ready for the peer through three scenarios.
   113  // First, committed evidence to a newly connected peer
   114  // Second, evidence to a peer that is behind
   115  // Third, evidence that was pending and became committed just before the peer caught up
   116  func TestReactorsGossipNoCommittedEvidence(t *testing.T) {
   117  	config := cfg.TestConfig()
   118  
   119  	val := types.NewMockPV()
   120  	var height int64 = 10
   121  
   122  	// DB1 is ahead of DB2
   123  	stateDB1 := initializeValidatorState(val, height-1)
   124  	stateDB2 := initializeValidatorState(val, height-2)
   125  	state, err := stateDB1.Load()
   126  	require.NoError(t, err)
   127  	state.LastBlockHeight++
   128  
   129  	// make reactors from statedb
   130  	reactors, pools := makeAndConnectReactorsAndPools(config, []sm.Store{stateDB1, stateDB2})
   131  
   132  	evList := sendEvidence(t, pools[0], val, 2)
   133  	pools[0].Update(state, evList)
   134  	require.EqualValues(t, uint32(0), pools[0].Size())
   135  
   136  	time.Sleep(100 * time.Millisecond)
   137  
   138  	peer := reactors[0].Switch.Peers().List()[0]
   139  	ps := peerState{height - 2}
   140  	peer.Set(types.PeerStateKey, ps)
   141  
   142  	peer = reactors[1].Switch.Peers().List()[0]
   143  	ps = peerState{height}
   144  	peer.Set(types.PeerStateKey, ps)
   145  
   146  	// wait to see that no evidence comes through
   147  	time.Sleep(300 * time.Millisecond)
   148  
   149  	// the second pool should not have received any evidence because it has already been committed
   150  	assert.Equal(t, uint32(0), pools[1].Size(), "second reactor should not have received evidence")
   151  
   152  	// the first reactor receives three more evidence
   153  	evList = make([]types.Evidence, 3)
   154  	for i := 0; i < 3; i++ {
   155  		ev := types.NewMockDuplicateVoteEvidenceWithValidator(height-3+int64(i),
   156  			time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), val, state.ChainID)
   157  		err := pools[0].AddEvidence(ev)
   158  		require.NoError(t, err)
   159  		evList[i] = ev
   160  	}
   161  
   162  	// wait to see that only one evidence is sent
   163  	time.Sleep(300 * time.Millisecond)
   164  
   165  	// the second pool should only have received the first evidence because it is behind
   166  	peerEv, _ := pools[1].PendingEvidence(10000)
   167  	assert.EqualValues(t, []types.Evidence{evList[0]}, peerEv)
   168  
   169  	// the last evidence is committed and the second reactor catches up in state to the first
   170  	// reactor. We therefore expect that the second reactor only receives one more evidence, the
   171  	// one that is still pending and not the evidence that has already been committed.
   172  	state.LastBlockHeight++
   173  	pools[0].Update(state, []types.Evidence{evList[2]})
   174  	// the first reactor should have the two remaining pending evidence
   175  	require.EqualValues(t, uint32(2), pools[0].Size())
   176  
   177  	// now update the state of the second reactor
   178  	pools[1].Update(state, types.EvidenceList{})
   179  	peer = reactors[0].Switch.Peers().List()[0]
   180  	ps = peerState{height}
   181  	peer.Set(types.PeerStateKey, ps)
   182  
   183  	// wait to see that only two evidence is sent
   184  	time.Sleep(300 * time.Millisecond)
   185  
   186  	peerEv, _ = pools[1].PendingEvidence(1000)
   187  	assert.EqualValues(t, []types.Evidence{evList[0], evList[1]}, peerEv)
   188  }
   189  
   190  func TestReactorBroadcastEvidenceMemoryLeak(t *testing.T) {
   191  	evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
   192  	evidenceDB := dbm.NewMemDB()
   193  	blockStore := &mocks.BlockStore{}
   194  	blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return(
   195  		&types.BlockMeta{Header: types.Header{Time: evidenceTime}},
   196  	)
   197  	val := types.NewMockPV()
   198  	stateStore := initializeValidatorState(val, 1)
   199  	pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
   200  	require.NoError(t, err)
   201  
   202  	p := &p2pmocks.Peer{}
   203  
   204  	p.On("IsRunning").Once().Return(true)
   205  	p.On("IsRunning").Return(false)
   206  	// check that we are not leaking any go-routines
   207  	// i.e. broadcastEvidenceRoutine finishes when peer is stopped
   208  	defer leaktest.CheckTimeout(t, 10*time.Second)()
   209  
   210  	p.On("Send", evidence.EvidenceChannel, mock.AnythingOfType("[]uint8")).Return(false)
   211  	quitChan := make(<-chan struct{})
   212  	p.On("Quit").Return(quitChan)
   213  	ps := peerState{2}
   214  	p.On("Get", types.PeerStateKey).Return(ps)
   215  	p.On("ID").Return("ABC")
   216  	p.On("String").Return("mock")
   217  
   218  	r := evidence.NewReactor(pool)
   219  	r.SetLogger(log.TestingLogger())
   220  	r.AddPeer(p)
   221  
   222  	_ = sendEvidence(t, pool, val, 2)
   223  }
   224  
   225  // evidenceLogger is a TestingLogger which uses a different
   226  // color for each validator ("validator" key must exist).
   227  func evidenceLogger() log.Logger {
   228  	return log.TestingLoggerWithColorFn(func(keyvals ...interface{}) term.FgBgColor {
   229  		for i := 0; i < len(keyvals)-1; i += 2 {
   230  			if keyvals[i] == "validator" {
   231  				return term.FgBgColor{Fg: term.Color(uint8(keyvals[i+1].(int) + 1))}
   232  			}
   233  		}
   234  		return term.FgBgColor{}
   235  	})
   236  }
   237  
   238  // connect N evidence reactors through N switches
   239  func makeAndConnectReactorsAndPools(config *cfg.Config, stateStores []sm.Store) ([]*evidence.Reactor,
   240  	[]*evidence.Pool) {
   241  	N := len(stateStores)
   242  
   243  	reactors := make([]*evidence.Reactor, N)
   244  	pools := make([]*evidence.Pool, N)
   245  	logger := evidenceLogger()
   246  	evidenceTime := time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
   247  
   248  	for i := 0; i < N; i++ {
   249  		evidenceDB := dbm.NewMemDB()
   250  		blockStore := &mocks.BlockStore{}
   251  		blockStore.On("LoadBlockMeta", mock.AnythingOfType("int64")).Return(
   252  			&types.BlockMeta{Header: types.Header{Time: evidenceTime}},
   253  		)
   254  		pool, err := evidence.NewPool(evidenceDB, stateStores[i], blockStore)
   255  		if err != nil {
   256  			panic(err)
   257  		}
   258  		pools[i] = pool
   259  		reactors[i] = evidence.NewReactor(pool)
   260  		reactors[i].SetLogger(logger.With("validator", i))
   261  	}
   262  
   263  	p2p.MakeConnectedSwitches(config.P2P, N, func(i int, s *p2p.Switch) *p2p.Switch {
   264  		s.AddReactor("EVIDENCE", reactors[i])
   265  		return s
   266  
   267  	}, p2p.Connect2Switches)
   268  
   269  	return reactors, pools
   270  }
   271  
   272  // wait for all evidence on all reactors
   273  func waitForEvidence(t *testing.T, evs types.EvidenceList, pools []*evidence.Pool) {
   274  	// wait for the evidence in all evpools
   275  	wg := new(sync.WaitGroup)
   276  	for i := 0; i < len(pools); i++ {
   277  		wg.Add(1)
   278  		go _waitForEvidence(t, wg, evs, i, pools)
   279  	}
   280  
   281  	done := make(chan struct{})
   282  	go func() {
   283  		wg.Wait()
   284  		close(done)
   285  	}()
   286  
   287  	timer := time.After(timeout)
   288  	select {
   289  	case <-timer:
   290  		t.Fatal("Timed out waiting for evidence")
   291  	case <-done:
   292  	}
   293  }
   294  
   295  // wait for all evidence on a single evpool
   296  func _waitForEvidence(
   297  	t *testing.T,
   298  	wg *sync.WaitGroup,
   299  	evs types.EvidenceList,
   300  	poolIdx int,
   301  	pools []*evidence.Pool,
   302  ) {
   303  	evpool := pools[poolIdx]
   304  	var evList []types.Evidence
   305  	currentPoolSize := 0
   306  	for currentPoolSize != len(evs) {
   307  		evList, _ = evpool.PendingEvidence(int64(len(evs) * 500)) // each evidence should not be more than 500 bytes
   308  		currentPoolSize = len(evList)
   309  		time.Sleep(time.Millisecond * 100)
   310  	}
   311  
   312  	// put the reaped evidence in a map so we can quickly check we got everything
   313  	evMap := make(map[string]types.Evidence)
   314  	for _, e := range evList {
   315  		evMap[string(e.Hash())] = e
   316  	}
   317  	for i, expectedEv := range evs {
   318  		gotEv := evMap[string(expectedEv.Hash())]
   319  		assert.Equal(t, expectedEv, gotEv,
   320  			fmt.Sprintf("evidence at index %d on pool %d don't match: %v vs %v",
   321  				i, poolIdx, expectedEv, gotEv))
   322  	}
   323  
   324  	wg.Done()
   325  }
   326  
   327  func sendEvidence(t *testing.T, evpool *evidence.Pool, val types.PrivValidator, n int) types.EvidenceList {
   328  	evList := make([]types.Evidence, n)
   329  	for i := 0; i < n; i++ {
   330  		ev := types.NewMockDuplicateVoteEvidenceWithValidator(int64(i+1),
   331  			time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), val, evidenceChainID)
   332  		err := evpool.AddEvidence(ev)
   333  		require.NoError(t, err)
   334  		evList[i] = ev
   335  	}
   336  	return evList
   337  }
   338  
   339  type peerState struct {
   340  	height int64
   341  }
   342  
   343  func (ps peerState) GetHeight() int64 {
   344  	return ps.height
   345  }
   346  
   347  func exampleVote(t byte) *types.Vote {
   348  	var stamp, err = time.Parse(types.TimeFormat, "2017-12-25T03:00:01.234Z")
   349  	if err != nil {
   350  		panic(err)
   351  	}
   352  
   353  	return &types.Vote{
   354  		Type:      tmproto.SignedMsgType(t),
   355  		Height:    3,
   356  		Round:     2,
   357  		Timestamp: stamp,
   358  		BlockID: types.BlockID{
   359  			Hash: tmhash.Sum([]byte("blockID_hash")),
   360  			PartSetHeader: types.PartSetHeader{
   361  				Total: 1000000,
   362  				Hash:  tmhash.Sum([]byte("blockID_part_set_header_hash")),
   363  			},
   364  		},
   365  		ValidatorAddress: crypto.AddressHash([]byte("validator_address")),
   366  		ValidatorIndex:   56789,
   367  	}
   368  }
   369  
   370  //nolint:lll //ignore line length for tests
   371  func TestEvidenceVectors(t *testing.T) {
   372  
   373  	val := &types.Validator{
   374  		Address:     crypto.AddressHash([]byte("validator_address")),
   375  		VotingPower: 10,
   376  	}
   377  
   378  	valSet := types.NewValidatorSet([]*types.Validator{val})
   379  
   380  	dupl := types.NewDuplicateVoteEvidence(
   381  		exampleVote(1),
   382  		exampleVote(2),
   383  		defaultEvidenceTime,
   384  		valSet,
   385  	)
   386  
   387  	testCases := []struct {
   388  		testName     string
   389  		evidenceList []types.Evidence
   390  		expBytes     string
   391  	}{
   392  		{"DuplicateVoteEvidence", []types.Evidence{dupl}, "0a85020a82020a79080210031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0b08b1d381d20510809dca6f32146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb031279080110031802224a0a208b01023386c371778ecb6368573e539afc3cc860ec3a2f614e54fe5652f4fc80122608c0843d122072db3d959635dff1bb567bedaa70573392c5159666a3f8caf11e413aac52207a2a0b08b1d381d20510809dca6f32146af1f4111082efb388211bc72c55bcd61e9ac3d538d5bb03180a200a2a060880dbaae105"},
   393  	}
   394  
   395  	for _, tc := range testCases {
   396  		tc := tc
   397  
   398  		evi := make([]tmproto.Evidence, len(tc.evidenceList))
   399  		for i := 0; i < len(tc.evidenceList); i++ {
   400  			ev, err := types.EvidenceToProto(tc.evidenceList[i])
   401  			require.NoError(t, err, tc.testName)
   402  			evi[i] = *ev
   403  		}
   404  
   405  		epl := tmproto.EvidenceList{
   406  			Evidence: evi,
   407  		}
   408  
   409  		bz, err := epl.Marshal()
   410  		require.NoError(t, err, tc.testName)
   411  
   412  		require.Equal(t, tc.expBytes, hex.EncodeToString(bz), tc.testName)
   413  
   414  	}
   415  
   416  }