github.com/MetalBlockchain/metalgo@v1.11.9/snow/consensus/snowman/poll/set_test.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package poll
     5  
     6  import (
     7  	"testing"
     8  
     9  	"github.com/prometheus/client_golang/prometheus"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/MetalBlockchain/metalgo/ids"
    13  	"github.com/MetalBlockchain/metalgo/utils/bag"
    14  	"github.com/MetalBlockchain/metalgo/utils/logging"
    15  )
    16  
    17  var (
    18  	blkID1 = ids.ID{1}
    19  	blkID2 = ids.ID{2}
    20  	blkID3 = ids.ID{3}
    21  	blkID4 = ids.ID{4}
    22  
    23  	vdr1 = ids.BuildTestNodeID([]byte{0x01})
    24  	vdr2 = ids.BuildTestNodeID([]byte{0x02})
    25  	vdr3 = ids.BuildTestNodeID([]byte{0x03})
    26  	vdr4 = ids.BuildTestNodeID([]byte{0x04})
    27  	vdr5 = ids.BuildTestNodeID([]byte{0x05}) // k = 5
    28  )
    29  
    30  func TestNewSetErrorOnPollsMetrics(t *testing.T) {
    31  	require := require.New(t)
    32  
    33  	alpha := 1
    34  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
    35  	log := logging.NoLog{}
    36  	registerer := prometheus.NewRegistry()
    37  
    38  	require.NoError(registerer.Register(prometheus.NewCounter(prometheus.CounterOpts{
    39  		Name: "polls",
    40  	})))
    41  
    42  	_, err := NewSet(factory, log, registerer)
    43  	require.ErrorIs(err, errFailedPollsMetric)
    44  }
    45  
    46  func TestNewSetErrorOnPollDurationMetrics(t *testing.T) {
    47  	require := require.New(t)
    48  
    49  	alpha := 1
    50  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
    51  	log := logging.NoLog{}
    52  	registerer := prometheus.NewRegistry()
    53  
    54  	require.NoError(registerer.Register(prometheus.NewCounter(prometheus.CounterOpts{
    55  		Name: "poll_duration_count",
    56  	})))
    57  
    58  	_, err := NewSet(factory, log, registerer)
    59  	require.ErrorIs(err, errFailedPollDurationMetrics)
    60  }
    61  
    62  func TestCreateAndFinishPollOutOfOrder_NewerFinishesFirst(t *testing.T) {
    63  	require := require.New(t)
    64  
    65  	vdrs := []ids.NodeID{vdr1, vdr2, vdr3} // k = 3
    66  	alpha := 3
    67  
    68  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
    69  	log := logging.NoLog{}
    70  	registerer := prometheus.NewRegistry()
    71  	s, err := NewSet(factory, log, registerer)
    72  	require.NoError(err)
    73  
    74  	// create two polls for the two blocks
    75  	vdrBag := bag.Of(vdrs...)
    76  	require.True(s.Add(1, vdrBag))
    77  
    78  	vdrBag = bag.Of(vdrs...)
    79  	require.True(s.Add(2, vdrBag))
    80  	require.Equal(2, s.Len())
    81  
    82  	// vote out of order
    83  	require.Empty(s.Vote(1, vdr1, blkID1))
    84  	require.Empty(s.Vote(2, vdr2, blkID2))
    85  	require.Empty(s.Vote(2, vdr3, blkID2))
    86  
    87  	// poll 2 finished
    88  	require.Empty(s.Vote(2, vdr1, blkID2)) // expect 2 to not have finished because 1 is still pending
    89  
    90  	require.Empty(s.Vote(1, vdr2, blkID1))
    91  
    92  	results := s.Vote(1, vdr3, blkID1) // poll 1 finished, poll 2 should be finished as well
    93  	require.Len(results, 2)
    94  	require.Equal(blkID1, results[0].List()[0])
    95  	require.Equal(blkID2, results[1].List()[0])
    96  }
    97  
    98  func TestCreateAndFinishPollOutOfOrder_OlderFinishesFirst(t *testing.T) {
    99  	require := require.New(t)
   100  
   101  	vdrs := []ids.NodeID{vdr1, vdr2, vdr3} // k = 3
   102  	alpha := 3
   103  
   104  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
   105  	log := logging.NoLog{}
   106  	registerer := prometheus.NewRegistry()
   107  	s, err := NewSet(factory, log, registerer)
   108  	require.NoError(err)
   109  
   110  	// create two polls for the two blocks
   111  	vdrBag := bag.Of(vdrs...)
   112  	require.True(s.Add(1, vdrBag))
   113  
   114  	vdrBag = bag.Of(vdrs...)
   115  	require.True(s.Add(2, vdrBag))
   116  	require.Equal(2, s.Len())
   117  
   118  	// vote out of order
   119  	require.Empty(s.Vote(1, vdr1, blkID1))
   120  	require.Empty(s.Vote(2, vdr2, blkID2))
   121  	require.Empty(s.Vote(2, vdr3, blkID2))
   122  
   123  	require.Empty(s.Vote(1, vdr2, blkID1))
   124  
   125  	results := s.Vote(1, vdr3, blkID1) // poll 1 finished, poll 2 still remaining
   126  	require.Len(results, 1)            // because 1 is the oldest
   127  	require.Equal(blkID1, results[0].List()[0])
   128  
   129  	results = s.Vote(2, vdr1, blkID2) // poll 2 finished
   130  	require.Len(results, 1)           // because 2 is the oldest now
   131  	require.Equal(blkID2, results[0].List()[0])
   132  }
   133  
   134  func TestCreateAndFinishPollOutOfOrder_UnfinishedPollsGaps(t *testing.T) {
   135  	require := require.New(t)
   136  
   137  	vdrs := []ids.NodeID{vdr1, vdr2, vdr3} // k = 3
   138  	alpha := 3
   139  
   140  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
   141  	log := logging.NoLog{}
   142  	registerer := prometheus.NewRegistry()
   143  	s, err := NewSet(factory, log, registerer)
   144  	require.NoError(err)
   145  
   146  	// create three polls for the two blocks
   147  	vdrBag := bag.Of(vdrs...)
   148  	require.True(s.Add(1, vdrBag))
   149  
   150  	vdrBag = bag.Of(vdrs...)
   151  	require.True(s.Add(2, vdrBag))
   152  
   153  	vdrBag = bag.Of(vdrs...)
   154  	require.True(s.Add(3, vdrBag))
   155  	require.Equal(3, s.Len())
   156  
   157  	// vote out of order
   158  	// 2 finishes first to create a gap of finished poll between two unfinished polls 1 and 3
   159  	require.Empty(s.Vote(2, vdr3, blkID2))
   160  	require.Empty(s.Vote(2, vdr2, blkID2))
   161  	require.Empty(s.Vote(2, vdr1, blkID2))
   162  
   163  	// 3 finishes now, 2 has already finished but 1 is not finished so we expect to receive no results still
   164  	require.Empty(s.Vote(3, vdr2, blkID3))
   165  	require.Empty(s.Vote(3, vdr3, blkID3))
   166  	require.Empty(s.Vote(3, vdr1, blkID3))
   167  
   168  	// 1 finishes now, 2 and 3 have already finished so we expect 3 items in results
   169  	require.Empty(s.Vote(1, vdr1, blkID1))
   170  	require.Empty(s.Vote(1, vdr2, blkID1))
   171  	results := s.Vote(1, vdr3, blkID1)
   172  	require.Len(results, 3)
   173  	require.Equal(blkID1, results[0].List()[0])
   174  	require.Equal(blkID2, results[1].List()[0])
   175  	require.Equal(blkID3, results[2].List()[0])
   176  }
   177  
   178  func TestCreateAndFinishSuccessfulPoll(t *testing.T) {
   179  	require := require.New(t)
   180  
   181  	vdrs := bag.Of(vdr1, vdr2) // k = 2
   182  	alpha := 2
   183  
   184  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
   185  	log := logging.NoLog{}
   186  	registerer := prometheus.NewRegistry()
   187  	s, err := NewSet(factory, log, registerer)
   188  	require.NoError(err)
   189  
   190  	require.Zero(s.Len())
   191  
   192  	require.True(s.Add(0, vdrs))
   193  	require.Equal(1, s.Len())
   194  
   195  	require.False(s.Add(0, vdrs))
   196  	require.Equal(1, s.Len())
   197  
   198  	require.Empty(s.Vote(1, vdr1, blkID1))
   199  	require.Empty(s.Vote(0, vdr1, blkID1))
   200  	require.Empty(s.Vote(0, vdr1, blkID1))
   201  
   202  	results := s.Vote(0, vdr2, blkID1)
   203  	require.Len(results, 1)
   204  	list := results[0].List()
   205  	require.Len(list, 1)
   206  	require.Equal(blkID1, list[0])
   207  	require.Equal(2, results[0].Count(blkID1))
   208  }
   209  
   210  func TestCreateAndFinishFailedPoll(t *testing.T) {
   211  	require := require.New(t)
   212  
   213  	vdrs := bag.Of(vdr1, vdr2) // k = 2
   214  	alpha := 1
   215  
   216  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
   217  	log := logging.NoLog{}
   218  	registerer := prometheus.NewRegistry()
   219  	s, err := NewSet(factory, log, registerer)
   220  	require.NoError(err)
   221  
   222  	require.Zero(s.Len())
   223  
   224  	require.True(s.Add(0, vdrs))
   225  	require.Equal(1, s.Len())
   226  
   227  	require.False(s.Add(0, vdrs))
   228  	require.Equal(1, s.Len())
   229  
   230  	require.Empty(s.Drop(1, vdr1))
   231  	require.Empty(s.Drop(0, vdr1))
   232  	require.Empty(s.Drop(0, vdr1))
   233  
   234  	results := s.Drop(0, vdr2)
   235  	require.Len(results, 1)
   236  	require.Empty(results[0].List())
   237  }
   238  
   239  func TestSetString(t *testing.T) {
   240  	require := require.New(t)
   241  
   242  	vdrs := bag.Of(vdr1) // k = 1
   243  	alpha := 1
   244  
   245  	factory := newEarlyTermNoTraversalTestFactory(require, alpha)
   246  	log := logging.NoLog{}
   247  	registerer := prometheus.NewRegistry()
   248  	s, err := NewSet(factory, log, registerer)
   249  	require.NoError(err)
   250  
   251  	expected := `current polls: (Size = 1)
   252      RequestID 0:
   253          waiting on Bag[ids.NodeID]: (Size = 1)
   254              NodeID-6HgC8KRBEhXYbF4riJyJFLSHt37UNuRt: 1
   255          received Bag[ids.ID]: (Size = 0)`
   256  	require.True(s.Add(0, vdrs))
   257  	require.Equal(expected, s.String())
   258  }