diff --git a/fvm/environment/derived_data_invalidator_test.go b/fvm/environment/derived_data_invalidator_test.go index 2eed1cf36fe..7c7038948f7 100644 --- a/fvm/environment/derived_data_invalidator_test.go +++ b/fvm/environment/derived_data_invalidator_test.go @@ -244,7 +244,7 @@ func TestMeterParamOverridesUpdated(t *testing.T) { snapshotTree := snapshot.NewSnapshotTree(nil) - ctx := fvm.NewContext(fvm.WithChain(flow.Testnet.Chain())) + ctx := fvm.NewContext(fvm.WithChain(flow.Emulator.Chain())) vm := fvm.NewVirtualMachine() executionSnapshot, _, err := vm.Run( diff --git a/fvm/executionParameters.go b/fvm/executionParameters.go index ac0ec6223f0..3c4fa8defc7 100644 --- a/fvm/executionParameters.go +++ b/fvm/executionParameters.go @@ -19,6 +19,7 @@ import ( "github.com/onflow/flow-go/fvm/storage" "github.com/onflow/flow-go/fvm/storage/derived" "github.com/onflow/flow-go/fvm/storage/state" + "github.com/onflow/flow-go/fvm/systemcontracts" ) func ProcedureStateParameters( @@ -143,10 +144,14 @@ func (computer ExecutionParametersComputer) getExecutionParameters() ( derived.StateExecutionParameters, error, ) { - // Check that the service account exists because all the settings are - // stored in it - serviceAddress := computer.ctx.Chain.ServiceAddress() - service := common.Address(serviceAddress) + sc := systemcontracts.SystemContractsForChain(computer.ctx.Chain.ChainID()) + + // The execution parameters are stored in the ExecutionParametersAccount. This is + // just the service account for all networks except mainnet and testnet. + // For mainnet and testnet, the execution parameters are stored in a separate + // account, so that they are separated from the frequently changing data on the + // service account. + service := common.Address(sc.ExecutionParametersAccount.Address) env := environment.NewScriptEnv( context.Background(), diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index e621d0ec2b5..44bbb371ca8 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -1080,7 +1080,11 @@ func TestTransactionFeeDeduction(t *testing.T) { func TestSettingExecutionWeights(t *testing.T) { + // change the chain so that the metering settings are read from the service account + chain := flow.Emulator.Chain() + t.Run("transaction should fail with high weights", newVMTest().withBootstrapProcedureOptions( + fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation), fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee), fvm.WithStorageMBPerFLOW(fvm.DefaultStorageMBPerFLOW), @@ -1089,6 +1093,8 @@ func TestSettingExecutionWeights(t *testing.T) { common.ComputationKindLoop: 100_000 << meter.MeterExecutionInternalPrecisionBytes, }, ), + ).withContextOptions( + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { @@ -1137,6 +1143,7 @@ func TestSettingExecutionWeights(t *testing.T) { ), ).withContextOptions( fvm.WithMemoryLimit(10_000_000_000), + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { // Create an account private key. @@ -1187,6 +1194,7 @@ func TestSettingExecutionWeights(t *testing.T) { ), ).withContextOptions( fvm.WithMemoryLimit(10_000_000_000), + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { @@ -1231,6 +1239,8 @@ func TestSettingExecutionWeights(t *testing.T) { fvm.WithExecutionMemoryWeights( memoryWeights, ), + ).withContextOptions( + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { privateKeys, err := testutil.GenerateAccountPrivateKeys(1) @@ -1298,6 +1308,8 @@ func TestSettingExecutionWeights(t *testing.T) { environment.ComputationKindCreateAccount: (fvm.DefaultComputationLimit + 1) << meter.MeterExecutionInternalPrecisionBytes, }, ), + ).withContextOptions( + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { txBody := flow.NewTransactionBody(). @@ -1334,6 +1346,8 @@ func TestSettingExecutionWeights(t *testing.T) { environment.ComputationKindCreateAccount: 100_000_000 << meter.MeterExecutionInternalPrecisionBytes, }, ), + ).withContextOptions( + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { @@ -1371,6 +1385,8 @@ func TestSettingExecutionWeights(t *testing.T) { environment.ComputationKindCreateAccount: 100_000_000 << meter.MeterExecutionInternalPrecisionBytes, }, ), + ).withContextOptions( + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { txBody := flow.NewTransactionBody(). @@ -1414,6 +1430,7 @@ func TestSettingExecutionWeights(t *testing.T) { fvm.WithAccountStorageLimit(true), fvm.WithTransactionFeesEnabled(true), fvm.WithMemoryLimit(math.MaxUint64), + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { // Use the maximum amount of computation so that the transaction still passes. @@ -1507,6 +1524,7 @@ func TestSettingExecutionWeights(t *testing.T) { fvm.WithAccountStorageLimit(true), fvm.WithTransactionFeesEnabled(true), fvm.WithMemoryLimit(math.MaxUint64), + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { // Create an account private key. @@ -2162,6 +2180,8 @@ func TestScriptExecutionLimit(t *testing.T) { t.Parallel() + chain := flow.Emulator.Chain() + script := fvm.Script([]byte(` access(all) fun main() { var s: Int256 = 1024102410241024 @@ -2203,6 +2223,7 @@ func TestScriptExecutionLimit(t *testing.T) { fvm.WithTransactionFeesEnabled(true), fvm.WithAccountStorageLimit(true), fvm.WithComputationLimit(10000), + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { scriptCtx := fvm.NewContextFromParent(ctx) @@ -2225,6 +2246,7 @@ func TestScriptExecutionLimit(t *testing.T) { fvm.WithTransactionFeesEnabled(true), fvm.WithAccountStorageLimit(true), fvm.WithComputationLimit(20000), + fvm.WithChain(chain), ).run( func(t *testing.T, vm fvm.VM, chain flow.Chain, ctx fvm.Context, snapshotTree snapshot.SnapshotTree) { scriptCtx := fvm.NewContextFromParent(ctx) diff --git a/fvm/systemcontracts/system_contracts.go b/fvm/systemcontracts/system_contracts.go index 7fd321d88bc..ba5e7854724 100644 --- a/fvm/systemcontracts/system_contracts.go +++ b/fvm/systemcontracts/system_contracts.go @@ -46,6 +46,10 @@ const ( // AccountNameEVMStorage is not a contract, but a special account that is used to store EVM state AccountNameEVMStorage = "EVMStorageAccount" + // AccountNameExecutionParametersAccount is not a contract, but a special account that is used to store execution parameters + // This is generally just the service account. For mainnet and testnet, it is a separate account, + // in order to separate it away from the frequently changing data on the service account. + AccountNameExecutionParametersAccount = "ExecutionParametersAccount" // Unqualified names of service events (not including address prefix or contract name) @@ -99,6 +103,11 @@ var ( evmStorageAddressTestnet = flow.HexToAddress("1a54ed2be7552821") // evmStorageAddressMainnet is the address of the EVM state storage contract on Mainnet evmStorageAddressMainnet = flow.HexToAddress("d421a63faae318f9") + + // executionParametersAddressTestnet is the address of the Execution Parameters contract on Testnet + executionParametersAddressTestnet = flow.HexToAddress("6997a2f2cf57b73a") + // executionParametersAddressMainnet is the address of the Execution Parameters contract on Mainnet + executionParametersAddressMainnet = flow.HexToAddress("f426ff57ee8f6110") ) // SystemContract represents a system contract on a particular chain. @@ -148,10 +157,11 @@ type SystemContracts struct { DKG SystemContract // service account related contracts - FlowServiceAccount SystemContract - NodeVersionBeacon SystemContract - RandomBeaconHistory SystemContract - FlowStorageFees SystemContract + FlowServiceAccount SystemContract + NodeVersionBeacon SystemContract + RandomBeaconHistory SystemContract + FlowStorageFees SystemContract + ExecutionParametersAccount SystemContract // token related contracts FlowFees SystemContract @@ -331,16 +341,28 @@ func init() { } } + executionParametersAccountFunc := func(chain flow.ChainID) flow.Address { + switch chain { + case flow.Mainnet: + return executionParametersAddressMainnet + case flow.Testnet: + return executionParametersAddressTestnet + default: + return serviceAddressFunc(chain) + } + } + contractAddressFunc = map[string]func(id flow.ChainID) flow.Address{ ContractNameIDTableStaking: epochAddressFunc, ContractNameEpoch: epochAddressFunc, ContractNameClusterQC: epochAddressFunc, ContractNameDKG: epochAddressFunc, - ContractNameNodeVersionBeacon: serviceAddressFunc, - ContractNameRandomBeaconHistory: serviceAddressFunc, - ContractNameServiceAccount: serviceAddressFunc, - ContractNameStorageFees: serviceAddressFunc, + ContractNameNodeVersionBeacon: serviceAddressFunc, + ContractNameRandomBeaconHistory: serviceAddressFunc, + ContractNameServiceAccount: serviceAddressFunc, + ContractNameStorageFees: serviceAddressFunc, + AccountNameExecutionParametersAccount: executionParametersAccountFunc, ContractNameFlowFees: nthAddressFunc(FlowFeesAccountIndex), ContractNameFungibleToken: nthAddressFunc(FungibleTokenAccountIndex), @@ -392,10 +414,11 @@ func init() { ClusterQC: addressOfContract(ContractNameClusterQC), DKG: addressOfContract(ContractNameDKG), - FlowServiceAccount: addressOfContract(ContractNameServiceAccount), - NodeVersionBeacon: addressOfContract(ContractNameNodeVersionBeacon), - RandomBeaconHistory: addressOfContract(ContractNameRandomBeaconHistory), - FlowStorageFees: addressOfContract(ContractNameStorageFees), + FlowServiceAccount: addressOfContract(ContractNameServiceAccount), + NodeVersionBeacon: addressOfContract(ContractNameNodeVersionBeacon), + RandomBeaconHistory: addressOfContract(ContractNameRandomBeaconHistory), + FlowStorageFees: addressOfContract(ContractNameStorageFees), + ExecutionParametersAccount: addressOfContract(AccountNameExecutionParametersAccount), FlowFees: addressOfContract(ContractNameFlowFees), FlowToken: addressOfContract(ContractNameFlowToken),