github.com/koko1123/flow-go-1@v0.29.6/utils/unittest/chain_suite.go (about)

     1  package unittest
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/stretchr/testify/mock"
     7  	"github.com/stretchr/testify/suite"
     8  
     9  	"github.com/koko1123/flow-go-1/model/chunks"
    10  	"github.com/koko1123/flow-go-1/model/flow"
    11  	mempool "github.com/koko1123/flow-go-1/module/mempool/mock"
    12  	module "github.com/koko1123/flow-go-1/module/mock"
    13  	realproto "github.com/koko1123/flow-go-1/state/protocol"
    14  	protocol "github.com/koko1123/flow-go-1/state/protocol/mock"
    15  	storerr "github.com/koko1123/flow-go-1/storage"
    16  	storage "github.com/koko1123/flow-go-1/storage/mock"
    17  )
    18  
    19  type BaseChainSuite struct {
    20  	suite.Suite
    21  
    22  	// IDENTITIES
    23  	ConID flow.Identifier
    24  	ExeID flow.Identifier
    25  	VerID flow.Identifier
    26  
    27  	Identities map[flow.Identifier]*flow.Identity
    28  	Approvers  flow.IdentityList
    29  
    30  	// BLOCKS
    31  	RootBlock             flow.Block
    32  	LatestSealedBlock     flow.Block
    33  	LatestFinalizedBlock  *flow.Block
    34  	UnfinalizedBlock      flow.Block
    35  	LatestExecutionResult *flow.ExecutionResult
    36  	Blocks                map[flow.Identifier]*flow.Block
    37  
    38  	// PROTOCOL STATE
    39  	State          *protocol.State
    40  	SealedSnapshot *protocol.Snapshot
    41  	FinalSnapshot  *protocol.Snapshot
    42  
    43  	// MEMPOOLS and STORAGE which are injected into Matching Engine
    44  	// mock storage.ExecutionReceipts: backed by in-memory map PersistedReceipts
    45  	ReceiptsDB *storage.ExecutionReceipts
    46  
    47  	ResultsDB        *storage.ExecutionResults
    48  	PersistedResults map[flow.Identifier]*flow.ExecutionResult
    49  
    50  	// mock mempool.IncorporatedResultSeals: backed by in-memory map PendingSeals
    51  	SealsPL      *mempool.IncorporatedResultSeals
    52  	PendingSeals map[flow.Identifier]*flow.IncorporatedResultSeal
    53  
    54  	// mock BLOCK STORAGE: backed by in-memory map Blocks
    55  	HeadersDB  *storage.Headers               // backed by map Blocks
    56  	IndexDB    *storage.Index                 // backed by map Blocks
    57  	PayloadsDB *storage.Payloads              // backed by map Blocks
    58  	SealsDB    *storage.Seals                 // backed by map SealsIndex
    59  	SealsIndex map[flow.Identifier]*flow.Seal // last valid seal for block
    60  
    61  	// mock mempool.ReceiptsForest: used to test whether or not Matching Engine stores receipts
    62  	ReceiptsPL *mempool.ExecutionTree
    63  
    64  	Assigner    *module.ChunkAssigner
    65  	Assignments map[flow.Identifier]*chunks.Assignment // index for assignments for given execution result
    66  
    67  	PendingReceipts *mempool.PendingReceipts
    68  }
    69  
    70  func (bc *BaseChainSuite) SetupChain() {
    71  
    72  	// ~~~~~~~~~~~~~~~~~~~~~~~~~~ SETUP IDENTITIES ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
    73  
    74  	// asign node Identities
    75  	con := IdentityFixture(WithRole(flow.RoleConsensus))
    76  	exe := IdentityFixture(WithRole(flow.RoleExecution))
    77  	ver := IdentityFixture(WithRole(flow.RoleVerification))
    78  
    79  	bc.ConID = con.NodeID
    80  	bc.ExeID = exe.NodeID
    81  	bc.VerID = ver.NodeID
    82  
    83  	bc.Identities = make(map[flow.Identifier]*flow.Identity)
    84  	bc.Identities[bc.ConID] = con
    85  	bc.Identities[bc.ExeID] = exe
    86  	bc.Identities[bc.VerID] = ver
    87  
    88  	// assign 4 nodes to the verification role
    89  	bc.Approvers = IdentityListFixture(4, WithRole(flow.RoleVerification))
    90  	for _, verifier := range bc.Approvers {
    91  		bc.Identities[verifier.ID()] = verifier
    92  	}
    93  
    94  	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETUP BLOCKS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
    95  	// RootBlock <- LatestSealedBlock <- LatestFinalizedBlock <- UnfinalizedBlock
    96  	bc.RootBlock = BlockFixture()
    97  	bc.LatestSealedBlock = *BlockWithParentFixture(bc.RootBlock.Header)
    98  	latestFinalizedBlock := BlockWithParentFixture(bc.LatestSealedBlock.Header)
    99  	bc.LatestFinalizedBlock = latestFinalizedBlock
   100  	bc.UnfinalizedBlock = *BlockWithParentFixture(bc.LatestFinalizedBlock.Header)
   101  
   102  	bc.Blocks = make(map[flow.Identifier]*flow.Block)
   103  	bc.Blocks[bc.RootBlock.ID()] = &bc.RootBlock
   104  	bc.Blocks[bc.LatestSealedBlock.ID()] = &bc.LatestSealedBlock
   105  	bc.Blocks[bc.LatestFinalizedBlock.ID()] = bc.LatestFinalizedBlock
   106  	bc.Blocks[bc.UnfinalizedBlock.ID()] = &bc.UnfinalizedBlock
   107  
   108  	// ~~~~~~~~~~~~~~~~~~~~~~~~ SETUP PROTOCOL STATE ~~~~~~~~~~~~~~~~~~~~~~~~ //
   109  	bc.State = &protocol.State{}
   110  
   111  	// define the protocol state snapshot of the latest finalized block
   112  	bc.State.On("Final").Return(
   113  		func() realproto.Snapshot {
   114  			return bc.FinalSnapshot
   115  		},
   116  		nil,
   117  	)
   118  	bc.FinalSnapshot = &protocol.Snapshot{}
   119  	bc.FinalSnapshot.On("Head").Return(
   120  		func() *flow.Header {
   121  			return bc.LatestFinalizedBlock.Header
   122  		},
   123  		nil,
   124  	)
   125  	bc.FinalSnapshot.On("SealedResult").Return(
   126  		func() *flow.ExecutionResult {
   127  			blockID := bc.LatestFinalizedBlock.ID()
   128  			seal, found := bc.SealsIndex[blockID]
   129  			if !found {
   130  				return nil
   131  			}
   132  			result, found := bc.PersistedResults[seal.ResultID]
   133  			if !found {
   134  				return nil
   135  			}
   136  			return result
   137  		},
   138  		func() *flow.Seal {
   139  			blockID := bc.LatestFinalizedBlock.ID()
   140  			seal, found := bc.SealsIndex[blockID]
   141  			if !found {
   142  				return nil
   143  			}
   144  			return seal
   145  		},
   146  		func() error {
   147  			blockID := bc.LatestFinalizedBlock.ID()
   148  			seal, found := bc.SealsIndex[blockID]
   149  			if !found {
   150  				return storerr.ErrNotFound
   151  			}
   152  			_, found = bc.PersistedResults[seal.ResultID]
   153  			if !found {
   154  				return storerr.ErrNotFound
   155  			}
   156  			return nil
   157  		},
   158  	)
   159  
   160  	// define the protocol state snapshot of the latest sealed block
   161  	bc.State.On("Sealed").Return(
   162  		func() realproto.Snapshot {
   163  			return bc.SealedSnapshot
   164  		},
   165  		nil,
   166  	)
   167  	bc.SealedSnapshot = &protocol.Snapshot{}
   168  	bc.SealedSnapshot.On("Head").Return(
   169  		func() *flow.Header {
   170  			return bc.LatestSealedBlock.Header
   171  		},
   172  		nil,
   173  	)
   174  
   175  	findBlockByHeight := func(blocks map[flow.Identifier]*flow.Block, height uint64) (*flow.Block, bool) {
   176  		for _, block := range blocks {
   177  			if block.Header.Height == height {
   178  				return block, true
   179  			}
   180  		}
   181  		return nil, false
   182  	}
   183  
   184  	// define the protocol state snapshot for any block in `bc.Blocks`
   185  	bc.State.On("AtBlockID", mock.Anything).Return(
   186  		func(blockID flow.Identifier) realproto.Snapshot {
   187  			block, found := bc.Blocks[blockID]
   188  			if !found {
   189  				return StateSnapshotForUnknownBlock()
   190  			}
   191  			return StateSnapshotForKnownBlock(block.Header, bc.Identities)
   192  		},
   193  	)
   194  
   195  	bc.State.On("AtHeight", mock.Anything).Return(
   196  		func(height uint64) realproto.Snapshot {
   197  			block, found := findBlockByHeight(bc.Blocks, height)
   198  			if found {
   199  				snapshot := &protocol.Snapshot{}
   200  				snapshot.On("Head").Return(
   201  					func() *flow.Header {
   202  						return block.Header
   203  					},
   204  					nil,
   205  				)
   206  				return snapshot
   207  			}
   208  			panic(fmt.Sprintf("unknown height: %v, final: %v, sealed: %v", height, bc.LatestFinalizedBlock.Header.Height, bc.LatestSealedBlock.Header.Height))
   209  		},
   210  	)
   211  
   212  	// ~~~~~~~~~~~~~~~~~~~~~~~ SETUP RESULTS STORAGE ~~~~~~~~~~~~~~~~~~~~~~~~ //
   213  	bc.PersistedResults = make(map[flow.Identifier]*flow.ExecutionResult)
   214  	bc.LatestExecutionResult = ExecutionResultFixture(WithBlock(&bc.LatestSealedBlock))
   215  	bc.PersistedResults[bc.LatestExecutionResult.ID()] = bc.LatestExecutionResult
   216  	bc.ResultsDB = &storage.ExecutionResults{}
   217  	bc.ResultsDB.On("ByID", mock.Anything).Return(
   218  		func(resultID flow.Identifier) *flow.ExecutionResult {
   219  			return bc.PersistedResults[resultID]
   220  		},
   221  		func(resultID flow.Identifier) error {
   222  			_, found := bc.PersistedResults[resultID]
   223  			if !found {
   224  				return storerr.ErrNotFound
   225  			}
   226  			return nil
   227  		},
   228  	).Maybe()
   229  	bc.ResultsDB.On("Store", mock.Anything).Return(
   230  		func(result *flow.ExecutionResult) error {
   231  			_, found := bc.PersistedResults[result.ID()]
   232  			if found {
   233  				return storerr.ErrAlreadyExists
   234  			}
   235  			return nil
   236  		},
   237  	).Maybe() // this call is optional
   238  	// ~~~~~~~~~~~~~~~~~~~~~~~ SETUP RECEIPTS STORAGE ~~~~~~~~~~~~~~~~~~~~~~~~ //
   239  	bc.ReceiptsDB = &storage.ExecutionReceipts{}
   240  
   241  	// ~~~~~~~~~~~~~~~~~~~~ SETUP BLOCK HEADER STORAGE ~~~~~~~~~~~~~~~~~~~~~ //
   242  	bc.HeadersDB = &storage.Headers{}
   243  	bc.HeadersDB.On("ByBlockID", mock.Anything).Return(
   244  		func(blockID flow.Identifier) *flow.Header {
   245  			block, found := bc.Blocks[blockID]
   246  			if !found {
   247  				return nil
   248  			}
   249  			return block.Header
   250  		},
   251  		func(blockID flow.Identifier) error {
   252  			_, found := bc.Blocks[blockID]
   253  			if !found {
   254  				return storerr.ErrNotFound
   255  			}
   256  			return nil
   257  		},
   258  	)
   259  	bc.HeadersDB.On("ByHeight", mock.Anything).Return(
   260  		func(blockHeight uint64) *flow.Header {
   261  			for _, b := range bc.Blocks {
   262  				if b.Header.Height == blockHeight {
   263  					return b.Header
   264  				}
   265  			}
   266  			return nil
   267  		},
   268  		func(blockHeight uint64) error {
   269  			for _, b := range bc.Blocks {
   270  				if b.Header.Height == blockHeight {
   271  					return nil
   272  				}
   273  			}
   274  			return storerr.ErrNotFound
   275  		},
   276  	)
   277  
   278  	// ~~~~~~~~~~~~~~~~~~~~ SETUP BLOCK PAYLOAD STORAGE ~~~~~~~~~~~~~~~~~~~~~ //
   279  	bc.IndexDB = &storage.Index{}
   280  	bc.IndexDB.On("ByBlockID", mock.Anything).Return(
   281  		func(blockID flow.Identifier) *flow.Index {
   282  			block, found := bc.Blocks[blockID]
   283  			if !found {
   284  				return nil
   285  			}
   286  			if block.Payload == nil {
   287  				return nil
   288  			}
   289  			return block.Payload.Index()
   290  		},
   291  		func(blockID flow.Identifier) error {
   292  			block, found := bc.Blocks[blockID]
   293  			if !found {
   294  				return storerr.ErrNotFound
   295  			}
   296  			if block.Payload == nil {
   297  				return storerr.ErrNotFound
   298  			}
   299  			return nil
   300  		},
   301  	)
   302  
   303  	bc.SealsIndex = make(map[flow.Identifier]*flow.Seal)
   304  	firtSeal := Seal.Fixture(Seal.WithBlock(bc.LatestSealedBlock.Header),
   305  		Seal.WithResult(bc.LatestExecutionResult))
   306  	for id, block := range bc.Blocks {
   307  		if id != bc.RootBlock.ID() {
   308  			bc.SealsIndex[block.ID()] = firtSeal
   309  		}
   310  	}
   311  
   312  	bc.PayloadsDB = &storage.Payloads{}
   313  	bc.PayloadsDB.On("ByBlockID", mock.Anything).Return(
   314  		func(blockID flow.Identifier) *flow.Payload {
   315  			block, found := bc.Blocks[blockID]
   316  			if !found {
   317  				return nil
   318  			}
   319  			if block.Payload == nil {
   320  				return nil
   321  			}
   322  			return block.Payload
   323  		},
   324  		func(blockID flow.Identifier) error {
   325  			block, found := bc.Blocks[blockID]
   326  			if !found {
   327  				return storerr.ErrNotFound
   328  			}
   329  			if block.Payload == nil {
   330  				return storerr.ErrNotFound
   331  			}
   332  			return nil
   333  		},
   334  	)
   335  
   336  	bc.SealsDB = &storage.Seals{}
   337  	bc.SealsDB.On("HighestInFork", mock.Anything).Return(
   338  		func(blockID flow.Identifier) *flow.Seal {
   339  			seal, found := bc.SealsIndex[blockID]
   340  			if !found {
   341  				return nil
   342  			}
   343  			return seal
   344  		},
   345  		func(blockID flow.Identifier) error {
   346  			seal, found := bc.SealsIndex[blockID]
   347  			if !found {
   348  				return storerr.ErrNotFound
   349  			}
   350  			if seal == nil {
   351  				return storerr.ErrNotFound
   352  			}
   353  			return nil
   354  		},
   355  	)
   356  
   357  	// ~~~~~~~~~~~~~~~~~~~~~~~ SETUP RECEIPTS MEMPOOL ~~~~~~~~~~~~~~~~~~~~~~ //
   358  	bc.ReceiptsPL = &mempool.ExecutionTree{}
   359  	bc.ReceiptsPL.On("Size").Return(uint(0)).Maybe() // only for metrics
   360  	bc.ReceiptsPL.On("HasReceipt", mock.AnythingOfType("*flow.ExecutionReceipt")).Return(false)
   361  
   362  	bc.PendingReceipts = &mempool.PendingReceipts{}
   363  
   364  	// ~~~~~~~~~~~~~~~~~~~~~~~~ SETUP SEALS MEMPOOL ~~~~~~~~~~~~~~~~~~~~~~~~ //
   365  	bc.PendingSeals = make(map[flow.Identifier]*flow.IncorporatedResultSeal)
   366  	bc.SealsPL = &mempool.IncorporatedResultSeals{}
   367  	bc.SealsPL.On("Size").Return(uint(0)).Maybe() // only for metrics
   368  	bc.SealsPL.On("Limit").Return(uint(1000)).Maybe()
   369  	bc.SealsPL.On("ByID", mock.Anything).Return(
   370  		func(sealID flow.Identifier) *flow.IncorporatedResultSeal {
   371  			return bc.PendingSeals[sealID]
   372  		},
   373  		func(sealID flow.Identifier) bool {
   374  			_, found := bc.PendingSeals[sealID]
   375  			return found
   376  		},
   377  	).Maybe()
   378  	bc.SealsPL.On("All").Return(
   379  		func() []*flow.IncorporatedResultSeal {
   380  			seals := make([]*flow.IncorporatedResultSeal, 0, len(bc.PendingSeals))
   381  			for _, seal := range bc.PendingSeals {
   382  				seals = append(seals, seal)
   383  			}
   384  			return seals
   385  		},
   386  	).Maybe()
   387  
   388  	bc.Assigner = &module.ChunkAssigner{}
   389  	bc.Assignments = make(map[flow.Identifier]*chunks.Assignment)
   390  }
   391  
   392  func StateSnapshotForUnknownBlock() *protocol.Snapshot {
   393  	snapshot := &protocol.Snapshot{}
   394  	snapshot.On("Identity", mock.Anything).Return(
   395  		nil, storerr.ErrNotFound,
   396  	)
   397  	snapshot.On("Identities", mock.Anything).Return(
   398  		nil, storerr.ErrNotFound,
   399  	)
   400  	snapshot.On("Head", mock.Anything).Return(
   401  		nil, storerr.ErrNotFound,
   402  	)
   403  	return snapshot
   404  }
   405  
   406  func StateSnapshotForKnownBlock(block *flow.Header, identities map[flow.Identifier]*flow.Identity) *protocol.Snapshot {
   407  	snapshot := &protocol.Snapshot{}
   408  	snapshot.On("Identity", mock.Anything).Return(
   409  		func(nodeID flow.Identifier) *flow.Identity {
   410  			return identities[nodeID]
   411  		},
   412  		func(nodeID flow.Identifier) error {
   413  			_, found := identities[nodeID]
   414  			if !found {
   415  				return realproto.IdentityNotFoundError{NodeID: nodeID}
   416  			}
   417  			return nil
   418  		},
   419  	)
   420  	snapshot.On("Identities", mock.Anything).Return(
   421  		func(selector flow.IdentityFilter) flow.IdentityList {
   422  			var idts flow.IdentityList
   423  			for _, i := range identities {
   424  				if selector(i) {
   425  					idts = append(idts, i)
   426  				}
   427  			}
   428  			return idts
   429  		},
   430  		func(selector flow.IdentityFilter) error {
   431  			return nil
   432  		},
   433  	)
   434  	snapshot.On("Head").Return(block, nil)
   435  	return snapshot
   436  }
   437  
   438  func ApprovalFor(result *flow.ExecutionResult, chunkIdx uint64, approverID flow.Identifier) *flow.ResultApproval {
   439  	return ResultApprovalFixture(
   440  		WithBlockID(result.BlockID),
   441  		WithExecutionResultID(result.ID()),
   442  		WithApproverID(approverID),
   443  		WithChunk(chunkIdx),
   444  	)
   445  }
   446  
   447  func EntityWithID(expectedID flow.Identifier) interface{} {
   448  	return mock.MatchedBy(
   449  		func(entity flow.Entity) bool {
   450  			return expectedID == entity.ID()
   451  		})
   452  }
   453  
   454  // subgraphFixture represents a subgraph of the blockchain:
   455  //
   456  //	Result   -----------------------------------> Block
   457  //	  |                                             |
   458  //	  |                                             v
   459  //	  |                                           ParentBlock
   460  //	  v
   461  //	PreviousResult  ---> PreviousResult.BlockID
   462  //
   463  // Depending on validity of the subgraph:
   464  //   - valid:   PreviousResult.BlockID == ParentBlock.ID()
   465  //   - invalid: PreviousResult.BlockID != ParentBlock.ID()
   466  type subgraphFixture struct {
   467  	Block              *flow.Block
   468  	ParentBlock        *flow.Block
   469  	Result             *flow.ExecutionResult
   470  	PreviousResult     *flow.ExecutionResult
   471  	IncorporatedResult *flow.IncorporatedResult
   472  	Assignment         *chunks.Assignment
   473  	Approvals          map[uint64]map[flow.Identifier]*flow.ResultApproval // chunkIndex -> Verifier Node ID -> Approval
   474  }
   475  
   476  // Generates a valid subgraph:
   477  // let
   478  //   - R1 be a result which pertains to blockA
   479  //   - R2 be R1's previous result,
   480  //     where R2 pertains to blockB
   481  //
   482  // The execution results form a valid subgraph if and only if:
   483  //
   484  //	blockA.ParentID == blockB.ID
   485  func (bc *BaseChainSuite) ValidSubgraphFixture() subgraphFixture {
   486  	// BLOCKS: <- previousBlock <- block
   487  	parentBlock := BlockFixture()
   488  	parentBlock.SetPayload(PayloadFixture(WithGuarantees(CollectionGuaranteesFixture(12)...)))
   489  	block := BlockWithParentFixture(parentBlock.Header)
   490  	block.SetPayload(PayloadFixture(WithGuarantees(CollectionGuaranteesFixture(12)...)))
   491  
   492  	// RESULTS for Blocks:
   493  	previousResult := ExecutionResultFixture(WithBlock(&parentBlock))
   494  	result := ExecutionResultFixture(
   495  		WithBlock(block),
   496  		WithPreviousResult(*previousResult),
   497  	)
   498  
   499  	// Exec Receipt for block with valid subgraph
   500  	incorporatedResult := IncorporatedResult.Fixture(IncorporatedResult.WithResult(result))
   501  
   502  	// assign each chunk to 50% of validation Nodes and generate respective approvals
   503  	assignment := chunks.NewAssignment()
   504  	assignedVerifiersPerChunk := uint(len(bc.Approvers) / 2)
   505  	approvals := make(map[uint64]map[flow.Identifier]*flow.ResultApproval)
   506  	for _, chunk := range incorporatedResult.Result.Chunks {
   507  		assignedVerifiers := bc.Approvers.Sample(assignedVerifiersPerChunk)
   508  		assignment.Add(chunk, assignedVerifiers.NodeIDs())
   509  
   510  		// generate approvals
   511  		chunkApprovals := make(map[flow.Identifier]*flow.ResultApproval)
   512  		for _, approver := range assignedVerifiers {
   513  			chunkApprovals[approver.NodeID] = ApprovalFor(incorporatedResult.Result, chunk.Index, approver.NodeID)
   514  		}
   515  		approvals[chunk.Index] = chunkApprovals
   516  	}
   517  
   518  	return subgraphFixture{
   519  		Block:              block,
   520  		ParentBlock:        &parentBlock,
   521  		Result:             result,
   522  		PreviousResult:     previousResult,
   523  		IncorporatedResult: incorporatedResult,
   524  		Assignment:         assignment,
   525  		Approvals:          approvals,
   526  	}
   527  }
   528  
   529  func (bc *BaseChainSuite) Extend(block *flow.Block) {
   530  	blockID := block.ID()
   531  	bc.Blocks[blockID] = block
   532  	if seal, ok := bc.SealsIndex[block.Header.ParentID]; ok {
   533  		bc.SealsIndex[block.ID()] = seal
   534  	}
   535  
   536  	for _, result := range block.Payload.Results {
   537  		// Exec Receipt for block with valid subgraph
   538  		incorporatedResult := IncorporatedResult.Fixture(IncorporatedResult.WithResult(result),
   539  			IncorporatedResult.WithIncorporatedBlockID(blockID))
   540  
   541  		// assign each chunk to 50% of validation Nodes and generate respective approvals
   542  		assignment := chunks.NewAssignment()
   543  		assignedVerifiersPerChunk := uint(len(bc.Approvers) / 2)
   544  		approvals := make(map[uint64]map[flow.Identifier]*flow.ResultApproval)
   545  		for _, chunk := range incorporatedResult.Result.Chunks {
   546  			assignedVerifiers := bc.Approvers.Sample(assignedVerifiersPerChunk)
   547  			assignment.Add(chunk, assignedVerifiers.NodeIDs())
   548  
   549  			// generate approvals
   550  			chunkApprovals := make(map[flow.Identifier]*flow.ResultApproval)
   551  			for _, approver := range assignedVerifiers {
   552  				chunkApprovals[approver.NodeID] = ApprovalFor(incorporatedResult.Result, chunk.Index, approver.NodeID)
   553  			}
   554  			approvals[chunk.Index] = chunkApprovals
   555  		}
   556  		bc.Assigner.On("Assign", incorporatedResult.Result, incorporatedResult.IncorporatedBlockID).Return(assignment, nil).Maybe()
   557  		bc.Assignments[incorporatedResult.Result.ID()] = assignment
   558  		bc.PersistedResults[result.ID()] = result
   559  	}
   560  	for _, seal := range block.Payload.Seals {
   561  		bc.SealsIndex[blockID] = seal
   562  	}
   563  }
   564  
   565  // addSubgraphFixtureToMempools adds add entities in subgraph to mempools and persistent storage mocks
   566  func (bc *BaseChainSuite) AddSubgraphFixtureToMempools(subgraph subgraphFixture) {
   567  	bc.Blocks[subgraph.ParentBlock.ID()] = subgraph.ParentBlock
   568  	bc.Blocks[subgraph.Block.ID()] = subgraph.Block
   569  	bc.PersistedResults[subgraph.PreviousResult.ID()] = subgraph.PreviousResult
   570  	bc.PersistedResults[subgraph.Result.ID()] = subgraph.Result
   571  	bc.Assigner.On("Assign", subgraph.IncorporatedResult.Result, subgraph.IncorporatedResult.IncorporatedBlockID).Return(subgraph.Assignment, nil).Maybe()
   572  }