github.com/koko1123/flow-go-1@v0.29.6/state/protocol/badger/snapshot_test.go (about) 1 // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED 2 3 package badger_test 4 5 import ( 6 "context" 7 "errors" 8 "math/rand" 9 "testing" 10 "time" 11 12 "github.com/dgraph-io/badger/v3" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/koko1123/flow-go-1/model/flow" 17 "github.com/koko1123/flow-go-1/model/flow/factory" 18 "github.com/koko1123/flow-go-1/model/flow/filter" 19 "github.com/koko1123/flow-go-1/state/protocol" 20 bprotocol "github.com/koko1123/flow-go-1/state/protocol/badger" 21 "github.com/koko1123/flow-go-1/state/protocol/inmem" 22 "github.com/koko1123/flow-go-1/state/protocol/seed" 23 "github.com/koko1123/flow-go-1/state/protocol/util" 24 "github.com/koko1123/flow-go-1/utils/unittest" 25 ) 26 27 func init() { 28 rand.Seed(time.Now().UnixNano()) 29 } 30 31 func TestHead(t *testing.T) { 32 participants := unittest.IdentityListFixture(5, unittest.WithAllRoles()) 33 rootSnapshot := unittest.RootSnapshotFixture(participants) 34 head, err := rootSnapshot.Head() 35 require.NoError(t, err) 36 util.RunWithBootstrapState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.State) { 37 38 t.Run("works with block number", func(t *testing.T) { 39 retrieved, err := state.AtHeight(head.Height).Head() 40 require.NoError(t, err) 41 require.Equal(t, head.ID(), retrieved.ID()) 42 }) 43 44 t.Run("works with block id", func(t *testing.T) { 45 retrieved, err := state.AtBlockID(head.ID()).Head() 46 require.NoError(t, err) 47 require.Equal(t, head.ID(), retrieved.ID()) 48 }) 49 50 t.Run("works with finalized block", func(t *testing.T) { 51 retrieved, err := state.Final().Head() 52 require.NoError(t, err) 53 require.Equal(t, head.ID(), retrieved.ID()) 54 }) 55 }) 56 } 57 58 // TestSnapshot_Params tests retrieving global protocol state parameters from 59 // a protocol state snapshot. 60 func TestSnapshot_Params(t *testing.T) { 61 participants := unittest.IdentityListFixture(5, unittest.WithAllRoles()) 62 rootSnapshot := unittest.RootSnapshotFixture(participants) 63 64 expectedChainID, err := rootSnapshot.Params().ChainID() 65 require.NoError(t, err) 66 expectedSporkID, err := rootSnapshot.Params().SporkID() 67 require.NoError(t, err) 68 expectedProtocolVersion, err := rootSnapshot.Params().ProtocolVersion() 69 require.NoError(t, err) 70 71 rootHeader, err := rootSnapshot.Head() 72 require.NoError(t, err) 73 74 util.RunWithFullProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.MutableState) { 75 // build some non-root blocks 76 head := rootHeader 77 const nBlocks = 10 78 for i := 0; i < nBlocks; i++ { 79 next := unittest.BlockWithParentFixture(head) 80 err = state.Extend(context.Background(), next) 81 require.NoError(t, err) 82 err = state.Finalize(context.Background(), next.ID()) 83 require.NoError(t, err) 84 head = next.Header 85 } 86 87 // test params from both root, final, and in between 88 snapshots := []protocol.Snapshot{ 89 state.AtHeight(0), 90 state.AtHeight(uint64(rand.Intn(nBlocks))), 91 state.Final(), 92 } 93 for _, snapshot := range snapshots { 94 t.Run("should be able to get chain ID from snapshot", func(t *testing.T) { 95 chainID, err := snapshot.Params().ChainID() 96 require.NoError(t, err) 97 assert.Equal(t, expectedChainID, chainID) 98 }) 99 t.Run("should be able to get spork ID from snapshot", func(t *testing.T) { 100 sporkID, err := snapshot.Params().SporkID() 101 require.NoError(t, err) 102 assert.Equal(t, expectedSporkID, sporkID) 103 }) 104 t.Run("should be able to get protocol version from snapshot", func(t *testing.T) { 105 protocolVersion, err := snapshot.Params().ProtocolVersion() 106 require.NoError(t, err) 107 assert.Equal(t, expectedProtocolVersion, protocolVersion) 108 }) 109 } 110 }) 111 } 112 113 // TestSnapshot_Descendants builds a sample chain with next structure: 114 // 115 // A (finalized) <- B <- C <- D <- E <- F 116 // <- G <- H <- I <- J 117 // 118 // snapshot.Descendants has to return [B, C, D, E, F, G, H, I, J]. 119 func TestSnapshot_Descendants(t *testing.T) { 120 participants := unittest.IdentityListFixture(5, unittest.WithAllRoles()) 121 rootSnapshot := unittest.RootSnapshotFixture(participants) 122 head, err := rootSnapshot.Head() 123 require.NoError(t, err) 124 util.RunWithFullProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.MutableState) { 125 var expectedBlocks []flow.Identifier 126 for i := 5; i > 3; i-- { 127 for _, block := range unittest.ChainFixtureFrom(i, head) { 128 err := state.Extend(context.Background(), block) 129 require.NoError(t, err) 130 expectedBlocks = append(expectedBlocks, block.ID()) 131 } 132 } 133 134 pendingBlocks, err := state.AtBlockID(head.ID()).Descendants() 135 require.NoError(t, err) 136 require.ElementsMatch(t, expectedBlocks, pendingBlocks) 137 }) 138 } 139 140 // TestSnapshot_ValidDescendants builds a sample chain with next structure: 141 // 142 // A (finalized) <- B <- C <- D <- E <- F 143 // <- G <- H <- I <- J 144 // 145 // snapshot.Descendants has to return [B, C, D, E, G, H, I]. [F, J] should be excluded because they aren't valid 146 func TestSnapshot_ValidDescendants(t *testing.T) { 147 participants := unittest.IdentityListFixture(5, unittest.WithAllRoles()) 148 rootSnapshot := unittest.RootSnapshotFixture(participants) 149 head, err := rootSnapshot.Head() 150 require.NoError(t, err) 151 util.RunWithFullProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.MutableState) { 152 var expectedBlocks []flow.Identifier 153 for i := 5; i > 3; i-- { 154 fork := unittest.ChainFixtureFrom(i, head) 155 for blockIndex, block := range fork { 156 err := state.Extend(context.Background(), block) 157 require.NoError(t, err) 158 // skip last block from fork 159 if blockIndex < len(fork)-1 { 160 err = state.MarkValid(block.ID()) 161 require.NoError(t, err) 162 expectedBlocks = append(expectedBlocks, block.ID()) 163 } 164 } 165 } 166 167 pendingBlocks, err := state.AtBlockID(head.ID()).ValidDescendants() 168 require.NoError(t, err) 169 require.ElementsMatch(t, expectedBlocks, pendingBlocks) 170 }) 171 } 172 173 func TestIdentities(t *testing.T) { 174 identities := unittest.IdentityListFixture(5, unittest.WithAllRoles()) 175 rootSnapshot := unittest.RootSnapshotFixture(identities) 176 util.RunWithBootstrapState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.State) { 177 178 t.Run("no filter", func(t *testing.T) { 179 actual, err := state.Final().Identities(filter.Any) 180 require.Nil(t, err) 181 assert.ElementsMatch(t, identities, actual) 182 }) 183 184 t.Run("single identity", func(t *testing.T) { 185 expected := identities.Sample(1)[0] 186 actual, err := state.Final().Identity(expected.NodeID) 187 require.Nil(t, err) 188 assert.Equal(t, expected, actual) 189 }) 190 191 t.Run("filtered", func(t *testing.T) { 192 filters := []flow.IdentityFilter{ 193 filter.HasRole(flow.RoleCollection), 194 filter.HasNodeID(identities.SamplePct(0.1).NodeIDs()...), 195 filter.HasWeight(true), 196 } 197 198 for _, filterfunc := range filters { 199 expected := identities.Filter(filterfunc) 200 actual, err := state.Final().Identities(filterfunc) 201 require.Nil(t, err) 202 assert.ElementsMatch(t, expected, actual) 203 } 204 }) 205 }) 206 } 207 208 func TestClusters(t *testing.T) { 209 nClusters := 3 210 nCollectors := 7 211 212 collectors := unittest.IdentityListFixture(nCollectors, unittest.WithRole(flow.RoleCollection)) 213 identities := append(unittest.IdentityListFixture(4, unittest.WithAllRolesExcept(flow.RoleCollection)), collectors...) 214 215 root, result, seal := unittest.BootstrapFixture(identities) 216 qc := unittest.QuorumCertificateFixture(unittest.QCWithBlockID(root.ID())) 217 setup := result.ServiceEvents[0].Event.(*flow.EpochSetup) 218 commit := result.ServiceEvents[1].Event.(*flow.EpochCommit) 219 setup.Assignments = unittest.ClusterAssignment(uint(nClusters), collectors) 220 clusterQCs := unittest.QuorumCertificatesFromAssignments(setup.Assignments) 221 commit.ClusterQCs = flow.ClusterQCVoteDatasFromQCs(clusterQCs) 222 seal.ResultID = result.ID() 223 224 rootSnapshot, err := inmem.SnapshotFromBootstrapState(root, result, seal, qc) 225 require.NoError(t, err) 226 227 util.RunWithBootstrapState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.State) { 228 expectedClusters, err := factory.NewClusterList(setup.Assignments, collectors) 229 require.NoError(t, err) 230 actualClusters, err := state.Final().Epochs().Current().Clustering() 231 require.NoError(t, err) 232 233 require.Equal(t, nClusters, len(expectedClusters)) 234 require.Equal(t, len(expectedClusters), len(actualClusters)) 235 236 for i := 0; i < nClusters; i++ { 237 expected := expectedClusters[i] 238 actual := actualClusters[i] 239 240 assert.Equal(t, len(expected), len(actual)) 241 assert.Equal(t, expected.Fingerprint(), actual.Fingerprint()) 242 } 243 }) 244 } 245 246 // TestSealingSegment tests querying sealing segment with respect to various snapshots. 247 // 248 // For each valid sealing segment, we also test bootstrapping with this sealing segment. 249 func TestSealingSegment(t *testing.T) { 250 identities := unittest.CompleteIdentitySet() 251 rootSnapshot := unittest.RootSnapshotFixture(identities) 252 head, err := rootSnapshot.Head() 253 require.NoError(t, err) 254 255 t.Run("root sealing segment", func(t *testing.T) { 256 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 257 expected, err := rootSnapshot.SealingSegment() 258 require.NoError(t, err) 259 actual, err := state.AtBlockID(head.ID()).SealingSegment() 260 require.NoError(t, err) 261 262 assert.Len(t, actual.ExecutionResults, 1) 263 assert.Len(t, actual.Blocks, 1) 264 unittest.AssertEqualBlocksLenAndOrder(t, expected.Blocks, actual.Blocks) 265 266 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(head.ID())) 267 }) 268 }) 269 270 // test sealing segment for non-root segment where the latest seal is the 271 // root seal, but the segment contains more than the root block. 272 // ROOT <- B1 273 // Expected sealing segment: [ROOT, B1] 274 t.Run("non-root with root seal as latest seal", func(t *testing.T) { 275 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 276 // build an extra block on top of root 277 block1 := unittest.BlockWithParentFixture(head) 278 buildBlock(t, state, block1) 279 280 segment, err := state.AtBlockID(block1.ID()).SealingSegment() 281 require.NoError(t, err) 282 283 // build a valid child B2 to ensure we have a QC 284 buildBlock(t, state, unittest.BlockWithParentFixture(block1.Header)) 285 286 // sealing segment should contain B1 and B2 287 // B2 is reference of snapshot, B1 is latest sealed 288 unittest.AssertEqualBlocksLenAndOrder(t, []*flow.Block{rootSnapshot.Encodable().SealingSegment.Lowest(), block1}, segment.Blocks) 289 assert.Len(t, segment.ExecutionResults, 1) 290 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(block1.ID())) 291 }) 292 }) 293 294 // test sealing segment for non-root segment with simple sealing structure 295 // (no blocks in between reference block and latest sealed) 296 // ROOT <- B1 <- B2(S1) 297 // Expected sealing segment: [B1, B2] 298 t.Run("non-root", func(t *testing.T) { 299 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 300 // build a block to seal 301 block1 := unittest.BlockWithParentFixture(head) 302 buildBlock(t, state, block1) 303 304 // build a block sealing block1 305 block2 := unittest.BlockWithParentFixture(block1.Header) 306 receipt1, seal1 := unittest.ReceiptAndSealForBlock(block1) 307 block2.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receipt1), unittest.WithSeals(seal1))) 308 buildBlock(t, state, block2) 309 310 segment, err := state.AtBlockID(block2.ID()).SealingSegment() 311 require.NoError(t, err) 312 313 // build a valid child B3 to ensure we have a QC 314 buildBlock(t, state, unittest.BlockWithParentFixture(block2.Header)) 315 316 // sealing segment should contain B1 and B2 317 // B2 is reference of snapshot, B1 is latest sealed 318 unittest.AssertEqualBlocksLenAndOrder(t, []*flow.Block{block1, block2}, segment.Blocks) 319 assert.Len(t, segment.ExecutionResults, 1) 320 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(block2.ID())) 321 }) 322 }) 323 324 // test sealing segment for sealing segment with a large number of blocks 325 // between the reference block and latest sealed 326 // ROOT <- B1 <- .... <- BN(S1) 327 // Expected sealing segment: [B1, ..., BN] 328 t.Run("long sealing segment", func(t *testing.T) { 329 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 330 331 // build a block to seal 332 block1 := unittest.BlockWithParentFixture(head) 333 buildBlock(t, state, block1) 334 335 parent := block1 336 // build a large chain of intermediary blocks 337 for i := 0; i < 100; i++ { 338 next := unittest.BlockWithParentFixture(parent.Header) 339 buildBlock(t, state, next) 340 parent = next 341 } 342 343 // build the block sealing block 1 344 blockN := unittest.BlockWithParentFixture(parent.Header) 345 receipt1, seal1 := unittest.ReceiptAndSealForBlock(block1) 346 blockN.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receipt1), unittest.WithSeals(seal1))) 347 buildBlock(t, state, blockN) 348 349 // build a valid child B3 to ensure we have a QC 350 buildBlock(t, state, unittest.BlockWithParentFixture(blockN.Header)) 351 352 segment, err := state.AtBlockID(blockN.ID()).SealingSegment() 353 require.NoError(t, err) 354 355 assert.Len(t, segment.ExecutionResults, 1) 356 // sealing segment should cover range [B1, BN] 357 assert.Len(t, segment.Blocks, 102) 358 // first and last blocks should be B1, BN 359 assert.Equal(t, block1.ID(), segment.Blocks[0].ID()) 360 assert.Equal(t, blockN.ID(), segment.Blocks[101].ID()) 361 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(blockN.ID())) 362 }) 363 }) 364 365 // test sealing segment where the segment blocks contain seals for 366 // ancestor blocks prior to the sealing segment 367 // ROOT <- B1 <- B2(R1) <- B3 <- B4(R2, S1) <- B5 <- B6(S2) 368 // Expected sealing segment: [B2, B3, B4] 369 t.Run("overlapping sealing segment", func(t *testing.T) { 370 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 371 372 block1 := unittest.BlockWithParentFixture(head) 373 buildBlock(t, state, block1) 374 receipt1, seal1 := unittest.ReceiptAndSealForBlock(block1) 375 376 block2 := unittest.BlockWithParentFixture(block1.Header) 377 block2.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receipt1))) 378 buildBlock(t, state, block2) 379 380 receipt2, seal2 := unittest.ReceiptAndSealForBlock(block2) 381 382 block3 := unittest.BlockWithParentFixture(block2.Header) 383 buildBlock(t, state, block3) 384 385 block4 := unittest.BlockWithParentFixture(block3.Header) 386 block4.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receipt2), unittest.WithSeals(seal1))) 387 buildBlock(t, state, block4) 388 389 block5 := unittest.BlockWithParentFixture(block4.Header) 390 buildBlock(t, state, block5) 391 392 block6 := unittest.BlockWithParentFixture(block5.Header) 393 block6.SetPayload(unittest.PayloadFixture(unittest.WithSeals(seal2))) 394 buildBlock(t, state, block6) 395 396 segment, err := state.AtBlockID(block6.ID()).SealingSegment() 397 require.NoError(t, err) 398 399 // build a valid child to ensure we have a QC 400 buildBlock(t, state, unittest.BlockWithParentFixture(block6.Header)) 401 402 // sealing segment should be [B2, B3, B4, B5, B6] 403 require.Len(t, segment.Blocks, 5) 404 unittest.AssertEqualBlocksLenAndOrder(t, []*flow.Block{block2, block3, block4, block5, block6}, segment.Blocks) 405 require.Len(t, segment.ExecutionResults, 1) 406 407 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(block6.ID())) 408 }) 409 }) 410 411 // test sealing segment where you have a chain that is 5 blocks long and the block 5 has a seal for block 2 412 // block 2 also contains a receipt but no result. 413 // ROOT -> B1(Result_A, Receipt_A_1) -> B2(Result_B, Receipt_B, Receipt_A_2) -> B3(Receipt_C, Result_C) -> B4 -> B5(Seal_C) 414 // the segment for B5 should be `[B2,B3,B4,B5] + [Result_A]` 415 t.Run("sealing segment with 4 blocks and 1 execution result decoupled", func(t *testing.T) { 416 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 417 // simulate scenario where execution result is missing from block payload 418 // SealingSegment() should get result from results db and store it on ExecutionReceipts 419 // field on SealingSegment 420 resultA := unittest.ExecutionResultFixture() 421 receiptA1 := unittest.ExecutionReceiptFixture(unittest.WithResult(resultA)) 422 receiptA2 := unittest.ExecutionReceiptFixture(unittest.WithResult(resultA)) 423 424 // receipt b also contains result b 425 receiptB := unittest.ExecutionReceiptFixture() 426 427 block1 := unittest.BlockWithParentFixture(head) 428 block1.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receiptA1))) 429 430 block2 := unittest.BlockWithParentFixture(block1.Header) 431 block2.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receiptB), unittest.WithReceiptsAndNoResults(receiptA2))) 432 receiptC, sealC := unittest.ReceiptAndSealForBlock(block2) 433 434 block3 := unittest.BlockWithParentFixture(block2.Header) 435 block3.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receiptC))) 436 437 block4 := unittest.BlockWithParentFixture(block3.Header) 438 439 block5 := unittest.BlockWithParentFixture(block4.Header) 440 block5.SetPayload(unittest.PayloadFixture(unittest.WithSeals(sealC))) 441 442 buildBlock(t, state, block1) 443 buildBlock(t, state, block2) 444 buildBlock(t, state, block3) 445 buildBlock(t, state, block4) 446 buildBlock(t, state, block5) 447 448 segment, err := state.AtBlockID(block5.ID()).SealingSegment() 449 require.NoError(t, err) 450 451 // build a valid child to ensure we have a QC 452 buildBlock(t, state, unittest.BlockWithParentFixture(block5.Header)) 453 454 require.Len(t, segment.Blocks, 4) 455 unittest.AssertEqualBlocksLenAndOrder(t, []*flow.Block{block2, block3, block4, block5}, segment.Blocks) 456 require.Contains(t, segment.ExecutionResults, resultA) 457 require.Len(t, segment.ExecutionResults, 2) 458 459 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(block5.ID())) 460 }) 461 }) 462 463 // test sealing segment where you have a chain that is 5 blocks long and the block 5 has a seal for block 2. 464 // even though block2 & block3 both reference ResultA it should be added to the segment execution results list once. 465 // block3 also references ResultB, so it should exist in the segment execution results as well. 466 // root -> B1[Result_A, Receipt_A_1] -> B2[Result_B, Receipt_B, Receipt_A_2] -> B3[Receipt_B_2, Receipt_for_seal, Receipt_A_3] -> B4 -> B5 (Seal_B2) 467 t.Run("sealing segment with 4 blocks and 2 execution result decoupled", func(t *testing.T) { 468 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 469 // simulate scenario where execution result is missing from block payload 470 // SealingSegment() should get result from results db and store it on ExecutionReceipts 471 // field on SealingSegment 472 resultA := unittest.ExecutionResultFixture() 473 474 // 3 execution receipts for Result_A 475 receiptA1 := unittest.ExecutionReceiptFixture(unittest.WithResult(resultA)) 476 receiptA2 := unittest.ExecutionReceiptFixture(unittest.WithResult(resultA)) 477 receiptA3 := unittest.ExecutionReceiptFixture(unittest.WithResult(resultA)) 478 479 // receipt b also contains result b 480 receiptB := unittest.ExecutionReceiptFixture() 481 // get second receipt for Result_B, now we have 2 receipts for a single execution result 482 receiptB2 := unittest.ExecutionReceiptFixture(unittest.WithResult(&receiptB.ExecutionResult)) 483 484 block1 := unittest.BlockWithParentFixture(head) 485 block1.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receiptA1))) 486 487 block2 := unittest.BlockWithParentFixture(block1.Header) 488 block2.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receiptB), unittest.WithReceiptsAndNoResults(receiptA2))) 489 490 receiptForSeal, seal := unittest.ReceiptAndSealForBlock(block2) 491 492 block3 := unittest.BlockWithParentFixture(block2.Header) 493 block3.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receiptForSeal), unittest.WithReceiptsAndNoResults(receiptB2, receiptA3))) 494 495 block4 := unittest.BlockWithParentFixture(block3.Header) 496 497 block5 := unittest.BlockWithParentFixture(block4.Header) 498 block5.SetPayload(unittest.PayloadFixture(unittest.WithSeals(seal))) 499 500 buildBlock(t, state, block1) 501 buildBlock(t, state, block2) 502 buildBlock(t, state, block3) 503 buildBlock(t, state, block4) 504 buildBlock(t, state, block5) 505 506 segment, err := state.AtBlockID(block5.ID()).SealingSegment() 507 require.NoError(t, err) 508 509 // build a valid child to ensure we have a QC 510 buildBlock(t, state, unittest.BlockWithParentFixture(block5.Header)) 511 512 require.Len(t, segment.Blocks, 4) 513 unittest.AssertEqualBlocksLenAndOrder(t, []*flow.Block{block2, block3, block4, block5}, segment.Blocks) 514 require.Contains(t, segment.ExecutionResults, resultA) 515 // ResultA should only be added once even though it is referenced in 2 different blocks 516 require.Len(t, segment.ExecutionResults, 2) 517 518 assertSealingSegmentBlocksQueryableAfterBootstrap(t, state.AtBlockID(block5.ID())) 519 }) 520 }) 521 522 // Test the case where the reference block of the snapshot contains no seal. 523 // We should consider the latest seal in a prior block. 524 // ROOT <- B1 <- B2(R1) <- B3 <- B4(S1) <- B5 525 // Expected sealing segment: [B1, B2, B3, B4, B5] 526 t.Run("sealing segment where highest block in segment does not seal lowest", func(t *testing.T) { 527 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 528 // build a block to seal 529 block1 := unittest.BlockWithParentFixture(head) 530 buildBlock(t, state, block1) 531 532 // build a block sealing block1 533 block2 := unittest.BlockWithParentFixture(block1.Header) 534 receipt1, seal1 := unittest.ReceiptAndSealForBlock(block1) 535 block2.SetPayload(unittest.PayloadFixture(unittest.WithReceipts(receipt1))) 536 buildBlock(t, state, block2) 537 538 block3 := unittest.BlockWithParentFixture(block2.Header) 539 buildBlock(t, state, block3) 540 541 block4 := unittest.BlockWithParentFixture(block3.Header) 542 block4.SetPayload(unittest.PayloadFixture(unittest.WithSeals(seal1))) 543 buildBlock(t, state, block4) 544 545 block5 := unittest.BlockWithParentFixture(block4.Header) 546 buildBlock(t, state, block5) 547 548 snapshot := state.AtBlockID(block5.ID()) 549 550 // build a valid child to ensure we have a QC 551 buildBlock(t, state, unittest.BlockWithParentFixture(block5.Header)) 552 553 segment, err := snapshot.SealingSegment() 554 require.NoError(t, err) 555 // sealing segment should contain B1 and B5 556 // B5 is reference of snapshot, B1 is latest sealed 557 unittest.AssertEqualBlocksLenAndOrder(t, []*flow.Block{block1, block2, block3, block4, block5}, segment.Blocks) 558 assert.Len(t, segment.ExecutionResults, 1) 559 560 assertSealingSegmentBlocksQueryableAfterBootstrap(t, snapshot) 561 }) 562 }) 563 } 564 565 func TestLatestSealedResult(t *testing.T) { 566 identities := unittest.CompleteIdentitySet() 567 rootSnapshot := unittest.RootSnapshotFixture(identities) 568 569 t.Run("root snapshot", func(t *testing.T) { 570 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 571 gotResult, gotSeal, err := state.Final().SealedResult() 572 require.NoError(t, err) 573 expectedResult, expectedSeal, err := rootSnapshot.SealedResult() 574 require.NoError(t, err) 575 576 assert.Equal(t, expectedResult, gotResult) 577 assert.Equal(t, expectedSeal, gotSeal) 578 }) 579 }) 580 581 t.Run("non-root snapshot", func(t *testing.T) { 582 head, err := rootSnapshot.Head() 583 require.NoError(t, err) 584 585 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 586 block1 := unittest.BlockWithParentFixture(head) 587 err = state.Extend(context.Background(), block1) 588 require.NoError(t, err) 589 590 block2 := unittest.BlockWithParentFixture(block1.Header) 591 receipt1, seal1 := unittest.ReceiptAndSealForBlock(block1) 592 block2.SetPayload(unittest.PayloadFixture(unittest.WithSeals(seal1), unittest.WithReceipts(receipt1))) 593 err = state.Extend(context.Background(), block2) 594 require.NoError(t, err) 595 596 // B1 <- B2(R1,S1) 597 // querying B2 should return result R1, seal S1 598 t.Run("reference block contains seal", func(t *testing.T) { 599 gotResult, gotSeal, err := state.AtBlockID(block2.ID()).SealedResult() 600 require.NoError(t, err) 601 assert.Equal(t, block2.Payload.Results[0], gotResult) 602 assert.Equal(t, block2.Payload.Seals[0], gotSeal) 603 }) 604 605 block3 := unittest.BlockWithParentFixture(block2.Header) 606 err = state.Extend(context.Background(), block3) 607 require.NoError(t, err) 608 609 // B1 <- B2(R1,S1) <- B3 610 // querying B3 should still return (R1,S1) even though they are in parent block 611 t.Run("reference block contains no seal", func(t *testing.T) { 612 gotResult, gotSeal, err := state.AtBlockID(block2.ID()).SealedResult() 613 require.NoError(t, err) 614 assert.Equal(t, &receipt1.ExecutionResult, gotResult) 615 assert.Equal(t, seal1, gotSeal) 616 }) 617 618 // B1 <- B2(R1,S1) <- B3 <- B4(R2,S2,R3,S3) 619 // There are two seals in B4 - should return latest by height (S3,R3) 620 t.Run("reference block contains multiple seals", func(t *testing.T) { 621 receipt2, seal2 := unittest.ReceiptAndSealForBlock(block2) 622 receipt3, seal3 := unittest.ReceiptAndSealForBlock(block3) 623 block4 := unittest.BlockWithParentFixture(block3.Header) 624 block4.SetPayload(unittest.PayloadFixture( 625 unittest.WithReceipts(receipt2, receipt3), 626 unittest.WithSeals(seal2, seal3), 627 )) 628 err = state.Extend(context.Background(), block4) 629 require.NoError(t, err) 630 631 gotResult, gotSeal, err := state.AtBlockID(block4.ID()).SealedResult() 632 require.NoError(t, err) 633 assert.Equal(t, &receipt3.ExecutionResult, gotResult) 634 assert.Equal(t, seal3, gotSeal) 635 }) 636 }) 637 }) 638 } 639 640 // test retrieving quorum certificate and seed 641 func TestQuorumCertificate(t *testing.T) { 642 identities := unittest.IdentityListFixture(5, unittest.WithAllRoles()) 643 rootSnapshot := unittest.RootSnapshotFixture(identities) 644 head, err := rootSnapshot.Head() 645 require.NoError(t, err) 646 647 // should not be able to get QC or random beacon seed from a block with no children 648 t.Run("no children", func(t *testing.T) { 649 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 650 651 // create a block to query 652 block1 := unittest.BlockWithParentFixture(head) 653 block1.SetPayload(flow.EmptyPayload()) 654 err := state.Extend(context.Background(), block1) 655 require.Nil(t, err) 656 657 _, err = state.AtBlockID(block1.ID()).QuorumCertificate() 658 assert.Error(t, err) 659 660 _, err = state.AtBlockID(block1.ID()).RandomSource() 661 assert.Error(t, err) 662 }) 663 }) 664 665 // should not be able to get random beacon seed from a block with only invalid 666 // or unvalidated children 667 t.Run("un-validated child", func(t *testing.T) { 668 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 669 670 // create a block to query 671 block1 := unittest.BlockWithParentFixture(head) 672 block1.SetPayload(flow.EmptyPayload()) 673 err := state.Extend(context.Background(), block1) 674 require.Nil(t, err) 675 676 // add child 677 unvalidatedChild := unittest.BlockWithParentFixture(head) 678 unvalidatedChild.SetPayload(flow.EmptyPayload()) 679 err = state.Extend(context.Background(), unvalidatedChild) 680 assert.Nil(t, err) 681 682 _, err = state.AtBlockID(block1.ID()).QuorumCertificate() 683 assert.Error(t, err) 684 685 _, err = state.AtBlockID(block1.ID()).RandomSource() 686 assert.Error(t, err) 687 }) 688 }) 689 690 // should be able to get QC and random beacon seed from root block 691 t.Run("root block", func(t *testing.T) { 692 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 693 // since we bootstrap with a root snapshot, this will be the root block 694 _, err := state.AtBlockID(head.ID()).QuorumCertificate() 695 assert.NoError(t, err) 696 randomSeed, err := state.AtBlockID(head.ID()).RandomSource() 697 assert.NoError(t, err) 698 assert.Equal(t, len(randomSeed), seed.RandomSourceLength) 699 }) 700 }) 701 702 // should be able to get QC and random beacon seed from a block with a valid child 703 t.Run("valid child", func(t *testing.T) { 704 util.RunWithFollowerProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.FollowerState) { 705 706 // add a block so we aren't testing against root 707 block1 := unittest.BlockWithParentFixture(head) 708 block1.SetPayload(flow.EmptyPayload()) 709 err := state.Extend(context.Background(), block1) 710 require.Nil(t, err) 711 err = state.MarkValid(block1.ID()) 712 require.Nil(t, err) 713 714 // add a valid child to block1 715 block2 := unittest.BlockWithParentFixture(block1.Header) 716 block2.SetPayload(flow.EmptyPayload()) 717 err = state.Extend(context.Background(), block2) 718 require.Nil(t, err) 719 err = state.MarkValid(block2.ID()) 720 require.Nil(t, err) 721 722 // should be able to get QC/seed 723 qc, err := state.AtBlockID(block1.ID()).QuorumCertificate() 724 assert.Nil(t, err) 725 // should have signatures from valid child (block 2) 726 assert.Equal(t, block2.Header.ParentVoterIndices, qc.SignerIndices) 727 assert.Equal(t, block2.Header.ParentVoterSigData, qc.SigData) 728 // should have view matching block1 view 729 assert.Equal(t, block1.Header.View, qc.View) 730 731 _, err = state.AtBlockID(block1.ID()).RandomSource() 732 require.Nil(t, err) 733 }) 734 }) 735 } 736 737 // test that we can query current/next/previous epochs from a snapshot 738 func TestSnapshot_EpochQuery(t *testing.T) { 739 identities := unittest.CompleteIdentitySet() 740 rootSnapshot := unittest.RootSnapshotFixture(identities) 741 result, _, err := rootSnapshot.SealedResult() 742 require.NoError(t, err) 743 744 util.RunWithFullProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.MutableState) { 745 epoch1Counter := result.ServiceEvents[0].Event.(*flow.EpochSetup).Counter 746 epoch2Counter := epoch1Counter + 1 747 748 epochBuilder := unittest.NewEpochBuilder(t, state) 749 // build epoch 1 (prepare epoch 2) 750 epochBuilder. 751 BuildEpoch(). 752 CompleteEpoch() 753 // build epoch 2 (prepare epoch 3) 754 epochBuilder. 755 BuildEpoch(). 756 CompleteEpoch() 757 758 // get heights of each phase in built epochs 759 epoch1, ok := epochBuilder.EpochHeights(1) 760 require.True(t, ok) 761 epoch2, ok := epochBuilder.EpochHeights(2) 762 require.True(t, ok) 763 764 // we should be able to query the current epoch from any block 765 t.Run("Current", func(t *testing.T) { 766 t.Run("epoch 1", func(t *testing.T) { 767 for _, height := range epoch1.Range() { 768 counter, err := state.AtHeight(height).Epochs().Current().Counter() 769 require.Nil(t, err) 770 assert.Equal(t, epoch1Counter, counter) 771 } 772 }) 773 774 t.Run("epoch 2", func(t *testing.T) { 775 for _, height := range epoch2.Range() { 776 counter, err := state.AtHeight(height).Epochs().Current().Counter() 777 require.Nil(t, err) 778 assert.Equal(t, epoch2Counter, counter) 779 } 780 }) 781 }) 782 783 // we should be unable to query next epoch before it is defined by EpochSetup 784 // event, afterward we should be able to query next epoch 785 t.Run("Next", func(t *testing.T) { 786 t.Run("epoch 1: before next epoch available", func(t *testing.T) { 787 for _, height := range epoch1.StakingRange() { 788 _, err := state.AtHeight(height).Epochs().Next().Counter() 789 assert.Error(t, err) 790 assert.True(t, errors.Is(err, protocol.ErrNextEpochNotSetup)) 791 } 792 }) 793 794 t.Run("epoch 2: after next epoch available", func(t *testing.T) { 795 for _, height := range append(epoch1.SetupRange(), epoch1.CommittedRange()...) { 796 counter, err := state.AtHeight(height).Epochs().Next().Counter() 797 require.Nil(t, err) 798 assert.Equal(t, epoch2Counter, counter) 799 } 800 }) 801 }) 802 803 // we should get a sentinel error when querying previous epoch from the 804 // first epoch after the root block, otherwise we should always be able 805 // to query previous epoch 806 t.Run("Previous", func(t *testing.T) { 807 t.Run("epoch 1", func(t *testing.T) { 808 for _, height := range epoch1.Range() { 809 _, err := state.AtHeight(height).Epochs().Previous().Counter() 810 assert.Error(t, err) 811 assert.True(t, errors.Is(err, protocol.ErrNoPreviousEpoch)) 812 } 813 }) 814 815 t.Run("epoch 2", func(t *testing.T) { 816 for _, height := range epoch2.Range() { 817 counter, err := state.AtHeight(height).Epochs().Previous().Counter() 818 require.Nil(t, err) 819 assert.Equal(t, epoch1Counter, counter) 820 } 821 }) 822 }) 823 }) 824 } 825 826 // test that querying the first view of an epoch returns the appropriate value 827 func TestSnapshot_EpochFirstView(t *testing.T) { 828 identities := unittest.CompleteIdentitySet() 829 rootSnapshot := unittest.RootSnapshotFixture(identities) 830 head, err := rootSnapshot.Head() 831 require.NoError(t, err) 832 result, _, err := rootSnapshot.SealedResult() 833 require.NoError(t, err) 834 835 util.RunWithFullProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.MutableState) { 836 837 epochBuilder := unittest.NewEpochBuilder(t, state) 838 // build epoch 1 (prepare epoch 2) 839 epochBuilder. 840 BuildEpoch(). 841 CompleteEpoch() 842 // build epoch 2 (prepare epoch 3) 843 epochBuilder. 844 BuildEpoch(). 845 CompleteEpoch() 846 847 // get heights of each phase in built epochs 848 epoch1, ok := epochBuilder.EpochHeights(1) 849 require.True(t, ok) 850 epoch2, ok := epochBuilder.EpochHeights(2) 851 require.True(t, ok) 852 853 // figure out the expected first views of the epochs 854 epoch1FirstView := head.View 855 epoch2FirstView := result.ServiceEvents[0].Event.(*flow.EpochSetup).FinalView + 1 856 857 // check first view for snapshots within epoch 1, with respect to a 858 // snapshot in either epoch 1 or epoch 2 (testing Current and Previous) 859 t.Run("epoch 1", func(t *testing.T) { 860 861 // test w.r.t. epoch 1 snapshot 862 t.Run("Current", func(t *testing.T) { 863 for _, height := range epoch1.Range() { 864 actualFirstView, err := state.AtHeight(height).Epochs().Current().FirstView() 865 require.Nil(t, err) 866 assert.Equal(t, epoch1FirstView, actualFirstView) 867 } 868 }) 869 870 // test w.r.t. epoch 2 snapshot 871 t.Run("Previous", func(t *testing.T) { 872 for _, height := range epoch2.Range() { 873 actualFirstView, err := state.AtHeight(height).Epochs().Previous().FirstView() 874 require.Nil(t, err) 875 assert.Equal(t, epoch1FirstView, actualFirstView) 876 } 877 }) 878 }) 879 880 // check first view for snapshots within epoch 2, with respect to a 881 // snapshot in either epoch 1 or epoch 2 (testing Next and Current) 882 t.Run("epoch 2", func(t *testing.T) { 883 884 // test w.r.t. epoch 1 snapshot 885 t.Run("Next", func(t *testing.T) { 886 for _, height := range append(epoch1.SetupRange(), epoch1.CommittedRange()...) { 887 actualFirstView, err := state.AtHeight(height).Epochs().Next().FirstView() 888 require.Nil(t, err) 889 assert.Equal(t, epoch2FirstView, actualFirstView) 890 } 891 }) 892 893 // test w.r.t. epoch 2 snapshot 894 t.Run("Current", func(t *testing.T) { 895 for _, height := range epoch2.Range() { 896 actualFirstView, err := state.AtHeight(height).Epochs().Current().FirstView() 897 require.Nil(t, err) 898 assert.Equal(t, epoch2FirstView, actualFirstView) 899 } 900 }) 901 }) 902 }) 903 } 904 905 // Test querying identities in different epoch phases. During staking phase we 906 // should see identities from last epoch and current epoch. After staking phase 907 // we should see identities from current epoch and next epoch. Identities from 908 // a non-current epoch should have weight 0. Identities that exist in consecutive 909 // epochs should be de-duplicated. 910 func TestSnapshot_CrossEpochIdentities(t *testing.T) { 911 912 // start with 20 identities in epoch 1 913 epoch1Identities := unittest.IdentityListFixture(20, unittest.WithAllRoles()) 914 // 1 identity added at epoch 2 that was not present in epoch 1 915 addedAtEpoch2 := unittest.IdentityFixture() 916 // 1 identity removed in epoch 2 that was present in epoch 1 917 removedAtEpoch2 := epoch1Identities.Sample(1)[0] 918 // epoch 2 has partial overlap with epoch 1 919 epoch2Identities := append( 920 epoch1Identities.Filter(filter.Not(filter.HasNodeID(removedAtEpoch2.NodeID))), 921 addedAtEpoch2) 922 // epoch 3 has no overlap with epoch 2 923 epoch3Identities := unittest.IdentityListFixture(10, unittest.WithAllRoles()) 924 925 rootSnapshot := unittest.RootSnapshotFixture(epoch1Identities) 926 util.RunWithFullProtocolState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.MutableState) { 927 928 epochBuilder := unittest.NewEpochBuilder(t, state) 929 // build epoch 1 (prepare epoch 2) 930 epochBuilder. 931 UsingSetupOpts(unittest.WithParticipants(epoch2Identities)). 932 BuildEpoch(). 933 CompleteEpoch() 934 // build epoch 2 (prepare epoch 3) 935 epochBuilder. 936 UsingSetupOpts(unittest.WithParticipants(epoch3Identities)). 937 BuildEpoch(). 938 CompleteEpoch() 939 940 // get heights of each phase in built epochs 941 epoch1, ok := epochBuilder.EpochHeights(1) 942 require.True(t, ok) 943 epoch2, ok := epochBuilder.EpochHeights(2) 944 require.True(t, ok) 945 946 t.Run("should be able to query at root block", func(t *testing.T) { 947 root, err := state.Params().Root() 948 require.NoError(t, err) 949 snapshot := state.AtHeight(root.Height) 950 identities, err := snapshot.Identities(filter.Any) 951 require.Nil(t, err) 952 953 // should have the right number of identities 954 assert.Equal(t, len(epoch1Identities), len(identities)) 955 // should have all epoch 1 identities 956 assert.ElementsMatch(t, epoch1Identities, identities) 957 }) 958 959 t.Run("should include next epoch after staking phase", func(t *testing.T) { 960 961 // get a snapshot from setup phase and commit phase of epoch 1 962 snapshots := []protocol.Snapshot{state.AtHeight(epoch1.Setup), state.AtHeight(epoch1.Committed)} 963 964 for _, snapshot := range snapshots { 965 phase, err := snapshot.Phase() 966 require.Nil(t, err) 967 968 t.Run("phase: "+phase.String(), func(t *testing.T) { 969 identities, err := snapshot.Identities(filter.Any) 970 require.Nil(t, err) 971 972 // should have the right number of identities 973 assert.Equal(t, len(epoch1Identities)+1, len(identities)) 974 // all current epoch identities should match configuration from EpochSetup event 975 assert.ElementsMatch(t, epoch1Identities, identities.Filter(epoch1Identities.Selector())) 976 977 // should contain single next epoch identity with 0 weight 978 nextEpochIdentity := identities.Filter(filter.HasNodeID(addedAtEpoch2.NodeID))[0] 979 assert.Equal(t, uint64(0), nextEpochIdentity.Weight) // should have 0 weight 980 nextEpochIdentity.Weight = addedAtEpoch2.Weight 981 assert.Equal(t, addedAtEpoch2, nextEpochIdentity) // should be equal besides weight 982 }) 983 } 984 }) 985 986 t.Run("should include previous epoch in staking phase", func(t *testing.T) { 987 988 // get a snapshot from staking phase of epoch 2 989 snapshot := state.AtHeight(epoch2.Staking) 990 identities, err := snapshot.Identities(filter.Any) 991 require.Nil(t, err) 992 993 // should have the right number of identities 994 assert.Equal(t, len(epoch2Identities)+1, len(identities)) 995 // all current epoch identities should match configuration from EpochSetup event 996 assert.ElementsMatch(t, epoch2Identities, identities.Filter(epoch2Identities.Selector())) 997 998 // should contain single previous epoch identity with 0 weight 999 lastEpochIdentity := identities.Filter(filter.HasNodeID(removedAtEpoch2.NodeID))[0] 1000 assert.Equal(t, uint64(0), lastEpochIdentity.Weight) // should have 0 weight 1001 lastEpochIdentity.Weight = removedAtEpoch2.Weight // overwrite weight 1002 assert.Equal(t, removedAtEpoch2, lastEpochIdentity) // should be equal besides weight 1003 }) 1004 1005 t.Run("should not include previous epoch after staking phase", func(t *testing.T) { 1006 1007 // get a snapshot from setup phase and commit phase of epoch 2 1008 snapshots := []protocol.Snapshot{state.AtHeight(epoch2.Setup), state.AtHeight(epoch2.Committed)} 1009 1010 for _, snapshot := range snapshots { 1011 phase, err := snapshot.Phase() 1012 require.Nil(t, err) 1013 1014 t.Run("phase: "+phase.String(), func(t *testing.T) { 1015 identities, err := snapshot.Identities(filter.Any) 1016 require.Nil(t, err) 1017 1018 // should have the right number of identities 1019 assert.Equal(t, len(epoch2Identities)+len(epoch3Identities), len(identities)) 1020 // all current epoch identities should match configuration from EpochSetup event 1021 assert.ElementsMatch(t, epoch2Identities, identities.Filter(epoch2Identities.Selector())) 1022 1023 // should contain next epoch identities with 0 weight 1024 for _, expected := range epoch3Identities { 1025 actual, exists := identities.ByNodeID(expected.NodeID) 1026 require.True(t, exists) 1027 assert.Equal(t, uint64(0), actual.Weight) // should have 0 weight 1028 actual.Weight = expected.Weight // overwrite weight 1029 assert.Equal(t, expected, actual) // should be equal besides weight 1030 } 1031 }) 1032 } 1033 }) 1034 }) 1035 } 1036 1037 // test that we can retrieve identities after a spork where the parent ID of the 1038 // root block is non-nil 1039 func TestSnapshot_PostSporkIdentities(t *testing.T) { 1040 expected := unittest.CompleteIdentitySet() 1041 root, result, seal := unittest.BootstrapFixture(expected, func(block *flow.Block) { 1042 block.Header.ParentID = unittest.IdentifierFixture() 1043 }) 1044 qc := unittest.QuorumCertificateFixture(unittest.QCWithBlockID(root.ID())) 1045 1046 rootSnapshot, err := inmem.SnapshotFromBootstrapState(root, result, seal, qc) 1047 require.NoError(t, err) 1048 1049 util.RunWithBootstrapState(t, rootSnapshot, func(db *badger.DB, state *bprotocol.State) { 1050 actual, err := state.Final().Identities(filter.Any) 1051 require.Nil(t, err) 1052 assert.ElementsMatch(t, expected, actual) 1053 }) 1054 }