github.com/koko1123/flow-go-1@v0.29.6/fvm/transaction_test.go (about)

     1  package fvm_test
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/onflow/cadence/runtime"
     9  	"github.com/onflow/cadence/runtime/common"
    10  	"github.com/onflow/cadence/runtime/sema"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/koko1123/flow-go-1/engine/execution/testutil"
    14  	"github.com/koko1123/flow-go-1/fvm"
    15  	"github.com/koko1123/flow-go-1/fvm/derived"
    16  	"github.com/koko1123/flow-go-1/fvm/environment"
    17  	"github.com/koko1123/flow-go-1/fvm/errors"
    18  	"github.com/koko1123/flow-go-1/fvm/state"
    19  	"github.com/koko1123/flow-go-1/fvm/utils"
    20  	"github.com/koko1123/flow-go-1/model/flow"
    21  	"github.com/koko1123/flow-go-1/utils/unittest"
    22  )
    23  
    24  func makeTwoAccounts(
    25  	t *testing.T,
    26  	aPubKeys []flow.AccountPublicKey,
    27  	bPubKeys []flow.AccountPublicKey,
    28  ) (
    29  	flow.Address,
    30  	flow.Address,
    31  	*state.TransactionState,
    32  ) {
    33  
    34  	txnState := state.NewTransactionState(
    35  		utils.NewSimpleView(),
    36  		state.DefaultParameters(),
    37  	)
    38  
    39  	a := flow.HexToAddress("1234")
    40  	b := flow.HexToAddress("5678")
    41  
    42  	// create accounts
    43  	accounts := environment.NewAccounts(txnState)
    44  	err := accounts.Create(aPubKeys, a)
    45  	require.NoError(t, err)
    46  	err = accounts.Create(bPubKeys, b)
    47  	require.NoError(t, err)
    48  
    49  	return a, b, txnState
    50  }
    51  
    52  func TestAccountFreezing(t *testing.T) {
    53  
    54  	chain := flow.Mainnet.Chain()
    55  	serviceAddress := chain.ServiceAddress()
    56  
    57  	t.Run("setFrozenAccount can be enabled", func(t *testing.T) {
    58  
    59  		address, _, st := makeTwoAccounts(t, nil, nil)
    60  		accounts := environment.NewAccounts(st)
    61  		derivedBlockData := derived.NewEmptyDerivedBlockData()
    62  
    63  		// account should no be frozen
    64  		frozen, err := accounts.GetAccountFrozen(address)
    65  		require.NoError(t, err)
    66  		require.False(t, frozen)
    67  
    68  		code := fmt.Sprintf(`
    69  			transaction {
    70  				prepare(auth: AuthAccount) {
    71  					setAccountFrozen(0x%s, true)
    72  				}
    73  			}
    74  		`, address.String())
    75  
    76  		tx := flow.TransactionBody{Script: []byte(code)}
    77  		tx.AddAuthorizer(chain.ServiceAddress())
    78  		proc := fvm.Transaction(&tx, derivedBlockData.NextTxIndexForTestingOnly())
    79  
    80  		context := fvm.NewContext(
    81  			fvm.WithChain(chain),
    82  			fvm.WithAuthorizationChecksEnabled(false),
    83  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
    84  			fvm.WithDerivedBlockData(derivedBlockData))
    85  
    86  		derivedBlockData = derived.NewEmptyDerivedBlockData()
    87  		derivedTxnData, err := derivedBlockData.NewDerivedTransactionData(0, 0)
    88  		require.NoError(t, err)
    89  
    90  		err = fvm.Run(proc.NewExecutor(context, st, derivedTxnData))
    91  		require.NoError(t, err)
    92  		require.NoError(t, proc.Err)
    93  
    94  		// account should be frozen now
    95  		frozen, err = accounts.GetAccountFrozen(address)
    96  		require.NoError(t, err)
    97  		require.True(t, frozen)
    98  	})
    99  
   100  	t.Run("freezing account triggers program cache eviction", func(t *testing.T) {
   101  		address, _, st := makeTwoAccounts(t, nil, nil)
   102  		accounts := environment.NewAccounts(st)
   103  		derivedBlockData := derived.NewEmptyDerivedBlockData()
   104  
   105  		// account should no be frozen
   106  		frozen, err := accounts.GetAccountFrozen(address)
   107  		require.NoError(t, err)
   108  		require.False(t, frozen)
   109  
   110  		vm := fvm.NewVirtualMachine()
   111  
   112  		// deploy code to account
   113  
   114  		whateverContractCode := `
   115  			pub contract Whatever {
   116  				pub fun say() {
   117  					log("Düsseldorf")
   118  				}
   119  			}
   120  		`
   121  
   122  		deployContract := []byte(fmt.Sprintf(
   123  			`
   124  			 transaction {
   125  			   prepare(signer: AuthAccount) {
   126  				   signer.contracts.add(name: "Whatever", code: "%s".decodeHex())
   127  			   }
   128  			 }
   129  	   `, hex.EncodeToString([]byte(whateverContractCode)),
   130  		))
   131  
   132  		proc := fvm.Transaction(
   133  			&flow.TransactionBody{Script: deployContract, Authorizers: []flow.Address{address}, Payer: address},
   134  			derivedBlockData.NextTxIndexForTestingOnly())
   135  		context := fvm.NewContext(
   136  			fvm.WithServiceAccount(false),
   137  			fvm.WithContractDeploymentRestricted(false),
   138  			fvm.WithCadenceLogging(true),
   139  			// run with limited processor to test just core of freezing, but still inside FVM
   140  			fvm.WithAuthorizationChecksEnabled(false),
   141  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   142  			fvm.WithDerivedBlockData(derivedBlockData))
   143  
   144  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   145  		require.NoError(t, err)
   146  		require.NoError(t, proc.Err)
   147  
   148  		// contracts should load now
   149  
   150  		code := func(a flow.Address) []byte {
   151  			return []byte(fmt.Sprintf(`
   152  				import Whatever from 0x%s
   153  
   154  				transaction {
   155  					execute {
   156  						Whatever.say()
   157  					}
   158  				}
   159  			`, a.String()))
   160  		}
   161  
   162  		proc = fvm.Transaction(
   163  			&flow.TransactionBody{Script: code(address)},
   164  			derivedBlockData.NextTxIndexForTestingOnly())
   165  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   166  		require.NoError(t, err)
   167  		require.NoError(t, proc.Err)
   168  		require.Len(t, proc.Logs, 1)
   169  		require.Contains(t, proc.Logs[0], "\"D\\u{fc}sseldorf\"")
   170  
   171  		// verify cache is populated
   172  
   173  		cadenceAddr := common.AddressLocation{
   174  			Address: common.MustBytesToAddress(address[:]),
   175  			Name:    "Whatever",
   176  		}
   177  		entry := derivedBlockData.GetProgramForTestingOnly(cadenceAddr)
   178  		require.NotNil(t, entry)
   179  
   180  		// freeze account
   181  
   182  		freezeTx := fmt.Sprintf(`
   183  				transaction {
   184  					prepare(auth: AuthAccount) {
   185  						setAccountFrozen(0x%s, true)
   186  					}
   187  				}
   188  			`,
   189  			address)
   190  		tx := &flow.TransactionBody{Script: []byte(freezeTx)}
   191  		tx.AddAuthorizer(chain.ServiceAddress())
   192  
   193  		proc = fvm.Transaction(tx, derivedBlockData.NextTxIndexForTestingOnly())
   194  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   195  		require.NoError(t, err)
   196  		require.NoError(t, proc.Err)
   197  
   198  		// verify cache is evicted
   199  
   200  		entry = derivedBlockData.GetProgramForTestingOnly(cadenceAddr)
   201  		require.Nil(t, entry)
   202  
   203  		// loading code from frozen account triggers error
   204  
   205  		proc = fvm.Transaction(
   206  			&flow.TransactionBody{Script: code(address)},
   207  			derivedBlockData.NextTxIndexForTestingOnly())
   208  
   209  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   210  		require.NoError(t, err)
   211  		require.Error(t, proc.Err)
   212  
   213  		// find frozen account specific error
   214  		require.True(t, errors.IsCadenceRuntimeError(proc.Err))
   215  
   216  		var rtErr runtime.Error
   217  		require.True(t, errors.As(proc.Err, &rtErr))
   218  
   219  		err = rtErr.Err
   220  
   221  		require.IsType(t, &runtime.ParsingCheckingError{}, err)
   222  		err = err.(*runtime.ParsingCheckingError).Err
   223  
   224  		require.IsType(t, &sema.CheckerError{}, err)
   225  		checkerErr := err.(*sema.CheckerError)
   226  
   227  		checkerErrors := checkerErr.ChildErrors()
   228  
   229  		require.Len(t, checkerErrors, 2)
   230  		require.IsType(t, &sema.ImportedProgramError{}, checkerErrors[0])
   231  
   232  		importedCheckerError := checkerErrors[0].(*sema.ImportedProgramError).Err
   233  		accountFrozenError := errors.FrozenAccountError{}
   234  
   235  		require.True(t, errors.As(importedCheckerError, &accountFrozenError))
   236  		require.Equal(t, address, accountFrozenError.Address())
   237  	})
   238  
   239  	t.Run("code from frozen account cannot be loaded", func(t *testing.T) {
   240  
   241  		frozenAddress, notFrozenAddress, st := makeTwoAccounts(t, nil, nil)
   242  		accounts := environment.NewAccounts(st)
   243  		derivedBlockData := derived.NewEmptyDerivedBlockData()
   244  
   245  		vm := fvm.NewVirtualMachine()
   246  
   247  		// deploy code to accounts
   248  		whateverContractCode := `
   249  			pub contract Whatever {
   250  				pub fun say() {
   251  					log("Düsseldorf")
   252  				}
   253  			}
   254  		`
   255  
   256  		deployContract := []byte(fmt.Sprintf(
   257  			`
   258  			 transaction {
   259  			   prepare(signer: AuthAccount) {
   260  				   signer.contracts.add(name: "Whatever", code: "%s".decodeHex())
   261  			   }
   262  			 }
   263  	   `, hex.EncodeToString([]byte(whateverContractCode)),
   264  		))
   265  
   266  		procFrozen := fvm.Transaction(
   267  			&flow.TransactionBody{Script: deployContract, Authorizers: []flow.Address{frozenAddress}, Payer: frozenAddress},
   268  			derivedBlockData.NextTxIndexForTestingOnly())
   269  		context := fvm.NewContext(
   270  			fvm.WithServiceAccount(false),
   271  			fvm.WithContractDeploymentRestricted(false),
   272  			fvm.WithCadenceLogging(true),
   273  			// run with limited processor to test just core of freezing, but still inside FVM
   274  			fvm.WithAuthorizationChecksEnabled(false),
   275  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   276  			fvm.WithDerivedBlockData(derivedBlockData))
   277  
   278  		err := vm.Run(context, procFrozen, st.ViewForTestingOnly())
   279  		require.NoError(t, err)
   280  		require.NoError(t, procFrozen.Err)
   281  
   282  		procNotFrozen := fvm.Transaction(
   283  			&flow.TransactionBody{Script: deployContract, Authorizers: []flow.Address{notFrozenAddress}, Payer: notFrozenAddress},
   284  			derivedBlockData.NextTxIndexForTestingOnly())
   285  		err = vm.Run(context, procNotFrozen, st.ViewForTestingOnly())
   286  		require.NoError(t, err)
   287  		require.NoError(t, procNotFrozen.Err)
   288  
   289  		// both contracts should load now
   290  
   291  		code := func(a flow.Address) []byte {
   292  			return []byte(fmt.Sprintf(`
   293  				import Whatever from 0x%s
   294  	
   295  				transaction {
   296  					execute {
   297  						Whatever.say()
   298  					}
   299  				}
   300  			`, a.String()))
   301  		}
   302  
   303  		// code from not frozen loads fine
   304  		proc := fvm.Transaction(
   305  			&flow.TransactionBody{Script: code(frozenAddress), Payer: serviceAddress},
   306  			derivedBlockData.NextTxIndexForTestingOnly())
   307  
   308  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   309  		require.NoError(t, err)
   310  		require.NoError(t, proc.Err)
   311  		require.Len(t, proc.Logs, 1)
   312  		require.Contains(t, proc.Logs[0], "\"D\\u{fc}sseldorf\"")
   313  
   314  		proc = fvm.Transaction(
   315  			&flow.TransactionBody{Script: code(notFrozenAddress)},
   316  			derivedBlockData.NextTxIndexForTestingOnly())
   317  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   318  		require.NoError(t, err)
   319  		require.NoError(t, proc.Err)
   320  		require.Len(t, proc.Logs, 1)
   321  		require.Contains(t, proc.Logs[0], "\"D\\u{fc}sseldorf\"")
   322  
   323  		// freeze account
   324  
   325  		freezeTx := fmt.Sprintf(`
   326  				transaction {
   327  					prepare(auth: AuthAccount) {
   328  						setAccountFrozen(0x%s, true)
   329  					}
   330  				}
   331  			`,
   332  			frozenAddress)
   333  		tx := &flow.TransactionBody{Script: []byte(freezeTx)}
   334  		tx.AddAuthorizer(chain.ServiceAddress())
   335  
   336  		proc = fvm.Transaction(tx, derivedBlockData.NextTxIndexForTestingOnly())
   337  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   338  		require.NoError(t, err)
   339  		require.NoError(t, proc.Err)
   340  
   341  		// make sure freeze status is correct
   342  		frozen, err := accounts.GetAccountFrozen(frozenAddress)
   343  		require.NoError(t, err)
   344  		require.True(t, frozen)
   345  
   346  		frozen, err = accounts.GetAccountFrozen(notFrozenAddress)
   347  		require.NoError(t, err)
   348  		require.False(t, frozen)
   349  
   350  		// loading code from frozen account triggers error
   351  		proc = fvm.Transaction(
   352  			&flow.TransactionBody{Script: code(frozenAddress)},
   353  			derivedBlockData.NextTxIndexForTestingOnly())
   354  
   355  		err = vm.Run(context, proc, st.ViewForTestingOnly())
   356  		require.NoError(t, err)
   357  		require.Error(t, proc.Err)
   358  
   359  		// find frozen account specific error
   360  		require.True(t, errors.IsCadenceRuntimeError(proc.Err))
   361  
   362  		var rtErr runtime.Error
   363  		require.True(t, errors.As(proc.Err, &rtErr))
   364  
   365  		err = rtErr.Err
   366  
   367  		require.IsType(t, &runtime.ParsingCheckingError{}, err)
   368  		err = err.(*runtime.ParsingCheckingError).Err
   369  
   370  		require.IsType(t, &sema.CheckerError{}, err)
   371  		checkerErr := err.(*sema.CheckerError)
   372  
   373  		checkerErrors := checkerErr.ChildErrors()
   374  
   375  		require.Len(t, checkerErrors, 2)
   376  		require.IsType(t, &sema.ImportedProgramError{}, checkerErrors[0])
   377  
   378  		importedCheckerError := checkerErrors[0].(*sema.ImportedProgramError).Err
   379  		accountFrozenError := errors.FrozenAccountError{}
   380  
   381  		require.True(t, errors.As(importedCheckerError, &accountFrozenError))
   382  		require.Equal(t, frozenAddress, accountFrozenError.Address())
   383  	})
   384  
   385  	t.Run("service account cannot freeze itself", func(t *testing.T) {
   386  
   387  		vm := fvm.NewVirtualMachine()
   388  		// create default context
   389  		derivedBlockData := derived.NewEmptyDerivedBlockData()
   390  		context := fvm.NewContext(
   391  			fvm.WithDerivedBlockData(derivedBlockData))
   392  
   393  		ledger := testutil.RootBootstrappedLedger(vm, context)
   394  
   395  		privateKeys, err := testutil.GenerateAccountPrivateKeys(1)
   396  		require.NoError(t, err)
   397  
   398  		// Bootstrap a ledger, creating accounts with the provided private keys and the root account.
   399  		accounts, err := testutil.CreateAccounts(vm, ledger, derivedBlockData, privateKeys, context.Chain)
   400  		require.NoError(t, err)
   401  
   402  		address := accounts[0]
   403  
   404  		codeAccount := fmt.Sprintf(`
   405  			transaction {
   406  				prepare(auth: AuthAccount) {}
   407  				execute {
   408  					setAccountFrozen(0x%s, true)
   409  				}
   410  			}
   411  		`, address.String())
   412  
   413  		codeService := fmt.Sprintf(`
   414  			transaction {
   415  				prepare(auth: AuthAccount) {}
   416  				execute {
   417  					setAccountFrozen(0x%s, true)
   418  				}
   419  			}
   420  		`, serviceAddress.String())
   421  
   422  		// sign tx by service account now
   423  		txBody := &flow.TransactionBody{Script: []byte(codeAccount)}
   424  		txBody.SetProposalKey(serviceAddress, 0, 0)
   425  		txBody.SetPayer(serviceAddress)
   426  		txBody.AddAuthorizer(serviceAddress)
   427  
   428  		err = testutil.SignEnvelope(txBody, serviceAddress, unittest.ServiceAccountPrivateKey)
   429  		require.NoError(t, err)
   430  
   431  		tx := fvm.Transaction(txBody, derivedBlockData.NextTxIndexForTestingOnly())
   432  		err = vm.Run(context, tx, ledger)
   433  		require.NoError(t, err)
   434  		require.NoError(t, tx.Err)
   435  
   436  		accountsService := environment.NewAccounts(state.NewTransactionState(
   437  			ledger,
   438  			state.DefaultParameters(),
   439  		))
   440  
   441  		frozen, err := accountsService.GetAccountFrozen(address)
   442  		require.NoError(t, err)
   443  		require.True(t, frozen)
   444  
   445  		// make sure service account is not frozen before
   446  		frozen, err = accountsService.GetAccountFrozen(serviceAddress)
   447  		require.NoError(t, err)
   448  		require.False(t, frozen)
   449  
   450  		// service account cannot be frozen
   451  		txBody = &flow.TransactionBody{Script: []byte(codeService)}
   452  		txBody.SetProposalKey(serviceAddress, 0, 1)
   453  		txBody.SetPayer(serviceAddress)
   454  		txBody.AddAuthorizer(serviceAddress)
   455  
   456  		err = testutil.SignPayload(txBody, accounts[0], privateKeys[0])
   457  		require.NoError(t, err)
   458  
   459  		err = testutil.SignEnvelope(txBody, serviceAddress, unittest.ServiceAccountPrivateKey)
   460  		require.NoError(t, err)
   461  
   462  		tx = fvm.Transaction(txBody, derivedBlockData.NextTxIndexForTestingOnly())
   463  		err = vm.Run(context, tx, ledger)
   464  		require.NoError(t, err)
   465  		require.Error(t, tx.Err)
   466  
   467  		accountsService = environment.NewAccounts(state.NewTransactionState(
   468  			ledger,
   469  			state.DefaultParameters(),
   470  		))
   471  
   472  		frozen, err = accountsService.GetAccountFrozen(serviceAddress)
   473  		require.NoError(t, err)
   474  		require.False(t, frozen)
   475  	})
   476  
   477  	t.Run("frozen account fail just tx, not execution", func(t *testing.T) {
   478  
   479  		frozenAddress, notFrozenAddress, st := makeTwoAccounts(t, nil, nil)
   480  		accounts := environment.NewAccounts(st)
   481  
   482  		vm := fvm.NewVirtualMachine()
   483  
   484  		// deploy code to accounts
   485  		whateverCode := []byte(`
   486  			transaction {
   487  				prepare(auth: AuthAccount) {
   488  					log("Szczebrzeszyn")
   489  				}
   490  			}
   491  		`)
   492  
   493  		derivedBlockData := derived.NewEmptyDerivedBlockData()
   494  		context := fvm.NewContext(
   495  			fvm.WithServiceAccount(false),
   496  			fvm.WithContractDeploymentRestricted(false),
   497  			fvm.WithCadenceLogging(true),
   498  			// run with limited processor to test just core of freezing, but still inside FVM
   499  			fvm.WithAccountKeyWeightThreshold(-1),
   500  			fvm.WithSequenceNumberCheckAndIncrementEnabled(false),
   501  			fvm.WithDerivedBlockData(derivedBlockData))
   502  
   503  		// freeze account
   504  
   505  		freezeTx := fmt.Sprintf(`
   506  				transaction {
   507  					prepare(auth: AuthAccount) {
   508  						setAccountFrozen(0x%s, true)
   509  					}
   510  				}
   511  			`,
   512  			frozenAddress)
   513  		tx := &flow.TransactionBody{Script: []byte(freezeTx)}
   514  		tx.AddAuthorizer(chain.ServiceAddress())
   515  
   516  		proc := fvm.Transaction(tx, derivedBlockData.NextTxIndexForTestingOnly())
   517  
   518  		derivedTxnData, err := derivedBlockData.NewDerivedTransactionData(0, 0)
   519  		require.NoError(t, err)
   520  
   521  		err = fvm.Run(proc.NewExecutor(
   522  			fvm.NewContextFromParent(
   523  				context,
   524  				fvm.WithAuthorizationChecksEnabled(false),
   525  			),
   526  			st,
   527  			derivedTxnData))
   528  		require.NoError(t, err)
   529  		require.NoError(t, proc.Err)
   530  
   531  		// make sure freeze status is correct
   532  		var frozen bool
   533  		frozen, err = accounts.GetAccountFrozen(frozenAddress)
   534  		require.NoError(t, err)
   535  		require.True(t, frozen)
   536  
   537  		frozen, err = accounts.GetAccountFrozen(notFrozenAddress)
   538  		require.NoError(t, err)
   539  		require.False(t, frozen)
   540  
   541  		t.Run("authorizer", func(t *testing.T) {
   542  
   543  			notFrozenProc := fvm.Transaction(
   544  				&flow.TransactionBody{
   545  					Script:      whateverCode,
   546  					Authorizers: []flow.Address{notFrozenAddress},
   547  					ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   548  					Payer:       notFrozenAddress},
   549  				derivedBlockData.NextTxIndexForTestingOnly())
   550  			// tx run OK by nonfrozen account
   551  			err = vm.Run(context, notFrozenProc, st.ViewForTestingOnly())
   552  			require.NoError(t, err)
   553  			require.NoError(t, notFrozenProc.Err)
   554  
   555  			frozenProc := fvm.Transaction(
   556  				&flow.TransactionBody{
   557  					Script:      whateverCode,
   558  					Authorizers: []flow.Address{frozenAddress},
   559  					ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   560  					Payer:       notFrozenAddress},
   561  				derivedBlockData.NextTxIndexForTestingOnly())
   562  			err = vm.Run(context, frozenProc, st.ViewForTestingOnly())
   563  			require.NoError(t, err)
   564  			require.Error(t, frozenProc.Err)
   565  
   566  			require.Equal(
   567  				t,
   568  				errors.ErrCodeFrozenAccountError,
   569  				frozenProc.Err.Code())
   570  
   571  			// The outer most coded error is a wrapper, not the actual
   572  			// FrozenAccountError itself.
   573  			_, ok := frozenProc.Err.(errors.FrozenAccountError)
   574  			require.False(t, ok)
   575  
   576  			// find frozen account specific error
   577  			var accountFrozenErr errors.FrozenAccountError
   578  			ok = errors.As(frozenProc.Err, &accountFrozenErr)
   579  			require.True(t, ok)
   580  			require.Equal(t, frozenAddress, accountFrozenErr.Address())
   581  		})
   582  
   583  		t.Run("proposal", func(t *testing.T) {
   584  
   585  			notFrozenProc := fvm.Transaction(
   586  				&flow.TransactionBody{
   587  					Script:      whateverCode,
   588  					Authorizers: []flow.Address{notFrozenAddress},
   589  					ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   590  					Payer:       notFrozenAddress,
   591  				},
   592  				derivedBlockData.NextTxIndexForTestingOnly())
   593  
   594  			// tx run OK by nonfrozen account
   595  			err = vm.Run(context, notFrozenProc, st.ViewForTestingOnly())
   596  			require.NoError(t, err)
   597  			require.NoError(t, notFrozenProc.Err)
   598  
   599  			frozenProc := fvm.Transaction(
   600  				&flow.TransactionBody{
   601  					Script:      whateverCode,
   602  					Authorizers: []flow.Address{notFrozenAddress},
   603  					ProposalKey: flow.ProposalKey{Address: frozenAddress},
   604  					Payer:       notFrozenAddress,
   605  				},
   606  				derivedBlockData.NextTxIndexForTestingOnly())
   607  			err = vm.Run(context, frozenProc, st.ViewForTestingOnly())
   608  			require.NoError(t, err)
   609  			require.Error(t, frozenProc.Err)
   610  
   611  			require.Equal(
   612  				t,
   613  				errors.ErrCodeFrozenAccountError,
   614  				frozenProc.Err.Code())
   615  
   616  			// The outer most coded error is a wrapper, not the actual
   617  			// FrozenAccountError itself.
   618  			_, ok := frozenProc.Err.(errors.FrozenAccountError)
   619  			require.False(t, ok)
   620  
   621  			// find frozen account specific error
   622  			var accountFrozenErr errors.FrozenAccountError
   623  			ok = errors.As(frozenProc.Err, &accountFrozenErr)
   624  			require.True(t, ok)
   625  			require.Equal(t, frozenAddress, accountFrozenErr.Address())
   626  		})
   627  
   628  		t.Run("payer", func(t *testing.T) {
   629  
   630  			notFrozenProc := fvm.Transaction(
   631  				&flow.TransactionBody{
   632  					Script:      whateverCode,
   633  					Authorizers: []flow.Address{notFrozenAddress},
   634  					ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   635  					Payer:       notFrozenAddress,
   636  				},
   637  				derivedBlockData.NextTxIndexForTestingOnly())
   638  
   639  			// tx run OK by nonfrozen account
   640  			err = vm.Run(context, notFrozenProc, st.ViewForTestingOnly())
   641  			require.NoError(t, err)
   642  			require.NoError(t, notFrozenProc.Err)
   643  
   644  			frozenProc := fvm.Transaction(
   645  				&flow.TransactionBody{
   646  					Script:      whateverCode,
   647  					Authorizers: []flow.Address{notFrozenAddress},
   648  					ProposalKey: flow.ProposalKey{Address: notFrozenAddress},
   649  					Payer:       frozenAddress,
   650  				},
   651  				derivedBlockData.NextTxIndexForTestingOnly())
   652  			err = vm.Run(context, frozenProc, st.ViewForTestingOnly())
   653  			require.NoError(t, err)
   654  			require.Error(t, frozenProc.Err)
   655  
   656  			require.Equal(
   657  				t,
   658  				errors.ErrCodeFrozenAccountError,
   659  				frozenProc.Err.Code())
   660  
   661  			// The outer most coded error is a wrapper, not the actual
   662  			// FrozenAccountError itself.
   663  			_, ok := frozenProc.Err.(errors.FrozenAccountError)
   664  			require.False(t, ok)
   665  
   666  			// find frozen account specific error
   667  			var accountFrozenErr errors.FrozenAccountError
   668  			ok = errors.As(frozenProc.Err, &accountFrozenErr)
   669  			require.True(t, ok)
   670  			require.Equal(t, frozenAddress, accountFrozenErr.Address())
   671  		})
   672  	})
   673  }