github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/forkchoice/protoarray/vote_test.go (about) 1 package protoarray 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/prysmaticlabs/prysm/shared/params" 8 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 9 "github.com/prysmaticlabs/prysm/shared/testutil/require" 10 ) 11 12 func TestVotes_CanFindHead(t *testing.T) { 13 balances := []uint64{1, 1} 14 f := setup(1, 1) 15 16 // The head should always start at the finalized block. 17 r, err := f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 18 require.NoError(t, err) 19 assert.Equal(t, params.BeaconConfig().ZeroHash, r, "Incorrect head with genesis") 20 21 // Insert block 2 into the tree and verify head is at 2: 22 // 0 23 // / 24 // 2 <- head 25 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(2), params.BeaconConfig().ZeroHash, [32]byte{}, 1, 1)) 26 27 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 28 require.NoError(t, err) 29 assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1") 30 31 // Insert block 1 into the tree and verify head is still at 2: 32 // 0 33 // / \ 34 // head -> 2 1 35 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(1), params.BeaconConfig().ZeroHash, [32]byte{}, 1, 1)) 36 37 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 38 require.NoError(t, err) 39 assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1") 40 41 // Add a vote to block 1 of the tree and verify head is switched to 1: 42 // 0 43 // / \ 44 // 2 1 <- +vote, new head 45 f.ProcessAttestation(context.Background(), []uint64{0}, indexToHash(1), 2) 46 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 47 require.NoError(t, err) 48 assert.Equal(t, indexToHash(1), r, "Incorrect head for with justified epoch at 1") 49 50 // Add a vote to block 2 of the tree and verify head is switched to 2: 51 // 0 52 // / \ 53 // vote, new head -> 2 1 54 f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(2), 2) 55 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 56 require.NoError(t, err) 57 assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1") 58 59 // Insert block 3 into the tree and verify head is still at 2: 60 // 0 61 // / \ 62 // head -> 2 1 63 // | 64 // 3 65 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(3), indexToHash(1), [32]byte{}, 1, 1)) 66 67 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 68 require.NoError(t, err) 69 assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1") 70 71 // Move validator 0's vote from 1 to 3 and verify head is still at 2: 72 // 0 73 // / \ 74 // head -> 2 1 <- old vote 75 // | 76 // 3 <- new vote 77 f.ProcessAttestation(context.Background(), []uint64{0}, indexToHash(3), 3) 78 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 79 require.NoError(t, err) 80 assert.Equal(t, indexToHash(2), r, "Incorrect head for with justified epoch at 1") 81 82 // Move validator 1's vote from 2 to 1 and verify head is switched to 3: 83 // 0 84 // / \ 85 // old vote -> 2 1 <- new vote 86 // | 87 // 3 <- head 88 f.ProcessAttestation(context.Background(), []uint64{1}, indexToHash(1), 3) 89 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 90 require.NoError(t, err) 91 assert.Equal(t, indexToHash(3), r, "Incorrect head for with justified epoch at 1") 92 93 // Insert block 4 into the tree and verify head is at 4: 94 // 0 95 // / \ 96 // 2 1 97 // | 98 // 3 99 // | 100 // 4 <- head 101 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(4), indexToHash(3), [32]byte{}, 1, 1)) 102 103 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 104 require.NoError(t, err) 105 assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1") 106 107 // Insert block 5 with justified epoch 2, it should be filtered out: 108 // 0 109 // / \ 110 // 2 1 111 // | 112 // 3 113 // | 114 // 4 <- head 115 // / 116 // 5 <- justified epoch = 2 117 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(5), indexToHash(4), [32]byte{}, 2, 2)) 118 119 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 120 require.NoError(t, err) 121 assert.Equal(t, indexToHash(4), r, "Incorrect head for with justified epoch at 1") 122 123 // Insert block 6 with justified epoch 0: 124 // 0 125 // / \ 126 // 2 1 127 // | 128 // 3 129 // | 130 // 4 <- head 131 // / \ 132 // 5 6 <- justified epoch = 0 133 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(6), indexToHash(4), [32]byte{}, 1, 1)) 134 135 // Moved 2 votes to block 5: 136 // 0 137 // / \ 138 // 2 1 139 // | 140 // 3 141 // | 142 // 4 143 // / \ 144 // 2 votes-> 5 6 145 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(6), indexToHash(4), [32]byte{}, 1, 1)) 146 147 f.ProcessAttestation(context.Background(), []uint64{0, 1}, indexToHash(5), 4) 148 149 // Inset blocks 7, 8 and 9: 150 // 6 should still be the head, even though 5 has all the votes. 151 // 0 152 // / \ 153 // 2 1 154 // | 155 // 3 156 // | 157 // 4 158 // / \ 159 // 5 6 <- head 160 // | 161 // 7 162 // | 163 // 8 164 // | 165 // 9 166 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(7), indexToHash(5), [32]byte{}, 2, 2)) 167 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(8), indexToHash(7), [32]byte{}, 2, 2)) 168 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(9), indexToHash(8), [32]byte{}, 2, 2)) 169 170 r, err = f.Head(context.Background(), 1, params.BeaconConfig().ZeroHash, balances, 1) 171 require.NoError(t, err) 172 assert.Equal(t, indexToHash(6), r, "Incorrect head for with justified epoch at 1") 173 174 // Update fork choice justified epoch to 1 and start block to 5. 175 // Verify 9 is the head: 176 // 0 177 // / \ 178 // 2 1 179 // | 180 // 3 181 // | 182 // 4 183 // / \ 184 // 5 6 185 // | 186 // 7 187 // | 188 // 8 189 // | 190 // 9 <- head 191 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 192 require.NoError(t, err) 193 assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2") 194 195 // Insert block 10 and 2 validators updated their vote to 9. 196 // Verify 9 is the head: 197 // 0 198 // / \ 199 // 2 1 200 // | 201 // 3 202 // | 203 // 4 204 // / \ 205 // 5 6 206 // | 207 // 7 208 // | 209 // 8 210 // / \ 211 // 2 votes->9 10 212 f.ProcessAttestation(context.Background(), []uint64{0, 1}, indexToHash(9), 5) 213 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(10), indexToHash(8), [32]byte{}, 2, 2)) 214 215 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 216 require.NoError(t, err) 217 assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2") 218 219 // Add 3 more validators to the system. 220 balances = []uint64{1, 1, 1, 1, 1} 221 // The new validators voted for 10. 222 f.ProcessAttestation(context.Background(), []uint64{2, 3, 4}, indexToHash(10), 5) 223 // The new head should be 10. 224 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 225 require.NoError(t, err) 226 assert.Equal(t, indexToHash(10), r, "Incorrect head for with justified epoch at 2") 227 228 // Set the balances of the last 2 validators to 0. 229 balances = []uint64{1, 1, 1, 0, 0} 230 // The head should be back to 9. 231 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 232 require.NoError(t, err) 233 assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1") 234 235 // Set the balances back to normal. 236 balances = []uint64{1, 1, 1, 1, 1} 237 // The head should be back to 10. 238 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 239 require.NoError(t, err) 240 assert.Equal(t, indexToHash(10), r, "Incorrect head for with justified epoch at 2") 241 242 // Remove the last 2 validators. 243 balances = []uint64{1, 1, 1} 244 // The head should be back to 9. 245 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 246 require.NoError(t, err) 247 assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 1") 248 249 // Verify pruning below the prune threshold does not affect head. 250 f.store.pruneThreshold = 1000 251 require.NoError(t, f.store.prune(context.Background(), indexToHash(5))) 252 assert.Equal(t, 11, len(f.store.nodes), "Incorrect nodes length after prune") 253 254 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 255 require.NoError(t, err) 256 assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2") 257 258 // Verify pruning above the prune threshold does prune: 259 // 0 260 // / \ 261 // 2 1 262 // | 263 // 3 264 // | 265 // 4 266 // -------pruned here ------ 267 // 5 6 268 // | 269 // 7 270 // | 271 // 8 272 // / \ 273 // 9 10 274 f.store.pruneThreshold = 1 275 require.NoError(t, f.store.prune(context.Background(), indexToHash(5))) 276 assert.Equal(t, 6, len(f.store.nodes), "Incorrect nodes length after prune") 277 278 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 279 require.NoError(t, err) 280 assert.Equal(t, indexToHash(9), r, "Incorrect head for with justified epoch at 2") 281 282 // Insert new block 11 and verify head is at 11. 283 // 5 6 284 // | 285 // 7 286 // | 287 // 8 288 // / \ 289 // 9 10 290 // | 291 // head-> 11 292 require.NoError(t, f.ProcessBlock(context.Background(), 0, indexToHash(11), indexToHash(9), [32]byte{}, 2, 2)) 293 294 r, err = f.Head(context.Background(), 2, indexToHash(5), balances, 2) 295 require.NoError(t, err) 296 assert.Equal(t, indexToHash(11), r, "Incorrect head for with justified epoch at 2") 297 }