github.com/onflow/flow-go@v0.33.17/engine/execution/computation/manager_test.go (about)

     1  package computation
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"math"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/ipfs/go-datastore"
    13  	dssync "github.com/ipfs/go-datastore/sync"
    14  	blockstore "github.com/ipfs/go-ipfs-blockstore"
    15  	"github.com/onflow/cadence"
    16  	jsoncdc "github.com/onflow/cadence/encoding/json"
    17  	"github.com/onflow/cadence/runtime/common"
    18  	"github.com/rs/zerolog"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/mock"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	"github.com/onflow/flow-go/engine/execution"
    24  	"github.com/onflow/flow-go/engine/execution/computation/committer"
    25  	"github.com/onflow/flow-go/engine/execution/computation/computer"
    26  	"github.com/onflow/flow-go/engine/execution/computation/query"
    27  	state2 "github.com/onflow/flow-go/engine/execution/state"
    28  	unittest2 "github.com/onflow/flow-go/engine/execution/state/unittest"
    29  	"github.com/onflow/flow-go/engine/execution/testutil"
    30  	"github.com/onflow/flow-go/fvm"
    31  	"github.com/onflow/flow-go/fvm/environment"
    32  	fvmErrors "github.com/onflow/flow-go/fvm/errors"
    33  	"github.com/onflow/flow-go/fvm/storage"
    34  	"github.com/onflow/flow-go/fvm/storage/derived"
    35  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    36  	"github.com/onflow/flow-go/fvm/systemcontracts"
    37  	"github.com/onflow/flow-go/ledger/complete"
    38  	"github.com/onflow/flow-go/ledger/complete/wal/fixtures"
    39  	"github.com/onflow/flow-go/model/flow"
    40  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    41  	"github.com/onflow/flow-go/module/executiondatasync/provider"
    42  	mocktracker "github.com/onflow/flow-go/module/executiondatasync/tracker/mock"
    43  	"github.com/onflow/flow-go/module/mempool/entity"
    44  	"github.com/onflow/flow-go/module/metrics"
    45  	module "github.com/onflow/flow-go/module/mock"
    46  	requesterunit "github.com/onflow/flow-go/module/state_synchronization/requester/unittest"
    47  	"github.com/onflow/flow-go/module/trace"
    48  	"github.com/onflow/flow-go/utils/unittest"
    49  )
    50  
    51  var scriptLogThreshold = 1 * time.Second
    52  
    53  func TestComputeBlockWithStorage(t *testing.T) {
    54  	chain := flow.Mainnet.Chain()
    55  
    56  	vm := fvm.NewVirtualMachine()
    57  	execCtx := fvm.NewContext(fvm.WithChain(chain))
    58  
    59  	privateKeys, err := testutil.GenerateAccountPrivateKeys(2)
    60  	require.NoError(t, err)
    61  
    62  	snapshotTree, accounts, err := testutil.CreateAccounts(
    63  		vm,
    64  		testutil.RootBootstrappedLedger(vm, execCtx),
    65  		privateKeys,
    66  		chain)
    67  	require.NoError(t, err)
    68  
    69  	tx1 := testutil.DeployCounterContractTransaction(accounts[0], chain)
    70  	tx1.SetProposalKey(chain.ServiceAddress(), 0, 0).
    71  		SetGasLimit(1000).
    72  		SetPayer(chain.ServiceAddress())
    73  
    74  	err = testutil.SignPayload(tx1, accounts[0], privateKeys[0])
    75  	require.NoError(t, err)
    76  
    77  	err = testutil.SignEnvelope(tx1, chain.ServiceAddress(), unittest.ServiceAccountPrivateKey)
    78  	require.NoError(t, err)
    79  
    80  	tx2 := testutil.CreateCounterTransaction(accounts[0], accounts[1])
    81  	tx2.SetProposalKey(chain.ServiceAddress(), 0, 0).
    82  		SetGasLimit(1000).
    83  		SetPayer(chain.ServiceAddress())
    84  
    85  	err = testutil.SignPayload(tx2, accounts[1], privateKeys[1])
    86  	require.NoError(t, err)
    87  
    88  	err = testutil.SignEnvelope(tx2, chain.ServiceAddress(), unittest.ServiceAccountPrivateKey)
    89  	require.NoError(t, err)
    90  
    91  	transactions := []*flow.TransactionBody{tx1, tx2}
    92  
    93  	col := flow.Collection{Transactions: transactions}
    94  
    95  	guarantee := flow.CollectionGuarantee{
    96  		CollectionID: col.ID(),
    97  		Signature:    nil,
    98  	}
    99  
   100  	block := flow.Block{
   101  		Header: &flow.Header{
   102  			View: 42,
   103  		},
   104  		Payload: &flow.Payload{
   105  			Guarantees: []*flow.CollectionGuarantee{&guarantee},
   106  		},
   107  	}
   108  
   109  	executableBlock := &entity.ExecutableBlock{
   110  		Block: &block,
   111  		CompleteCollections: map[flow.Identifier]*entity.CompleteCollection{
   112  			guarantee.ID(): {
   113  				Guarantee:    &guarantee,
   114  				Transactions: transactions,
   115  			},
   116  		},
   117  		StartState: unittest.StateCommitmentPointerFixture(),
   118  	}
   119  
   120  	me := new(module.Local)
   121  	me.On("NodeID").Return(unittest.IdentifierFixture())
   122  	me.On("Sign", mock.Anything, mock.Anything).Return(nil, nil)
   123  	me.On("SignFunc", mock.Anything, mock.Anything, mock.Anything).
   124  		Return(nil, nil)
   125  
   126  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   127  	trackerStorage := mocktracker.NewMockStorage()
   128  
   129  	prov := provider.NewProvider(
   130  		zerolog.Nop(),
   131  		metrics.NewNoopCollector(),
   132  		execution_data.DefaultSerializer,
   133  		bservice,
   134  		trackerStorage,
   135  	)
   136  
   137  	blockComputer, err := computer.NewBlockComputer(
   138  		vm,
   139  		execCtx,
   140  		metrics.NewNoopCollector(),
   141  		trace.NewNoopTracer(),
   142  		zerolog.Nop(),
   143  		committer.NewNoopViewCommitter(),
   144  		me,
   145  		prov,
   146  		nil,
   147  		testutil.ProtocolStateWithSourceFixture(nil),
   148  		testMaxConcurrency)
   149  	require.NoError(t, err)
   150  
   151  	derivedChainData, err := derived.NewDerivedChainData(10)
   152  	require.NoError(t, err)
   153  
   154  	engine := &Manager{
   155  		blockComputer:    blockComputer,
   156  		derivedChainData: derivedChainData,
   157  	}
   158  
   159  	returnedComputationResult, err := engine.ComputeBlock(
   160  		context.Background(),
   161  		unittest.IdentifierFixture(),
   162  		executableBlock,
   163  		snapshotTree)
   164  	require.NoError(t, err)
   165  
   166  	hasUpdates := false
   167  	for _, snapshot := range returnedComputationResult.AllExecutionSnapshots() {
   168  		if len(snapshot.WriteSet) > 0 {
   169  			hasUpdates = true
   170  			break
   171  		}
   172  	}
   173  	require.True(t, hasUpdates)
   174  	require.Equal(t, returnedComputationResult.BlockExecutionResult.Size(), 1+1) // 1 coll + 1 system chunk
   175  	assert.NotEmpty(t, returnedComputationResult.AllExecutionSnapshots()[0].UpdatedRegisters())
   176  }
   177  
   178  func TestComputeBlock_Uploader(t *testing.T) {
   179  
   180  	noopCollector := &metrics.NoopCollector{}
   181  
   182  	ledger, err := complete.NewLedger(&fixtures.NoopWAL{}, 10, noopCollector, zerolog.Nop(), complete.DefaultPathFinderVersion)
   183  	require.NoError(t, err)
   184  
   185  	compactor := fixtures.NewNoopCompactor(ledger)
   186  	<-compactor.Ready()
   187  	defer func() {
   188  		<-ledger.Done()
   189  		<-compactor.Done()
   190  	}()
   191  
   192  	me := new(module.Local)
   193  	me.On("NodeID").Return(unittest.IdentifierFixture())
   194  	me.On("Sign", mock.Anything, mock.Anything).Return(nil, nil)
   195  	me.On("SignFunc", mock.Anything, mock.Anything, mock.Anything).
   196  		Return(nil, nil)
   197  
   198  	computationResult := unittest2.ComputationResultFixture(
   199  		t,
   200  		unittest.IdentifierFixture(),
   201  		[][]flow.Identifier{
   202  			{unittest.IdentifierFixture()},
   203  			{unittest.IdentifierFixture()},
   204  		})
   205  
   206  	blockComputer := &FakeBlockComputer{
   207  		computationResult: computationResult,
   208  	}
   209  
   210  	derivedChainData, err := derived.NewDerivedChainData(10)
   211  	require.NoError(t, err)
   212  
   213  	manager := &Manager{
   214  		blockComputer:    blockComputer,
   215  		derivedChainData: derivedChainData,
   216  	}
   217  
   218  	_, err = manager.ComputeBlock(
   219  		context.Background(),
   220  		unittest.IdentifierFixture(),
   221  		computationResult.ExecutableBlock,
   222  		state2.NewLedgerStorageSnapshot(
   223  			ledger,
   224  			flow.StateCommitment(ledger.InitialState())))
   225  	require.NoError(t, err)
   226  }
   227  
   228  func TestExecuteScript(t *testing.T) {
   229  
   230  	logger := zerolog.Nop()
   231  
   232  	execCtx := fvm.NewContext(fvm.WithLogger(logger))
   233  
   234  	me := new(module.Local)
   235  	me.On("NodeID").Return(unittest.IdentifierFixture())
   236  	me.On("Sign", mock.Anything, mock.Anything).Return(nil, nil)
   237  	me.On("SignFunc", mock.Anything, mock.Anything, mock.Anything).
   238  		Return(nil, nil)
   239  
   240  	vm := fvm.NewVirtualMachine()
   241  
   242  	ledger := testutil.RootBootstrappedLedger(vm, execCtx, fvm.WithExecutionMemoryLimit(math.MaxUint64))
   243  
   244  	sc := systemcontracts.SystemContractsForChain(execCtx.Chain.ChainID())
   245  
   246  	script := []byte(fmt.Sprintf(
   247  		`
   248  			import FungibleToken from %s
   249  
   250  			pub fun main() {}
   251  		`,
   252  		sc.FungibleToken.Address.HexWithPrefix(),
   253  	))
   254  
   255  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   256  	trackerStorage := mocktracker.NewMockStorage()
   257  
   258  	prov := provider.NewProvider(
   259  		zerolog.Nop(),
   260  		metrics.NewNoopCollector(),
   261  		execution_data.DefaultSerializer,
   262  		bservice,
   263  		trackerStorage,
   264  	)
   265  
   266  	engine, err := New(logger,
   267  		metrics.NewNoopCollector(),
   268  		trace.NewNoopTracer(),
   269  		me,
   270  		testutil.ProtocolStateWithSourceFixture(nil),
   271  		execCtx,
   272  		committer.NewNoopViewCommitter(),
   273  		prov,
   274  		ComputationConfig{
   275  			QueryConfig:          query.NewDefaultConfig(),
   276  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   277  			MaxConcurrency:       1,
   278  		},
   279  	)
   280  	require.NoError(t, err)
   281  
   282  	header := unittest.BlockHeaderFixture()
   283  	_, err = engine.ExecuteScript(
   284  		context.Background(),
   285  		script,
   286  		nil,
   287  		header,
   288  		ledger)
   289  	require.NoError(t, err)
   290  }
   291  
   292  // Balance script used to swallow errors, which meant that even if the view was empty, a script that did nothing but get
   293  // the balance of an account would succeed and return 0.
   294  func TestExecuteScript_BalanceScriptFailsIfViewIsEmpty(t *testing.T) {
   295  
   296  	logger := zerolog.Nop()
   297  
   298  	execCtx := fvm.NewContext(fvm.WithLogger(logger))
   299  
   300  	me := new(module.Local)
   301  	me.On("NodeID").Return(unittest.IdentifierFixture())
   302  	me.On("Sign", mock.Anything, mock.Anything).Return(nil, nil)
   303  	me.On("SignFunc", mock.Anything, mock.Anything, mock.Anything).
   304  		Return(nil, nil)
   305  
   306  	snapshot := snapshot.NewReadFuncStorageSnapshot(
   307  		func(id flow.RegisterID) (flow.RegisterValue, error) {
   308  			return nil, fmt.Errorf("error getting register")
   309  		})
   310  
   311  	sc := systemcontracts.SystemContractsForChain(execCtx.Chain.ChainID())
   312  
   313  	script := []byte(fmt.Sprintf(
   314  		`
   315  			pub fun main(): UFix64 {
   316  				return getAccount(%s).balance
   317  			}
   318  		`,
   319  		sc.FungibleToken.Address.HexWithPrefix(),
   320  	))
   321  
   322  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   323  	trackerStorage := mocktracker.NewMockStorage()
   324  
   325  	prov := provider.NewProvider(
   326  		zerolog.Nop(),
   327  		metrics.NewNoopCollector(),
   328  		execution_data.DefaultSerializer,
   329  		bservice,
   330  		trackerStorage,
   331  	)
   332  
   333  	engine, err := New(logger,
   334  		metrics.NewNoopCollector(),
   335  		trace.NewNoopTracer(),
   336  		me,
   337  		testutil.ProtocolStateWithSourceFixture(nil),
   338  		execCtx,
   339  		committer.NewNoopViewCommitter(),
   340  		prov,
   341  		ComputationConfig{
   342  			QueryConfig:          query.NewDefaultConfig(),
   343  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   344  			MaxConcurrency:       1,
   345  		},
   346  	)
   347  	require.NoError(t, err)
   348  
   349  	header := unittest.BlockHeaderFixture()
   350  	_, err = engine.ExecuteScript(
   351  		context.Background(),
   352  		script,
   353  		nil,
   354  		header,
   355  		snapshot)
   356  	require.ErrorContains(t, err, "error getting register")
   357  }
   358  
   359  func TestExecuteScripPanicsAreHandled(t *testing.T) {
   360  
   361  	ctx := fvm.NewContext()
   362  
   363  	buffer := &bytes.Buffer{}
   364  	log := zerolog.New(buffer)
   365  
   366  	header := unittest.BlockHeaderFixture()
   367  
   368  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   369  	trackerStorage := mocktracker.NewMockStorage()
   370  
   371  	prov := provider.NewProvider(
   372  		zerolog.Nop(),
   373  		metrics.NewNoopCollector(),
   374  		execution_data.DefaultSerializer,
   375  		bservice,
   376  		trackerStorage,
   377  	)
   378  
   379  	manager, err := New(log,
   380  		metrics.NewNoopCollector(),
   381  		trace.NewNoopTracer(),
   382  		nil,
   383  		testutil.ProtocolStateWithSourceFixture(nil),
   384  		ctx,
   385  		committer.NewNoopViewCommitter(),
   386  		prov,
   387  		ComputationConfig{
   388  			QueryConfig:          query.NewDefaultConfig(),
   389  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   390  			MaxConcurrency:       1,
   391  			NewCustomVirtualMachine: func() fvm.VM {
   392  				return &PanickingVM{}
   393  			},
   394  		},
   395  	)
   396  	require.NoError(t, err)
   397  
   398  	_, err = manager.ExecuteScript(
   399  		context.Background(),
   400  		[]byte("whatever"),
   401  		nil,
   402  		header,
   403  		nil)
   404  
   405  	require.Error(t, err)
   406  
   407  	require.Contains(t, buffer.String(), "Verunsicherung")
   408  }
   409  
   410  func TestExecuteScript_LongScriptsAreLogged(t *testing.T) {
   411  
   412  	ctx := fvm.NewContext()
   413  
   414  	buffer := &bytes.Buffer{}
   415  	log := zerolog.New(buffer)
   416  
   417  	header := unittest.BlockHeaderFixture()
   418  
   419  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   420  	trackerStorage := mocktracker.NewMockStorage()
   421  
   422  	prov := provider.NewProvider(
   423  		zerolog.Nop(),
   424  		metrics.NewNoopCollector(),
   425  		execution_data.DefaultSerializer,
   426  		bservice,
   427  		trackerStorage,
   428  	)
   429  
   430  	manager, err := New(log,
   431  		metrics.NewNoopCollector(),
   432  		trace.NewNoopTracer(),
   433  		nil,
   434  		testutil.ProtocolStateWithSourceFixture(nil),
   435  		ctx,
   436  		committer.NewNoopViewCommitter(),
   437  		prov,
   438  		ComputationConfig{
   439  			QueryConfig: query.QueryConfig{
   440  				LogTimeThreshold:   1 * time.Millisecond,
   441  				ExecutionTimeLimit: query.DefaultExecutionTimeLimit,
   442  			},
   443  			DerivedDataCacheSize: 10,
   444  			MaxConcurrency:       1,
   445  			NewCustomVirtualMachine: func() fvm.VM {
   446  				return &LongRunningVM{duration: 2 * time.Millisecond}
   447  			},
   448  		},
   449  	)
   450  	require.NoError(t, err)
   451  
   452  	_, err = manager.ExecuteScript(
   453  		context.Background(),
   454  		[]byte("whatever"),
   455  		nil,
   456  		header,
   457  		nil)
   458  
   459  	require.NoError(t, err)
   460  
   461  	require.Contains(t, buffer.String(), "exceeded threshold")
   462  }
   463  
   464  func TestExecuteScript_ShortScriptsAreNotLogged(t *testing.T) {
   465  
   466  	ctx := fvm.NewContext()
   467  
   468  	buffer := &bytes.Buffer{}
   469  	log := zerolog.New(buffer)
   470  
   471  	header := unittest.BlockHeaderFixture()
   472  
   473  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   474  	trackerStorage := mocktracker.NewMockStorage()
   475  
   476  	prov := provider.NewProvider(
   477  		zerolog.Nop(),
   478  		metrics.NewNoopCollector(),
   479  		execution_data.DefaultSerializer,
   480  		bservice,
   481  		trackerStorage,
   482  	)
   483  
   484  	manager, err := New(log,
   485  		metrics.NewNoopCollector(),
   486  		trace.NewNoopTracer(),
   487  		nil,
   488  		testutil.ProtocolStateWithSourceFixture(nil),
   489  		ctx,
   490  		committer.NewNoopViewCommitter(),
   491  		prov,
   492  		ComputationConfig{
   493  			QueryConfig: query.QueryConfig{
   494  				LogTimeThreshold:   1 * time.Second,
   495  				ExecutionTimeLimit: query.DefaultExecutionTimeLimit,
   496  			},
   497  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   498  			MaxConcurrency:       1,
   499  			NewCustomVirtualMachine: func() fvm.VM {
   500  				return &LongRunningVM{duration: 0}
   501  			},
   502  		},
   503  	)
   504  	require.NoError(t, err)
   505  
   506  	_, err = manager.ExecuteScript(
   507  		context.Background(),
   508  		[]byte("whatever"),
   509  		nil,
   510  		header,
   511  		nil)
   512  
   513  	require.NoError(t, err)
   514  
   515  	require.NotContains(t, buffer.String(), "exceeded threshold")
   516  }
   517  
   518  type PanickingExecutor struct{}
   519  
   520  func (PanickingExecutor) Cleanup() {}
   521  
   522  func (PanickingExecutor) Preprocess() error {
   523  	return nil
   524  }
   525  
   526  func (PanickingExecutor) Execute() error {
   527  	panic("panic, but expected with sentinel for test: Verunsicherung ")
   528  }
   529  
   530  func (PanickingExecutor) Output() fvm.ProcedureOutput {
   531  	return fvm.ProcedureOutput{}
   532  }
   533  
   534  type PanickingVM struct{}
   535  
   536  func (p *PanickingVM) NewExecutor(
   537  	f fvm.Context,
   538  	procedure fvm.Procedure,
   539  	txn storage.TransactionPreparer,
   540  ) fvm.ProcedureExecutor {
   541  	return PanickingExecutor{}
   542  }
   543  
   544  func (p *PanickingVM) Run(
   545  	f fvm.Context,
   546  	procedure fvm.Procedure,
   547  	storageSnapshot snapshot.StorageSnapshot,
   548  ) (
   549  	*snapshot.ExecutionSnapshot,
   550  	fvm.ProcedureOutput,
   551  	error,
   552  ) {
   553  	panic("panic, but expected with sentinel for test: Verunsicherung ")
   554  }
   555  
   556  func (p *PanickingVM) GetAccount(
   557  	ctx fvm.Context,
   558  	address flow.Address,
   559  	storageSnapshot snapshot.StorageSnapshot,
   560  ) (
   561  	*flow.Account,
   562  	error,
   563  ) {
   564  	panic("not expected")
   565  }
   566  
   567  type LongRunningExecutor struct {
   568  	duration time.Duration
   569  }
   570  
   571  func (LongRunningExecutor) Cleanup() {}
   572  
   573  func (LongRunningExecutor) Preprocess() error {
   574  	return nil
   575  }
   576  
   577  func (l LongRunningExecutor) Execute() error {
   578  	time.Sleep(l.duration)
   579  	return nil
   580  }
   581  
   582  func (LongRunningExecutor) Output() fvm.ProcedureOutput {
   583  	return fvm.ProcedureOutput{
   584  		Value: cadence.NewVoid(),
   585  	}
   586  }
   587  
   588  type LongRunningVM struct {
   589  	duration time.Duration
   590  }
   591  
   592  func (l *LongRunningVM) NewExecutor(
   593  	f fvm.Context,
   594  	procedure fvm.Procedure,
   595  	txn storage.TransactionPreparer,
   596  ) fvm.ProcedureExecutor {
   597  	return LongRunningExecutor{
   598  		duration: l.duration,
   599  	}
   600  }
   601  
   602  func (l *LongRunningVM) Run(
   603  	f fvm.Context,
   604  	procedure fvm.Procedure,
   605  	storageSnapshot snapshot.StorageSnapshot,
   606  ) (
   607  	*snapshot.ExecutionSnapshot,
   608  	fvm.ProcedureOutput,
   609  	error,
   610  ) {
   611  	time.Sleep(l.duration)
   612  
   613  	snapshot := &snapshot.ExecutionSnapshot{}
   614  	output := fvm.ProcedureOutput{
   615  		Value: cadence.NewVoid(),
   616  	}
   617  	return snapshot, output, nil
   618  }
   619  
   620  func (l *LongRunningVM) GetAccount(
   621  	ctx fvm.Context,
   622  	address flow.Address,
   623  	storageSnapshot snapshot.StorageSnapshot,
   624  ) (
   625  	*flow.Account,
   626  	error,
   627  ) {
   628  	panic("not expected")
   629  }
   630  
   631  type FakeBlockComputer struct {
   632  	computationResult *execution.ComputationResult
   633  }
   634  
   635  func (f *FakeBlockComputer) ExecuteBlock(
   636  	context.Context,
   637  	flow.Identifier,
   638  	*entity.ExecutableBlock,
   639  	snapshot.StorageSnapshot,
   640  	*derived.DerivedBlockData,
   641  ) (
   642  	*execution.ComputationResult,
   643  	error,
   644  ) {
   645  	return f.computationResult, nil
   646  }
   647  
   648  func TestExecuteScriptTimeout(t *testing.T) {
   649  
   650  	timeout := 1 * time.Millisecond
   651  	manager, err := New(
   652  		zerolog.Nop(),
   653  		metrics.NewNoopCollector(),
   654  		trace.NewNoopTracer(),
   655  		nil,
   656  		testutil.ProtocolStateWithSourceFixture(nil),
   657  		fvm.NewContext(),
   658  		committer.NewNoopViewCommitter(),
   659  		nil,
   660  		ComputationConfig{
   661  			QueryConfig: query.QueryConfig{
   662  				LogTimeThreshold:   query.DefaultLogTimeThreshold,
   663  				ExecutionTimeLimit: timeout,
   664  			},
   665  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   666  			MaxConcurrency:       1,
   667  		},
   668  	)
   669  
   670  	require.NoError(t, err)
   671  
   672  	script := []byte(`
   673  	pub fun main(): Int {
   674  		var i = 0
   675  		while i < 10000 {
   676  			i = i + 1
   677  		}
   678  		return i
   679  	}
   680  	`)
   681  
   682  	header := unittest.BlockHeaderFixture()
   683  	value, err := manager.ExecuteScript(
   684  		context.Background(),
   685  		script,
   686  		nil,
   687  		header,
   688  		nil)
   689  
   690  	require.Error(t, err)
   691  	require.Nil(t, value)
   692  	require.Contains(t, err.Error(), fvmErrors.ErrCodeScriptExecutionTimedOutError.String())
   693  }
   694  
   695  func TestExecuteScriptCancelled(t *testing.T) {
   696  
   697  	timeout := 30 * time.Second
   698  	manager, err := New(
   699  		zerolog.Nop(),
   700  		metrics.NewNoopCollector(),
   701  		trace.NewNoopTracer(),
   702  		nil,
   703  		testutil.ProtocolStateWithSourceFixture(nil),
   704  		fvm.NewContext(),
   705  		committer.NewNoopViewCommitter(),
   706  		nil,
   707  		ComputationConfig{
   708  			QueryConfig: query.QueryConfig{
   709  				LogTimeThreshold:   query.DefaultLogTimeThreshold,
   710  				ExecutionTimeLimit: timeout,
   711  			},
   712  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   713  			MaxConcurrency:       1,
   714  		},
   715  	)
   716  
   717  	require.NoError(t, err)
   718  
   719  	script := []byte(`
   720  	pub fun main(): Int {
   721  		var i = 0
   722  		var j = 0 
   723  		while i < 10000000 {
   724  			i = i + 1
   725  			j = i + j
   726  		}
   727  		return i
   728  	}
   729  	`)
   730  
   731  	var value []byte
   732  	var wg sync.WaitGroup
   733  	reqCtx, cancel := context.WithCancel(context.Background())
   734  	wg.Add(1)
   735  	go func() {
   736  		header := unittest.BlockHeaderFixture()
   737  		value, err = manager.ExecuteScript(
   738  			reqCtx,
   739  			script,
   740  			nil,
   741  			header,
   742  			nil)
   743  		wg.Done()
   744  	}()
   745  	cancel()
   746  	wg.Wait()
   747  	require.Nil(t, value)
   748  	require.Contains(t, err.Error(), fvmErrors.ErrCodeScriptExecutionCancelledError.String())
   749  }
   750  
   751  func Test_EventEncodingFailsOnlyTxAndCarriesOn(t *testing.T) {
   752  
   753  	chain := flow.Mainnet.Chain()
   754  	vm := fvm.NewVirtualMachine()
   755  
   756  	eventEncoder := &testingEventEncoder{
   757  		realEncoder: environment.NewCadenceEventEncoder(),
   758  	}
   759  
   760  	execCtx := fvm.NewContext(
   761  		fvm.WithChain(chain),
   762  		fvm.WithEventEncoder(eventEncoder),
   763  	)
   764  
   765  	privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   766  	require.NoError(t, err)
   767  	snapshotTree, accounts, err := testutil.CreateAccounts(
   768  		vm,
   769  		testutil.RootBootstrappedLedger(vm, execCtx),
   770  		privateKeys,
   771  		chain)
   772  	require.NoError(t, err)
   773  
   774  	// setup transactions
   775  	account := accounts[0]
   776  	privKey := privateKeys[0]
   777  	// tx1 deploys contract version 1
   778  	tx1 := testutil.DeployEventContractTransaction(account, chain, 1)
   779  	prepareTx(t, tx1, account, privKey, 0, chain)
   780  
   781  	// tx2 emits event which will fail encoding
   782  	tx2 := testutil.CreateEmitEventTransaction(account, account)
   783  	prepareTx(t, tx2, account, privKey, 1, chain)
   784  
   785  	// tx3 emits event that will work fine
   786  	tx3 := testutil.CreateEmitEventTransaction(account, account)
   787  	prepareTx(t, tx3, account, privKey, 2, chain)
   788  
   789  	transactions := []*flow.TransactionBody{tx1, tx2, tx3}
   790  
   791  	col := flow.Collection{Transactions: transactions}
   792  
   793  	guarantee := flow.CollectionGuarantee{
   794  		CollectionID: col.ID(),
   795  		Signature:    nil,
   796  	}
   797  
   798  	block := flow.Block{
   799  		Header: &flow.Header{
   800  			View: 26,
   801  		},
   802  		Payload: &flow.Payload{
   803  			Guarantees: []*flow.CollectionGuarantee{&guarantee},
   804  		},
   805  	}
   806  
   807  	executableBlock := &entity.ExecutableBlock{
   808  		Block: &block,
   809  		CompleteCollections: map[flow.Identifier]*entity.CompleteCollection{
   810  			guarantee.ID(): {
   811  				Guarantee:    &guarantee,
   812  				Transactions: transactions,
   813  			},
   814  		},
   815  		StartState: unittest.StateCommitmentPointerFixture(),
   816  	}
   817  
   818  	me := new(module.Local)
   819  	me.On("NodeID").Return(unittest.IdentifierFixture())
   820  	me.On("Sign", mock.Anything, mock.Anything).Return(nil, nil)
   821  	me.On("SignFunc", mock.Anything, mock.Anything, mock.Anything).
   822  		Return(nil, nil)
   823  
   824  	bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore())))
   825  	trackerStorage := mocktracker.NewMockStorage()
   826  
   827  	prov := provider.NewProvider(
   828  		zerolog.Nop(),
   829  		metrics.NewNoopCollector(),
   830  		execution_data.DefaultSerializer,
   831  		bservice,
   832  		trackerStorage,
   833  	)
   834  
   835  	blockComputer, err := computer.NewBlockComputer(
   836  		vm,
   837  		execCtx,
   838  		metrics.NewNoopCollector(),
   839  		trace.NewNoopTracer(),
   840  		zerolog.Nop(),
   841  		committer.NewNoopViewCommitter(),
   842  		me,
   843  		prov,
   844  		nil,
   845  		testutil.ProtocolStateWithSourceFixture(nil),
   846  		testMaxConcurrency)
   847  	require.NoError(t, err)
   848  
   849  	derivedChainData, err := derived.NewDerivedChainData(10)
   850  	require.NoError(t, err)
   851  
   852  	engine := &Manager{
   853  		blockComputer:    blockComputer,
   854  		derivedChainData: derivedChainData,
   855  	}
   856  
   857  	eventEncoder.enabled = true
   858  
   859  	returnedComputationResult, err := engine.ComputeBlock(
   860  		context.Background(),
   861  		unittest.IdentifierFixture(),
   862  		executableBlock,
   863  		snapshotTree)
   864  	require.NoError(t, err)
   865  
   866  	txResults := returnedComputationResult.AllTransactionResults()
   867  	require.Len(t, txResults, 4) // 2 txs + 1 system tx
   868  
   869  	require.Empty(t, txResults[0].ErrorMessage)
   870  	require.Contains(t, txResults[1].ErrorMessage, "I failed encoding")
   871  	require.Empty(t, txResults[2].ErrorMessage)
   872  
   873  	colRes := returnedComputationResult.CollectionExecutionResultAt(0)
   874  	events := colRes.Events()
   875  	require.Len(t, events, 2) // 1 collection + 1 system chunk
   876  
   877  	// first event should be contract deployed
   878  	assert.EqualValues(t, "flow.AccountContractAdded", events[0].Type)
   879  
   880  	// second event should come from tx3 (index 2)  as tx2 (index 1) should fail encoding
   881  	hasValidEventValue(t, events[1], 1)
   882  	assert.Equal(t, events[1].TransactionIndex, uint32(2))
   883  }
   884  
   885  type testingEventEncoder struct {
   886  	realEncoder *environment.CadenceEventEncoder
   887  	calls       int
   888  	enabled     bool
   889  }
   890  
   891  func (e *testingEventEncoder) Encode(event cadence.Event) ([]byte, error) {
   892  	defer func() {
   893  		if e.enabled {
   894  			e.calls++
   895  		}
   896  	}()
   897  
   898  	if e.calls == 1 && e.enabled {
   899  		return nil, fmt.Errorf("I failed encoding")
   900  	}
   901  	return e.realEncoder.Encode(event)
   902  }
   903  
   904  func TestScriptStorageMutationsDiscarded(t *testing.T) {
   905  
   906  	timeout := 10 * time.Second
   907  	chain := flow.Mainnet.Chain()
   908  	ctx := fvm.NewContext(fvm.WithChain(chain))
   909  	manager, _ := New(
   910  		zerolog.Nop(),
   911  		metrics.NewExecutionCollector(ctx.Tracer),
   912  		trace.NewNoopTracer(),
   913  		nil,
   914  		testutil.ProtocolStateWithSourceFixture(nil),
   915  		ctx,
   916  		committer.NewNoopViewCommitter(),
   917  		nil,
   918  		ComputationConfig{
   919  			QueryConfig: query.QueryConfig{
   920  				LogTimeThreshold:   query.DefaultLogTimeThreshold,
   921  				ExecutionTimeLimit: timeout,
   922  			},
   923  			DerivedDataCacheSize: derived.DefaultDerivedDataCacheSize,
   924  			MaxConcurrency:       1,
   925  		},
   926  	)
   927  	vm := manager.vm
   928  
   929  	// Create an account private key.
   930  	privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   931  	require.NoError(t, err)
   932  
   933  	// Bootstrap a ledger, creating accounts with the provided private keys
   934  	// and the root account.
   935  	snapshotTree, accounts, err := testutil.CreateAccounts(
   936  		vm,
   937  		testutil.RootBootstrappedLedger(vm, ctx),
   938  		privateKeys,
   939  		chain)
   940  	require.NoError(t, err)
   941  	account := accounts[0]
   942  	address := cadence.NewAddress(account)
   943  	commonAddress, _ := common.HexToAddress(address.Hex())
   944  
   945  	script := []byte(`
   946  	pub fun main(account: Address) {
   947  		let acc = getAuthAccount(account)
   948  		acc.save(3, to: /storage/x)
   949  	}
   950  	`)
   951  
   952  	header := unittest.BlockHeaderFixture()
   953  	_, err = manager.ExecuteScript(
   954  		context.Background(),
   955  		script,
   956  		[][]byte{jsoncdc.MustEncode(address)},
   957  		header,
   958  		snapshotTree)
   959  
   960  	require.NoError(t, err)
   961  
   962  	env := environment.NewScriptEnvironmentFromStorageSnapshot(
   963  		ctx.EnvironmentParams,
   964  		snapshotTree)
   965  
   966  	rt := env.BorrowCadenceRuntime()
   967  	defer env.ReturnCadenceRuntime(rt)
   968  
   969  	path, err := cadence.NewPath(common.PathDomainStorage, "x")
   970  	require.NoError(t, err)
   971  
   972  	v, err := rt.ReadStored(commonAddress, path)
   973  	// the save should not update account storage by writing the updates
   974  	// back to the snapshotTree
   975  	require.NoError(t, err)
   976  	require.Equal(t, nil, v)
   977  }