github.com/onflow/flow-go@v0.33.17/fvm/fvm_blockcontext_test.go (about)

     1  package fvm_test
     2  
     3  import (
     4  	"crypto/rand"
     5  	"encoding/base64"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"math"
     9  	"strconv"
    10  	"testing"
    11  
    12  	"github.com/onflow/cadence"
    13  	"github.com/onflow/cadence/encoding/ccf"
    14  	jsoncdc "github.com/onflow/cadence/encoding/json"
    15  	"github.com/onflow/cadence/runtime"
    16  	"github.com/stretchr/testify/mock"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	"github.com/onflow/flow-go/crypto"
    20  	"github.com/onflow/flow-go/crypto/hash"
    21  	"github.com/onflow/flow-go/engine/execution/testutil"
    22  	"github.com/onflow/flow-go/fvm"
    23  	"github.com/onflow/flow-go/fvm/blueprints"
    24  	envMock "github.com/onflow/flow-go/fvm/environment/mock"
    25  	errors "github.com/onflow/flow-go/fvm/errors"
    26  	"github.com/onflow/flow-go/fvm/storage/snapshot"
    27  	"github.com/onflow/flow-go/fvm/systemcontracts"
    28  	"github.com/onflow/flow-go/model/flow"
    29  	"github.com/onflow/flow-go/utils/unittest"
    30  )
    31  
    32  func transferTokensTx(chain flow.Chain) *flow.TransactionBody {
    33  	sc := systemcontracts.SystemContractsForChain(chain.ChainID())
    34  	return flow.NewTransactionBody().
    35  		SetScript([]byte(fmt.Sprintf(
    36  			`
    37  							// This transaction is a template for a transaction that
    38  							// could be used by anyone to send tokens to another account
    39  							// that has been set up to receive tokens.
    40  							//
    41  							// The withdraw amount and the account from getAccount
    42  							// would be the parameters to the transaction
    43  
    44  							import FungibleToken from 0x%s
    45  							import FlowToken from 0x%s
    46  
    47  							transaction(amount: UFix64, to: Address) {
    48  
    49  								// The Vault resource that holds the tokens that are being transferred
    50  								let sentVault: @FungibleToken.Vault
    51  
    52  								prepare(signer: AuthAccount) {
    53  
    54  									// Get a reference to the signer's stored vault
    55  									let vaultRef = signer.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)
    56  										?? panic("Could not borrow reference to the owner's Vault!")
    57  
    58  									// Withdraw tokens from the signer's stored vault
    59  									self.sentVault <- vaultRef.withdraw(amount: amount)
    60  								}
    61  
    62  								execute {
    63  
    64  									// Get the recipient's public account object
    65  									let recipient = getAccount(to)
    66  
    67  									// Get a reference to the recipient's Receiver
    68  									let receiverRef = recipient.getCapability(/public/flowTokenReceiver)
    69  										.borrow<&{FungibleToken.Receiver}>()
    70  										?? panic("Could not borrow receiver reference to the recipient's Vault")
    71  
    72  									// Deposit the withdrawn tokens in the recipient's receiver
    73  									receiverRef.deposit(from: <-self.sentVault)
    74  								}
    75  							}`,
    76  			sc.FungibleToken.Address.Hex(),
    77  			sc.FlowToken.Address.Hex(),
    78  		)),
    79  		)
    80  }
    81  
    82  func filterAccountCreatedEvents(events []flow.Event) []flow.Event {
    83  	var accountCreatedEvents []flow.Event
    84  	for _, event := range events {
    85  		if event.Type != flow.EventAccountCreated {
    86  			continue
    87  		}
    88  		accountCreatedEvents = append(accountCreatedEvents, event)
    89  		break
    90  	}
    91  	return accountCreatedEvents
    92  }
    93  
    94  func TestBlockContext_ExecuteTransaction(t *testing.T) {
    95  
    96  	t.Parallel()
    97  
    98  	chain, vm := createChainAndVm(flow.Testnet)
    99  
   100  	ctx := fvm.NewContext(
   101  		fvm.WithChain(chain),
   102  		fvm.WithCadenceLogging(true),
   103  	)
   104  
   105  	t.Run("Success", func(t *testing.T) {
   106  		txBody := flow.NewTransactionBody().
   107  			SetScript([]byte(`
   108  	            transaction {
   109  	              prepare(signer: AuthAccount) {}
   110  	            }
   111  	        `)).
   112  			AddAuthorizer(unittest.AddressFixture())
   113  
   114  		err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
   115  		require.NoError(t, err)
   116  
   117  		_, output, err := vm.Run(
   118  			ctx,
   119  			fvm.Transaction(txBody, 0),
   120  			testutil.RootBootstrappedLedger(vm, ctx))
   121  		require.NoError(t, err)
   122  		require.NoError(t, output.Err)
   123  	})
   124  
   125  	t.Run("Failure", func(t *testing.T) {
   126  		txBody := flow.NewTransactionBody().
   127  			SetScript([]byte(`
   128                  transaction {
   129                    var x: Int
   130  
   131                    prepare(signer: AuthAccount) {
   132                      self.x = 0
   133                    }
   134  
   135                    execute {
   136                      self.x = 1
   137                    }
   138  
   139                    post {
   140                      self.x == 2
   141                    }
   142                  }
   143              `))
   144  
   145  		err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
   146  		require.NoError(t, err)
   147  
   148  		_, output, err := vm.Run(
   149  			ctx,
   150  			fvm.Transaction(txBody, 0),
   151  			testutil.RootBootstrappedLedger(vm, ctx))
   152  		require.NoError(t, err)
   153  		require.Error(t, output.Err)
   154  	})
   155  
   156  	t.Run("Logs", func(t *testing.T) {
   157  		txBody := flow.NewTransactionBody().
   158  			SetScript([]byte(`
   159                  transaction {
   160                    execute {
   161                      log("foo")
   162                      log("bar")
   163                    }
   164                  }
   165              `))
   166  
   167  		err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
   168  		require.NoError(t, err)
   169  
   170  		_, output, err := vm.Run(
   171  			ctx,
   172  			fvm.Transaction(txBody, 0),
   173  			testutil.RootBootstrappedLedger(vm, ctx))
   174  		require.NoError(t, err)
   175  		require.NoError(t, output.Err)
   176  
   177  		require.Equal(t, []string{"\"foo\"", "\"bar\""}, output.Logs)
   178  	})
   179  
   180  	t.Run("Events", func(t *testing.T) {
   181  		txBody := flow.NewTransactionBody().
   182  			SetScript([]byte(`
   183                  transaction {
   184                    prepare(signer: AuthAccount) {
   185                      AuthAccount(payer: signer)
   186                    }
   187                  }
   188              `)).
   189  			AddAuthorizer(chain.ServiceAddress())
   190  
   191  		err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
   192  		require.NoError(t, err)
   193  
   194  		_, output, err := vm.Run(
   195  			ctx,
   196  			fvm.Transaction(txBody, 0),
   197  			testutil.RootBootstrappedLedger(vm, ctx))
   198  		require.NoError(t, err)
   199  		require.NoError(t, output.Err)
   200  
   201  		require.Len(t, filterAccountCreatedEvents(output.Events), 1)
   202  	})
   203  }
   204  
   205  func TestBlockContext_DeployContract(t *testing.T) {
   206  
   207  	t.Parallel()
   208  
   209  	chain, vm := createChainAndVm(flow.Mainnet)
   210  
   211  	ctx := fvm.NewContext(
   212  		fvm.WithChain(chain),
   213  		fvm.WithCadenceLogging(true),
   214  	)
   215  
   216  	t.Run("account update with set code succeeds as service account", func(t *testing.T) {
   217  
   218  		// Create an account private key.
   219  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   220  		require.NoError(t, err)
   221  
   222  		// Bootstrap a ledger, creating accounts with the provided private keys
   223  		// and the root account.
   224  		snapshotTree, accounts, err := testutil.CreateAccounts(
   225  			vm,
   226  			testutil.RootBootstrappedLedger(vm, ctx),
   227  			privateKeys,
   228  			chain)
   229  		require.NoError(t, err)
   230  
   231  		txBody := testutil.DeployCounterContractTransaction(accounts[0], chain)
   232  
   233  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   234  		txBody.SetPayer(chain.ServiceAddress())
   235  
   236  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   237  		require.NoError(t, err)
   238  
   239  		err = testutil.SignEnvelope(
   240  			txBody,
   241  			chain.ServiceAddress(),
   242  			unittest.ServiceAccountPrivateKey)
   243  		require.NoError(t, err)
   244  
   245  		_, output, err := vm.Run(
   246  			ctx,
   247  			fvm.Transaction(txBody, 0),
   248  			snapshotTree)
   249  		require.NoError(t, err)
   250  		require.NoError(t, output.Err)
   251  	})
   252  
   253  	t.Run("account with deployed contract has `contracts.names` filled", func(t *testing.T) {
   254  
   255  		// Create an account private key.
   256  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   257  		require.NoError(t, err)
   258  
   259  		// Bootstrap a ledger, creating accounts with the provided private keys
   260  		// and the root account.
   261  		snapshotTree, accounts, err := testutil.CreateAccounts(
   262  			vm,
   263  			testutil.RootBootstrappedLedger(vm, ctx),
   264  			privateKeys,
   265  			chain)
   266  		require.NoError(t, err)
   267  
   268  		txBody := testutil.DeployCounterContractTransaction(accounts[0], chain)
   269  
   270  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   271  		txBody.SetPayer(chain.ServiceAddress())
   272  
   273  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   274  		require.NoError(t, err)
   275  
   276  		err = testutil.SignEnvelope(
   277  			txBody,
   278  			chain.ServiceAddress(),
   279  			unittest.ServiceAccountPrivateKey)
   280  		require.NoError(t, err)
   281  
   282  		executionSnapshot, output, err := vm.Run(
   283  			ctx,
   284  			fvm.Transaction(txBody, 0),
   285  			snapshotTree)
   286  		require.NoError(t, err)
   287  		require.NoError(t, output.Err)
   288  
   289  		snapshotTree = snapshotTree.Append(executionSnapshot)
   290  
   291  		// transaction will panic if `contracts.names` is incorrect
   292  		txBody = flow.NewTransactionBody().
   293  			SetScript([]byte(`
   294  				transaction {
   295  					prepare(signer: AuthAccount) {
   296  						var s : String = ""
   297  						for name in signer.contracts.names {
   298  							s = s.concat(name).concat(",")
   299  						}
   300  						if s != "Container," {
   301  							panic(s)
   302  						}
   303  					}
   304  				}
   305  			`)).
   306  			AddAuthorizer(accounts[0])
   307  
   308  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 1)
   309  		txBody.SetPayer(chain.ServiceAddress())
   310  
   311  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   312  		require.NoError(t, err)
   313  
   314  		err = testutil.SignEnvelope(
   315  			txBody,
   316  			chain.ServiceAddress(),
   317  			unittest.ServiceAccountPrivateKey)
   318  		require.NoError(t, err)
   319  
   320  		_, output, err = vm.Run(
   321  			ctx,
   322  			fvm.Transaction(txBody, 0),
   323  			snapshotTree)
   324  		require.NoError(t, err)
   325  		require.NoError(t, output.Err)
   326  	})
   327  
   328  	t.Run("account update with checker heavy contract (local replay limit)", func(t *testing.T) {
   329  		// Create an account private key.
   330  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   331  		require.NoError(t, err)
   332  
   333  		// Bootstrap a ledger, creating accounts with the provided private keys
   334  		// and the root account.
   335  		snapshotTree, accounts, err := testutil.CreateAccounts(
   336  			vm,
   337  			testutil.RootBootstrappedLedger(vm, ctx),
   338  			privateKeys,
   339  			chain)
   340  		require.NoError(t, err)
   341  
   342  		txBody := testutil.DeployLocalReplayLimitedTransaction(
   343  			accounts[0],
   344  			chain)
   345  
   346  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   347  		txBody.SetPayer(chain.ServiceAddress())
   348  
   349  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   350  		require.NoError(t, err)
   351  
   352  		err = testutil.SignEnvelope(
   353  			txBody,
   354  			chain.ServiceAddress(),
   355  			unittest.ServiceAccountPrivateKey)
   356  		require.NoError(t, err)
   357  
   358  		_, output, err := vm.Run(
   359  			ctx,
   360  			fvm.Transaction(txBody, 0),
   361  			snapshotTree)
   362  		require.NoError(t, err)
   363  
   364  		var parsingCheckingError *runtime.ParsingCheckingError
   365  		require.ErrorAs(t, output.Err, &parsingCheckingError)
   366  		require.ErrorContains(
   367  			t,
   368  			output.Err,
   369  			"program too ambiguous, local replay limit of 64 tokens exceeded")
   370  	})
   371  
   372  	t.Run("account update with checker heavy contract (global replay limit)", func(t *testing.T) {
   373  		// Create an account private key.
   374  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   375  		require.NoError(t, err)
   376  
   377  		// Bootstrap a ledger, creating accounts with the provided private keys
   378  		// and the root account.
   379  		snapshotTree, accounts, err := testutil.CreateAccounts(
   380  			vm,
   381  			testutil.RootBootstrappedLedger(vm, ctx),
   382  			privateKeys,
   383  			chain)
   384  		require.NoError(t, err)
   385  
   386  		txBody := testutil.DeployGlobalReplayLimitedTransaction(
   387  			accounts[0],
   388  			chain)
   389  
   390  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   391  		txBody.SetPayer(chain.ServiceAddress())
   392  
   393  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   394  		require.NoError(t, err)
   395  
   396  		err = testutil.SignEnvelope(
   397  			txBody,
   398  			chain.ServiceAddress(),
   399  			unittest.ServiceAccountPrivateKey)
   400  		require.NoError(t, err)
   401  
   402  		_, output, err := vm.Run(
   403  			ctx,
   404  			fvm.Transaction(txBody, 0),
   405  			snapshotTree)
   406  		require.NoError(t, err)
   407  
   408  		var parsingCheckingError *runtime.ParsingCheckingError
   409  		require.ErrorAs(t, output.Err, &parsingCheckingError)
   410  		require.ErrorContains(
   411  			t,
   412  			output.Err,
   413  			"program too ambiguous, global replay limit of 1024 tokens exceeded")
   414  	})
   415  
   416  	t.Run("account update with set code fails if not signed by service account", func(t *testing.T) {
   417  		// Create an account private key.
   418  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   419  		require.NoError(t, err)
   420  
   421  		// Bootstrap a ledger, creating accounts with the provided private keys
   422  		// and the root account.
   423  		snapshotTree, accounts, err := testutil.CreateAccounts(
   424  			vm,
   425  			testutil.RootBootstrappedLedger(vm, ctx),
   426  			privateKeys,
   427  			chain)
   428  		require.NoError(t, err)
   429  
   430  		txBody := testutil.DeployUnauthorizedCounterContractTransaction(
   431  			accounts[0])
   432  
   433  		err = testutil.SignTransaction(txBody, accounts[0], privateKeys[0], 0)
   434  		require.NoError(t, err)
   435  
   436  		_, output, err := vm.Run(
   437  			ctx,
   438  			fvm.Transaction(txBody, 0),
   439  			snapshotTree)
   440  		require.NoError(t, err)
   441  
   442  		require.Error(t, output.Err)
   443  
   444  		require.ErrorContains(
   445  			t,
   446  			output.Err,
   447  			"deploying contracts requires authorization from specific accounts")
   448  		require.True(t, errors.IsCadenceRuntimeError(output.Err))
   449  	})
   450  
   451  	t.Run("account update with set code fails if not signed by service account if dis-allowed in the state", func(t *testing.T) {
   452  		ctx := fvm.NewContext(
   453  			fvm.WithChain(chain),
   454  			fvm.WithCadenceLogging(true),
   455  			fvm.WithContractDeploymentRestricted(false),
   456  		)
   457  		restricted := true
   458  
   459  		// Create an account private key.
   460  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   461  		require.NoError(t, err)
   462  
   463  		// Bootstrap a ledger, creating accounts with the provided private keys
   464  		// and the root account.
   465  		snapshotTree, accounts, err := testutil.CreateAccounts(
   466  			vm,
   467  			testutil.RootBootstrappedLedger(
   468  				vm,
   469  				ctx,
   470  				fvm.WithRestrictedContractDeployment(&restricted)),
   471  			privateKeys,
   472  			chain)
   473  		require.NoError(t, err)
   474  
   475  		txBody := testutil.DeployUnauthorizedCounterContractTransaction(
   476  			accounts[0])
   477  		txBody.SetProposalKey(accounts[0], 0, 0)
   478  		txBody.SetPayer(accounts[0])
   479  
   480  		err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
   481  		require.NoError(t, err)
   482  
   483  		_, output, err := vm.Run(
   484  			ctx,
   485  			fvm.Transaction(txBody, 0),
   486  
   487  			snapshotTree)
   488  		require.NoError(t, err)
   489  		require.Error(t, output.Err)
   490  
   491  		require.ErrorContains(
   492  			t,
   493  			output.Err,
   494  			"deploying contracts requires authorization from specific accounts")
   495  		require.True(t, errors.IsCadenceRuntimeError(output.Err))
   496  	})
   497  
   498  	t.Run("account update with set succeeds if not signed by service account if allowed in the state", func(t *testing.T) {
   499  
   500  		// Create an account private key.
   501  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   502  		require.NoError(t, err)
   503  
   504  		// Bootstrap a ledger, creating accounts with the provided private keys
   505  		// and the root account.
   506  		restricted := false
   507  		snapshotTree, accounts, err := testutil.CreateAccounts(
   508  			vm,
   509  			testutil.RootBootstrappedLedger(
   510  				vm,
   511  				ctx,
   512  				fvm.WithRestrictedContractDeployment(&restricted)),
   513  			privateKeys,
   514  			chain)
   515  		require.NoError(t, err)
   516  
   517  		txBody := testutil.DeployUnauthorizedCounterContractTransaction(
   518  			accounts[0])
   519  		txBody.SetProposalKey(accounts[0], 0, 0)
   520  		txBody.SetPayer(accounts[0])
   521  
   522  		err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
   523  		require.NoError(t, err)
   524  
   525  		_, output, err := vm.Run(
   526  			ctx,
   527  			fvm.Transaction(txBody, 0),
   528  			snapshotTree)
   529  		require.NoError(t, err)
   530  		require.NoError(t, output.Err)
   531  	})
   532  
   533  	t.Run("account update with update code succeeds if not signed by service account", func(t *testing.T) {
   534  		// Create an account private key.
   535  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   536  		require.NoError(t, err)
   537  
   538  		// Bootstrap a ledger, creating accounts with the provided private keys
   539  		// and the root account.
   540  		snapshotTree, accounts, err := testutil.CreateAccounts(
   541  			vm,
   542  			testutil.RootBootstrappedLedger(vm, ctx),
   543  			privateKeys,
   544  			chain)
   545  		require.NoError(t, err)
   546  
   547  		txBody := testutil.DeployCounterContractTransaction(accounts[0], chain)
   548  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   549  		txBody.SetPayer(chain.ServiceAddress())
   550  
   551  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   552  		require.NoError(t, err)
   553  
   554  		err = testutil.SignEnvelope(
   555  			txBody,
   556  			chain.ServiceAddress(),
   557  			unittest.ServiceAccountPrivateKey)
   558  		require.NoError(t, err)
   559  
   560  		executionSnapshot, output, err := vm.Run(
   561  			ctx,
   562  			fvm.Transaction(txBody, 0),
   563  			snapshotTree)
   564  		require.NoError(t, err)
   565  		require.NoError(t, output.Err)
   566  
   567  		snapshotTree = snapshotTree.Append(executionSnapshot)
   568  
   569  		txBody = testutil.UpdateUnauthorizedCounterContractTransaction(
   570  			accounts[0])
   571  		txBody.SetProposalKey(accounts[0], 0, 0)
   572  		txBody.SetPayer(accounts[0])
   573  
   574  		err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
   575  		require.NoError(t, err)
   576  
   577  		_, output, err = vm.Run(
   578  			ctx,
   579  			fvm.Transaction(txBody, 0),
   580  			snapshotTree)
   581  		require.NoError(t, err)
   582  		require.NoError(t, output.Err)
   583  	})
   584  
   585  	t.Run("account update with code removal fails if not signed by service account", func(t *testing.T) {
   586  
   587  		// Create an account private key.
   588  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   589  		require.NoError(t, err)
   590  
   591  		// Bootstrap a ledger, creating accounts with the provided private keys
   592  		// and the root account.
   593  		snapshotTree, accounts, err := testutil.CreateAccounts(
   594  			vm,
   595  			testutil.RootBootstrappedLedger(vm, ctx),
   596  			privateKeys,
   597  			chain)
   598  		require.NoError(t, err)
   599  
   600  		txBody := testutil.DeployCounterContractTransaction(accounts[0], chain)
   601  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   602  		txBody.SetPayer(chain.ServiceAddress())
   603  
   604  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   605  		require.NoError(t, err)
   606  
   607  		err = testutil.SignEnvelope(
   608  			txBody,
   609  			chain.ServiceAddress(),
   610  			unittest.ServiceAccountPrivateKey)
   611  		require.NoError(t, err)
   612  
   613  		executionSnapshot, output, err := vm.Run(
   614  			ctx,
   615  			fvm.Transaction(txBody, 0),
   616  			snapshotTree)
   617  		require.NoError(t, err)
   618  		require.NoError(t, output.Err)
   619  
   620  		snapshotTree = snapshotTree.Append(executionSnapshot)
   621  
   622  		txBody = testutil.RemoveUnauthorizedCounterContractTransaction(
   623  			accounts[0])
   624  		txBody.SetProposalKey(accounts[0], 0, 0)
   625  		txBody.SetPayer(accounts[0])
   626  
   627  		err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
   628  		require.NoError(t, err)
   629  
   630  		_, output, err = vm.Run(
   631  			ctx,
   632  			fvm.Transaction(txBody, 0),
   633  			snapshotTree)
   634  		require.NoError(t, err)
   635  		require.Error(t, output.Err)
   636  
   637  		require.ErrorContains(
   638  			t,
   639  			output.Err,
   640  			"removing contracts requires authorization from specific accounts")
   641  		require.True(t, errors.IsCadenceRuntimeError(output.Err))
   642  	})
   643  
   644  	t.Run("account update with code removal succeeds if signed by service account", func(t *testing.T) {
   645  		// Create an account private key.
   646  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   647  		require.NoError(t, err)
   648  
   649  		// Bootstrap a ledger, creating accounts with the provided private keys
   650  		// and the root account.
   651  		snapshotTree, accounts, err := testutil.CreateAccounts(
   652  			vm,
   653  			testutil.RootBootstrappedLedger(vm, ctx),
   654  			privateKeys,
   655  			chain)
   656  		require.NoError(t, err)
   657  
   658  		txBody := testutil.DeployCounterContractTransaction(accounts[0], chain)
   659  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   660  		txBody.SetPayer(chain.ServiceAddress())
   661  
   662  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   663  		require.NoError(t, err)
   664  
   665  		err = testutil.SignEnvelope(
   666  			txBody,
   667  			chain.ServiceAddress(),
   668  			unittest.ServiceAccountPrivateKey)
   669  		require.NoError(t, err)
   670  
   671  		executionSnapshot, output, err := vm.Run(
   672  			ctx,
   673  			fvm.Transaction(txBody, 0),
   674  			snapshotTree)
   675  		require.NoError(t, err)
   676  		require.NoError(t, output.Err)
   677  
   678  		snapshotTree = snapshotTree.Append(executionSnapshot)
   679  
   680  		txBody = testutil.RemoveCounterContractTransaction(accounts[0], chain)
   681  		txBody.SetProposalKey(accounts[0], 0, 0)
   682  		txBody.SetPayer(chain.ServiceAddress())
   683  
   684  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   685  		require.NoError(t, err)
   686  
   687  		err = testutil.SignEnvelope(
   688  			txBody,
   689  			chain.ServiceAddress(),
   690  			unittest.ServiceAccountPrivateKey)
   691  		require.NoError(t, err)
   692  
   693  		_, output, err = vm.Run(
   694  			ctx,
   695  			fvm.Transaction(txBody, 0),
   696  			snapshotTree)
   697  		require.NoError(t, err)
   698  		require.NoError(t, output.Err)
   699  	})
   700  
   701  	t.Run("account update with set code succeeds when account is added as authorized account", func(t *testing.T) {
   702  		// Create an account private key.
   703  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   704  		require.NoError(t, err)
   705  
   706  		// Bootstrap a ledger, creating accounts with the provided private keys
   707  		// and the root account.
   708  		snapshotTree, accounts, err := testutil.CreateAccounts(
   709  			vm,
   710  			testutil.RootBootstrappedLedger(vm, ctx),
   711  			privateKeys,
   712  			chain)
   713  		require.NoError(t, err)
   714  
   715  		// setup a new authorizer account
   716  		authTxBody, err := blueprints.SetContractDeploymentAuthorizersTransaction(
   717  			chain.ServiceAddress(),
   718  			[]flow.Address{chain.ServiceAddress(), accounts[0]})
   719  		require.NoError(t, err)
   720  
   721  		authTxBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   722  		authTxBody.SetPayer(chain.ServiceAddress())
   723  		err = testutil.SignEnvelope(
   724  			authTxBody,
   725  			chain.ServiceAddress(),
   726  			unittest.ServiceAccountPrivateKey)
   727  		require.NoError(t, err)
   728  
   729  		executionSnapshot, output, err := vm.Run(
   730  			ctx,
   731  			fvm.Transaction(authTxBody, 0),
   732  			snapshotTree)
   733  		require.NoError(t, err)
   734  		require.NoError(t, output.Err)
   735  
   736  		snapshotTree = snapshotTree.Append(executionSnapshot)
   737  
   738  		// test deploying a new contract (not authorized by service account)
   739  		txBody := testutil.DeployUnauthorizedCounterContractTransaction(accounts[0])
   740  		txBody.SetProposalKey(accounts[0], 0, 0)
   741  		txBody.SetPayer(accounts[0])
   742  
   743  		err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
   744  		require.NoError(t, err)
   745  
   746  		_, output, err = vm.Run(
   747  			ctx,
   748  			fvm.Transaction(txBody, 0),
   749  			snapshotTree)
   750  		require.NoError(t, err)
   751  		require.NoError(t, output.Err)
   752  	})
   753  
   754  }
   755  
   756  func TestBlockContext_ExecuteTransaction_WithArguments(t *testing.T) {
   757  
   758  	t.Parallel()
   759  
   760  	chain, vm := createChainAndVm(flow.Mainnet)
   761  
   762  	ctx := fvm.NewContext(
   763  		fvm.WithChain(chain),
   764  		fvm.WithCadenceLogging(true),
   765  	)
   766  
   767  	arg1, _ := jsoncdc.Encode(cadence.NewInt(42))
   768  	fooString, _ := cadence.NewString("foo")
   769  	arg2, _ := jsoncdc.Encode(fooString)
   770  
   771  	var tests = []struct {
   772  		label       string
   773  		script      string
   774  		args        [][]byte
   775  		authorizers []flow.Address
   776  		check       func(t *testing.T, output fvm.ProcedureOutput)
   777  	}{
   778  		{
   779  			label:  "No parameters",
   780  			script: `transaction { execute { log("Hello, World!") } }`,
   781  			args:   [][]byte{arg1},
   782  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   783  				require.Error(t, output.Err)
   784  			},
   785  		},
   786  		{
   787  			label:  "Single parameter",
   788  			script: `transaction(x: Int) { execute { log(x) } }`,
   789  			args:   [][]byte{arg1},
   790  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   791  				require.NoError(t, output.Err)
   792  				require.Len(t, output.Logs, 1)
   793  				require.Equal(t, "42", output.Logs[0])
   794  			},
   795  		},
   796  		{
   797  			label:  "Multiple parameters",
   798  			script: `transaction(x: Int, y: String) { execute { log(x); log(y) } }`,
   799  			args:   [][]byte{arg1, arg2},
   800  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   801  				require.NoError(t, output.Err)
   802  				require.Len(t, output.Logs, 2)
   803  				require.Equal(t, "42", output.Logs[0])
   804  				require.Equal(t, `"foo"`, output.Logs[1])
   805  			},
   806  		},
   807  		{
   808  			label: "Parameters and authorizer",
   809  			script: `
   810                  transaction(x: Int, y: String) {
   811                      prepare(acct: AuthAccount) { log(acct.address) }
   812                      execute { log(x); log(y) }
   813                  }`,
   814  			args:        [][]byte{arg1, arg2},
   815  			authorizers: []flow.Address{chain.ServiceAddress()},
   816  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   817  				require.NoError(t, output.Err)
   818  				require.ElementsMatch(
   819  					t,
   820  					[]string{"0x" + chain.ServiceAddress().Hex(), "42", `"foo"`},
   821  					output.Logs)
   822  			},
   823  		},
   824  	}
   825  
   826  	for _, tt := range tests {
   827  		t.Run(tt.label, func(t *testing.T) {
   828  			txBody := flow.NewTransactionBody().
   829  				SetScript([]byte(tt.script)).
   830  				SetArguments(tt.args)
   831  
   832  			for _, authorizer := range tt.authorizers {
   833  				txBody.AddAuthorizer(authorizer)
   834  			}
   835  
   836  			err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
   837  			require.NoError(t, err)
   838  
   839  			_, output, err := vm.Run(
   840  				ctx,
   841  				fvm.Transaction(txBody, 0),
   842  				testutil.RootBootstrappedLedger(vm, ctx))
   843  			require.NoError(t, err)
   844  
   845  			tt.check(t, output)
   846  		})
   847  	}
   848  }
   849  func gasLimitScript(depth int) string {
   850  	return fmt.Sprintf(`
   851          pub fun foo(_ i: Int) {
   852              if i <= 0 {
   853                  return
   854              }
   855              log("foo")
   856              foo(i-1)
   857          }
   858  
   859          transaction { execute { foo(%d) } }
   860      `, depth)
   861  }
   862  
   863  func TestBlockContext_ExecuteTransaction_GasLimit(t *testing.T) {
   864  
   865  	t.Parallel()
   866  
   867  	chain, vm := createChainAndVm(flow.Mainnet)
   868  
   869  	ctx := fvm.NewContext(
   870  		fvm.WithChain(chain),
   871  		fvm.WithCadenceLogging(true),
   872  	)
   873  
   874  	var tests = []struct {
   875  		label    string
   876  		script   string
   877  		gasLimit uint64
   878  		check    func(t *testing.T, output fvm.ProcedureOutput)
   879  	}{
   880  		{
   881  			label:    "Zero",
   882  			script:   gasLimitScript(100),
   883  			gasLimit: 0,
   884  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   885  				// gas limit of zero is ignored by runtime
   886  				require.NoError(t, output.Err)
   887  			},
   888  		},
   889  		{
   890  			label:    "Insufficient",
   891  			script:   gasLimitScript(100),
   892  			gasLimit: 5,
   893  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   894  				require.Error(t, output.Err)
   895  			},
   896  		},
   897  		{
   898  			label:    "Sufficient",
   899  			script:   gasLimitScript(100),
   900  			gasLimit: 1000,
   901  			check: func(t *testing.T, output fvm.ProcedureOutput) {
   902  				require.NoError(t, output.Err)
   903  				require.Len(t, output.Logs, 100)
   904  			},
   905  		},
   906  	}
   907  
   908  	for _, tt := range tests {
   909  		t.Run(tt.label, func(t *testing.T) {
   910  			txBody := flow.NewTransactionBody().
   911  				SetScript([]byte(tt.script)).
   912  				SetGasLimit(tt.gasLimit)
   913  
   914  			err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
   915  			require.NoError(t, err)
   916  
   917  			_, output, err := vm.Run(
   918  				ctx,
   919  				fvm.Transaction(txBody, 0),
   920  				testutil.RootBootstrappedLedger(vm, ctx))
   921  			require.NoError(t, err)
   922  
   923  			tt.check(t, output)
   924  		})
   925  	}
   926  }
   927  
   928  func TestBlockContext_ExecuteTransaction_StorageLimit(t *testing.T) {
   929  
   930  	t.Parallel()
   931  
   932  	b := make([]byte, 1000000) // 1MB
   933  	_, err := rand.Read(b)
   934  	require.NoError(t, err)
   935  	longString := base64.StdEncoding.EncodeToString(b) // 1.3 times 1MB
   936  
   937  	script := fmt.Sprintf(`
   938  			access(all) contract Container {
   939  				access(all) resource Counter {
   940  					pub var longString: String
   941  					init() {
   942  						self.longString = "%s"
   943  					}
   944  				}
   945  			}`, longString)
   946  
   947  	bootstrapOptions := []fvm.BootstrapProcedureOption{
   948  		fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee),
   949  		fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation),
   950  		fvm.WithStorageMBPerFLOW(fvm.DefaultStorageMBPerFLOW),
   951  		// The evm account has a storage exception, and if we don't bootstrap with evm,
   952  		// the first created account will have that address.
   953  		fvm.WithSetupEVMEnabled(true),
   954  	}
   955  
   956  	t.Run("Storing too much data fails", newVMTest().withBootstrapProcedureOptions(bootstrapOptions...).
   957  		run(
   958  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
   959  				// this test requires storage limits to be enforced
   960  				ctx.LimitAccountStorage = true
   961  
   962  				// Create an account private key.
   963  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   964  				require.NoError(t, err)
   965  
   966  				// Bootstrap a ledger, creating accounts with the provided
   967  				// private keys and the root account.
   968  				snapshotTree, accounts, err := testutil.CreateAccounts(
   969  					vm,
   970  					snapshotTree,
   971  					privateKeys,
   972  					chain)
   973  				require.NoError(t, err)
   974  
   975  				txBody := testutil.CreateContractDeploymentTransaction(
   976  					"Container",
   977  					script,
   978  					accounts[0],
   979  					chain)
   980  
   981  				txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
   982  				txBody.SetPayer(chain.ServiceAddress())
   983  
   984  				err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   985  				require.NoError(t, err)
   986  
   987  				err = testutil.SignEnvelope(
   988  					txBody,
   989  					chain.ServiceAddress(),
   990  					unittest.ServiceAccountPrivateKey)
   991  				require.NoError(t, err)
   992  
   993  				_, output, err := vm.Run(
   994  					ctx,
   995  					fvm.Transaction(txBody, 0),
   996  					snapshotTree)
   997  				require.NoError(t, err)
   998  
   999  				require.True(
  1000  					t,
  1001  					errors.IsStorageCapacityExceededError(output.Err))
  1002  			}))
  1003  	t.Run("Increasing storage capacity works", newVMTest().withBootstrapProcedureOptions(bootstrapOptions...).
  1004  		run(
  1005  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1006  				ctx.LimitAccountStorage = true // this test requires storage limits to be enforced
  1007  
  1008  				// Create an account private key.
  1009  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1010  				require.NoError(t, err)
  1011  
  1012  				// Bootstrap a ledger, creating accounts with the provided
  1013  				// private keys and the root account.
  1014  				snapshotTree, accounts, err := testutil.CreateAccounts(
  1015  					vm,
  1016  					snapshotTree,
  1017  					privateKeys,
  1018  					chain)
  1019  				require.NoError(t, err)
  1020  
  1021  				sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1022  				// deposit more flow to increase capacity
  1023  				txBody := flow.NewTransactionBody().
  1024  					SetScript([]byte(fmt.Sprintf(
  1025  						`
  1026  					import FungibleToken from %s
  1027  					import FlowToken from %s
  1028  
  1029  					transaction {
  1030  						prepare(signer: AuthAccount, service: AuthAccount) {
  1031  							signer.contracts.add(name: "%s", code: "%s".decodeHex())
  1032  
  1033  							let vaultRef = service.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)!
  1034  							// deposit additional flow
  1035  							let payment <- vaultRef.withdraw(amount: 10.0) as! @FlowToken.Vault
  1036  
  1037  							let receiver = signer.getCapability(/public/flowTokenReceiver)!.borrow<&{FungibleToken.Receiver}>()
  1038  								?? panic("Could not borrow receiver reference to the recipient's Vault")
  1039  							receiver.deposit(from: <-payment)
  1040  						}
  1041  					}`,
  1042  						sc.FungibleToken.Address.HexWithPrefix(),
  1043  						sc.FlowToken.Address.HexWithPrefix(),
  1044  						"Container",
  1045  						hex.EncodeToString([]byte(script)),
  1046  					))).
  1047  					AddAuthorizer(accounts[0]).
  1048  					AddAuthorizer(chain.ServiceAddress()).
  1049  					SetProposalKey(chain.ServiceAddress(), 0, 0).
  1050  					SetPayer(chain.ServiceAddress())
  1051  
  1052  				err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
  1053  				require.NoError(t, err)
  1054  
  1055  				err = testutil.SignEnvelope(
  1056  					txBody,
  1057  					chain.ServiceAddress(),
  1058  					unittest.ServiceAccountPrivateKey)
  1059  				require.NoError(t, err)
  1060  
  1061  				_, output, err := vm.Run(
  1062  					ctx,
  1063  					fvm.Transaction(txBody, 0),
  1064  					snapshotTree)
  1065  				require.NoError(t, err)
  1066  				require.NoError(t, output.Err)
  1067  			}))
  1068  }
  1069  
  1070  func TestBlockContext_ExecuteTransaction_InteractionLimitReached(t *testing.T) {
  1071  	t.Parallel()
  1072  
  1073  	b := make([]byte, 1000000) // 1MB
  1074  	_, err := rand.Read(b)
  1075  	require.NoError(t, err)
  1076  	longString := base64.StdEncoding.EncodeToString(b) // ~1.3 times 1MB
  1077  
  1078  	// save a really large contract to an account should fail because of interaction limit reached
  1079  	script := fmt.Sprintf(`
  1080  			access(all) contract Container {
  1081  				access(all) resource Counter {
  1082  					pub var longString: String
  1083  					init() {
  1084  						self.longString = "%s"
  1085  					}
  1086  				}
  1087  			}`, longString)
  1088  
  1089  	bootstrapOptions := []fvm.BootstrapProcedureOption{
  1090  		fvm.WithTransactionFee(fvm.DefaultTransactionFees),
  1091  	}
  1092  
  1093  	t.Run("Using to much interaction fails", newVMTest().withBootstrapProcedureOptions(bootstrapOptions...).
  1094  		withContextOptions(fvm.WithTransactionFeesEnabled(true)).
  1095  		run(
  1096  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1097  				ctx.MaxStateInteractionSize = 500_000
  1098  
  1099  				// Create an account private key.
  1100  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1101  				require.NoError(t, err)
  1102  
  1103  				// Bootstrap a ledger, creating accounts with the provided
  1104  				// private keys and the root account.
  1105  				snapshotTree, accounts, err := testutil.CreateAccounts(
  1106  					vm,
  1107  					snapshotTree,
  1108  					privateKeys,
  1109  					chain)
  1110  				require.NoError(t, err)
  1111  
  1112  				n := 0
  1113  				seqNum := func() uint64 {
  1114  					sn := n
  1115  					n++
  1116  					return uint64(sn)
  1117  				}
  1118  				// fund account so the payer can pay for the next transaction.
  1119  				txBody := transferTokensTx(chain).
  1120  					SetProposalKey(chain.ServiceAddress(), 0, seqNum()).
  1121  					AddAuthorizer(chain.ServiceAddress()).
  1122  					AddArgument(
  1123  						jsoncdc.MustEncode(cadence.UFix64(100_000_000))).
  1124  					AddArgument(
  1125  						jsoncdc.MustEncode(cadence.NewAddress(accounts[0]))).
  1126  					SetPayer(chain.ServiceAddress())
  1127  
  1128  				err = testutil.SignEnvelope(
  1129  					txBody,
  1130  					chain.ServiceAddress(),
  1131  					unittest.ServiceAccountPrivateKey)
  1132  				require.NoError(t, err)
  1133  
  1134  				executionSnapshot, output, err := vm.Run(
  1135  					ctx,
  1136  					fvm.Transaction(txBody, 0),
  1137  					snapshotTree)
  1138  				require.NoError(t, err)
  1139  				require.NoError(t, output.Err)
  1140  
  1141  				snapshotTree = snapshotTree.Append(executionSnapshot)
  1142  
  1143  				ctx.MaxStateInteractionSize = 500_000
  1144  
  1145  				txBody = testutil.CreateContractDeploymentTransaction(
  1146  					"Container",
  1147  					script,
  1148  					accounts[0],
  1149  					chain)
  1150  
  1151  				txBody.SetProposalKey(chain.ServiceAddress(), 0, seqNum())
  1152  				txBody.SetPayer(accounts[0])
  1153  
  1154  				err = testutil.SignPayload(
  1155  					txBody,
  1156  					chain.ServiceAddress(),
  1157  					unittest.ServiceAccountPrivateKey)
  1158  				require.NoError(t, err)
  1159  
  1160  				err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
  1161  				require.NoError(t, err)
  1162  
  1163  				_, output, err = vm.Run(
  1164  					ctx,
  1165  					fvm.Transaction(txBody, 0),
  1166  					snapshotTree)
  1167  				require.NoError(t, err)
  1168  
  1169  				require.True(
  1170  					t,
  1171  					errors.IsLedgerInteractionLimitExceededError(output.Err))
  1172  			}))
  1173  
  1174  	t.Run("Using to much interaction but not failing because of service account", newVMTest().withBootstrapProcedureOptions(bootstrapOptions...).
  1175  		withContextOptions(fvm.WithTransactionFeesEnabled(true)).
  1176  		run(
  1177  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1178  				ctx.MaxStateInteractionSize = 500_000
  1179  
  1180  				// Create an account private key.
  1181  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1182  				require.NoError(t, err)
  1183  
  1184  				// Bootstrap a ledger, creating accounts with the provided
  1185  				// private keys and the root account.
  1186  				snapshotTree, accounts, err := testutil.CreateAccounts(
  1187  					vm,
  1188  					snapshotTree,
  1189  					privateKeys,
  1190  					chain)
  1191  				require.NoError(t, err)
  1192  
  1193  				txBody := testutil.CreateContractDeploymentTransaction(
  1194  					"Container",
  1195  					script,
  1196  					accounts[0],
  1197  					chain)
  1198  
  1199  				txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
  1200  				txBody.SetPayer(chain.ServiceAddress())
  1201  
  1202  				err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
  1203  				require.NoError(t, err)
  1204  
  1205  				err = testutil.SignEnvelope(
  1206  					txBody,
  1207  					chain.ServiceAddress(),
  1208  					unittest.ServiceAccountPrivateKey)
  1209  				require.NoError(t, err)
  1210  
  1211  				_, output, err := vm.Run(
  1212  					ctx,
  1213  					fvm.Transaction(txBody, 0),
  1214  					snapshotTree)
  1215  				require.NoError(t, err)
  1216  				require.NoError(t, output.Err)
  1217  			}))
  1218  
  1219  	t.Run("Using to much interaction fails but does not panic", newVMTest().withBootstrapProcedureOptions(bootstrapOptions...).
  1220  		withContextOptions(
  1221  			fvm.WithAuthorizationChecksEnabled(false),
  1222  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
  1223  		).
  1224  		run(
  1225  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1226  				ctx.MaxStateInteractionSize = 50_000
  1227  
  1228  				// Create an account private key.
  1229  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1230  				require.NoError(t, err)
  1231  
  1232  				// Bootstrap a ledger, creating accounts with the provided
  1233  				// private keys and the root account.
  1234  				snapshotTree, accounts, err := testutil.CreateAccounts(
  1235  					vm,
  1236  					snapshotTree,
  1237  					privateKeys,
  1238  					chain)
  1239  				require.NoError(t, err)
  1240  
  1241  				_, txBody := testutil.CreateMultiAccountCreationTransaction(
  1242  					t,
  1243  					chain,
  1244  					40)
  1245  
  1246  				txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
  1247  				txBody.SetPayer(accounts[0])
  1248  
  1249  				err = testutil.SignPayload(
  1250  					txBody,
  1251  					chain.ServiceAddress(),
  1252  					unittest.ServiceAccountPrivateKey)
  1253  				require.NoError(t, err)
  1254  
  1255  				err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
  1256  				require.NoError(t, err)
  1257  
  1258  				_, output, err := vm.Run(
  1259  					ctx,
  1260  					fvm.Transaction(txBody, 0),
  1261  					snapshotTree)
  1262  				require.NoError(t, err)
  1263  				require.Error(t, output.Err)
  1264  
  1265  				require.True(t, errors.IsCadenceRuntimeError(output.Err))
  1266  			}))
  1267  }
  1268  
  1269  var createAccountScript = []byte(`
  1270      transaction {
  1271          prepare(signer: AuthAccount) {
  1272              let acct = AuthAccount(payer: signer)
  1273          }
  1274      }
  1275  `)
  1276  
  1277  func TestBlockContext_ExecuteScript(t *testing.T) {
  1278  
  1279  	t.Parallel()
  1280  
  1281  	chain, vm := createChainAndVm(flow.Mainnet)
  1282  
  1283  	ctx := fvm.NewContext(
  1284  		fvm.WithChain(chain),
  1285  		fvm.WithCadenceLogging(true),
  1286  	)
  1287  
  1288  	t.Run("script success", func(t *testing.T) {
  1289  		code := []byte(`
  1290              pub fun main(): Int {
  1291                  return 42
  1292              }
  1293          `)
  1294  
  1295  		_, output, err := vm.Run(
  1296  			ctx,
  1297  			fvm.Script(code),
  1298  			testutil.RootBootstrappedLedger(vm, ctx))
  1299  		require.NoError(t, err)
  1300  
  1301  		require.NoError(t, output.Err)
  1302  	})
  1303  
  1304  	t.Run("script failure", func(t *testing.T) {
  1305  		code := []byte(`
  1306              pub fun main(): Int {
  1307                  assert(1 == 2)
  1308                  return 42
  1309              }
  1310          `)
  1311  
  1312  		_, output, err := vm.Run(
  1313  			ctx,
  1314  			fvm.Script(code),
  1315  			testutil.RootBootstrappedLedger(vm, ctx))
  1316  		require.NoError(t, err)
  1317  
  1318  		require.Error(t, output.Err)
  1319  	})
  1320  
  1321  	t.Run("script logs", func(t *testing.T) {
  1322  		code := []byte(`
  1323              pub fun main(): Int {
  1324                  log("foo")
  1325                  log("bar")
  1326                  return 42
  1327              }
  1328          `)
  1329  
  1330  		_, output, err := vm.Run(
  1331  			ctx,
  1332  			fvm.Script(code),
  1333  			testutil.RootBootstrappedLedger(vm, ctx))
  1334  		require.NoError(t, err)
  1335  
  1336  		require.NoError(t, output.Err)
  1337  		require.Len(t, output.Logs, 2)
  1338  		require.Equal(t, "\"foo\"", output.Logs[0])
  1339  		require.Equal(t, "\"bar\"", output.Logs[1])
  1340  	})
  1341  
  1342  	t.Run("storage ID allocation", func(t *testing.T) {
  1343  		// Create an account private key.
  1344  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1345  		require.NoError(t, err)
  1346  
  1347  		// Bootstrap a ledger, creating accounts with the provided private
  1348  		// keys and the root account.
  1349  		snapshotTree, accounts, err := testutil.CreateAccounts(
  1350  			vm,
  1351  			testutil.RootBootstrappedLedger(vm, ctx),
  1352  			privateKeys,
  1353  			chain)
  1354  		require.NoError(t, err)
  1355  
  1356  		// Deploy the test contract
  1357  
  1358  		const contract = `
  1359  			pub contract Test {
  1360  
  1361  				pub struct Foo {}
  1362  
  1363                  pub let foos: [Foo]
  1364  
  1365  				init() {
  1366  					self.foos = []
  1367  				}
  1368  
  1369  				pub fun add() {
  1370  					self.foos.append(Foo())
  1371  				}
  1372  			}
  1373  		`
  1374  
  1375  		address := accounts[0]
  1376  
  1377  		txBody := testutil.CreateContractDeploymentTransaction(
  1378  			"Test",
  1379  			contract,
  1380  			address,
  1381  			chain)
  1382  
  1383  		txBody.SetProposalKey(chain.ServiceAddress(), 0, 0)
  1384  		txBody.SetPayer(chain.ServiceAddress())
  1385  
  1386  		err = testutil.SignPayload(txBody, address, privateKeys[0])
  1387  		require.NoError(t, err)
  1388  
  1389  		err = testutil.SignEnvelope(
  1390  			txBody,
  1391  			chain.ServiceAddress(),
  1392  			unittest.ServiceAccountPrivateKey)
  1393  		require.NoError(t, err)
  1394  
  1395  		executionSnapshot, output, err := vm.Run(
  1396  			ctx,
  1397  			fvm.Transaction(txBody, 0),
  1398  			snapshotTree)
  1399  		require.NoError(t, err)
  1400  		require.NoError(t, output.Err)
  1401  
  1402  		snapshotTree = snapshotTree.Append(executionSnapshot)
  1403  
  1404  		// Run test script
  1405  
  1406  		code := []byte(fmt.Sprintf(
  1407  			`
  1408  			  import Test from 0x%s
  1409  
  1410  			  pub fun main() {
  1411  			      Test.add()
  1412  			  }
  1413  			`,
  1414  			address.String(),
  1415  		))
  1416  
  1417  		_, output, err = vm.Run(ctx, fvm.Script(code), snapshotTree)
  1418  		require.NoError(t, err)
  1419  
  1420  		require.NoError(t, output.Err)
  1421  	})
  1422  }
  1423  
  1424  func TestBlockContext_GetBlockInfo(t *testing.T) {
  1425  
  1426  	t.Parallel()
  1427  
  1428  	chain, vm := createChainAndVm(flow.Mainnet)
  1429  
  1430  	ctx := fvm.NewContext(
  1431  		fvm.WithChain(chain),
  1432  		fvm.WithCadenceLogging(true),
  1433  	)
  1434  
  1435  	blocks := new(envMock.Blocks)
  1436  
  1437  	block1 := unittest.BlockFixture()
  1438  	block2 := unittest.BlockWithParentFixture(block1.Header)
  1439  	block3 := unittest.BlockWithParentFixture(block2.Header)
  1440  
  1441  	blocks.On("ByHeightFrom", block1.Header.Height, block1.Header).Return(block1.Header, nil)
  1442  	blocks.On("ByHeightFrom", block2.Header.Height, block1.Header).Return(block2.Header, nil)
  1443  
  1444  	type logPanic struct{}
  1445  	blocks.On("ByHeightFrom", block3.Header.Height, block1.Header).Run(func(args mock.Arguments) { panic(logPanic{}) })
  1446  
  1447  	blockCtx := fvm.NewContextFromParent(ctx, fvm.WithBlocks(blocks), fvm.WithBlockHeader(block1.Header))
  1448  
  1449  	t.Run("works as transaction", func(t *testing.T) {
  1450  		txBody := flow.NewTransactionBody().
  1451  			SetScript([]byte(`
  1452                  transaction {
  1453                      execute {
  1454                          let block = getCurrentBlock()
  1455                          log(block)
  1456  
  1457                          let nextBlock = getBlock(at: block.height + UInt64(1))
  1458                          log(nextBlock)
  1459                      }
  1460                  }
  1461              `))
  1462  
  1463  		err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
  1464  		require.NoError(t, err)
  1465  
  1466  		_, output, err := vm.Run(
  1467  			blockCtx,
  1468  			fvm.Transaction(txBody, 0),
  1469  			testutil.RootBootstrappedLedger(vm, ctx))
  1470  		require.NoError(t, err)
  1471  		require.NoError(t, output.Err)
  1472  
  1473  		require.Len(t, output.Logs, 2)
  1474  		require.Equal(
  1475  			t,
  1476  			fmt.Sprintf(
  1477  				"Block(height: %v, view: %v, id: 0x%x, timestamp: %.8f)",
  1478  				block1.Header.Height,
  1479  				block1.Header.View,
  1480  				block1.ID(),
  1481  				float64(block1.Header.Timestamp.Unix()),
  1482  			),
  1483  			output.Logs[0],
  1484  		)
  1485  		require.Equal(
  1486  			t,
  1487  			fmt.Sprintf(
  1488  				"Block(height: %v, view: %v, id: 0x%x, timestamp: %.8f)",
  1489  				block2.Header.Height,
  1490  				block2.Header.View,
  1491  				block2.ID(),
  1492  				float64(block2.Header.Timestamp.Unix()),
  1493  			),
  1494  			output.Logs[1],
  1495  		)
  1496  	})
  1497  
  1498  	t.Run("works as script", func(t *testing.T) {
  1499  		code := []byte(`
  1500              pub fun main() {
  1501                  let block = getCurrentBlock()
  1502                  log(block)
  1503  
  1504                  let nextBlock = getBlock(at: block.height + UInt64(1))
  1505                  log(nextBlock)
  1506              }
  1507          `)
  1508  
  1509  		_, output, err := vm.Run(
  1510  			blockCtx,
  1511  			fvm.Script(code),
  1512  			testutil.RootBootstrappedLedger(vm, ctx))
  1513  		require.NoError(t, err)
  1514  		require.NoError(t, output.Err)
  1515  
  1516  		require.Len(t, output.Logs, 2)
  1517  		require.Equal(t,
  1518  			fmt.Sprintf(
  1519  				"Block(height: %v, view: %v, id: 0x%x, timestamp: %.8f)",
  1520  				block1.Header.Height,
  1521  				block1.Header.View,
  1522  				block1.ID(),
  1523  				float64(block1.Header.Timestamp.Unix()),
  1524  			),
  1525  			output.Logs[0],
  1526  		)
  1527  		require.Equal(
  1528  			t,
  1529  			fmt.Sprintf(
  1530  				"Block(height: %v, view: %v, id: 0x%x, timestamp: %.8f)",
  1531  				block2.Header.Height,
  1532  				block2.Header.View,
  1533  				block2.ID(),
  1534  				float64(block2.Header.Timestamp.Unix()),
  1535  			),
  1536  			output.Logs[1],
  1537  		)
  1538  	})
  1539  
  1540  	t.Run("panics if external function panics in transaction", func(t *testing.T) {
  1541  		tx := flow.NewTransactionBody().
  1542  			SetScript([]byte(`
  1543                  transaction {
  1544                      execute {
  1545                          let block = getCurrentBlock()
  1546                          let nextBlock = getBlock(at: block.height + UInt64(2))
  1547                      }
  1548                  }
  1549              `))
  1550  
  1551  		err := testutil.SignTransactionAsServiceAccount(tx, 0, chain)
  1552  		require.NoError(t, err)
  1553  
  1554  		_, output, err := vm.Run(
  1555  			blockCtx,
  1556  			fvm.Transaction(tx, 0),
  1557  			testutil.RootBootstrappedLedger(vm, ctx))
  1558  		require.NoError(t, err)
  1559  		require.Error(t, output.Err)
  1560  	})
  1561  
  1562  	t.Run("panics if external function panics in script", func(t *testing.T) {
  1563  		script := []byte(`
  1564              pub fun main() {
  1565                  let block = getCurrentBlock()
  1566                  let nextBlock = getBlock(at: block.height + UInt64(2))
  1567              }
  1568          `)
  1569  
  1570  		_, output, err := vm.Run(
  1571  			blockCtx,
  1572  			fvm.Script(script),
  1573  			testutil.RootBootstrappedLedger(vm, ctx))
  1574  		require.NoError(t, err)
  1575  		require.Error(t, output.Err)
  1576  	})
  1577  }
  1578  
  1579  func TestBlockContext_GetAccount(t *testing.T) {
  1580  
  1581  	t.Parallel()
  1582  
  1583  	const count = 100
  1584  
  1585  	chain, vm := createChainAndVm(flow.Mainnet)
  1586  
  1587  	ctx := fvm.NewContext(
  1588  		fvm.WithChain(chain),
  1589  		fvm.WithCadenceLogging(true),
  1590  	)
  1591  
  1592  	snapshotTree := testutil.RootBootstrappedLedger(vm, ctx)
  1593  	sequenceNumber := uint64(0)
  1594  
  1595  	createAccount := func() (flow.Address, crypto.PublicKey) {
  1596  		privateKey, txBody := testutil.CreateAccountCreationTransaction(
  1597  			t,
  1598  			chain)
  1599  
  1600  		txBody.SetProposalKey(chain.ServiceAddress(), 0, sequenceNumber)
  1601  		txBody.SetPayer(chain.ServiceAddress())
  1602  		sequenceNumber++
  1603  
  1604  		rootHasher := hash.NewSHA2_256()
  1605  
  1606  		err := txBody.SignEnvelope(
  1607  			chain.ServiceAddress(),
  1608  			0,
  1609  			unittest.ServiceAccountPrivateKey.PrivateKey,
  1610  			rootHasher,
  1611  		)
  1612  		require.NoError(t, err)
  1613  
  1614  		// execute the transaction
  1615  		executionSnapshot, output, err := vm.Run(
  1616  			ctx,
  1617  			fvm.Transaction(txBody, 0),
  1618  			snapshotTree)
  1619  		require.NoError(t, err)
  1620  		require.NoError(t, output.Err)
  1621  
  1622  		snapshotTree = snapshotTree.Append(executionSnapshot)
  1623  
  1624  		accountCreatedEvents := filterAccountCreatedEvents(output.Events)
  1625  
  1626  		require.Len(t, accountCreatedEvents, 1)
  1627  
  1628  		// read the address of the account created (e.g. "0x01" and convert it
  1629  		// to flow.address)
  1630  		data, err := ccf.Decode(nil, accountCreatedEvents[0].Payload)
  1631  		require.NoError(t, err)
  1632  		address := flow.ConvertAddress(
  1633  			data.(cadence.Event).Fields[0].(cadence.Address))
  1634  
  1635  		return address, privateKey.PublicKey(
  1636  			fvm.AccountKeyWeightThreshold).PublicKey
  1637  	}
  1638  
  1639  	addressGen := chain.NewAddressGenerator()
  1640  	// skip the addresses of 4 reserved accounts
  1641  	for i := 0; i < 4; i++ {
  1642  		_, err := addressGen.NextAddress()
  1643  		require.NoError(t, err)
  1644  	}
  1645  
  1646  	// create a bunch of accounts
  1647  	accounts := make(map[flow.Address]crypto.PublicKey, count)
  1648  	for i := 0; i < count; i++ {
  1649  		address, key := createAccount()
  1650  		expectedAddress, err := addressGen.NextAddress()
  1651  		require.NoError(t, err)
  1652  
  1653  		require.Equal(t, expectedAddress, address)
  1654  		accounts[address] = key
  1655  	}
  1656  
  1657  	// happy path - get each of the created account and check if it is the right one
  1658  	t.Run("get accounts", func(t *testing.T) {
  1659  		for address, expectedKey := range accounts {
  1660  			account, err := vm.GetAccount(ctx, address, snapshotTree)
  1661  			require.NoError(t, err)
  1662  
  1663  			require.Len(t, account.Keys, 1)
  1664  			actualKey := account.Keys[0].PublicKey
  1665  			require.Equal(t, expectedKey, actualKey)
  1666  		}
  1667  	})
  1668  
  1669  	// non-happy path - get an account that was never created
  1670  	t.Run("get a non-existing account", func(t *testing.T) {
  1671  		address, err := addressGen.NextAddress()
  1672  		require.NoError(t, err)
  1673  
  1674  		account, err := vm.GetAccount(ctx, address, snapshotTree)
  1675  		require.True(t, errors.IsAccountNotFoundError(err))
  1676  		require.Nil(t, account)
  1677  	})
  1678  }
  1679  
  1680  func TestBlockContext_Random(t *testing.T) {
  1681  	chain, vm := createChainAndVm(flow.Mainnet)
  1682  	header := &flow.Header{Height: 42}
  1683  	source := testutil.EntropyProviderFixture(nil)
  1684  	ctx := fvm.NewContext(
  1685  		fvm.WithChain(chain),
  1686  		fvm.WithBlockHeader(header),
  1687  		fvm.WithEntropyProvider(source),
  1688  		fvm.WithCadenceLogging(true),
  1689  	)
  1690  
  1691  	tx_code := []byte(`
  1692  	transaction {
  1693  		execute {
  1694  			let rand1 = unsafeRandom()
  1695  			log(rand1)
  1696  			let rand2 = unsafeRandom()
  1697  			log(rand2)
  1698  		}
  1699  	}
  1700  	`)
  1701  
  1702  	getTxRandoms := func(t *testing.T) [2]uint64 {
  1703  		txBody := flow.NewTransactionBody().SetScript(tx_code)
  1704  		err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
  1705  		require.NoError(t, err)
  1706  
  1707  		_, output, err := vm.Run(
  1708  			ctx,
  1709  			fvm.Transaction(txBody, 0),
  1710  			testutil.RootBootstrappedLedger(vm, ctx))
  1711  		require.NoError(t, err)
  1712  		require.NoError(t, output.Err)
  1713  		require.Len(t, output.Logs, 2)
  1714  
  1715  		r1, err := strconv.ParseUint(output.Logs[0], 10, 64)
  1716  		require.NoError(t, err)
  1717  		r2, err := strconv.ParseUint(output.Logs[1], 10, 64)
  1718  		require.NoError(t, err)
  1719  		return [2]uint64{r1, r2}
  1720  	}
  1721  
  1722  	// - checks that unsafeRandom works on transactions
  1723  	// - (sanity) checks that two successive randoms aren't equal
  1724  	t.Run("single transaction", func(t *testing.T) {
  1725  		randoms := getTxRandoms(t)
  1726  		require.NotEqual(t, randoms[1], randoms[0], "extremely unlikely to be equal")
  1727  	})
  1728  
  1729  	// checks that two transactions with different IDs do not generate the same randoms
  1730  	t.Run("two transactions", func(t *testing.T) {
  1731  		// getLoggedRandoms generates different tx IDs because envelope signature is randomized
  1732  		randoms1 := getTxRandoms(t)
  1733  		randoms2 := getTxRandoms(t)
  1734  		require.NotEqual(t, randoms1[0], randoms2[0], "extremely unlikely to be equal")
  1735  	})
  1736  
  1737  	script_string := `
  1738  	pub fun main(a: Int8) {
  1739  		let rand = unsafeRandom()
  1740  		log(rand)
  1741  		let rand%d = unsafeRandom()
  1742  		log(rand%d)
  1743  	}
  1744  	`
  1745  
  1746  	getScriptRandoms := func(t *testing.T, codeSalt int, arg int) [2]uint64 {
  1747  		script_code := []byte(fmt.Sprintf(script_string, codeSalt, codeSalt))
  1748  		script := fvm.Script(script_code).WithArguments(
  1749  			jsoncdc.MustEncode(cadence.Int8(arg)))
  1750  
  1751  		_, output, err := vm.Run(ctx, script, testutil.RootBootstrappedLedger(vm, ctx))
  1752  		require.NoError(t, err)
  1753  		require.NoError(t, output.Err)
  1754  
  1755  		r1, err := strconv.ParseUint(output.Logs[0], 10, 64)
  1756  		require.NoError(t, err)
  1757  		r2, err := strconv.ParseUint(output.Logs[1], 10, 64)
  1758  		require.NoError(t, err)
  1759  		return [2]uint64{r1, r2}
  1760  	}
  1761  
  1762  	// - checks that unsafeRandom works on scripts
  1763  	// - (sanity) checks that two successive randoms aren't equal
  1764  	t.Run("single script", func(t *testing.T) {
  1765  		randoms := getScriptRandoms(t, 1, 0)
  1766  		require.NotEqual(t, randoms[1], randoms[0], "extremely unlikely to be equal")
  1767  	})
  1768  
  1769  	// checks that two scripts with different codes do not generate the same randoms
  1770  	t.Run("two script codes", func(t *testing.T) {
  1771  		// getScriptRandoms generates different scripts IDs using different codes
  1772  		randoms1 := getScriptRandoms(t, 1, 0)
  1773  		randoms2 := getScriptRandoms(t, 2, 0)
  1774  		require.NotEqual(t, randoms1[0], randoms2[0], "extremely unlikely to be equal")
  1775  	})
  1776  
  1777  	// checks that two scripts with same codes but different arguments do not generate the same randoms
  1778  	t.Run("same script codes different arguments", func(t *testing.T) {
  1779  		// getScriptRandoms generates different scripts IDs using different arguments
  1780  		randoms1 := getScriptRandoms(t, 1, 0)
  1781  		randoms2 := getScriptRandoms(t, 1, 1)
  1782  		require.NotEqual(t, randoms1[0], randoms2[0], "extremely unlikely to be equal")
  1783  	})
  1784  
  1785  }
  1786  
  1787  func TestBlockContext_ExecuteTransaction_CreateAccount_WithMonotonicAddresses(t *testing.T) {
  1788  
  1789  	t.Parallel()
  1790  
  1791  	chain, vm := createChainAndVm(flow.MonotonicEmulator)
  1792  
  1793  	ctx := fvm.NewContext(
  1794  		fvm.WithChain(chain),
  1795  	)
  1796  
  1797  	txBody := flow.NewTransactionBody().
  1798  		SetScript(createAccountScript).
  1799  		AddAuthorizer(chain.ServiceAddress())
  1800  
  1801  	err := testutil.SignTransactionAsServiceAccount(txBody, 0, chain)
  1802  	require.NoError(t, err)
  1803  
  1804  	_, output, err := vm.Run(
  1805  		ctx,
  1806  		fvm.Transaction(txBody, 0),
  1807  		testutil.RootBootstrappedLedger(vm, ctx))
  1808  	require.NoError(t, err)
  1809  	require.NoError(t, output.Err)
  1810  
  1811  	accountCreatedEvents := filterAccountCreatedEvents(output.Events)
  1812  
  1813  	require.Len(t, accountCreatedEvents, 1)
  1814  
  1815  	data, err := ccf.Decode(nil, accountCreatedEvents[0].Payload)
  1816  	require.NoError(t, err)
  1817  	address := flow.ConvertAddress(
  1818  		data.(cadence.Event).Fields[0].(cadence.Address))
  1819  
  1820  	require.Equal(t, flow.HexToAddress("05"), address)
  1821  }
  1822  
  1823  func TestBlockContext_ExecuteTransaction_FailingTransactions(t *testing.T) {
  1824  	getBalance := func(
  1825  		vm fvm.VM,
  1826  		chain flow.Chain,
  1827  		ctx fvm.Context,
  1828  		storageSnapshot snapshot.StorageSnapshot,
  1829  		address flow.Address,
  1830  	) uint64 {
  1831  
  1832  		sc := systemcontracts.SystemContractsForChain(chain.ChainID())
  1833  		code := []byte(fmt.Sprintf(
  1834  			`
  1835  					import FungibleToken from 0x%s
  1836  					import FlowToken from 0x%s
  1837  
  1838  					pub fun main(account: Address): UFix64 {
  1839  						let acct = getAccount(account)
  1840  						let vaultRef = acct.getCapability(/public/flowTokenBalance)
  1841  							.borrow<&FlowToken.Vault{FungibleToken.Balance}>()
  1842  							?? panic("Could not borrow Balance reference to the Vault")
  1843  
  1844  						return vaultRef.balance
  1845  					}
  1846  				`,
  1847  			sc.FungibleToken.Address.Hex(),
  1848  			sc.FlowToken.Address.Hex(),
  1849  		))
  1850  		script := fvm.Script(code).WithArguments(
  1851  			jsoncdc.MustEncode(cadence.NewAddress(address)),
  1852  		)
  1853  
  1854  		_, output, err := vm.Run(ctx, script, storageSnapshot)
  1855  		require.NoError(t, err)
  1856  		require.NoError(t, output.Err)
  1857  		return output.Value.ToGoValue().(uint64)
  1858  	}
  1859  
  1860  	t.Run("Transaction fails because of storage", newVMTest().withBootstrapProcedureOptions(
  1861  		fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation),
  1862  		fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee),
  1863  		fvm.WithStorageMBPerFLOW(fvm.DefaultStorageMBPerFLOW),
  1864  		fvm.WithExecutionMemoryLimit(math.MaxUint64),
  1865  		// The evm account has a storage exception, and if we don't bootstrap with evm,
  1866  		// the first created account will have that address.
  1867  		fvm.WithSetupEVMEnabled(true),
  1868  	).run(
  1869  		func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1870  			ctx.LimitAccountStorage = true // this test requires storage limits to be enforced
  1871  
  1872  			// Create an account private key.
  1873  			privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1874  			require.NoError(t, err)
  1875  
  1876  			// Bootstrap a ledger, creating accounts with the provided private
  1877  			// keys and the root account.
  1878  			snapshotTree, accounts, err := testutil.CreateAccounts(
  1879  				vm,
  1880  				snapshotTree,
  1881  				privateKeys,
  1882  				chain)
  1883  			require.NoError(t, err)
  1884  
  1885  			balanceBefore := getBalance(
  1886  				vm,
  1887  				chain,
  1888  				ctx,
  1889  				snapshotTree,
  1890  				accounts[0])
  1891  
  1892  			txBody := transferTokensTx(chain).
  1893  				AddAuthorizer(accounts[0]).
  1894  				AddArgument(jsoncdc.MustEncode(cadence.UFix64(1))).
  1895  				AddArgument(jsoncdc.MustEncode(
  1896  					cadence.NewAddress(chain.ServiceAddress())))
  1897  
  1898  			txBody.SetProposalKey(accounts[0], 0, 0)
  1899  			txBody.SetPayer(accounts[0])
  1900  
  1901  			err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
  1902  			require.NoError(t, err)
  1903  
  1904  			executionSnapshot, output, err := vm.Run(
  1905  				ctx,
  1906  				fvm.Transaction(txBody, 0),
  1907  				snapshotTree)
  1908  			require.NoError(t, err)
  1909  
  1910  			snapshotTree = snapshotTree.Append(executionSnapshot)
  1911  
  1912  			require.True(t, errors.IsStorageCapacityExceededError(output.Err))
  1913  
  1914  			balanceAfter := getBalance(
  1915  				vm,
  1916  				chain,
  1917  				ctx,
  1918  				snapshotTree.Append(executionSnapshot),
  1919  				accounts[0])
  1920  
  1921  			require.Equal(t, balanceAfter, balanceBefore)
  1922  		}),
  1923  	)
  1924  
  1925  	t.Run("Transaction fails because of recipient account not existing", newVMTest().withBootstrapProcedureOptions(
  1926  		fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation),
  1927  		fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee),
  1928  		fvm.WithStorageMBPerFLOW(fvm.DefaultStorageMBPerFLOW),
  1929  		fvm.WithExecutionMemoryLimit(math.MaxUint64),
  1930  	).run(
  1931  		func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1932  			ctx.LimitAccountStorage = true // this test requires storage limits to be enforced
  1933  
  1934  			// Create an account private key.
  1935  			privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  1936  			require.NoError(t, err)
  1937  
  1938  			// Bootstrap a ledger, creating accounts with the provided private
  1939  			// keys and the root account.
  1940  			snapshotTree, accounts, err := testutil.CreateAccounts(
  1941  				vm,
  1942  				snapshotTree,
  1943  				privateKeys,
  1944  				chain)
  1945  			require.NoError(t, err)
  1946  
  1947  			// non-existent account
  1948  			lastAddress, err := chain.AddressAtIndex((1 << 45) - 1)
  1949  			require.NoError(t, err)
  1950  
  1951  			balanceBefore := getBalance(
  1952  				vm,
  1953  				chain,
  1954  				ctx,
  1955  				snapshotTree,
  1956  				accounts[0])
  1957  
  1958  			// transfer tokens to non-existent account
  1959  			txBody := transferTokensTx(chain).
  1960  				AddAuthorizer(accounts[0]).
  1961  				AddArgument(jsoncdc.MustEncode(cadence.UFix64(1))).
  1962  				AddArgument(jsoncdc.MustEncode(cadence.NewAddress(lastAddress)))
  1963  
  1964  			txBody.SetProposalKey(accounts[0], 0, 0)
  1965  			txBody.SetPayer(accounts[0])
  1966  
  1967  			err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
  1968  			require.NoError(t, err)
  1969  
  1970  			executionSnapshot, output, err := vm.Run(
  1971  				ctx,
  1972  				fvm.Transaction(txBody, 0),
  1973  				snapshotTree)
  1974  			require.NoError(t, err)
  1975  
  1976  			snapshotTree = snapshotTree.Append(executionSnapshot)
  1977  
  1978  			require.True(t, errors.IsCadenceRuntimeError(output.Err))
  1979  
  1980  			balanceAfter := getBalance(
  1981  				vm,
  1982  				chain,
  1983  				ctx,
  1984  				snapshotTree.Append(executionSnapshot),
  1985  				accounts[0])
  1986  
  1987  			require.Equal(t, balanceAfter, balanceBefore)
  1988  		}),
  1989  	)
  1990  
  1991  	t.Run("Transaction sequence number check fails and sequence number is not incremented", newVMTest().withBootstrapProcedureOptions(
  1992  		fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation),
  1993  		fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee),
  1994  	).
  1995  		run(
  1996  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  1997  				// this test requires storage limits to be enforced
  1998  				ctx.LimitAccountStorage = true
  1999  
  2000  				// Create an account private key.
  2001  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  2002  				require.NoError(t, err)
  2003  
  2004  				// Bootstrap a ledger, creating accounts with the provided
  2005  				// private keys and the root account.
  2006  				snapshotTree, accounts, err := testutil.CreateAccounts(
  2007  					vm,
  2008  					snapshotTree,
  2009  					privateKeys,
  2010  					chain)
  2011  				require.NoError(t, err)
  2012  
  2013  				txBody := transferTokensTx(chain).
  2014  					AddAuthorizer(accounts[0]).
  2015  					AddArgument(jsoncdc.MustEncode(cadence.UFix64(1_0000_0000_0000))).
  2016  					AddArgument(jsoncdc.MustEncode(
  2017  						cadence.NewAddress(chain.ServiceAddress())))
  2018  
  2019  				// set wrong sequence number
  2020  				txBody.SetProposalKey(accounts[0], 0, 10)
  2021  				txBody.SetPayer(accounts[0])
  2022  
  2023  				err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
  2024  				require.NoError(t, err)
  2025  
  2026  				_, output, err := vm.Run(
  2027  					ctx,
  2028  					fvm.Transaction(txBody, 0),
  2029  					snapshotTree)
  2030  				require.NoError(t, err)
  2031  
  2032  				require.Equal(
  2033  					t,
  2034  					errors.ErrCodeInvalidProposalSeqNumberError,
  2035  					output.Err.Code())
  2036  
  2037  				// The outer most coded error is a wrapper, not the actual
  2038  				// InvalidProposalSeqNumberError itself.
  2039  				_, ok := output.Err.(errors.InvalidProposalSeqNumberError)
  2040  				require.False(t, ok)
  2041  
  2042  				var seqNumErr errors.InvalidProposalSeqNumberError
  2043  				ok = errors.As(output.Err, &seqNumErr)
  2044  				require.True(t, ok)
  2045  				require.Equal(t, uint64(0), seqNumErr.CurrentSeqNumber())
  2046  			}),
  2047  	)
  2048  
  2049  	t.Run("Transaction invocation fails but sequence number is incremented", newVMTest().withBootstrapProcedureOptions(
  2050  		fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation),
  2051  		fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee),
  2052  		fvm.WithStorageMBPerFLOW(fvm.DefaultStorageMBPerFLOW),
  2053  	).
  2054  		run(
  2055  			func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) {
  2056  				// this test requires storage limits to be enforced
  2057  				ctx.LimitAccountStorage = true
  2058  
  2059  				// Create an account private key.
  2060  				privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
  2061  				require.NoError(t, err)
  2062  
  2063  				// Bootstrap a ledger, creating accounts with the provided
  2064  				// private keys and the root account.
  2065  				snapshotTree, accounts, err := testutil.CreateAccounts(
  2066  					vm,
  2067  					snapshotTree,
  2068  					privateKeys,
  2069  					chain)
  2070  				require.NoError(t, err)
  2071  
  2072  				txBody := transferTokensTx(chain).
  2073  					AddAuthorizer(accounts[0]).
  2074  					AddArgument(jsoncdc.MustEncode(
  2075  						cadence.UFix64(1_0000_0000_0000))).
  2076  					AddArgument(jsoncdc.MustEncode(
  2077  						cadence.NewAddress(chain.ServiceAddress())))
  2078  
  2079  				txBody.SetProposalKey(accounts[0], 0, 0)
  2080  				txBody.SetPayer(accounts[0])
  2081  
  2082  				err = testutil.SignEnvelope(txBody, accounts[0], privateKeys[0])
  2083  				require.NoError(t, err)
  2084  
  2085  				executionSnapshot, output, err := vm.Run(
  2086  					ctx,
  2087  					fvm.Transaction(txBody, 0),
  2088  					snapshotTree)
  2089  				require.NoError(t, err)
  2090  
  2091  				snapshotTree = snapshotTree.Append(executionSnapshot)
  2092  
  2093  				require.True(t, errors.IsCadenceRuntimeError(output.Err))
  2094  
  2095  				// send it again
  2096  				_, output, err = vm.Run(
  2097  					ctx,
  2098  					fvm.Transaction(txBody, 0),
  2099  					snapshotTree)
  2100  				require.NoError(t, err)
  2101  
  2102  				require.Equal(
  2103  					t,
  2104  					errors.ErrCodeInvalidProposalSeqNumberError,
  2105  					output.Err.Code())
  2106  
  2107  				// The outer most coded error is a wrapper, not the actual
  2108  				// InvalidProposalSeqNumberError itself.
  2109  				_, ok := output.Err.(errors.InvalidProposalSeqNumberError)
  2110  				require.False(t, ok)
  2111  
  2112  				var seqNumErr errors.InvalidProposalSeqNumberError
  2113  				ok = errors.As(output.Err, &seqNumErr)
  2114  				require.True(t, ok)
  2115  				require.Equal(t, uint64(1), seqNumErr.CurrentSeqNumber())
  2116  			}),
  2117  	)
  2118  }