gitlab.com/gpdionisio/tendermint@v0.34.19-dev2/blockchain/v1/pool_test.go (about)

     1  package v1
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  
     9  	"github.com/tendermint/tendermint/libs/log"
    10  	"github.com/tendermint/tendermint/p2p"
    11  	"github.com/tendermint/tendermint/types"
    12  )
    13  
    14  type testPeer struct {
    15  	id     p2p.ID
    16  	base   int64
    17  	height int64
    18  }
    19  
    20  type testBcR struct {
    21  	logger log.Logger
    22  }
    23  
    24  type testValues struct {
    25  	numRequestsSent int
    26  }
    27  
    28  var testResults testValues
    29  
    30  func resetPoolTestResults() {
    31  	testResults.numRequestsSent = 0
    32  }
    33  
    34  func (testR *testBcR) sendPeerError(err error, peerID p2p.ID) {
    35  }
    36  
    37  func (testR *testBcR) sendStatusRequest() {
    38  }
    39  
    40  func (testR *testBcR) sendBlockRequest(peerID p2p.ID, height int64) error {
    41  	testResults.numRequestsSent++
    42  	return nil
    43  }
    44  
    45  func (testR *testBcR) resetStateTimer(name string, timer **time.Timer, timeout time.Duration) {
    46  }
    47  
    48  func (testR *testBcR) switchToConsensus() {
    49  
    50  }
    51  
    52  func newTestBcR() *testBcR {
    53  	testBcR := &testBcR{logger: log.TestingLogger()}
    54  	return testBcR
    55  }
    56  
    57  type tPBlocks struct {
    58  	id     p2p.ID
    59  	create bool
    60  }
    61  
    62  // Makes a block pool with specified current height, list of peers, block requests and block responses
    63  func makeBlockPool(bcr *testBcR, height int64, peers []BpPeer, blocks map[int64]tPBlocks) *BlockPool {
    64  	bPool := NewBlockPool(height, bcr)
    65  	bPool.SetLogger(bcr.logger)
    66  
    67  	txs := []types.Tx{types.Tx("foo"), types.Tx("bar")}
    68  
    69  	var maxH int64
    70  	for _, p := range peers {
    71  		if p.Height > maxH {
    72  			maxH = p.Height
    73  		}
    74  		bPool.peers[p.ID] = NewBpPeer(p.ID, p.Base, p.Height, bcr.sendPeerError, nil)
    75  		bPool.peers[p.ID].SetLogger(bcr.logger)
    76  
    77  	}
    78  	bPool.MaxPeerHeight = maxH
    79  	for h, p := range blocks {
    80  		bPool.blocks[h] = p.id
    81  		bPool.peers[p.id].RequestSent(h)
    82  		if p.create {
    83  			// simulate that a block at height h has been received
    84  			_ = bPool.peers[p.id].AddBlock(types.MakeBlock(h, txs, nil, nil), 100)
    85  		}
    86  	}
    87  	return bPool
    88  }
    89  
    90  func assertPeerSetsEquivalent(t *testing.T, set1 map[p2p.ID]*BpPeer, set2 map[p2p.ID]*BpPeer) {
    91  	assert.Equal(t, len(set1), len(set2))
    92  	for peerID, peer1 := range set1 {
    93  		peer2 := set2[peerID]
    94  		assert.NotNil(t, peer2)
    95  		assert.Equal(t, peer1.NumPendingBlockRequests, peer2.NumPendingBlockRequests)
    96  		assert.Equal(t, peer1.Height, peer2.Height)
    97  		assert.Equal(t, peer1.Base, peer2.Base)
    98  		assert.Equal(t, len(peer1.blocks), len(peer2.blocks))
    99  		for h, block1 := range peer1.blocks {
   100  			block2 := peer2.blocks[h]
   101  			// block1 and block2 could be nil if a request was made but no block was received
   102  			assert.Equal(t, block1, block2)
   103  		}
   104  	}
   105  }
   106  
   107  func assertBlockPoolEquivalent(t *testing.T, poolWanted, pool *BlockPool) {
   108  	assert.Equal(t, poolWanted.blocks, pool.blocks)
   109  	assertPeerSetsEquivalent(t, poolWanted.peers, pool.peers)
   110  	assert.Equal(t, poolWanted.MaxPeerHeight, pool.MaxPeerHeight)
   111  	assert.Equal(t, poolWanted.Height, pool.Height)
   112  
   113  }
   114  
   115  func TestBlockPoolUpdatePeer(t *testing.T) {
   116  	testBcR := newTestBcR()
   117  
   118  	tests := []struct {
   119  		name       string
   120  		pool       *BlockPool
   121  		args       testPeer
   122  		poolWanted *BlockPool
   123  		errWanted  error
   124  	}{
   125  		{
   126  			name:       "add a first short peer",
   127  			pool:       makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   128  			args:       testPeer{"P1", 0, 50},
   129  			errWanted:  errPeerTooShort,
   130  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   131  		},
   132  		{
   133  			name:       "add a first good peer",
   134  			pool:       makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   135  			args:       testPeer{"P1", 0, 101},
   136  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 101}}, map[int64]tPBlocks{}),
   137  		},
   138  		{
   139  			name:       "add a first good peer with base",
   140  			pool:       makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   141  			args:       testPeer{"P1", 10, 101},
   142  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Base: 10, Height: 101}}, map[int64]tPBlocks{}),
   143  		},
   144  		{
   145  			name:       "increase the height of P1 from 120 to 123",
   146  			pool:       makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
   147  			args:       testPeer{"P1", 0, 123},
   148  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 123}}, map[int64]tPBlocks{}),
   149  		},
   150  		{
   151  			name:       "decrease the height of P1 from 120 to 110",
   152  			pool:       makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
   153  			args:       testPeer{"P1", 0, 110},
   154  			errWanted:  errPeerLowersItsHeight,
   155  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   156  		},
   157  		{
   158  			name: "decrease the height of P1 from 105 to 102 with blocks",
   159  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 105}},
   160  				map[int64]tPBlocks{
   161  					100: {"P1", true}, 101: {"P1", true}, 102: {"P1", true}}),
   162  			args:      testPeer{"P1", 0, 102},
   163  			errWanted: errPeerLowersItsHeight,
   164  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{},
   165  				map[int64]tPBlocks{}),
   166  		},
   167  	}
   168  
   169  	for _, tt := range tests {
   170  		tt := tt
   171  		t.Run(tt.name, func(t *testing.T) {
   172  			pool := tt.pool
   173  			err := pool.UpdatePeer(tt.args.id, tt.args.base, tt.args.height)
   174  			assert.Equal(t, tt.errWanted, err)
   175  			assert.Equal(t, tt.poolWanted.blocks, tt.pool.blocks)
   176  			assertPeerSetsEquivalent(t, tt.poolWanted.peers, tt.pool.peers)
   177  			assert.Equal(t, tt.poolWanted.MaxPeerHeight, tt.pool.MaxPeerHeight)
   178  		})
   179  	}
   180  }
   181  
   182  func TestBlockPoolRemovePeer(t *testing.T) {
   183  	testBcR := newTestBcR()
   184  
   185  	type args struct {
   186  		peerID p2p.ID
   187  		err    error
   188  	}
   189  
   190  	tests := []struct {
   191  		name       string
   192  		pool       *BlockPool
   193  		args       args
   194  		poolWanted *BlockPool
   195  	}{
   196  		{
   197  			name:       "attempt to delete non-existing peer",
   198  			pool:       makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
   199  			args:       args{"P99", nil},
   200  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
   201  		},
   202  		{
   203  			name:       "delete the only peer without blocks",
   204  			pool:       makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}}, map[int64]tPBlocks{}),
   205  			args:       args{"P1", nil},
   206  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   207  		},
   208  		{
   209  			name: "delete the shortest of two peers without blocks",
   210  			pool: makeBlockPool(
   211  				testBcR,
   212  				100,
   213  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}},
   214  				map[int64]tPBlocks{}),
   215  			args:       args{"P1", nil},
   216  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 120}}, map[int64]tPBlocks{}),
   217  		},
   218  		{
   219  			name: "delete the tallest of two peers without blocks",
   220  			pool: makeBlockPool(
   221  				testBcR,
   222  				100,
   223  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 120}},
   224  				map[int64]tPBlocks{}),
   225  			args:       args{"P2", nil},
   226  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
   227  		},
   228  		{
   229  			name: "delete the only peer with block requests sent and blocks received",
   230  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
   231  				map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
   232  			args:       args{"P1", nil},
   233  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   234  		},
   235  		{
   236  			name: "delete the shortest of two peers with block requests sent and blocks received",
   237  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 200}},
   238  				map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
   239  			args:       args{"P1", nil},
   240  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 200}}, map[int64]tPBlocks{}),
   241  		},
   242  		{
   243  			name: "delete the tallest of two peers with block requests sent and blocks received",
   244  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 110}},
   245  				map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
   246  			args:       args{"P1", nil},
   247  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P2", Height: 110}}, map[int64]tPBlocks{}),
   248  		},
   249  	}
   250  
   251  	for _, tt := range tests {
   252  		tt := tt
   253  		t.Run(tt.name, func(t *testing.T) {
   254  			tt.pool.RemovePeer(tt.args.peerID, tt.args.err)
   255  			assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
   256  		})
   257  	}
   258  }
   259  
   260  func TestBlockPoolRemoveShortPeers(t *testing.T) {
   261  	testBcR := newTestBcR()
   262  
   263  	tests := []struct {
   264  		name       string
   265  		pool       *BlockPool
   266  		poolWanted *BlockPool
   267  	}{
   268  		{
   269  			name: "no short peers",
   270  			pool: makeBlockPool(testBcR, 100,
   271  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 110}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
   272  			poolWanted: makeBlockPool(testBcR, 100,
   273  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 110}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
   274  		},
   275  
   276  		{
   277  			name: "one short peer",
   278  			pool: makeBlockPool(testBcR, 100,
   279  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 90}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
   280  			poolWanted: makeBlockPool(testBcR, 100,
   281  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P3", Height: 120}}, map[int64]tPBlocks{}),
   282  		},
   283  
   284  		{
   285  			name: "all short peers",
   286  			pool: makeBlockPool(testBcR, 100,
   287  				[]BpPeer{{ID: "P1", Height: 90}, {ID: "P2", Height: 91}, {ID: "P3", Height: 92}}, map[int64]tPBlocks{}),
   288  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   289  		},
   290  	}
   291  
   292  	for _, tt := range tests {
   293  		tt := tt
   294  		t.Run(tt.name, func(t *testing.T) {
   295  			pool := tt.pool
   296  			pool.removeShortPeers()
   297  			assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
   298  		})
   299  	}
   300  }
   301  
   302  func TestBlockPoolSendRequestBatch(t *testing.T) {
   303  	type testPeerResult struct {
   304  		id                      p2p.ID
   305  		numPendingBlockRequests int
   306  	}
   307  
   308  	testBcR := newTestBcR()
   309  
   310  	tests := []struct {
   311  		name               string
   312  		pool               *BlockPool
   313  		maxRequestsPerPeer int
   314  		expRequests        map[int64]bool
   315  		expRequestsSent    int
   316  		expPeerResults     []testPeerResult
   317  	}{
   318  		{
   319  			name:               "one peer - send up to maxRequestsPerPeer block requests",
   320  			pool:               makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
   321  			maxRequestsPerPeer: 2,
   322  			expRequests:        map[int64]bool{10: true, 11: true},
   323  			expRequestsSent:    2,
   324  			expPeerResults:     []testPeerResult{{id: "P1", numPendingBlockRequests: 2}},
   325  		},
   326  		{
   327  			name: "multiple peers - stops at gap between height and base",
   328  			pool: makeBlockPool(testBcR, 10, []BpPeer{
   329  				{ID: "P1", Base: 1, Height: 12},
   330  				{ID: "P2", Base: 15, Height: 100},
   331  			}, map[int64]tPBlocks{}),
   332  			maxRequestsPerPeer: 10,
   333  			expRequests:        map[int64]bool{10: true, 11: true, 12: true},
   334  			expRequestsSent:    3,
   335  			expPeerResults: []testPeerResult{
   336  				{id: "P1", numPendingBlockRequests: 3},
   337  				{id: "P2", numPendingBlockRequests: 0},
   338  			},
   339  		},
   340  		{
   341  			name: "n peers - send n*maxRequestsPerPeer block requests",
   342  			pool: makeBlockPool(
   343  				testBcR,
   344  				10,
   345  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   346  				map[int64]tPBlocks{}),
   347  			maxRequestsPerPeer: 2,
   348  			expRequests:        map[int64]bool{10: true, 11: true},
   349  			expRequestsSent:    4,
   350  			expPeerResults: []testPeerResult{
   351  				{id: "P1", numPendingBlockRequests: 2},
   352  				{id: "P2", numPendingBlockRequests: 2}},
   353  		},
   354  	}
   355  
   356  	for _, tt := range tests {
   357  		tt := tt
   358  		t.Run(tt.name, func(t *testing.T) {
   359  			resetPoolTestResults()
   360  
   361  			var pool = tt.pool
   362  			maxRequestsPerPeer = tt.maxRequestsPerPeer
   363  			pool.MakeNextRequests(10)
   364  
   365  			assert.Equal(t, tt.expRequestsSent, testResults.numRequestsSent)
   366  			for _, tPeer := range tt.expPeerResults {
   367  				var peer = pool.peers[tPeer.id]
   368  				assert.NotNil(t, peer)
   369  				assert.Equal(t, tPeer.numPendingBlockRequests, peer.NumPendingBlockRequests)
   370  			}
   371  		})
   372  	}
   373  }
   374  
   375  func TestBlockPoolAddBlock(t *testing.T) {
   376  	testBcR := newTestBcR()
   377  	txs := []types.Tx{types.Tx("foo"), types.Tx("bar")}
   378  
   379  	type args struct {
   380  		peerID    p2p.ID
   381  		block     *types.Block
   382  		blockSize int
   383  	}
   384  	tests := []struct {
   385  		name       string
   386  		pool       *BlockPool
   387  		args       args
   388  		poolWanted *BlockPool
   389  		errWanted  error
   390  	}{
   391  		{name: "block from unknown peer",
   392  			pool: makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
   393  			args: args{
   394  				peerID:    "P2",
   395  				block:     types.MakeBlock(int64(10), txs, nil, nil),
   396  				blockSize: 100,
   397  			},
   398  			poolWanted: makeBlockPool(testBcR, 10, []BpPeer{{ID: "P1", Height: 100}}, map[int64]tPBlocks{}),
   399  			errWanted:  errBadDataFromPeer,
   400  		},
   401  		{name: "unexpected block 11 from known peer - waiting for 10",
   402  			pool: makeBlockPool(testBcR, 10,
   403  				[]BpPeer{{ID: "P1", Height: 100}},
   404  				map[int64]tPBlocks{10: {"P1", false}}),
   405  			args: args{
   406  				peerID:    "P1",
   407  				block:     types.MakeBlock(int64(11), txs, nil, nil),
   408  				blockSize: 100,
   409  			},
   410  			poolWanted: makeBlockPool(testBcR, 10,
   411  				[]BpPeer{{ID: "P1", Height: 100}},
   412  				map[int64]tPBlocks{10: {"P1", false}}),
   413  			errWanted: errMissingBlock,
   414  		},
   415  		{name: "unexpected block 10 from known peer - already have 10",
   416  			pool: makeBlockPool(testBcR, 10,
   417  				[]BpPeer{{ID: "P1", Height: 100}},
   418  				map[int64]tPBlocks{10: {"P1", true}, 11: {"P1", false}}),
   419  			args: args{
   420  				peerID:    "P1",
   421  				block:     types.MakeBlock(int64(10), txs, nil, nil),
   422  				blockSize: 100,
   423  			},
   424  			poolWanted: makeBlockPool(testBcR, 10,
   425  				[]BpPeer{{ID: "P1", Height: 100}},
   426  				map[int64]tPBlocks{10: {"P1", true}, 11: {"P1", false}}),
   427  			errWanted: errDuplicateBlock,
   428  		},
   429  		{name: "unexpected block 10 from known peer P2 - expected 10 to come from P1",
   430  			pool: makeBlockPool(testBcR, 10,
   431  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   432  				map[int64]tPBlocks{10: {"P1", false}}),
   433  			args: args{
   434  				peerID:    "P2",
   435  				block:     types.MakeBlock(int64(10), txs, nil, nil),
   436  				blockSize: 100,
   437  			},
   438  			poolWanted: makeBlockPool(testBcR, 10,
   439  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   440  				map[int64]tPBlocks{10: {"P1", false}}),
   441  			errWanted: errBadDataFromPeer,
   442  		},
   443  		{name: "expected block from known peer",
   444  			pool: makeBlockPool(testBcR, 10,
   445  				[]BpPeer{{ID: "P1", Height: 100}},
   446  				map[int64]tPBlocks{10: {"P1", false}}),
   447  			args: args{
   448  				peerID:    "P1",
   449  				block:     types.MakeBlock(int64(10), txs, nil, nil),
   450  				blockSize: 100,
   451  			},
   452  			poolWanted: makeBlockPool(testBcR, 10,
   453  				[]BpPeer{{ID: "P1", Height: 100}},
   454  				map[int64]tPBlocks{10: {"P1", true}}),
   455  			errWanted: nil,
   456  		},
   457  	}
   458  
   459  	for _, tt := range tests {
   460  		tt := tt
   461  		t.Run(tt.name, func(t *testing.T) {
   462  			err := tt.pool.AddBlock(tt.args.peerID, tt.args.block, tt.args.blockSize)
   463  			assert.Equal(t, tt.errWanted, err)
   464  			assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
   465  		})
   466  	}
   467  }
   468  
   469  func TestBlockPoolFirstTwoBlocksAndPeers(t *testing.T) {
   470  	testBcR := newTestBcR()
   471  
   472  	tests := []struct {
   473  		name         string
   474  		pool         *BlockPool
   475  		firstWanted  int64
   476  		secondWanted int64
   477  		errWanted    error
   478  	}{
   479  		{
   480  			name: "both blocks missing",
   481  			pool: makeBlockPool(testBcR, 10,
   482  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   483  				map[int64]tPBlocks{15: {"P1", true}, 16: {"P2", true}}),
   484  			errWanted: errMissingBlock,
   485  		},
   486  		{
   487  			name: "second block missing",
   488  			pool: makeBlockPool(testBcR, 15,
   489  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   490  				map[int64]tPBlocks{15: {"P1", true}, 18: {"P2", true}}),
   491  			firstWanted: 15,
   492  			errWanted:   errMissingBlock,
   493  		},
   494  		{
   495  			name: "first block missing",
   496  			pool: makeBlockPool(testBcR, 15,
   497  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   498  				map[int64]tPBlocks{16: {"P2", true}, 18: {"P2", true}}),
   499  			secondWanted: 16,
   500  			errWanted:    errMissingBlock,
   501  		},
   502  		{
   503  			name: "both blocks present",
   504  			pool: makeBlockPool(testBcR, 10,
   505  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   506  				map[int64]tPBlocks{10: {"P1", true}, 11: {"P2", true}}),
   507  			firstWanted:  10,
   508  			secondWanted: 11,
   509  		},
   510  	}
   511  
   512  	for _, tt := range tests {
   513  		tt := tt
   514  		t.Run(tt.name, func(t *testing.T) {
   515  			pool := tt.pool
   516  			gotFirst, gotSecond, err := pool.FirstTwoBlocksAndPeers()
   517  			assert.Equal(t, tt.errWanted, err)
   518  
   519  			if tt.firstWanted != 0 {
   520  				peer := pool.blocks[tt.firstWanted]
   521  				block := pool.peers[peer].blocks[tt.firstWanted]
   522  				assert.Equal(t, block, gotFirst.block,
   523  					"BlockPool.FirstTwoBlocksAndPeers() gotFirst = %v, want %v",
   524  					tt.firstWanted, gotFirst.block.Height)
   525  			}
   526  
   527  			if tt.secondWanted != 0 {
   528  				peer := pool.blocks[tt.secondWanted]
   529  				block := pool.peers[peer].blocks[tt.secondWanted]
   530  				assert.Equal(t, block, gotSecond.block,
   531  					"BlockPool.FirstTwoBlocksAndPeers() gotFirst = %v, want %v",
   532  					tt.secondWanted, gotSecond.block.Height)
   533  			}
   534  		})
   535  	}
   536  }
   537  
   538  func TestBlockPoolInvalidateFirstTwoBlocks(t *testing.T) {
   539  	testBcR := newTestBcR()
   540  
   541  	tests := []struct {
   542  		name       string
   543  		pool       *BlockPool
   544  		poolWanted *BlockPool
   545  	}{
   546  		{
   547  			name: "both blocks missing",
   548  			pool: makeBlockPool(testBcR, 10,
   549  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   550  				map[int64]tPBlocks{15: {"P1", true}, 16: {"P2", true}}),
   551  			poolWanted: makeBlockPool(testBcR, 10,
   552  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   553  				map[int64]tPBlocks{15: {"P1", true}, 16: {"P2", true}}),
   554  		},
   555  		{
   556  			name: "second block missing",
   557  			pool: makeBlockPool(testBcR, 15,
   558  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   559  				map[int64]tPBlocks{15: {"P1", true}, 18: {"P2", true}}),
   560  			poolWanted: makeBlockPool(testBcR, 15,
   561  				[]BpPeer{{ID: "P2", Height: 100}},
   562  				map[int64]tPBlocks{18: {"P2", true}}),
   563  		},
   564  		{
   565  			name: "first block missing",
   566  			pool: makeBlockPool(testBcR, 15,
   567  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   568  				map[int64]tPBlocks{18: {"P1", true}, 16: {"P2", true}}),
   569  			poolWanted: makeBlockPool(testBcR, 15,
   570  				[]BpPeer{{ID: "P1", Height: 100}},
   571  				map[int64]tPBlocks{18: {"P1", true}}),
   572  		},
   573  		{
   574  			name: "both blocks present",
   575  			pool: makeBlockPool(testBcR, 10,
   576  				[]BpPeer{{ID: "P1", Height: 100}, {ID: "P2", Height: 100}},
   577  				map[int64]tPBlocks{10: {"P1", true}, 11: {"P2", true}}),
   578  			poolWanted: makeBlockPool(testBcR, 10,
   579  				[]BpPeer{},
   580  				map[int64]tPBlocks{}),
   581  		},
   582  	}
   583  
   584  	for _, tt := range tests {
   585  		tt := tt
   586  		t.Run(tt.name, func(t *testing.T) {
   587  			tt.pool.InvalidateFirstTwoBlocks(errNoPeerResponse)
   588  			assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
   589  		})
   590  	}
   591  }
   592  
   593  func TestProcessedCurrentHeightBlock(t *testing.T) {
   594  	testBcR := newTestBcR()
   595  
   596  	tests := []struct {
   597  		name       string
   598  		pool       *BlockPool
   599  		poolWanted *BlockPool
   600  	}{
   601  		{
   602  			name: "one peer",
   603  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
   604  				map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", true}}),
   605  			poolWanted: makeBlockPool(testBcR, 101, []BpPeer{{ID: "P1", Height: 120}},
   606  				map[int64]tPBlocks{101: {"P1", true}}),
   607  		},
   608  		{
   609  			name: "multiple peers",
   610  			pool: makeBlockPool(testBcR, 100,
   611  				[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
   612  				map[int64]tPBlocks{
   613  					100: {"P1", true}, 104: {"P1", true}, 105: {"P1", false},
   614  					101: {"P2", true}, 103: {"P2", false},
   615  					102: {"P3", true}, 106: {"P3", true}}),
   616  			poolWanted: makeBlockPool(testBcR, 101,
   617  				[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
   618  				map[int64]tPBlocks{
   619  					104: {"P1", true}, 105: {"P1", false},
   620  					101: {"P2", true}, 103: {"P2", false},
   621  					102: {"P3", true}, 106: {"P3", true}}),
   622  		},
   623  	}
   624  
   625  	for _, tt := range tests {
   626  		tt := tt
   627  		t.Run(tt.name, func(t *testing.T) {
   628  			tt.pool.ProcessedCurrentHeightBlock()
   629  			assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
   630  		})
   631  	}
   632  }
   633  
   634  func TestRemovePeerAtCurrentHeight(t *testing.T) {
   635  	testBcR := newTestBcR()
   636  
   637  	tests := []struct {
   638  		name       string
   639  		pool       *BlockPool
   640  		poolWanted *BlockPool
   641  	}{
   642  		{
   643  			name: "one peer, remove peer for block at H",
   644  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
   645  				map[int64]tPBlocks{100: {"P1", false}, 101: {"P1", true}}),
   646  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   647  		},
   648  		{
   649  			name: "one peer, remove peer for block at H+1",
   650  			pool: makeBlockPool(testBcR, 100, []BpPeer{{ID: "P1", Height: 120}},
   651  				map[int64]tPBlocks{100: {"P1", true}, 101: {"P1", false}}),
   652  			poolWanted: makeBlockPool(testBcR, 100, []BpPeer{}, map[int64]tPBlocks{}),
   653  		},
   654  		{
   655  			name: "multiple peers, remove peer for block at H",
   656  			pool: makeBlockPool(testBcR, 100,
   657  				[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
   658  				map[int64]tPBlocks{
   659  					100: {"P1", false}, 104: {"P1", true}, 105: {"P1", false},
   660  					101: {"P2", true}, 103: {"P2", false},
   661  					102: {"P3", true}, 106: {"P3", true}}),
   662  			poolWanted: makeBlockPool(testBcR, 100,
   663  				[]BpPeer{{ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
   664  				map[int64]tPBlocks{
   665  					101: {"P2", true}, 103: {"P2", false},
   666  					102: {"P3", true}, 106: {"P3", true}}),
   667  		},
   668  		{
   669  			name: "multiple peers, remove peer for block at H+1",
   670  			pool: makeBlockPool(testBcR, 100,
   671  				[]BpPeer{{ID: "P1", Height: 120}, {ID: "P2", Height: 120}, {ID: "P3", Height: 130}},
   672  				map[int64]tPBlocks{
   673  					100: {"P1", true}, 104: {"P1", true}, 105: {"P1", false},
   674  					101: {"P2", false}, 103: {"P2", false},
   675  					102: {"P3", true}, 106: {"P3", true}}),
   676  			poolWanted: makeBlockPool(testBcR, 100,
   677  				[]BpPeer{{ID: "P1", Height: 120}, {ID: "P3", Height: 130}},
   678  				map[int64]tPBlocks{
   679  					100: {"P1", true}, 104: {"P1", true}, 105: {"P1", false},
   680  					102: {"P3", true}, 106: {"P3", true}}),
   681  		},
   682  	}
   683  
   684  	for _, tt := range tests {
   685  		tt := tt
   686  		t.Run(tt.name, func(t *testing.T) {
   687  			tt.pool.RemovePeerAtCurrentHeights(errNoPeerResponse)
   688  			assertBlockPoolEquivalent(t, tt.poolWanted, tt.pool)
   689  		})
   690  	}
   691  }