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