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  }