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 }