github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/execution/ingestion/mocks/block_store.go (about)

     1  package mocks
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/onflow/flow-go/engine/execution"
    11  	executionUnittest "github.com/onflow/flow-go/engine/execution/state/unittest"
    12  	"github.com/onflow/flow-go/model/flow"
    13  	"github.com/onflow/flow-go/module/mempool/entity"
    14  	"github.com/onflow/flow-go/utils/unittest"
    15  )
    16  
    17  type BlockResult struct {
    18  	Block  *entity.ExecutableBlock
    19  	Result *execution.ComputationResult
    20  }
    21  
    22  // MockBlockStore contains mocked block computation result
    23  // it ensures that as blocks computation result are created, the block's start state
    24  // is the same as its parent block's end state.
    25  // it also stores which block is executed, so that the mock execution state or computer
    26  // can determine what result to return
    27  type MockBlockStore struct {
    28  	sync.Mutex
    29  	ResultByBlock map[flow.Identifier]*BlockResult
    30  	Executed      map[flow.Identifier]struct{}
    31  	RootBlock     *flow.Header
    32  }
    33  
    34  func NewMockBlockStore(t *testing.T) *MockBlockStore {
    35  	rootBlock := unittest.ExecutableBlockFixtureWithParent([][]flow.Identifier{{}},
    36  		unittest.BlockHeaderFixture(), unittest.StateCommitmentPointerFixture())
    37  	rootResult := executionUnittest.ComputationResultForBlockFixture(t,
    38  		unittest.IdentifierFixture(), rootBlock)
    39  
    40  	blockResult := &BlockResult{
    41  		Block:  rootBlock,
    42  		Result: rootResult,
    43  	}
    44  
    45  	byBlock := make(map[flow.Identifier]*BlockResult)
    46  	byBlock[rootResult.Block.ID()] = blockResult
    47  
    48  	executed := make(map[flow.Identifier]struct{})
    49  	executed[rootResult.Block.ID()] = struct{}{}
    50  	return &MockBlockStore{
    51  		ResultByBlock: byBlock,
    52  		Executed:      executed,
    53  		RootBlock:     rootBlock.Block.Header,
    54  	}
    55  }
    56  
    57  func (bs *MockBlockStore) MarkExecuted(computationResult *execution.ComputationResult) error {
    58  	bs.Lock()
    59  	defer bs.Unlock()
    60  	blockID := computationResult.ExecutableBlock.Block.Header.ID()
    61  	_, executed := bs.Executed[blockID]
    62  	if executed {
    63  		return fmt.Errorf("block %s already executed", blockID)
    64  	}
    65  
    66  	expected, exist := bs.ResultByBlock[blockID]
    67  	if !exist {
    68  		return fmt.Errorf("block %s not found", blockID)
    69  	}
    70  
    71  	if expected.Result != computationResult {
    72  		return fmt.Errorf("block %s expected %v, got %v", blockID, expected, computationResult)
    73  	}
    74  	bs.Executed[blockID] = struct{}{}
    75  	return nil
    76  }
    77  
    78  func (bs *MockBlockStore) CreateBlockAndMockResult(t *testing.T, block *entity.ExecutableBlock) *execution.ComputationResult {
    79  	bs.Lock()
    80  	defer bs.Unlock()
    81  	blockID := block.ID()
    82  	_, exist := bs.ResultByBlock[blockID]
    83  	require.False(t, exist, "block %s already exists", blockID)
    84  
    85  	parent := block.Block.Header.ParentID
    86  	parentResult, ok := bs.ResultByBlock[parent]
    87  	require.True(t, ok, "parent block %s not found", parent)
    88  
    89  	previousExecutionResultID := parentResult.Result.ExecutionReceipt.ExecutionResult.ID()
    90  
    91  	previousCommit := parentResult.Result.CurrentEndState()
    92  
    93  	block.StartState = &previousCommit
    94  
    95  	// mock computation result
    96  	cr := executionUnittest.ComputationResultForBlockFixture(t,
    97  		previousExecutionResultID,
    98  		block,
    99  	)
   100  	result := &BlockResult{
   101  		Block:  block,
   102  		Result: cr,
   103  	}
   104  	bs.ResultByBlock[blockID] = result
   105  	return cr
   106  }
   107  
   108  func (bs *MockBlockStore) GetExecuted(blockID flow.Identifier) (*BlockResult, error) {
   109  	bs.Lock()
   110  	defer bs.Unlock()
   111  	_, exist := bs.Executed[blockID]
   112  	if !exist {
   113  		return nil, fmt.Errorf("block %s not executed", blockID)
   114  	}
   115  
   116  	result, exist := bs.ResultByBlock[blockID]
   117  	if !exist {
   118  		return nil, fmt.Errorf("block %s not found", blockID)
   119  	}
   120  	return result, nil
   121  }
   122  
   123  func (bs *MockBlockStore) AssertExecuted(t *testing.T, alias string, block flow.Identifier) {
   124  	bs.Lock()
   125  	defer bs.Unlock()
   126  	_, exist := bs.Executed[block]
   127  	require.True(t, exist, "block %s not executed", alias)
   128  }
   129  
   130  func (bs *MockBlockStore) AssertNotExecuted(t *testing.T, alias string, block flow.Identifier) {
   131  	bs.Lock()
   132  	defer bs.Unlock()
   133  	_, exist := bs.Executed[block]
   134  	require.False(t, exist, "block %s executed", alias)
   135  }