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