From 5c65c322d2ed59de072fd9edbde96c301a0e1bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 25 Nov 2024 16:16:55 -0800 Subject: [PATCH 01/21] update to Cadence with account storage map support: feature/combine-domain-payloads-and-domain-storage-maps --- cmd/util/ledger/util/atree_util.go | 6 ++++-- cmd/util/ledger/util/util.go | 14 -------------- go.mod | 6 +++--- go.sum | 6 ++++++ 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/cmd/util/ledger/util/atree_util.go b/cmd/util/ledger/util/atree_util.go index 73fd30812e3..5354247f805 100644 --- a/cmd/util/ledger/util/atree_util.go +++ b/cmd/util/ledger/util/atree_util.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/onflow/atree" + "github.com/onflow/cadence/interpreter" "github.com/onflow/cadence/common" "github.com/onflow/cadence/runtime" @@ -104,10 +105,11 @@ func LoadAtreeSlabsInStorage( } func CheckStorageHealth( + inter *interpreter.Interpreter, address common.Address, storage *runtime.Storage, registers registers.Registers, - domains []string, + domains []common.StorageDomain, nWorkers int, ) error { @@ -117,7 +119,7 @@ func CheckStorageHealth( } for _, domain := range domains { - _ = storage.GetStorageMap(address, domain, false) + _ = storage.GetDomainStorageMap(inter, address, domain, false) } return storage.CheckHealth() diff --git a/cmd/util/ledger/util/util.go b/cmd/util/ledger/util/util.go index 14af2ae3b29..62fcf601dc7 100644 --- a/cmd/util/ledger/util/util.go +++ b/cmd/util/ledger/util/util.go @@ -10,8 +10,6 @@ import ( "github.com/onflow/atree" "github.com/onflow/cadence/common" - "github.com/onflow/cadence/runtime" - "github.com/onflow/cadence/stdlib" "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/ledger" @@ -247,15 +245,3 @@ func (p *PayloadsLedger) AllocateSlabIndex(owner []byte) (atree.SlabIndex, error panic("AllocateSlabIndex not expected to be called") } - -var StorageMapDomains = []string{ - common.PathDomainStorage.Identifier(), - common.PathDomainPrivate.Identifier(), - common.PathDomainPublic.Identifier(), - runtime.StorageDomainContract, - stdlib.InboxStorageDomain, - stdlib.CapabilityControllerStorageDomain, - stdlib.CapabilityControllerTagStorageDomain, - stdlib.PathCapabilityStorageDomain, - stdlib.AccountCapabilityStorageDomain, -} diff --git a/go.mod b/go.mod index eacd5e0ded0..38e4b914020 100644 --- a/go.mod +++ b/go.mod @@ -47,8 +47,8 @@ require ( github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multihash v0.2.3 - github.com/onflow/atree v0.8.0 - github.com/onflow/cadence v1.2.2 + github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf + github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 github.com/onflow/crypto v0.25.2 github.com/onflow/flow v0.3.4 github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 @@ -297,7 +297,7 @@ require ( github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect diff --git a/go.sum b/go.sum index 15ec48eea52..6c55d45459c 100644 --- a/go.sum +++ b/go.sum @@ -911,10 +911,14 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= +github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf h1:MDB/hdwr5GMsZHIIrAw3gBnmWBy5XjsZ4/6kftv9d5c= +github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf/go.mod h1:U8PGG42VrSJqjdfJ9NGQ2fenkyFRYlgtfHsZM61H4zY= github.com/onflow/boxo v0.0.0-20240201202436-f2477b92f483 h1:LpiQhTAfM9CAmNVEs0n//cBBgCg+vJSiIxTHYUklZ84= github.com/onflow/boxo v0.0.0-20240201202436-f2477b92f483/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80= github.com/onflow/cadence v1.2.2 h1:LwigF/2lPiXlwX5rFn71KeMpmW5Iu/f/JtsPLLULBCc= github.com/onflow/cadence v1.2.2/go.mod h1:PYX1xLejqswtDsQzN93x/VpfSKNyjUk6hrkc/mpv7xs= +github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 h1:G4eOurxUXdAZsjHZPDU/hzr6kQ06gNoQLxGbfnzeVxI= +github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5/go.mod h1:XNnLHuRy9Ta9BF3BK/1LEkcId+RdDge36mNRfPiCVzE= github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= github.com/onflow/flow v0.3.4 h1:FXUWVdYB90f/rjNcY0Owo30gL790tiYff9Pb/sycXYE= @@ -1235,6 +1239,8 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= From e7d04a437ec9931218df2b76a9bf2d85bbea2288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 25 Nov 2024 16:17:28 -0800 Subject: [PATCH 02/21] inject scheduleAccountV2Migration function into service account AccountV2Migration contract --- engine/execution/computation/manager.go | 1 + fvm/context.go | 4 +- fvm/environment/env.go | 6 +- fvm/environment/runtime.go | 4 +- fvm/environment/system_contracts_test.go | 5 +- fvm/executionParameters_test.go | 3 + fvm/fvm_bench_test.go | 1 + fvm/fvm_test.go | 2 + fvm/runtime/reusable_cadence_runtime.go | 93 +++++++++++++++++++- fvm/runtime/reusable_cadence_runtime_test.go | 10 ++- 10 files changed, 114 insertions(+), 15 deletions(-) diff --git a/engine/execution/computation/manager.go b/engine/execution/computation/manager.go index e13a2d03791..b3f76a433cf 100644 --- a/engine/execution/computation/manager.go +++ b/engine/execution/computation/manager.go @@ -233,6 +233,7 @@ func DefaultFVMOptions(chainID flow.ChainID, cadenceTracing bool, extensiveTraci runtime.Config{ TracingEnabled: cadenceTracing, }, + chainID, )), fvm.WithEVMEnabled(true), } diff --git a/fvm/context.go b/fvm/context.go index fd198633b54..9c9f212cd0e 100644 --- a/fvm/context.go +++ b/fvm/context.go @@ -95,8 +95,8 @@ func WithChain(chain flow.Chain) Option { } } -// WithGasLimit sets the computation limit for a virtual machine context. -// @depricated, please use WithComputationLimit instead. +// Deprecated: WithGasLimit sets the computation limit for a virtual machine context. +// Use WithComputationLimit instead. func WithGasLimit(limit uint64) Option { return func(ctx Context) Context { ctx.ComputationLimit = limit diff --git a/fvm/environment/env.go b/fvm/environment/env.go index e23e9c64deb..31538eee086 100644 --- a/fvm/environment/env.go +++ b/fvm/environment/env.go @@ -113,11 +113,11 @@ type EnvironmentParams struct { } func DefaultEnvironmentParams() EnvironmentParams { + const chainID = flow.Mainnet return EnvironmentParams{ - Chain: flow.Mainnet.Chain(), + Chain: chainID.Chain(), ServiceAccountEnabled: true, - - RuntimeParams: DefaultRuntimeParams(), + RuntimeParams: DefaultRuntimeParams(chainID), ProgramLoggerParams: DefaultProgramLoggerParams(), EventEmitterParams: DefaultEventEmitterParams(), BlockInfoParams: DefaultBlockInfoParams(), diff --git a/fvm/environment/runtime.go b/fvm/environment/runtime.go index ace1bfce698..a542989212f 100644 --- a/fvm/environment/runtime.go +++ b/fvm/environment/runtime.go @@ -4,17 +4,19 @@ import ( cadenceRuntime "github.com/onflow/cadence/runtime" "github.com/onflow/flow-go/fvm/runtime" + "github.com/onflow/flow-go/model/flow" ) type RuntimeParams struct { runtime.ReusableCadenceRuntimePool } -func DefaultRuntimeParams() RuntimeParams { +func DefaultRuntimeParams(chainID flow.ChainID) RuntimeParams { return RuntimeParams{ ReusableCadenceRuntimePool: runtime.NewReusableCadenceRuntimePool( 0, cadenceRuntime.Config{}, + chainID, ), } } diff --git a/fvm/environment/system_contracts_test.go b/fvm/environment/system_contracts_test.go index e5870107956..77e8ea4a6a0 100644 --- a/fvm/environment/system_contracts_test.go +++ b/fvm/environment/system_contracts_test.go @@ -54,10 +54,13 @@ func TestSystemContractsInvoke(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + const chainID = flow.Mainnet + tracer := tracing.NewTracerSpan() runtimePool := reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, + chainID, func(_ runtime.Config) runtime.Runtime { return &testutil.TestInterpreterRuntime{ InvokeContractFunc: tc.contractFunction, @@ -70,7 +73,7 @@ func TestSystemContractsInvoke(t *testing.T) { }, ) invoker := environment.NewSystemContracts( - flow.Mainnet.Chain(), + chainID.Chain(), tracer, environment.NewProgramLogger( tracer, diff --git a/fvm/executionParameters_test.go b/fvm/executionParameters_test.go index da40c12c281..cc81703a1f1 100644 --- a/fvm/executionParameters_test.go +++ b/fvm/executionParameters_test.go @@ -19,6 +19,7 @@ import ( "github.com/onflow/flow-go/fvm/meter" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/runtime/testutil" + "github.com/onflow/flow-go/model/flow" ) func TestGetExecutionMemoryWeights(t *testing.T) { @@ -36,6 +37,7 @@ func TestGetExecutionMemoryWeights(t *testing.T) { ReadStoredFunc: readStored, }, runtime.Config{}, + flow.Emulator, ), ) envMock.On("ReturnCadenceRuntime", mock.Anything).Return() @@ -166,6 +168,7 @@ func TestGetExecutionEffortWeights(t *testing.T) { ReadStoredFunc: readStored, }, runtime.Config{}, + flow.Emulator, ), ) envMock.On("ReturnCadenceRuntime", mock.Anything).Return() diff --git a/fvm/fvm_bench_test.go b/fvm/fvm_bench_test.go index 566cf81653a..4c0d97f23f5 100644 --- a/fvm/fvm_bench_test.go +++ b/fvm/fvm_bench_test.go @@ -165,6 +165,7 @@ func NewBasicBlockExecutor(tb testing.TB, chain flow.Chain, logger zerolog.Logge reusableRuntime.NewReusableCadenceRuntimePool( computation.ReusableCadenceRuntimePoolSize, runtime.Config{}, + chain.ChainID(), ), ), fvm.WithEVMEnabled(true), diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index eedc9e50c8b..651f422e3c5 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -2451,6 +2451,7 @@ func TestCapabilityControllers(t *testing.T) { reusableRuntime.NewReusableCadenceRuntimePool( 1, runtime.Config{}, + flow.Emulator, ), ), ). @@ -2505,6 +2506,7 @@ func TestStorageIterationWithBrokenValues(t *testing.T) { reusableRuntime.NewReusableCadenceRuntimePool( 1, runtime.Config{}, + flow.Emulator, ), ), fvm.WithContractDeploymentRestricted(false), diff --git a/fvm/runtime/reusable_cadence_runtime.go b/fvm/runtime/reusable_cadence_runtime.go index 138156897b1..1f10ee2ac03 100644 --- a/fvm/runtime/reusable_cadence_runtime.go +++ b/fvm/runtime/reusable_cadence_runtime.go @@ -3,12 +3,15 @@ package runtime import ( "github.com/onflow/cadence" "github.com/onflow/cadence/common" + cadenceErrors "github.com/onflow/cadence/errors" "github.com/onflow/cadence/interpreter" "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/sema" "github.com/onflow/cadence/stdlib" "github.com/onflow/flow-go/fvm/errors" + "github.com/onflow/flow-go/fvm/systemcontracts" + "github.com/onflow/flow-go/model/flow" ) // Note: this is a subset of environment.Environment, redeclared to handle @@ -26,6 +29,18 @@ var randomSourceFunctionType = &sema.FunctionType{ ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.ByteArrayType), } +// scheduleAccountV2MigrationType is the type of the `scheduleAccountV2Migration` function. +// This defies the signature as `func (address: Address): Bool` +var scheduleAccountV2MigrationType = &sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Identifier: "address", + TypeAnnotation: sema.AddressTypeAnnotation, + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.BoolType), +} + type ReusableCadenceRuntime struct { runtime.Runtime TxRuntimeEnv runtime.Environment @@ -34,13 +49,25 @@ type ReusableCadenceRuntime struct { fvmEnv Environment } -func NewReusableCadenceRuntime(rt runtime.Runtime, config runtime.Config) *ReusableCadenceRuntime { +func NewReusableCadenceRuntime( + rt runtime.Runtime, + config runtime.Config, + chainID flow.ChainID, +) *ReusableCadenceRuntime { reusable := &ReusableCadenceRuntime{ Runtime: rt, TxRuntimeEnv: runtime.NewBaseInterpreterEnvironment(config), ScriptRuntimeEnv: runtime.NewScriptInterpreterEnvironment(config), } + reusable.declareRandomSourceHistory() + reusable.declareScheduleAccountV2Migration(chainID) + + return reusable +} + +func (reusable *ReusableCadenceRuntime) declareRandomSourceHistory() { + // Declare the `randomSourceHistory` function. This function is **only** used by the // System transaction, to fill the `RandomBeaconHistory` contract via the heartbeat // resource. This allows the `RandomBeaconHistory` contract to be a standard contract, @@ -63,8 +90,9 @@ func NewReusableCadenceRuntime(rt runtime.Runtime, config runtime.Config) *Reusa var err error var source []byte - if reusable.fvmEnv != nil { - source, err = reusable.fvmEnv.RandomSourceHistory() + fvmEnv := reusable.fvmEnv + if fvmEnv != nil { + source, err = fvmEnv.RandomSourceHistory() } else { err = errors.NewOperationNotSupportedError("randomSourceHistory") } @@ -81,8 +109,56 @@ func NewReusableCadenceRuntime(rt runtime.Runtime, config runtime.Config) *Reusa } reusable.TxRuntimeEnv.DeclareValue(blockRandomSource, nil) +} - return reusable +func (reusable *ReusableCadenceRuntime) declareScheduleAccountV2Migration(chainID flow.ChainID) { + + serviceAccount := systemcontracts.SystemContractsForChain(chainID).FlowServiceAccount + + blockRandomSource := stdlib.StandardLibraryValue{ + Name: "scheduleAccountV2Migration", + Type: scheduleAccountV2MigrationType, + Kind: common.DeclarationKindFunction, + Value: interpreter.NewUnmeteredStaticHostFunctionValue( + scheduleAccountV2MigrationType, + func(invocation interpreter.Invocation) interpreter.Value { + if len(invocation.Arguments) != 1 { + panic(errors.NewInvalidArgumentErrorf( + "scheduleAccountV2Migration should be called with exactly one argument of type Address", + )) + } + + addressValue, ok := invocation.Arguments[0].(interpreter.AddressValue) + if !ok { + panic(errors.NewInvalidArgumentErrorf( + "scheduleAccountV2Migration should be called with exactly one argument of type Address", + )) + } + + storage := invocation.Interpreter.Storage() + + runtimeStorage, ok := storage.(*runtime.Storage) + if !ok { + panic(cadenceErrors.NewUnexpectedError("interpreter storage is not a runtime.Storage")) + } + + result := runtimeStorage.ScheduleV2Migration(common.Address(addressValue)) + + return interpreter.AsBoolValue(result) + }, + ), + } + + accountV2MigrationLocation := common.NewAddressLocation( + nil, + common.Address(serviceAccount.Address), + "AccountV2Migration", + ) + + reusable.TxRuntimeEnv.DeclareValue( + blockRandomSource, + accountV2MigrationLocation, + ) } func (reusable *ReusableCadenceRuntime) SetFvmEnvironment(fvmEnv Environment) { @@ -165,6 +241,8 @@ type ReusableCadenceRuntimePool struct { config runtime.Config + chainID flow.ChainID + // When newCustomRuntime is nil, the pool will create standard cadence // interpreter runtimes via runtime.NewInterpreterRuntime. Otherwise, the // pool will create runtimes using this function. @@ -176,6 +254,7 @@ type ReusableCadenceRuntimePool struct { func newReusableCadenceRuntimePool( poolSize int, config runtime.Config, + chainID flow.ChainID, newCustomRuntime CadenceRuntimeConstructor, ) ReusableCadenceRuntimePool { var pool chan *ReusableCadenceRuntime @@ -186,6 +265,7 @@ func newReusableCadenceRuntimePool( return ReusableCadenceRuntimePool{ pool: pool, config: config, + chainID: chainID, newCustomRuntime: newCustomRuntime, } } @@ -193,10 +273,12 @@ func newReusableCadenceRuntimePool( func NewReusableCadenceRuntimePool( poolSize int, config runtime.Config, + chainID flow.ChainID, ) ReusableCadenceRuntimePool { return newReusableCadenceRuntimePool( poolSize, config, + chainID, nil, ) } @@ -204,11 +286,13 @@ func NewReusableCadenceRuntimePool( func NewCustomReusableCadenceRuntimePool( poolSize int, config runtime.Config, + chainID flow.ChainID, newCustomRuntime CadenceRuntimeConstructor, ) ReusableCadenceRuntimePool { return newReusableCadenceRuntimePool( poolSize, config, + chainID, newCustomRuntime, ) } @@ -233,6 +317,7 @@ func (pool ReusableCadenceRuntimePool) Borrow( pool.newRuntime(), }, pool.config, + pool.chainID, ) } diff --git a/fvm/runtime/reusable_cadence_runtime_test.go b/fvm/runtime/reusable_cadence_runtime_test.go index 758fa2f7426..590a31a4034 100644 --- a/fvm/runtime/reusable_cadence_runtime_test.go +++ b/fvm/runtime/reusable_cadence_runtime_test.go @@ -5,10 +5,12 @@ import ( "github.com/onflow/cadence/runtime" "github.com/stretchr/testify/require" + + "github.com/onflow/flow-go/model/flow" ) func TestReusableCadenceRuntimePoolUnbuffered(t *testing.T) { - pool := NewReusableCadenceRuntimePool(0, runtime.Config{}) + pool := NewReusableCadenceRuntimePool(0, runtime.Config{}, flow.Emulator) require.Nil(t, pool.pool) entry := pool.Borrow(nil) @@ -23,7 +25,7 @@ func TestReusableCadenceRuntimePoolUnbuffered(t *testing.T) { } func TestReusableCadenceRuntimePoolBuffered(t *testing.T) { - pool := NewReusableCadenceRuntimePool(100, runtime.Config{}) + pool := NewReusableCadenceRuntimePool(100, runtime.Config{}, flow.Emulator) require.NotNil(t, pool.pool) select { @@ -50,7 +52,7 @@ func TestReusableCadenceRuntimePoolBuffered(t *testing.T) { } func TestReusableCadenceRuntimePoolSharing(t *testing.T) { - pool := NewReusableCadenceRuntimePool(100, runtime.Config{}) + pool := NewReusableCadenceRuntimePool(100, runtime.Config{}, flow.Emulator) require.NotNil(t, pool.pool) select { @@ -59,7 +61,7 @@ func TestReusableCadenceRuntimePoolSharing(t *testing.T) { default: } - var otherPool ReusableCadenceRuntimePool = pool + var otherPool = pool entry := otherPool.Borrow(nil) require.NotNil(t, entry) From 95ca4de555d59f62f3f573ddcb1967c2fbb7ab57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Nov 2024 14:32:26 -0800 Subject: [PATCH 03/21] update dependencies in other modules --- insecure/go.mod | 6 +++--- insecure/go.sum | 3 +++ integration/go.mod | 6 +++--- integration/go.sum | 3 +++ 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/insecure/go.mod b/insecure/go.mod index 2690e0f7796..bbebf5dd361 100644 --- a/insecure/go.mod +++ b/insecure/go.mod @@ -202,8 +202,8 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onflow/atree v0.8.0 // indirect - github.com/onflow/cadence v1.2.2 // indirect + github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf // indirect + github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 // indirect github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 // indirect github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 // indirect github.com/onflow/flow-ft/lib/go/contracts v1.0.1 // indirect @@ -266,7 +266,7 @@ require ( github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect diff --git a/insecure/go.sum b/insecure/go.sum index 8e25d6b07da..720507c1abc 100644 --- a/insecure/go.sum +++ b/insecure/go.sum @@ -856,8 +856,10 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= +github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf/go.mod h1:U8PGG42VrSJqjdfJ9NGQ2fenkyFRYlgtfHsZM61H4zY= github.com/onflow/cadence v1.2.2 h1:LwigF/2lPiXlwX5rFn71KeMpmW5Iu/f/JtsPLLULBCc= github.com/onflow/cadence v1.2.2/go.mod h1:PYX1xLejqswtDsQzN93x/VpfSKNyjUk6hrkc/mpv7xs= +github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5/go.mod h1:XNnLHuRy9Ta9BF3BK/1LEkcId+RdDge36mNRfPiCVzE= github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 h1:R86HaOuk6vpuECZnriEUE7bw9inC2AtdSn8lL/iwQLQ= @@ -1175,6 +1177,7 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/integration/go.mod b/integration/go.mod index eff334d5a9d..f5850d43a09 100644 --- a/integration/go.mod +++ b/integration/go.mod @@ -20,7 +20,7 @@ require ( github.com/ipfs/go-ds-badger2 v0.1.3 github.com/ipfs/go-ds-pebble v0.3.1-0.20240828032824-d745b9d3200b github.com/libp2p/go-libp2p v0.32.2 - github.com/onflow/cadence v1.2.2 + github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 github.com/onflow/crypto v0.25.2 github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 @@ -241,7 +241,7 @@ require ( github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onflow/atree v0.8.0 // indirect + github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf // indirect github.com/onflow/flow-ft/lib/go/contracts v1.0.1 // indirect github.com/onflow/flow-ft/lib/go/templates v1.0.1 // indirect github.com/onflow/flow-nft/lib/go/contracts v1.2.2 // indirect @@ -307,7 +307,7 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/yhassanzadeh13/go-libp2p-pubsub v0.6.11-flow-expose-msg.0.20240220190333-03695dea34a3 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zeebo/blake3 v0.2.3 // indirect + github.com/zeebo/blake3 v0.2.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect diff --git a/integration/go.sum b/integration/go.sum index 851b9d536cc..9129a8222f6 100644 --- a/integration/go.sum +++ b/integration/go.sum @@ -734,8 +734,10 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= +github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf/go.mod h1:U8PGG42VrSJqjdfJ9NGQ2fenkyFRYlgtfHsZM61H4zY= github.com/onflow/cadence v1.2.2 h1:LwigF/2lPiXlwX5rFn71KeMpmW5Iu/f/JtsPLLULBCc= github.com/onflow/cadence v1.2.2/go.mod h1:PYX1xLejqswtDsQzN93x/VpfSKNyjUk6hrkc/mpv7xs= +github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5/go.mod h1:XNnLHuRy9Ta9BF3BK/1LEkcId+RdDge36mNRfPiCVzE= github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 h1:R86HaOuk6vpuECZnriEUE7bw9inC2AtdSn8lL/iwQLQ= @@ -1028,6 +1030,7 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= From 8e6fbbf6deb0460869c3677518bc468d2f975bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Nov 2024 16:04:58 -0800 Subject: [PATCH 04/21] export address generator constructor --- model/flow/address_test.go | 16 ++++++++-------- model/flow/chain.go | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/model/flow/address_test.go b/model/flow/address_test.go index 706ae4f7861..e575ff8ea97 100644 --- a/model/flow/address_test.go +++ b/model/flow/address_test.go @@ -149,7 +149,7 @@ func testAddressConstants(t *testing.T) { assert.Equal(t, address, chain.ServiceAddress()) // check high state values: generation should fail for high value states - state = chain.newAddressGeneratorAtIndex(maxIndex - 1) + state = chain.NewAddressGeneratorAtIndex(maxIndex - 1) _, err = state.NextAddress() assert.NoError(t, err) _, err = state.NextAddress() @@ -200,7 +200,7 @@ func testAddressGeneration(t *testing.T) { // this is only a sanity check of the implementation and not an exhaustive proof if chainID == Mainnet { r := uint64(rand.Intn(maxIndex - loop)) - state = chain.newAddressGeneratorAtIndex(r) + state = chain.NewAddressGeneratorAtIndex(r) for i := 0; i < loop; i++ { address, err := state.NextAddress() require.NoError(t, err) @@ -213,7 +213,7 @@ func testAddressGeneration(t *testing.T) { // All distances between any two addresses must be larger than d. // this is only a sanity check of the implementation and not an exhaustive proof r := uint64(rand.Intn(maxIndex - loop - 1)) - state = chain.newAddressGeneratorAtIndex(r) + state = chain.NewAddressGeneratorAtIndex(r) refAddress, err := state.NextAddress() require.NoError(t, err) for i := 0; i < loop; i++ { @@ -226,7 +226,7 @@ func testAddressGeneration(t *testing.T) { // sanity check of valid account addresses. // All valid addresses must pass IsValid. r = uint64(rand.Intn(maxIndex - loop)) - state = chain.newAddressGeneratorAtIndex(r) + state = chain.NewAddressGeneratorAtIndex(r) for i := 0; i < loop; i++ { address, err := state.NextAddress() require.NoError(t, err) @@ -241,7 +241,7 @@ func testAddressGeneration(t *testing.T) { assert.False(t, check, "account address format should be invalid") r = uint64(rand.Intn(maxIndex - loop)) - state = chain.newAddressGeneratorAtIndex(r) + state = chain.NewAddressGeneratorAtIndex(r) for i := 0; i < loop; i++ { address, err := state.NextAddress() require.NoError(t, err) @@ -271,7 +271,7 @@ func testAddressesIntersection(t *testing.T) { // a valid address in one network must be invalid in all other networks r := uint64(rand.Intn(maxIndex - loop)) - state := chain.newAddressGeneratorAtIndex(r) + state := chain.NewAddressGeneratorAtIndex(r) for k := 0; k < loop; k++ { address, err := state.NextAddress() require.NoError(t, err) @@ -297,7 +297,7 @@ func testAddressesIntersection(t *testing.T) { // build invalid addresses using `invalidCodeWord` and make sure they all // fail the check for all networks r = uint64(rand.Intn(maxIndex - loop)) - state = chain.newAddressGeneratorAtIndex(r) + state = chain.NewAddressGeneratorAtIndex(r) for k := 0; k < loop; k++ { address, err := state.NextAddress() require.NoError(t, err) @@ -328,7 +328,7 @@ func testIndexFromAddress(t *testing.T) { // random valid index r := uint64(rand.Intn(maxIndex)) + 1 // generate the address - address := chain.newAddressGeneratorAtIndex(r).CurrentAddress() + address := chain.NewAddressGeneratorAtIndex(r).CurrentAddress() // extract the index and compare index, err := chain.IndexFromAddress(address) assert.NoError(t, err) // address should be valid diff --git a/model/flow/chain.go b/model/flow/chain.go index 1a17e5a164e..1aeed8313e2 100644 --- a/model/flow/chain.go +++ b/model/flow/chain.go @@ -82,7 +82,7 @@ func (c ChainID) getChainCodeWord() uint64 { } type chainImpl interface { - newAddressGeneratorAtIndex(index uint64) AddressGenerator + NewAddressGeneratorAtIndex(index uint64) AddressGenerator // IsValid returns true if a given address is a valid account address on a given chain, // and false otherwise. // @@ -102,7 +102,7 @@ type chainImpl interface { // where addresses are simply the index of the account. type monotonicImpl struct{} -func (m *monotonicImpl) newAddressGeneratorAtIndex(index uint64) AddressGenerator { +func (m *monotonicImpl) NewAddressGeneratorAtIndex(index uint64) AddressGenerator { return &MonotonicAddressGenerator{ index: index, } @@ -131,7 +131,7 @@ type linearCodeImpl struct { chainID ChainID } -func (l *linearCodeImpl) newAddressGeneratorAtIndex(index uint64) AddressGenerator { +func (l *linearCodeImpl) NewAddressGeneratorAtIndex(index uint64) AddressGenerator { return &linearCodeAddressGenerator{ index: index, chainCodeWord: l.chainID.getChainCodeWord(), @@ -262,6 +262,7 @@ func (c ChainID) String() string { // Chain is the interface for address generation implementations. type Chain interface { NewAddressGenerator() AddressGenerator + NewAddressGeneratorAtIndex(index uint64) AddressGenerator AddressAtIndex(index uint64) (Address, error) ServiceAddress() Address BytesToAddressGenerator(b []byte) AddressGenerator @@ -271,13 +272,12 @@ type Chain interface { ChainID() ChainID // required for tests zeroAddress() Address - newAddressGeneratorAtIndex(index uint64) AddressGenerator } // NewAddressGenerator returns a new AddressGenerator with an // initialized index. func (id *addressedChain) NewAddressGenerator() AddressGenerator { - return id.newAddressGeneratorAtIndex(0) + return id.NewAddressGeneratorAtIndex(0) } // AddressAtIndex returns the index-th generated account address. @@ -285,7 +285,7 @@ func (id *addressedChain) AddressAtIndex(index uint64) (Address, error) { if index > maxIndex { return EmptyAddress, fmt.Errorf("index must be less or equal to %x", maxIndex) } - return id.newAddressGeneratorAtIndex(index).CurrentAddress(), nil + return id.NewAddressGeneratorAtIndex(index).CurrentAddress(), nil } // ServiceAddress returns the root (first) generated account address. @@ -307,7 +307,7 @@ func (id *addressedChain) BytesToAddressGenerator(b []byte) AddressGenerator { bytes := slices.EnsureByteSliceSize(b, addressIndexLength) index := uint48(bytes[:]) - return id.newAddressGeneratorAtIndex(index) + return id.NewAddressGeneratorAtIndex(index) } // ChainID returns the chain ID of the chain. From de4b564ac5ce06f0b161e4c9628e71899c256a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Nov 2024 16:14:58 -0800 Subject: [PATCH 05/21] add AccountV2Migration contract --- fvm/accountV2Migration/AccountV2Migration.cdc | 84 +++++++++++ fvm/accountV2Migration/contract.go | 133 ++++++++++++++++++ fvm/bootstrap.go | 16 +++ fvm/runtime/reusable_cadence_runtime.go | 87 +++--------- fvm/systemcontracts/system_contracts.go | 10 ++ 5 files changed, 259 insertions(+), 71 deletions(-) create mode 100644 fvm/accountV2Migration/AccountV2Migration.cdc create mode 100644 fvm/accountV2Migration/contract.go diff --git a/fvm/accountV2Migration/AccountV2Migration.cdc b/fvm/accountV2Migration/AccountV2Migration.cdc new file mode 100644 index 00000000000..069408c1f59 --- /dev/null +++ b/fvm/accountV2Migration/AccountV2Migration.cdc @@ -0,0 +1,84 @@ +access(all) +contract AccountV2Migration { + + access(all) + event Migrated( + addressStartIndex: UInt64, + count: UInt64 + ) + + access(all) + resource Admin { + access(all) + fun setEnabled(_ isEnabled: Bool) { + AccountV2Migration.isEnabled = isEnabled + } + + access(all) + fun setNextAddressStartIndex(_ nextAddressStartIndex: UInt64) { + AccountV2Migration.nextAddressStartIndex = nextAddressStartIndex + } + + access(all) + fun setBatchSize(_ batchSize: UInt64) { + AccountV2Migration.batchSize = batchSize + } + + access(all) + fun migrateNextBatch() { + AccountV2Migration.migrateNextBatch() + } + } + + access(all) + let adminStoragePath: StoragePath + + access(all) + var isEnabled: Bool + + access(all) + var nextAddressStartIndex: UInt64 + + access(all) + var batchSize: UInt64 + + init() { + self.adminStoragePath = /storage/accountV2MigrationAdmin + self.isEnabled = false + self.nextAddressStartIndex = 1 + self.batchSize = 10 + + self.account.storage.save( + <-create Admin(), + to: self.adminStoragePath + ) + } + + access(contract) + fun migrateNextBatch() { + if !self.isEnabled { + return + } + + let batchSize = self.batchSize + if batchSize <= 0 { + return + } + + let startIndex = self.nextAddressStartIndex + + if !scheduleAccountV2Migration( + addressStartIndex: startIndex, + count: batchSize + ) { + return + } + + self.nextAddressStartIndex = startIndex + batchSize + + emit Migrated( + addressStartIndex: startIndex, + count: batchSize + ) + } +} diff --git a/fvm/accountV2Migration/contract.go b/fvm/accountV2Migration/contract.go new file mode 100644 index 00000000000..49b3286dfad --- /dev/null +++ b/fvm/accountV2Migration/contract.go @@ -0,0 +1,133 @@ +package accountV2Migration + +import ( + _ "embed" + + "github.com/onflow/cadence/common" + cadenceErrors "github.com/onflow/cadence/errors" + "github.com/onflow/cadence/interpreter" + "github.com/onflow/cadence/runtime" + "github.com/onflow/cadence/sema" + "github.com/onflow/cadence/stdlib" + + "github.com/onflow/flow-go/fvm/errors" + "github.com/onflow/flow-go/fvm/systemcontracts" + "github.com/onflow/flow-go/model/flow" +) + +//go:embed AccountV2Migration.cdc +var ContractCode []byte + +const ContractName = "AccountV2Migration" + +const scheduleAccountV2MigrationFunctionName = "scheduleAccountV2Migration" + +// scheduleAccountV2MigrationType is the type of the `scheduleAccountV2Migration` function. +// This defines the signature as `func(addressStartIndex: UInt64, count: UInt64): Bool` +var scheduleAccountV2MigrationType = &sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Identifier: "addressStartIndex", + TypeAnnotation: sema.UInt64TypeAnnotation, + }, + { + Identifier: "count", + TypeAnnotation: sema.UInt64TypeAnnotation, + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.BoolType), +} + +func DeclareScheduleAccountV2MigrationFunction(environment runtime.Environment, chainID flow.ChainID) { + + functionType := scheduleAccountV2MigrationType + + functionValue := stdlib.StandardLibraryValue{ + Name: scheduleAccountV2MigrationFunctionName, + Type: functionType, + Kind: common.DeclarationKindFunction, + Value: interpreter.NewUnmeteredStaticHostFunctionValue( + functionType, + func(invocation interpreter.Invocation) interpreter.Value { + inter := invocation.Interpreter + + // Get interpreter storage + + storage := inter.Storage() + + runtimeStorage, ok := storage.(*runtime.Storage) + if !ok { + panic(cadenceErrors.NewUnexpectedError("interpreter storage is not a runtime.Storage")) + } + + // Check the number of arguments + + actualArgumentCount := len(invocation.Arguments) + expectedArgumentCount := len(functionType.Parameters) + + if actualArgumentCount != expectedArgumentCount { + panic(errors.NewInvalidArgumentErrorf( + "incorrect number of arguments: got %d, expected %d", + actualArgumentCount, + expectedArgumentCount, + )) + } + + // Get addressStartIndex argument + + firstArgument := invocation.Arguments[0] + addressStartIndexValue, ok := firstArgument.(interpreter.UInt64Value) + if !ok { + panic(errors.NewInvalidArgumentErrorf( + "incorrect type for argument 0: got `%s`, expected `%s`", + firstArgument.StaticType(inter), + sema.UInt64Type, + )) + } + addressStartIndex := uint64(addressStartIndexValue) + + // Get count argument + + secondArgument := invocation.Arguments[1] + countValue, ok := secondArgument.(interpreter.UInt64Value) + if !ok { + panic(errors.NewInvalidArgumentErrorf( + "incorrect type for argument 1: got `%s`, expected `%s`", + secondArgument.StaticType(inter), + sema.UInt64Type, + )) + } + count := uint64(countValue) + + // Schedule the account V2 migration for addresses + + addressGenerator := chainID.Chain().NewAddressGeneratorAtIndex(addressStartIndex) + for i := uint64(0); i < count; i++ { + address, err := addressGenerator.NextAddress() + if err != nil { + panic(err) + } + + if !runtimeStorage.ScheduleV2Migration(common.Address(address)) { + return interpreter.FalseValue + } + } + + return interpreter.TrueValue + }, + ), + } + + sc := systemcontracts.SystemContractsForChain(chainID) + + accountV2MigrationLocation := common.NewAddressLocation( + nil, + common.Address(sc.AccountV2Migration.Address), + ContractName, + ) + + environment.DeclareValue( + functionValue, + accountV2MigrationLocation, + ) +} diff --git a/fvm/bootstrap.go b/fvm/bootstrap.go index 0f3526c8d83..10e89692cb8 100644 --- a/fvm/bootstrap.go +++ b/fvm/bootstrap.go @@ -8,6 +8,7 @@ import ( "github.com/onflow/flow-core-contracts/lib/go/contracts" "github.com/onflow/flow-core-contracts/lib/go/templates" + "github.com/onflow/flow-go/fvm/accountV2Migration" "github.com/onflow/flow-go/fvm/blueprints" "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/fvm/errors" @@ -447,6 +448,8 @@ func (b *bootstrapExecutor) Execute() error { // set the list of nodes which are allowed to stake in this network b.setStakingAllowlist(service, b.identities.NodeIDs()) + b.deployAccountV2MigrationContract(service) + return nil } @@ -1067,6 +1070,19 @@ func (b *bootstrapExecutor) deployStakingCollection( panicOnMetaInvokeErrf("failed to deploy FlowStakingCollection contract: %s", txError, err) } +func (b *bootstrapExecutor) deployAccountV2MigrationContract(deployTo flow.Address) { + tx := blueprints.DeployContractTransaction( + deployTo, + accountV2Migration.ContractCode, + accountV2Migration.ContractName, + ) + txError, err := b.invokeMetaTransaction( + b.ctx, + Transaction(tx, 0), + ) + panicOnMetaInvokeErrf("failed to deploy AccountV2Migration contract: %s", txError, err) +} + func (b *bootstrapExecutor) setContractDeploymentRestrictions( service flow.Address, deployment *bool, diff --git a/fvm/runtime/reusable_cadence_runtime.go b/fvm/runtime/reusable_cadence_runtime.go index 1f10ee2ac03..544be1223d2 100644 --- a/fvm/runtime/reusable_cadence_runtime.go +++ b/fvm/runtime/reusable_cadence_runtime.go @@ -3,14 +3,13 @@ package runtime import ( "github.com/onflow/cadence" "github.com/onflow/cadence/common" - cadenceErrors "github.com/onflow/cadence/errors" "github.com/onflow/cadence/interpreter" "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/sema" "github.com/onflow/cadence/stdlib" + "github.com/onflow/flow-go/fvm/accountV2Migration" "github.com/onflow/flow-go/fvm/errors" - "github.com/onflow/flow-go/fvm/systemcontracts" "github.com/onflow/flow-go/model/flow" ) @@ -23,24 +22,11 @@ type Environment interface { } // randomSourceFunctionType is the type of the `randomSource` function. -// This defies the signature as `func (): [UInt8]` +// This defines the signature as `func(): [UInt8]` var randomSourceFunctionType = &sema.FunctionType{ - Parameters: []sema.Parameter{}, ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.ByteArrayType), } -// scheduleAccountV2MigrationType is the type of the `scheduleAccountV2Migration` function. -// This defies the signature as `func (address: Address): Bool` -var scheduleAccountV2MigrationType = &sema.FunctionType{ - Parameters: []sema.Parameter{ - { - Identifier: "address", - TypeAnnotation: sema.AddressTypeAnnotation, - }, - }, - ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.BoolType), -} - type ReusableCadenceRuntime struct { runtime.Runtime TxRuntimeEnv runtime.Environment @@ -61,7 +47,7 @@ func NewReusableCadenceRuntime( } reusable.declareRandomSourceHistory() - reusable.declareScheduleAccountV2Migration(chainID) + accountV2Migration.DeclareScheduleAccountV2MigrationFunction(reusable.TxRuntimeEnv, chainID) return reusable } @@ -76,16 +62,25 @@ func (reusable *ReusableCadenceRuntime) declareRandomSourceHistory() { // it is not part of the cadence standard library, and can just be injected from here. // It also doesnt need user documentation, since it is not (and should not) // be called by the user. If it is called by the user it will panic. + functionType := randomSourceFunctionType + blockRandomSource := stdlib.StandardLibraryValue{ Name: "randomSourceHistory", - Type: randomSourceFunctionType, + Type: functionType, Kind: common.DeclarationKindFunction, Value: interpreter.NewUnmeteredStaticHostFunctionValue( - randomSourceFunctionType, + functionType, func(invocation interpreter.Invocation) interpreter.Value { - if len(invocation.Arguments) != 0 { + + actualArgumentCount := len(invocation.Arguments) + expectedArgumentCount := len(functionType.Parameters) + + if actualArgumentCount != expectedArgumentCount { panic(errors.NewInvalidArgumentErrorf( - "randomSourceHistory should be called without arguments")) + "incorrect number of arguments: got %d, expected %d", + actualArgumentCount, + expectedArgumentCount, + )) } var err error @@ -111,56 +106,6 @@ func (reusable *ReusableCadenceRuntime) declareRandomSourceHistory() { reusable.TxRuntimeEnv.DeclareValue(blockRandomSource, nil) } -func (reusable *ReusableCadenceRuntime) declareScheduleAccountV2Migration(chainID flow.ChainID) { - - serviceAccount := systemcontracts.SystemContractsForChain(chainID).FlowServiceAccount - - blockRandomSource := stdlib.StandardLibraryValue{ - Name: "scheduleAccountV2Migration", - Type: scheduleAccountV2MigrationType, - Kind: common.DeclarationKindFunction, - Value: interpreter.NewUnmeteredStaticHostFunctionValue( - scheduleAccountV2MigrationType, - func(invocation interpreter.Invocation) interpreter.Value { - if len(invocation.Arguments) != 1 { - panic(errors.NewInvalidArgumentErrorf( - "scheduleAccountV2Migration should be called with exactly one argument of type Address", - )) - } - - addressValue, ok := invocation.Arguments[0].(interpreter.AddressValue) - if !ok { - panic(errors.NewInvalidArgumentErrorf( - "scheduleAccountV2Migration should be called with exactly one argument of type Address", - )) - } - - storage := invocation.Interpreter.Storage() - - runtimeStorage, ok := storage.(*runtime.Storage) - if !ok { - panic(cadenceErrors.NewUnexpectedError("interpreter storage is not a runtime.Storage")) - } - - result := runtimeStorage.ScheduleV2Migration(common.Address(addressValue)) - - return interpreter.AsBoolValue(result) - }, - ), - } - - accountV2MigrationLocation := common.NewAddressLocation( - nil, - common.Address(serviceAccount.Address), - "AccountV2Migration", - ) - - reusable.TxRuntimeEnv.DeclareValue( - blockRandomSource, - accountV2MigrationLocation, - ) -} - func (reusable *ReusableCadenceRuntime) SetFvmEnvironment(fvmEnv Environment) { reusable.fvmEnv = fvmEnv } diff --git a/fvm/systemcontracts/system_contracts.go b/fvm/systemcontracts/system_contracts.go index ad9f66c4a65..efb1d250678 100644 --- a/fvm/systemcontracts/system_contracts.go +++ b/fvm/systemcontracts/system_contracts.go @@ -44,6 +44,7 @@ const ( ContractNameEVM = "EVM" ContractNameBurner = "Burner" ContractNameCrypto = "Crypto" + ContractNameAccountV2Migration = "AccountV2Migration" // AccountNameEVMStorage is not a contract, but a special account that is used to store EVM state AccountNameEVMStorage = "EVMStorageAccount" @@ -174,6 +175,9 @@ type SystemContracts struct { // Utility contracts Burner SystemContract Crypto SystemContract + + // Migration contracts + AccountV2Migration SystemContract } // AsTemplateEnv returns a template environment with all system contracts filled in. @@ -233,6 +237,8 @@ func (c SystemContracts) All() []SystemContract { c.Burner, c.Crypto, + + c.AccountV2Migration, } } @@ -371,6 +377,8 @@ func init() { ContractNameBurner: burnerAddressFunc, ContractNameCrypto: serviceAddressFunc, + + ContractNameAccountV2Migration: serviceAddressFunc, } getSystemContractsForChain := func(chainID flow.ChainID) *SystemContracts { @@ -427,6 +435,8 @@ func init() { Burner: addressOfContract(ContractNameBurner), Crypto: addressOfContract(ContractNameCrypto), + + AccountV2Migration: addressOfContract(ContractNameAccountV2Migration), } return contracts From f611094fe464676e6b4c83d05be24c703aa2b4df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Nov 2024 16:51:31 -0800 Subject: [PATCH 06/21] temporarily unrestrict availability scheduleAccountV2Migration function --- fvm/accountV2Migration/contract.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/fvm/accountV2Migration/contract.go b/fvm/accountV2Migration/contract.go index 49b3286dfad..0ea0c851eb1 100644 --- a/fvm/accountV2Migration/contract.go +++ b/fvm/accountV2Migration/contract.go @@ -11,7 +11,6 @@ import ( "github.com/onflow/cadence/stdlib" "github.com/onflow/flow-go/fvm/errors" - "github.com/onflow/flow-go/fvm/systemcontracts" "github.com/onflow/flow-go/model/flow" ) @@ -118,16 +117,18 @@ func DeclareScheduleAccountV2MigrationFunction(environment runtime.Environment, ), } - sc := systemcontracts.SystemContractsForChain(chainID) - - accountV2MigrationLocation := common.NewAddressLocation( - nil, - common.Address(sc.AccountV2Migration.Address), - ContractName, - ) + // TODO: restrict, but requires to be set during bootstrapping + //sc := systemcontracts.SystemContractsForChain(chainID) + // + //accountV2MigrationLocation := common.NewAddressLocation( + // nil, + // common.Address(sc.AccountV2Migration.Address), + // ContractName, + //) environment.DeclareValue( functionValue, - accountV2MigrationLocation, + // TODO: accountV2MigrationLocation, + nil, ) } From c75d4fc964645e7ca9f17f5793c74e92673b41d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Nov 2024 16:51:57 -0800 Subject: [PATCH 07/21] call account migration function from system chunk transaction --- .../scripts/systemChunkTransactionTemplate.cdc | 12 ++++++++---- fvm/blueprints/system.go | 9 ++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc b/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc index 7c9564e1486..5e868aa66b7 100644 --- a/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc +++ b/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc @@ -2,6 +2,7 @@ import FlowEpoch from "FlowEpoch" import NodeVersionBeacon from "NodeVersionBeacon" import RandomBeaconHistory from "RandomBeaconHistory" import EVM from "EVM" +import AccountV2Migration from "AccountV2Migration" transaction { prepare(serviceAccount: auth(BorrowValue) &Account) { @@ -19,9 +20,12 @@ transaction { ?? panic("Couldn't borrow RandomBeaconHistory.Heartbeat Resource") randomBeaconHistoryHeartbeat.heartbeat(randomSourceHistory: randomSourceHistory()) - let evmHeartbeat = serviceAccount.storage.borrow<&EVM.Heartbeat>(from: /storage/EVMHeartbeat) - if evmHeartbeat != nil { // skip if not available - evmHeartbeat!.heartbeat() - } + let evmHeartbeat = serviceAccount.storage + .borrow<&EVM.Heartbeat>(from: /storage/EVMHeartbeat) + evmHeartbeat?.heartbeat() + + let accountV2MigrationAdmin = serviceAccount.storage + .borrow<&AccountV2Migration.Admin>(from: AccountV2Migration.adminStoragePath) + accountV2MigrationAdmin?.migrateNextBatch() } } diff --git a/fvm/blueprints/system.go b/fvm/blueprints/system.go index 466f8ee47f9..46c5ffb61a7 100644 --- a/fvm/blueprints/system.go +++ b/fvm/blueprints/system.go @@ -21,7 +21,9 @@ var systemChunkTransactionTemplate string // TODO: when the EVM contract is moved to the flow-core-contracts, we can // just directly use the replace address functionality of the templates package. -var placeholderEVMAddress = "\"EVM\"" +const placeholderEVMAddress = "\"EVM\"" + +const placeholderAccountV2MigrationAddress = "\"AccountV2Migration\"" func prepareSystemContractCode(chainID flow.ChainID) string { sc := systemcontracts.SystemContractsForChain(chainID) @@ -34,6 +36,11 @@ func prepareSystemContractCode(chainID flow.ChainID) string { placeholderEVMAddress, sc.EVMContract.Address.HexWithPrefix(), ) + code = strings.ReplaceAll( + code, + placeholderAccountV2MigrationAddress, + sc.AccountV2Migration.Address.HexWithPrefix(), + ) return code } From b31696ca52c739717a54939d74bd9fab0da5cfa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 26 Nov 2024 17:10:59 -0800 Subject: [PATCH 08/21] add missing argument for new chain parameter --- engine/execution/computation/computer/computer_test.go | 8 ++++++-- engine/execution/computation/manager_benchmark_test.go | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/engine/execution/computation/computer/computer_test.go b/engine/execution/computation/computer/computer_test.go index 0d7899100ad..620bdf30bc1 100644 --- a/engine/execution/computation/computer/computer_test.go +++ b/engine/execution/computation/computer/computer_test.go @@ -598,7 +598,8 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { // create a block with 2 collections with 2 transactions each block := generateBlock(collectionCount, transactionsPerCollection, rag) - serviceEvents := systemcontracts.ServiceEventsForChain(execCtx.Chain.ChainID()) + chainID := execCtx.Chain.ChainID() + serviceEvents := systemcontracts.ServiceEventsForChain(chainID) randomSource := unittest.EpochSetupRandomSourceFixture() payload, err := ccf.Decode(nil, unittest.EpochSetupFixtureCCF(randomSource)) @@ -700,6 +701,7 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, + chainID, func(_ runtime.Config) runtime.Runtime { return emittingRuntime }, @@ -747,7 +749,7 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { // make sure event index sequence are valid for i := 0; i < result.BlockExecutionResult.Size(); i++ { collectionResult := result.CollectionExecutionResultAt(i) - unittest.EnsureEventsIndexSeq(t, collectionResult.Events(), execCtx.Chain.ChainID()) + unittest.EnsureEventsIndexSeq(t, collectionResult.Events(), chainID) } sEvents := result.AllServiceEvents() // all events should have been collected @@ -815,6 +817,7 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, + execCtx.Chain.ChainID(), func(_ runtime.Config) runtime.Runtime { return rt })), @@ -930,6 +933,7 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, + execCtx.Chain.ChainID(), func(_ runtime.Config) runtime.Runtime { return rt })), diff --git a/engine/execution/computation/manager_benchmark_test.go b/engine/execution/computation/manager_benchmark_test.go index d22b1ec9a8b..338bda23129 100644 --- a/engine/execution/computation/manager_benchmark_test.go +++ b/engine/execution/computation/manager_benchmark_test.go @@ -160,6 +160,7 @@ func benchmarkComputeBlock( reusableRuntime.NewReusableCadenceRuntimePool( ReusableCadenceRuntimePoolSize, runtime.Config{}, + chainID, )), ) snapshotTree := testutil.RootBootstrappedLedger( From 0906f96cb44a7cdacfe7b4d077422b05543ecd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Nov 2024 14:22:52 -0800 Subject: [PATCH 09/21] update to latest commit of feature branch --- go.mod | 6 +++--- go.sum | 20 ++++++-------------- insecure/go.mod | 6 +++--- insecure/go.sum | 19 +++++++------------ integration/go.mod | 6 +++--- integration/go.sum | 18 +++++++----------- 6 files changed, 29 insertions(+), 46 deletions(-) diff --git a/go.mod b/go.mod index 38e4b914020..3be00ad2a69 100644 --- a/go.mod +++ b/go.mod @@ -47,8 +47,8 @@ require ( github.com/multiformats/go-multiaddr v0.12.2 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multihash v0.2.3 - github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf - github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 + github.com/onflow/atree v0.8.1 + github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a github.com/onflow/crypto v0.25.2 github.com/onflow/flow v0.3.4 github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 @@ -68,7 +68,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/vmihailenco/msgpack v4.0.4+incompatible github.com/vmihailenco/msgpack/v4 v4.3.11 go.opentelemetry.io/otel v1.24.0 diff --git a/go.sum b/go.sum index 6c55d45459c..0e794d33c79 100644 --- a/go.sum +++ b/go.sum @@ -711,7 +711,6 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -909,16 +908,12 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= -github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= -github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf h1:MDB/hdwr5GMsZHIIrAw3gBnmWBy5XjsZ4/6kftv9d5c= -github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf/go.mod h1:U8PGG42VrSJqjdfJ9NGQ2fenkyFRYlgtfHsZM61H4zY= +github.com/onflow/atree v0.8.1 h1:DAnPnL9/Ks3LaAnkQVokokTBG/znTW0DJfovDtJDhLI= +github.com/onflow/atree v0.8.1/go.mod h1:FT6udJF9Q7VQTu3wknDhFX+VV4D44ZGdqtTAE5iztck= github.com/onflow/boxo v0.0.0-20240201202436-f2477b92f483 h1:LpiQhTAfM9CAmNVEs0n//cBBgCg+vJSiIxTHYUklZ84= github.com/onflow/boxo v0.0.0-20240201202436-f2477b92f483/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80= -github.com/onflow/cadence v1.2.2 h1:LwigF/2lPiXlwX5rFn71KeMpmW5Iu/f/JtsPLLULBCc= -github.com/onflow/cadence v1.2.2/go.mod h1:PYX1xLejqswtDsQzN93x/VpfSKNyjUk6hrkc/mpv7xs= -github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 h1:G4eOurxUXdAZsjHZPDU/hzr6kQ06gNoQLxGbfnzeVxI= -github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5/go.mod h1:XNnLHuRy9Ta9BF3BK/1LEkcId+RdDge36mNRfPiCVzE= +github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a h1:6Fabl4+VgUu4CT4d2UNAGZ6LU11dczZdCX9WhI0vV/4= +github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a/go.mod h1:9GseQ6usHUS1z+B05g86CH+w406XdMxMIpr+RFrTr/4= github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= github.com/onflow/flow v0.3.4 h1:FXUWVdYB90f/rjNcY0Owo30gL790tiYff9Pb/sycXYE= @@ -1173,8 +1168,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= @@ -1234,11 +1229,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= diff --git a/insecure/go.mod b/insecure/go.mod index bbebf5dd361..9ad0b159793 100644 --- a/insecure/go.mod +++ b/insecure/go.mod @@ -14,7 +14,7 @@ require ( github.com/onflow/flow-go v0.36.2-0.20240717162253-d5d2e606ef53 github.com/rs/zerolog v1.29.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/yhassanzadeh13/go-libp2p-pubsub v0.6.11-flow-expose-msg.0.20240220190333-03695dea34a3 // libp2p v0.32.0 go.uber.org/atomic v1.11.0 google.golang.org/grpc v1.63.2 @@ -202,8 +202,8 @@ require ( github.com/multiformats/go-varint v0.0.7 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf // indirect - github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 // indirect + github.com/onflow/atree v0.8.1 // indirect + github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a // indirect github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 // indirect github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 // indirect github.com/onflow/flow-ft/lib/go/contracts v1.0.1 // indirect diff --git a/insecure/go.sum b/insecure/go.sum index 720507c1abc..f51ddb45d5c 100644 --- a/insecure/go.sum +++ b/insecure/go.sum @@ -660,7 +660,6 @@ github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -854,12 +853,10 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= -github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= -github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf/go.mod h1:U8PGG42VrSJqjdfJ9NGQ2fenkyFRYlgtfHsZM61H4zY= -github.com/onflow/cadence v1.2.2 h1:LwigF/2lPiXlwX5rFn71KeMpmW5Iu/f/JtsPLLULBCc= -github.com/onflow/cadence v1.2.2/go.mod h1:PYX1xLejqswtDsQzN93x/VpfSKNyjUk6hrkc/mpv7xs= -github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5/go.mod h1:XNnLHuRy9Ta9BF3BK/1LEkcId+RdDge36mNRfPiCVzE= +github.com/onflow/atree v0.8.1 h1:DAnPnL9/Ks3LaAnkQVokokTBG/znTW0DJfovDtJDhLI= +github.com/onflow/atree v0.8.1/go.mod h1:FT6udJF9Q7VQTu3wknDhFX+VV4D44ZGdqtTAE5iztck= +github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a h1:6Fabl4+VgUu4CT4d2UNAGZ6LU11dczZdCX9WhI0vV/4= +github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a/go.mod h1:9GseQ6usHUS1z+B05g86CH+w406XdMxMIpr+RFrTr/4= github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 h1:R86HaOuk6vpuECZnriEUE7bw9inC2AtdSn8lL/iwQLQ= @@ -1109,8 +1106,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= @@ -1172,11 +1169,9 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= diff --git a/integration/go.mod b/integration/go.mod index f5850d43a09..e10fb1abc5b 100644 --- a/integration/go.mod +++ b/integration/go.mod @@ -20,7 +20,7 @@ require ( github.com/ipfs/go-ds-badger2 v0.1.3 github.com/ipfs/go-ds-pebble v0.3.1-0.20240828032824-d745b9d3200b github.com/libp2p/go-libp2p v0.32.2 - github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5 + github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a github.com/onflow/crypto v0.25.2 github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 github.com/onflow/flow-core-contracts/lib/go/templates v1.4.0 @@ -34,7 +34,7 @@ require ( github.com/prometheus/common v0.46.0 github.com/psiemens/graceland v1.0.0 github.com/rs/zerolog v1.29.0 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 go.einride.tech/pid v0.1.0 go.uber.org/atomic v1.11.0 go.uber.org/mock v0.4.0 @@ -241,7 +241,7 @@ require ( github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-varint v0.0.7 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf // indirect + github.com/onflow/atree v0.8.1 // indirect github.com/onflow/flow-ft/lib/go/contracts v1.0.1 // indirect github.com/onflow/flow-ft/lib/go/templates v1.0.1 // indirect github.com/onflow/flow-nft/lib/go/contracts v1.2.2 // indirect diff --git a/integration/go.sum b/integration/go.sum index 9129a8222f6..07953dbfb93 100644 --- a/integration/go.sum +++ b/integration/go.sum @@ -560,7 +560,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -732,12 +731,10 @@ github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onflow/atree v0.8.0 h1:qg5c6J1gVDNObughpEeWm8oxqhPGdEyGrda121GM4u0= -github.com/onflow/atree v0.8.0/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo= -github.com/onflow/atree v0.8.1-0.20241028213850-07c884e4abcf/go.mod h1:U8PGG42VrSJqjdfJ9NGQ2fenkyFRYlgtfHsZM61H4zY= -github.com/onflow/cadence v1.2.2 h1:LwigF/2lPiXlwX5rFn71KeMpmW5Iu/f/JtsPLLULBCc= -github.com/onflow/cadence v1.2.2/go.mod h1:PYX1xLejqswtDsQzN93x/VpfSKNyjUk6hrkc/mpv7xs= -github.com/onflow/cadence v1.2.3-0.20241125225033-c8a61764cba5/go.mod h1:XNnLHuRy9Ta9BF3BK/1LEkcId+RdDge36mNRfPiCVzE= +github.com/onflow/atree v0.8.1 h1:DAnPnL9/Ks3LaAnkQVokokTBG/znTW0DJfovDtJDhLI= +github.com/onflow/atree v0.8.1/go.mod h1:FT6udJF9Q7VQTu3wknDhFX+VV4D44ZGdqtTAE5iztck= +github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a h1:6Fabl4+VgUu4CT4d2UNAGZ6LU11dczZdCX9WhI0vV/4= +github.com/onflow/cadence v1.2.3-0.20241127215308-d0026257ee4a/go.mod h1:9GseQ6usHUS1z+B05g86CH+w406XdMxMIpr+RFrTr/4= github.com/onflow/crypto v0.25.2 h1:GjHunqVt+vPcdqhxxhAXiMIF3YiLX7gTuTR5O+VG2ns= github.com/onflow/crypto v0.25.2/go.mod h1:fY7eLqUdMKV8EGOw301unP8h7PvLVy8/6gVR++/g0BY= github.com/onflow/flow-core-contracts/lib/go/contracts v1.4.0 h1:R86HaOuk6vpuECZnriEUE7bw9inC2AtdSn8lL/iwQLQ= @@ -967,8 +964,9 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= @@ -1025,11 +1023,9 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg= -github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ= +github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= From 2a04742bdc2ad2000195475f972298e75d54f9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 27 Nov 2024 14:23:12 -0800 Subject: [PATCH 10/21] add function to return storage format of an account --- fvm/accountV2Migration/AccountV2Migration.cdc | 18 ++++ fvm/accountV2Migration/contract.go | 92 ++++++++++++++++++- fvm/accounts_test.go | 32 +++++++ fvm/runtime/reusable_cadence_runtime.go | 2 +- 4 files changed, 142 insertions(+), 2 deletions(-) diff --git a/fvm/accountV2Migration/AccountV2Migration.cdc b/fvm/accountV2Migration/AccountV2Migration.cdc index 069408c1f59..67c73c8e94d 100644 --- a/fvm/accountV2Migration/AccountV2Migration.cdc +++ b/fvm/accountV2Migration/AccountV2Migration.cdc @@ -1,6 +1,18 @@ access(all) contract AccountV2Migration { + access(all) + enum StorageFormat: UInt8 { + access(all) + case Unknown + + access(all) + case V1 + + access(all) + case V2 + } + access(all) event Migrated( addressStartIndex: UInt64, @@ -81,4 +93,10 @@ contract AccountV2Migration { count: batchSize ) } + + access(all) + fun getAccountStorageFormat(address: Address): StorageFormat? { + let rawStorageFormat = getAccountStorageFormat(address: address) + return StorageFormat(rawValue: rawStorageFormat) + } } diff --git a/fvm/accountV2Migration/contract.go b/fvm/accountV2Migration/contract.go index 0ea0c851eb1..17c807cbaaf 100644 --- a/fvm/accountV2Migration/contract.go +++ b/fvm/accountV2Migration/contract.go @@ -37,7 +37,12 @@ var scheduleAccountV2MigrationType = &sema.FunctionType{ ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.BoolType), } -func DeclareScheduleAccountV2MigrationFunction(environment runtime.Environment, chainID flow.ChainID) { +func DeclareFunctions(environment runtime.Environment, chainID flow.ChainID) { + declareScheduleAccountV2MigrationFunction(environment, chainID) + declareGetAccountStorageFormatFunction(environment) +} + +func declareScheduleAccountV2MigrationFunction(environment runtime.Environment, chainID flow.ChainID) { functionType := scheduleAccountV2MigrationType @@ -132,3 +137,88 @@ func DeclareScheduleAccountV2MigrationFunction(environment runtime.Environment, nil, ) } + +const getAccountStorageFormatFunctionName = "getAccountStorageFormat" + +// getAccountStorageFormatType is the type of the `getAccountStorageFormat` function. +// This defines the signature as `func(address: Address): UInt8` +var getAccountStorageFormatType = &sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Identifier: "address", + TypeAnnotation: sema.AddressTypeAnnotation, + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.UInt8Type), +} + +func declareGetAccountStorageFormatFunction(environment runtime.Environment) { + + functionType := getAccountStorageFormatType + + functionValue := stdlib.StandardLibraryValue{ + Name: getAccountStorageFormatFunctionName, + Type: functionType, + Kind: common.DeclarationKindFunction, + Value: interpreter.NewUnmeteredStaticHostFunctionValue( + functionType, + func(invocation interpreter.Invocation) interpreter.Value { + inter := invocation.Interpreter + + // Get interpreter storage + + storage := inter.Storage() + + runtimeStorage, ok := storage.(*runtime.Storage) + if !ok { + panic(cadenceErrors.NewUnexpectedError("interpreter storage is not a runtime.Storage")) + } + + // Check the number of arguments + + actualArgumentCount := len(invocation.Arguments) + expectedArgumentCount := len(functionType.Parameters) + + if actualArgumentCount != expectedArgumentCount { + panic(errors.NewInvalidArgumentErrorf( + "incorrect number of arguments: got %d, expected %d", + actualArgumentCount, + expectedArgumentCount, + )) + } + + // Get addressStartIndex argument + + firstArgument := invocation.Arguments[0] + addressValue, ok := firstArgument.(interpreter.AddressValue) + if !ok { + panic(errors.NewInvalidArgumentErrorf( + "incorrect type for argument 0: got `%s`, expected `%s`", + firstArgument.StaticType(inter), + sema.TheAddressType, + )) + } + address := common.Address(addressValue) + + // Get and return the storage format for the account + + return interpreter.UInt8Value(runtimeStorage.AccountStorageFormat(address)) + }, + ), + } + + // TODO: restrict, but requires to be set during bootstrapping + //sc := systemcontracts.SystemContractsForChain(chainID) + // + //accountV2MigrationLocation := common.NewAddressLocation( + // nil, + // common.Address(sc.AccountV2Migration.Address), + // ContractName, + //) + + environment.DeclareValue( + functionValue, + // TODO: accountV2MigrationLocation, + nil, + ) +} diff --git a/fvm/accounts_test.go b/fvm/accounts_test.go index 3cbffead859..a43e293cadb 100644 --- a/fvm/accounts_test.go +++ b/fvm/accounts_test.go @@ -1758,3 +1758,35 @@ func TestGetStorageCapacity(t *testing.T) { }), ) } + +func TestAccountV2Migration_getAccountStorageFormat(t *testing.T) { + + t.Run( + "service account", + newVMTest().run(func( + t *testing.T, + vm fvm.VM, + chain flow.Chain, + ctx fvm.Context, + snapshotTree snapshot.SnapshotTree, + ) { + serviceAddress := chain.ServiceAddress() + + script := fvm.Script([]byte(fmt.Sprintf( + ` + import AccountV2Migration from %[1]s + + access(all) fun main() { + let storageFormat = AccountV2Migration.getAccountStorageFormat(address: %[1]s) + assert(storageFormat == AccountV2Migration.StorageFormat.V1) + } + `, + serviceAddress.HexWithPrefix(), + ))) + + _, output, err := vm.Run(ctx, script, snapshotTree) + require.NoError(t, err) + require.NoError(t, output.Err) + }), + ) +} diff --git a/fvm/runtime/reusable_cadence_runtime.go b/fvm/runtime/reusable_cadence_runtime.go index 544be1223d2..e3aa21955b3 100644 --- a/fvm/runtime/reusable_cadence_runtime.go +++ b/fvm/runtime/reusable_cadence_runtime.go @@ -47,7 +47,7 @@ func NewReusableCadenceRuntime( } reusable.declareRandomSourceHistory() - accountV2Migration.DeclareScheduleAccountV2MigrationFunction(reusable.TxRuntimeEnv, chainID) + accountV2Migration.DeclareFunctions(reusable.TxRuntimeEnv, chainID) return reusable } From 579414020c91c80b1e4b90f51afdf625d72f22d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 3 Dec 2024 12:01:21 -0800 Subject: [PATCH 11/21] fix setup for AccountV2Migration contract --- .../computation/computer/computer_test.go | 3 -- engine/execution/computation/manager.go | 1 - .../computation/manager_benchmark_test.go | 1 - fvm/accountV2Migration/contract.go | 41 +++++++++---------- fvm/environment/env.go | 2 +- fvm/environment/runtime.go | 4 +- fvm/executionParameters_test.go | 3 -- fvm/fvm_bench_test.go | 1 - fvm/fvm_test.go | 2 - fvm/runtime/reusable_cadence_runtime.go | 13 ------ fvm/script.go | 11 ++++- fvm/transactionInvoker.go | 26 +++++++++--- 12 files changed, 50 insertions(+), 58 deletions(-) diff --git a/engine/execution/computation/computer/computer_test.go b/engine/execution/computation/computer/computer_test.go index 620bdf30bc1..c58fa21feaf 100644 --- a/engine/execution/computation/computer/computer_test.go +++ b/engine/execution/computation/computer/computer_test.go @@ -701,7 +701,6 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, - chainID, func(_ runtime.Config) runtime.Runtime { return emittingRuntime }, @@ -817,7 +816,6 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, - execCtx.Chain.ChainID(), func(_ runtime.Config) runtime.Runtime { return rt })), @@ -933,7 +931,6 @@ func TestBlockExecutor_ExecuteBlock(t *testing.T) { reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, - execCtx.Chain.ChainID(), func(_ runtime.Config) runtime.Runtime { return rt })), diff --git a/engine/execution/computation/manager.go b/engine/execution/computation/manager.go index b3f76a433cf..e13a2d03791 100644 --- a/engine/execution/computation/manager.go +++ b/engine/execution/computation/manager.go @@ -233,7 +233,6 @@ func DefaultFVMOptions(chainID flow.ChainID, cadenceTracing bool, extensiveTraci runtime.Config{ TracingEnabled: cadenceTracing, }, - chainID, )), fvm.WithEVMEnabled(true), } diff --git a/engine/execution/computation/manager_benchmark_test.go b/engine/execution/computation/manager_benchmark_test.go index 338bda23129..d22b1ec9a8b 100644 --- a/engine/execution/computation/manager_benchmark_test.go +++ b/engine/execution/computation/manager_benchmark_test.go @@ -160,7 +160,6 @@ func benchmarkComputeBlock( reusableRuntime.NewReusableCadenceRuntimePool( ReusableCadenceRuntimePoolSize, runtime.Config{}, - chainID, )), ) snapshotTree := testutil.RootBootstrappedLedger( diff --git a/fvm/accountV2Migration/contract.go b/fvm/accountV2Migration/contract.go index 17c807cbaaf..2bf1352cdb0 100644 --- a/fvm/accountV2Migration/contract.go +++ b/fvm/accountV2Migration/contract.go @@ -11,6 +11,7 @@ import ( "github.com/onflow/cadence/stdlib" "github.com/onflow/flow-go/fvm/errors" + "github.com/onflow/flow-go/fvm/systemcontracts" "github.com/onflow/flow-go/model/flow" ) @@ -39,7 +40,7 @@ var scheduleAccountV2MigrationType = &sema.FunctionType{ func DeclareFunctions(environment runtime.Environment, chainID flow.ChainID) { declareScheduleAccountV2MigrationFunction(environment, chainID) - declareGetAccountStorageFormatFunction(environment) + declareGetAccountStorageFormatFunction(environment, chainID) } func declareScheduleAccountV2MigrationFunction(environment runtime.Environment, chainID flow.ChainID) { @@ -122,19 +123,17 @@ func declareScheduleAccountV2MigrationFunction(environment runtime.Environment, ), } - // TODO: restrict, but requires to be set during bootstrapping - //sc := systemcontracts.SystemContractsForChain(chainID) - // - //accountV2MigrationLocation := common.NewAddressLocation( - // nil, - // common.Address(sc.AccountV2Migration.Address), - // ContractName, - //) + sc := systemcontracts.SystemContractsForChain(chainID) + + accountV2MigrationLocation := common.NewAddressLocation( + nil, + common.Address(sc.AccountV2Migration.Address), + ContractName, + ) environment.DeclareValue( functionValue, - // TODO: accountV2MigrationLocation, - nil, + accountV2MigrationLocation, ) } @@ -152,7 +151,7 @@ var getAccountStorageFormatType = &sema.FunctionType{ ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.UInt8Type), } -func declareGetAccountStorageFormatFunction(environment runtime.Environment) { +func declareGetAccountStorageFormatFunction(environment runtime.Environment, chainID flow.ChainID) { functionType := getAccountStorageFormatType @@ -207,18 +206,16 @@ func declareGetAccountStorageFormatFunction(environment runtime.Environment) { ), } - // TODO: restrict, but requires to be set during bootstrapping - //sc := systemcontracts.SystemContractsForChain(chainID) - // - //accountV2MigrationLocation := common.NewAddressLocation( - // nil, - // common.Address(sc.AccountV2Migration.Address), - // ContractName, - //) + sc := systemcontracts.SystemContractsForChain(chainID) + + accountV2MigrationLocation := common.NewAddressLocation( + nil, + common.Address(sc.AccountV2Migration.Address), + ContractName, + ) environment.DeclareValue( functionValue, - // TODO: accountV2MigrationLocation, - nil, + accountV2MigrationLocation, ) } diff --git a/fvm/environment/env.go b/fvm/environment/env.go index 31538eee086..fb3dd6a28bb 100644 --- a/fvm/environment/env.go +++ b/fvm/environment/env.go @@ -117,7 +117,7 @@ func DefaultEnvironmentParams() EnvironmentParams { return EnvironmentParams{ Chain: chainID.Chain(), ServiceAccountEnabled: true, - RuntimeParams: DefaultRuntimeParams(chainID), + RuntimeParams: DefaultRuntimeParams(), ProgramLoggerParams: DefaultProgramLoggerParams(), EventEmitterParams: DefaultEventEmitterParams(), BlockInfoParams: DefaultBlockInfoParams(), diff --git a/fvm/environment/runtime.go b/fvm/environment/runtime.go index a542989212f..ace1bfce698 100644 --- a/fvm/environment/runtime.go +++ b/fvm/environment/runtime.go @@ -4,19 +4,17 @@ import ( cadenceRuntime "github.com/onflow/cadence/runtime" "github.com/onflow/flow-go/fvm/runtime" - "github.com/onflow/flow-go/model/flow" ) type RuntimeParams struct { runtime.ReusableCadenceRuntimePool } -func DefaultRuntimeParams(chainID flow.ChainID) RuntimeParams { +func DefaultRuntimeParams() RuntimeParams { return RuntimeParams{ ReusableCadenceRuntimePool: runtime.NewReusableCadenceRuntimePool( 0, cadenceRuntime.Config{}, - chainID, ), } } diff --git a/fvm/executionParameters_test.go b/fvm/executionParameters_test.go index cc81703a1f1..da40c12c281 100644 --- a/fvm/executionParameters_test.go +++ b/fvm/executionParameters_test.go @@ -19,7 +19,6 @@ import ( "github.com/onflow/flow-go/fvm/meter" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/runtime/testutil" - "github.com/onflow/flow-go/model/flow" ) func TestGetExecutionMemoryWeights(t *testing.T) { @@ -37,7 +36,6 @@ func TestGetExecutionMemoryWeights(t *testing.T) { ReadStoredFunc: readStored, }, runtime.Config{}, - flow.Emulator, ), ) envMock.On("ReturnCadenceRuntime", mock.Anything).Return() @@ -168,7 +166,6 @@ func TestGetExecutionEffortWeights(t *testing.T) { ReadStoredFunc: readStored, }, runtime.Config{}, - flow.Emulator, ), ) envMock.On("ReturnCadenceRuntime", mock.Anything).Return() diff --git a/fvm/fvm_bench_test.go b/fvm/fvm_bench_test.go index 4c0d97f23f5..566cf81653a 100644 --- a/fvm/fvm_bench_test.go +++ b/fvm/fvm_bench_test.go @@ -165,7 +165,6 @@ func NewBasicBlockExecutor(tb testing.TB, chain flow.Chain, logger zerolog.Logge reusableRuntime.NewReusableCadenceRuntimePool( computation.ReusableCadenceRuntimePoolSize, runtime.Config{}, - chain.ChainID(), ), ), fvm.WithEVMEnabled(true), diff --git a/fvm/fvm_test.go b/fvm/fvm_test.go index 651f422e3c5..eedc9e50c8b 100644 --- a/fvm/fvm_test.go +++ b/fvm/fvm_test.go @@ -2451,7 +2451,6 @@ func TestCapabilityControllers(t *testing.T) { reusableRuntime.NewReusableCadenceRuntimePool( 1, runtime.Config{}, - flow.Emulator, ), ), ). @@ -2506,7 +2505,6 @@ func TestStorageIterationWithBrokenValues(t *testing.T) { reusableRuntime.NewReusableCadenceRuntimePool( 1, runtime.Config{}, - flow.Emulator, ), ), fvm.WithContractDeploymentRestricted(false), diff --git a/fvm/runtime/reusable_cadence_runtime.go b/fvm/runtime/reusable_cadence_runtime.go index e3aa21955b3..2a00b133256 100644 --- a/fvm/runtime/reusable_cadence_runtime.go +++ b/fvm/runtime/reusable_cadence_runtime.go @@ -8,9 +8,7 @@ import ( "github.com/onflow/cadence/sema" "github.com/onflow/cadence/stdlib" - "github.com/onflow/flow-go/fvm/accountV2Migration" "github.com/onflow/flow-go/fvm/errors" - "github.com/onflow/flow-go/model/flow" ) // Note: this is a subset of environment.Environment, redeclared to handle @@ -38,7 +36,6 @@ type ReusableCadenceRuntime struct { func NewReusableCadenceRuntime( rt runtime.Runtime, config runtime.Config, - chainID flow.ChainID, ) *ReusableCadenceRuntime { reusable := &ReusableCadenceRuntime{ Runtime: rt, @@ -47,7 +44,6 @@ func NewReusableCadenceRuntime( } reusable.declareRandomSourceHistory() - accountV2Migration.DeclareFunctions(reusable.TxRuntimeEnv, chainID) return reusable } @@ -186,8 +182,6 @@ type ReusableCadenceRuntimePool struct { config runtime.Config - chainID flow.ChainID - // When newCustomRuntime is nil, the pool will create standard cadence // interpreter runtimes via runtime.NewInterpreterRuntime. Otherwise, the // pool will create runtimes using this function. @@ -199,7 +193,6 @@ type ReusableCadenceRuntimePool struct { func newReusableCadenceRuntimePool( poolSize int, config runtime.Config, - chainID flow.ChainID, newCustomRuntime CadenceRuntimeConstructor, ) ReusableCadenceRuntimePool { var pool chan *ReusableCadenceRuntime @@ -210,7 +203,6 @@ func newReusableCadenceRuntimePool( return ReusableCadenceRuntimePool{ pool: pool, config: config, - chainID: chainID, newCustomRuntime: newCustomRuntime, } } @@ -218,12 +210,10 @@ func newReusableCadenceRuntimePool( func NewReusableCadenceRuntimePool( poolSize int, config runtime.Config, - chainID flow.ChainID, ) ReusableCadenceRuntimePool { return newReusableCadenceRuntimePool( poolSize, config, - chainID, nil, ) } @@ -231,13 +221,11 @@ func NewReusableCadenceRuntimePool( func NewCustomReusableCadenceRuntimePool( poolSize int, config runtime.Config, - chainID flow.ChainID, newCustomRuntime CadenceRuntimeConstructor, ) ReusableCadenceRuntimePool { return newReusableCadenceRuntimePool( poolSize, config, - chainID, newCustomRuntime, ) } @@ -262,7 +250,6 @@ func (pool ReusableCadenceRuntimePool) Borrow( pool.newRuntime(), }, pool.config, - pool.chainID, ) } diff --git a/fvm/script.go b/fvm/script.go index 4d8a86323b8..0ab196d432e 100644 --- a/fvm/script.go +++ b/fvm/script.go @@ -8,6 +8,7 @@ import ( "github.com/onflow/cadence/common" "github.com/onflow/cadence/runtime" + "github.com/onflow/flow-go/fvm/accountV2Migration" "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm" @@ -201,10 +202,11 @@ func (executor *scriptExecutor) executeScript() error { rt := executor.env.BorrowCadenceRuntime() defer executor.env.ReturnCadenceRuntime(rt) + chainID := executor.ctx.Chain.ChainID() + if executor.ctx.EVMEnabled { - chain := executor.ctx.Chain err := evm.SetupEnvironment( - chain.ChainID(), + chainID, executor.env, rt.ScriptRuntimeEnv, debug.NopTracer, // we shouldn't trace during script execution @@ -214,6 +216,11 @@ func (executor *scriptExecutor) executeScript() error { } } + accountV2Migration.DeclareFunctions( + rt.ScriptRuntimeEnv, + chainID, + ) + value, err := rt.ExecuteScript( runtime.Script{ Source: executor.proc.Script, diff --git a/fvm/transactionInvoker.go b/fvm/transactionInvoker.go index 6edf2ec5405..26b002fce2a 100644 --- a/fvm/transactionInvoker.go +++ b/fvm/transactionInvoker.go @@ -10,6 +10,7 @@ import ( "go.opentelemetry.io/otel/attribute" otelTrace "go.opentelemetry.io/otel/trace" + "github.com/onflow/flow-go/fvm/accountV2Migration" "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm" @@ -189,11 +190,12 @@ func (executor *transactionExecutor) preprocess() error { // infrequently modified and are expensive to compute. For now this includes // reading meter parameter overrides and parsing programs. func (executor *transactionExecutor) preprocessTransactionBody() error { - // setup evm + chainID := executor.ctx.Chain.ChainID() + + // setup EVM if executor.ctx.EVMEnabled { - chain := executor.ctx.Chain err := evm.SetupEnvironment( - chain.ChainID(), + chainID, executor.env, executor.cadenceRuntime.TxRuntimeEnv, executor.ctx.EVMTracer, @@ -202,6 +204,12 @@ func (executor *transactionExecutor) preprocessTransactionBody() error { return err } } + + accountV2Migration.DeclareFunctions( + executor.cadenceRuntime.TxRuntimeEnv, + chainID, + ) + // get meter parameters executionParameters, executionStateRead, err := getExecutionParameters( executor.env.Logger(), @@ -257,11 +265,12 @@ func (executor *transactionExecutor) execute() error { } func (executor *transactionExecutor) ExecuteTransactionBody() error { - // setup evm + chainID := executor.ctx.Chain.ChainID() + + // setup EVM if executor.ctx.EVMEnabled { - chain := executor.ctx.Chain err := evm.SetupEnvironment( - chain.ChainID(), + chainID, executor.env, executor.cadenceRuntime.TxRuntimeEnv, executor.ctx.EVMTracer, @@ -271,6 +280,11 @@ func (executor *transactionExecutor) ExecuteTransactionBody() error { } } + accountV2Migration.DeclareFunctions( + executor.cadenceRuntime.TxRuntimeEnv, + chainID, + ) + var invalidator derived.TransactionInvalidator if !executor.errs.CollectedError() { From b1c86c516b42440fbe3b26fc0fbab9b6e44e9121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 3 Dec 2024 12:01:53 -0800 Subject: [PATCH 12/21] adjust expected state commitments and system chunk transaction hashes --- engine/execution/state/bootstrap/bootstrap_test.go | 2 +- fvm/blueprints/system_test.go | 8 ++++---- utils/unittest/execution_state.go | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engine/execution/state/bootstrap/bootstrap_test.go b/engine/execution/state/bootstrap/bootstrap_test.go index 5a9d394a5ac..5ee4bc54a61 100644 --- a/engine/execution/state/bootstrap/bootstrap_test.go +++ b/engine/execution/state/bootstrap/bootstrap_test.go @@ -53,7 +53,7 @@ func TestBootstrapLedger(t *testing.T) { } func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) { - expectedStateCommitmentBytes, _ := hex.DecodeString("6e70a1ff40e4312a547d588a4355a538610bc22844a1faa907b4ec333ff1eca9") + expectedStateCommitmentBytes, _ := hex.DecodeString("947bc69537b9e5b5256b36c4e68097417348903727fde7a30dba34b3e1b5c42f") expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes) require.NoError(t, err) diff --git a/fvm/blueprints/system_test.go b/fvm/blueprints/system_test.go index a63ce1c28c9..ef36826f232 100644 --- a/fvm/blueprints/system_test.go +++ b/fvm/blueprints/system_test.go @@ -18,10 +18,10 @@ func TestSystemChunkTransactionHash(t *testing.T) { // this is formatted in a way that the resulting error message is easy to copy-paste into the test. expectedHashes := []chainHash{ - {chainId: "flow-mainnet", expectedHash: "0e56f890392ad3f2a0dcc7a0e859b6d41f3c17556aa85a0f8831ae25a6537e39"}, - {chainId: "flow-testnet", expectedHash: "69c922177af520e8ecaf0ba97cb174a3ebbd03de6d5b5d1f6b6c043a9638dba3"}, - {chainId: "flow-previewnet", expectedHash: "2ec3b6b7e7d70a651600eb80f775cb57613a0a168c847b70040c469f09066a55"}, - {chainId: "flow-emulator", expectedHash: "7dcc0daaecebc7be33b068ed5c8da0620c89fd896abfc498fc0cc32a261aab1f"}, + {chainId: "flow-mainnet", expectedHash: "a1f19de15909715a088bfdf7dd86beea6f31d1c200ce40fb8eaf73e34eafc440"}, + {chainId: "flow-testnet", expectedHash: "a43e32867ddda18f3f4012e450adbc52d4b761e029c3e6ff9f45de2553c54499"}, + {chainId: "flow-previewnet", expectedHash: "46c0987d1e99aa18005a28cf01b97b2816fb0d10f3a2a42dc324bc1dcc5c7450"}, + {chainId: "flow-emulator", expectedHash: "15de5e19fdf2c4b8182d49681a5f4a08e8724c04f822f730ee8b06f242e9f914"}, } var actualHashes []chainHash diff --git a/utils/unittest/execution_state.go b/utils/unittest/execution_state.go index a5e911b3771..6af9904b3dd 100644 --- a/utils/unittest/execution_state.go +++ b/utils/unittest/execution_state.go @@ -23,7 +23,7 @@ const ServiceAccountPrivateKeySignAlgo = crypto.ECDSAP256 const ServiceAccountPrivateKeyHashAlgo = hash.SHA2_256 // Pre-calculated state commitment with root account with the above private key -const GenesisStateCommitmentHex = "c42fc978c2702793d2640e3ed8644ba54db4e92aa5d0501234dfbb9bbc5784fd" +const GenesisStateCommitmentHex = "cc19c6f693542f77bfffb179ee7e15ab62a99c842fabc3e146c2b04c235f3460" var GenesisStateCommitment flow.StateCommitment @@ -87,10 +87,10 @@ func genesisCommitHexByChainID(chainID flow.ChainID) string { return GenesisStateCommitmentHex } if chainID == flow.Testnet { - return "e29456decb9ee90ad3ed1e1239383c18897b031ea851ff07f5f616657df4d4a0" + return "c0404acd8d02516d35cf37e49183e57985d7eee9510fc53fd3e0066138702740" } if chainID == flow.Sandboxnet { return "e1c08b17f9e5896f03fe28dd37ca396c19b26628161506924fbf785834646ea1" } - return "e1989abf50fba23015251a313eefe2ceff45639a75252f4da5970dcda32dd95e" + return "eb6a97d98d9260f04df1257b510c3ee41af3e04bd96dc54727de85cc5112bdaf" } From 06420d12a8d7d9d0a3cf6fdc0142b7d4d79b4532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 3 Dec 2024 12:02:56 -0800 Subject: [PATCH 13/21] remove chain ID arguments --- fvm/environment/system_contracts_test.go | 1 - fvm/runtime/reusable_cadence_runtime_test.go | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fvm/environment/system_contracts_test.go b/fvm/environment/system_contracts_test.go index 77e8ea4a6a0..9ec300f86cd 100644 --- a/fvm/environment/system_contracts_test.go +++ b/fvm/environment/system_contracts_test.go @@ -60,7 +60,6 @@ func TestSystemContractsInvoke(t *testing.T) { runtimePool := reusableRuntime.NewCustomReusableCadenceRuntimePool( 0, runtime.Config{}, - chainID, func(_ runtime.Config) runtime.Runtime { return &testutil.TestInterpreterRuntime{ InvokeContractFunc: tc.contractFunction, diff --git a/fvm/runtime/reusable_cadence_runtime_test.go b/fvm/runtime/reusable_cadence_runtime_test.go index 590a31a4034..cf6a2a44867 100644 --- a/fvm/runtime/reusable_cadence_runtime_test.go +++ b/fvm/runtime/reusable_cadence_runtime_test.go @@ -5,12 +5,10 @@ import ( "github.com/onflow/cadence/runtime" "github.com/stretchr/testify/require" - - "github.com/onflow/flow-go/model/flow" ) func TestReusableCadenceRuntimePoolUnbuffered(t *testing.T) { - pool := NewReusableCadenceRuntimePool(0, runtime.Config{}, flow.Emulator) + pool := NewReusableCadenceRuntimePool(0, runtime.Config{}) require.Nil(t, pool.pool) entry := pool.Borrow(nil) @@ -25,7 +23,7 @@ func TestReusableCadenceRuntimePoolUnbuffered(t *testing.T) { } func TestReusableCadenceRuntimePoolBuffered(t *testing.T) { - pool := NewReusableCadenceRuntimePool(100, runtime.Config{}, flow.Emulator) + pool := NewReusableCadenceRuntimePool(100, runtime.Config{}) require.NotNil(t, pool.pool) select { @@ -52,7 +50,7 @@ func TestReusableCadenceRuntimePoolBuffered(t *testing.T) { } func TestReusableCadenceRuntimePoolSharing(t *testing.T) { - pool := NewReusableCadenceRuntimePool(100, runtime.Config{}, flow.Emulator) + pool := NewReusableCadenceRuntimePool(100, runtime.Config{}) require.NotNil(t, pool.pool) select { From 0a393efd916ef03d767996025d7fbfa689e7a49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 3 Dec 2024 14:51:56 -0800 Subject: [PATCH 14/21] add new weight for string template expressions --- fvm/meter/memory_meter.go | 45 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/fvm/meter/memory_meter.go b/fvm/meter/memory_meter.go index c9f2ca35d4a..a02561507d3 100644 --- a/fvm/meter/memory_meter.go +++ b/fvm/meter/memory_meter.go @@ -184,28 +184,29 @@ var ( common.MemoryKindWhileStatement: 25, common.MemoryKindRemoveStatement: 33, - common.MemoryKindBooleanExpression: 9, - common.MemoryKindNilExpression: 1, - common.MemoryKindStringExpression: 17, - common.MemoryKindIntegerExpression: 33, - common.MemoryKindFixedPointExpression: 49, - common.MemoryKindArrayExpression: 25, - common.MemoryKindDictionaryExpression: 25, - common.MemoryKindIdentifierExpression: 1, - common.MemoryKindInvocationExpression: 49, - common.MemoryKindMemberExpression: 25, - common.MemoryKindIndexExpression: 33, - common.MemoryKindConditionalExpression: 49, - common.MemoryKindUnaryExpression: 25, - common.MemoryKindBinaryExpression: 41, - common.MemoryKindFunctionExpression: 25, - common.MemoryKindCastingExpression: 41, - common.MemoryKindCreateExpression: 9, - common.MemoryKindDestroyExpression: 17, - common.MemoryKindReferenceExpression: 33, - common.MemoryKindForceExpression: 17, - common.MemoryKindPathExpression: 1, - common.MemoryKindAttachExpression: 33, + common.MemoryKindBooleanExpression: 9, + common.MemoryKindNilExpression: 1, + common.MemoryKindStringExpression: 17, + common.MemoryKindStringTemplateExpression: 49, + common.MemoryKindIntegerExpression: 33, + common.MemoryKindFixedPointExpression: 49, + common.MemoryKindArrayExpression: 25, + common.MemoryKindDictionaryExpression: 25, + common.MemoryKindIdentifierExpression: 1, + common.MemoryKindInvocationExpression: 49, + common.MemoryKindMemberExpression: 25, + common.MemoryKindIndexExpression: 33, + common.MemoryKindConditionalExpression: 49, + common.MemoryKindUnaryExpression: 25, + common.MemoryKindBinaryExpression: 41, + common.MemoryKindFunctionExpression: 25, + common.MemoryKindCastingExpression: 41, + common.MemoryKindCreateExpression: 9, + common.MemoryKindDestroyExpression: 17, + common.MemoryKindReferenceExpression: 33, + common.MemoryKindForceExpression: 17, + common.MemoryKindPathExpression: 1, + common.MemoryKindAttachExpression: 33, common.MemoryKindConstantSizedType: 25, common.MemoryKindDictionaryType: 33, From a1ca332fdf5fb9df62ecb3934d1bb9b10f10dc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 5 Dec 2024 12:23:34 -0800 Subject: [PATCH 15/21] fix address generation --- fvm/accountV2Migration/contract.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fvm/accountV2Migration/contract.go b/fvm/accountV2Migration/contract.go index 2bf1352cdb0..0d62dceb7d5 100644 --- a/fvm/accountV2Migration/contract.go +++ b/fvm/accountV2Migration/contract.go @@ -108,14 +108,15 @@ func declareScheduleAccountV2MigrationFunction(environment runtime.Environment, addressGenerator := chainID.Chain().NewAddressGeneratorAtIndex(addressStartIndex) for i := uint64(0); i < count; i++ { - address, err := addressGenerator.NextAddress() - if err != nil { - panic(err) - } - + address := addressGenerator.CurrentAddress() if !runtimeStorage.ScheduleV2Migration(common.Address(address)) { return interpreter.FalseValue } + + _, err := addressGenerator.NextAddress() + if err != nil { + panic(err) + } } return interpreter.TrueValue From 8b597cbd1036bcef59f92fb51d8eb3d086cc6e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 5 Dec 2024 12:24:05 -0800 Subject: [PATCH 16/21] test account v2 format migration of service account --- fvm/accountV2Migration/contract.go | 2 + fvm/accounts_test.go | 123 +++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/fvm/accountV2Migration/contract.go b/fvm/accountV2Migration/contract.go index 0d62dceb7d5..dd1f8ee8a8f 100644 --- a/fvm/accountV2Migration/contract.go +++ b/fvm/accountV2Migration/contract.go @@ -220,3 +220,5 @@ func declareGetAccountStorageFormatFunction(environment runtime.Environment, cha accountV2MigrationLocation, ) } + +const MigratedEventTypeQualifiedIdentifier = ContractName + ".Migrated" diff --git a/fvm/accounts_test.go b/fvm/accounts_test.go index a43e293cadb..9a9bf7e6660 100644 --- a/fvm/accounts_test.go +++ b/fvm/accounts_test.go @@ -6,15 +6,19 @@ import ( "testing" "github.com/onflow/cadence" + "github.com/onflow/cadence/common" "github.com/onflow/cadence/encoding/ccf" jsoncdc "github.com/onflow/cadence/encoding/json" "github.com/onflow/cadence/format" + "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/stdlib" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/onflow/flow-go/engine/execution/testutil" "github.com/onflow/flow-go/fvm" + "github.com/onflow/flow-go/fvm/accountV2Migration" + reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/storage/snapshot" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" @@ -1772,6 +1776,43 @@ func TestAccountV2Migration_getAccountStorageFormat(t *testing.T) { ) { serviceAddress := chain.ServiceAddress() + script := fvm.Script([]byte(fmt.Sprintf( + ` + import AccountV2Migration from %[1]s + + access(all) fun main() { + let storageFormat = AccountV2Migration.getAccountStorageFormat(address: %[1]s) + assert(storageFormat == AccountV2Migration.StorageFormat.V1) + } + `, + serviceAddress.HexWithPrefix(), + ))) + + _, output, err := vm.Run(ctx, script, snapshotTree) + require.NoError(t, err) + require.NoError(t, output.Err) + }), + ) +} + +func TestAccountV2Migration_migrate(t *testing.T) { + + t.Run( + "service account", + newVMTest().withContextOptions( + fvm.WithAuthorizationChecksEnabled(false), + fvm.WithSequenceNumberCheckAndIncrementEnabled(false), + ).run(func( + t *testing.T, + vm fvm.VM, + chain flow.Chain, + ctx fvm.Context, + snapshotTree snapshot.SnapshotTree, + ) { + serviceAddress := chain.ServiceAddress() + + // Ensure the account is in V1 format after bootstrapping + script := fvm.Script([]byte(fmt.Sprintf( ` import AccountV2Migration from %[1]s @@ -1787,6 +1828,88 @@ func TestAccountV2Migration_getAccountStorageFormat(t *testing.T) { _, output, err := vm.Run(ctx, script, snapshotTree) require.NoError(t, err) require.NoError(t, output.Err) + + // Enable the storage format V2 feature for all subsequent transactions and scripts + + ctx = fvm.NewContextFromParent( + ctx, + fvm.WithReusableCadenceRuntimePool( + reusableRuntime.NewReusableCadenceRuntimePool( + 1, + runtime.Config{ + StorageFormatV2Enabled: true, + }, + ), + ), + ) + + // Enable the account V2 migration and migrate the first batch + + serviceAddressIndex, err := chain.IndexFromAddress(serviceAddress) + require.NoError(t, err) + + batchSize := serviceAddressIndex + 1 + + tx := fvm.Transaction( + flow.NewTransactionBody(). + SetScript([]byte(fmt.Sprintf( + ` + import AccountV2Migration from %[1]s + + transaction { + prepare(signer: auth(Storage) &Account) { + let admin = signer.storage + .borrow<&AccountV2Migration.Admin>( + from: AccountV2Migration.adminStoragePath + ) + ?? panic("missing account V2 migration admin resource") + admin.setEnabled(true) + admin.setBatchSize(%[2]d) + admin.migrateNextBatch() + } + } + `, + serviceAddress.HexWithPrefix(), + batchSize, + ))). + AddAuthorizer(chain.ServiceAddress()), + 0, + ) + executionSnapshot, output, err := vm.Run(ctx, tx, snapshotTree) + require.NoError(t, err) + require.NoError(t, output.Err) + + require.Len(t, output.Events, 1) + + event := output.Events[0] + + accountV2MigrationLocation := common.AddressLocation{ + Address: common.Address(serviceAddress), + Name: accountV2Migration.ContractName, + } + expectedEventTypeID := accountV2MigrationLocation. + TypeID(nil, accountV2Migration.MigratedEventTypeQualifiedIdentifier) + assert.Equal(t, flow.EventType(expectedEventTypeID), event.Type) + + snapshotTree = snapshotTree.Append(executionSnapshot) + + // Ensure the account is in V2 format after the migration + + script = fvm.Script([]byte(fmt.Sprintf( + ` + import AccountV2Migration from %[1]s + + access(all) fun main() { + let storageFormat = AccountV2Migration.getAccountStorageFormat(address: %[1]s) + assert(storageFormat == AccountV2Migration.StorageFormat.V2) + } + `, + serviceAddress.HexWithPrefix(), + ))) + + _, output, err = vm.Run(ctx, script, snapshotTree) + require.NoError(t, err) + require.NoError(t, output.Err) }), ) } From f86dd292a2b788d198b31c73c7784ed9ca74ae56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 6 Dec 2024 14:15:29 -0800 Subject: [PATCH 17/21] remove enabled flag, use batch size --- fvm/accountV2Migration/AccountV2Migration.cdc | 15 +-------------- fvm/accounts_test.go | 1 - 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/fvm/accountV2Migration/AccountV2Migration.cdc b/fvm/accountV2Migration/AccountV2Migration.cdc index 67c73c8e94d..f5bc9aa7b46 100644 --- a/fvm/accountV2Migration/AccountV2Migration.cdc +++ b/fvm/accountV2Migration/AccountV2Migration.cdc @@ -21,11 +21,6 @@ contract AccountV2Migration { access(all) resource Admin { - access(all) - fun setEnabled(_ isEnabled: Bool) { - AccountV2Migration.isEnabled = isEnabled - } - access(all) fun setNextAddressStartIndex(_ nextAddressStartIndex: UInt64) { AccountV2Migration.nextAddressStartIndex = nextAddressStartIndex @@ -45,9 +40,6 @@ contract AccountV2Migration { access(all) let adminStoragePath: StoragePath - access(all) - var isEnabled: Bool - access(all) var nextAddressStartIndex: UInt64 @@ -56,9 +48,8 @@ contract AccountV2Migration { init() { self.adminStoragePath = /storage/accountV2MigrationAdmin - self.isEnabled = false self.nextAddressStartIndex = 1 - self.batchSize = 10 + self.batchSize = 0 self.account.storage.save( <-create Admin(), @@ -68,10 +59,6 @@ contract AccountV2Migration { access(contract) fun migrateNextBatch() { - if !self.isEnabled { - return - } - let batchSize = self.batchSize if batchSize <= 0 { return diff --git a/fvm/accounts_test.go b/fvm/accounts_test.go index 9a9bf7e6660..42e36f04fbe 100644 --- a/fvm/accounts_test.go +++ b/fvm/accounts_test.go @@ -1863,7 +1863,6 @@ func TestAccountV2Migration_migrate(t *testing.T) { from: AccountV2Migration.adminStoragePath ) ?? panic("missing account V2 migration admin resource") - admin.setEnabled(true) admin.setBatchSize(%[2]d) admin.migrateNextBatch() } From 814c47aa25628fe40876dfc8dd876dc61461402e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 6 Dec 2024 14:15:41 -0800 Subject: [PATCH 18/21] verify migration event --- fvm/accounts_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fvm/accounts_test.go b/fvm/accounts_test.go index 42e36f04fbe..f8c87552b1b 100644 --- a/fvm/accounts_test.go +++ b/fvm/accounts_test.go @@ -1890,6 +1890,15 @@ func TestAccountV2Migration_migrate(t *testing.T) { TypeID(nil, accountV2Migration.MigratedEventTypeQualifiedIdentifier) assert.Equal(t, flow.EventType(expectedEventTypeID), event.Type) + decodedEventPayload, err := ccf.Decode(nil, event.Payload) + require.NoError(t, err) + + require.IsType(t, cadence.Event{}, decodedEventPayload) + + eventFields := decodedEventPayload.(cadence.Composite).FieldsMappedByName() + assert.Equal(t, cadence.UInt64(1), eventFields["addressStartIndex"]) + assert.Equal(t, cadence.UInt64(batchSize), eventFields["count"]) + snapshotTree = snapshotTree.Append(executionSnapshot) // Ensure the account is in V2 format after the migration From e910cd0ff64809c8f9ca6ee07eb49f016bf6b3a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 6 Dec 2024 14:16:16 -0800 Subject: [PATCH 19/21] add integration test for account storage format v2 migration using internal emulator --- integration/internal/emulator/blockchain.go | 18 +- integration/internal/emulator/config.go | 45 +++-- .../systemChunkTransactionTemplate.cdc | 5 + integration/migration/accountV2_test.go | 183 ++++++++++++++++++ 4 files changed, 231 insertions(+), 20 deletions(-) create mode 100644 integration/migration/accountV2_test.go diff --git a/integration/internal/emulator/blockchain.go b/integration/internal/emulator/blockchain.go index b16a042f868..fcf38781931 100644 --- a/integration/internal/emulator/blockchain.go +++ b/integration/internal/emulator/blockchain.go @@ -51,6 +51,7 @@ import ( "github.com/onflow/flow-go/fvm/environment" fvmerrors "github.com/onflow/flow-go/fvm/errors" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" + "github.com/onflow/flow-go/fvm/systemcontracts" flowgo "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/module/metrics" ) @@ -129,7 +130,9 @@ func (b *Blockchain) ReloadBlockchain() (*Blockchain, error) { fvm.WithReusableCadenceRuntimePool( reusableRuntime.NewReusableCadenceRuntimePool( 0, - runtime.Config{}), + runtime.Config{ + StorageFormatV2Enabled: b.conf.AccountStorageFormatV2Enabled, + }), ), fvm.WithEntropyProvider(b.entropyProvider), fvm.WithEVMEnabled(true), @@ -1002,13 +1005,24 @@ func (b *Blockchain) systemChunkTransaction() (*flowgo.TransactionBody, error) { }, ) + sc := systemcontracts.SystemContractsForChain(b.conf.ChainID) + // TODO: move this to `templates.Environment` struct script = strings.ReplaceAll( script, `import EVM from "EVM"`, fmt.Sprintf( "import EVM from %s", - serviceAddress.HexWithPrefix(), + sc.EVMContract.Address.HexWithPrefix(), + ), + ) + + script = strings.ReplaceAll( + script, + `import AccountV2Migration from "AccountV2Migration"`, + fmt.Sprintf( + `import AccountV2Migration from %s`, + sc.AccountV2Migration.Address.HexWithPrefix(), ), ) diff --git a/integration/internal/emulator/config.go b/integration/internal/emulator/config.go index d87be0a162c..c5be8bc587b 100644 --- a/integration/internal/emulator/config.go +++ b/integration/internal/emulator/config.go @@ -16,24 +16,25 @@ import ( // config is a set of configuration options for an emulated emulator. type config struct { - ServiceKey *ServiceKey - Store EmulatorStorage - SimpleAddresses bool - GenesisTokenSupply cadence.UFix64 - TransactionMaxGasLimit uint64 - ScriptGasLimit uint64 - TransactionExpiry uint - StorageLimitEnabled bool - TransactionFeesEnabled bool - ExecutionEffortWeights meter.ExecutionEffortWeights - ContractRemovalEnabled bool - MinimumStorageReservation cadence.UFix64 - StorageMBPerFLOW cadence.UFix64 - Logger zerolog.Logger - ServerLogger zerolog.Logger - TransactionValidationEnabled bool - ChainID flowgo.ChainID - AutoMine bool + ServiceKey *ServiceKey + Store EmulatorStorage + SimpleAddresses bool + GenesisTokenSupply cadence.UFix64 + TransactionMaxGasLimit uint64 + ScriptGasLimit uint64 + TransactionExpiry uint + StorageLimitEnabled bool + TransactionFeesEnabled bool + ExecutionEffortWeights meter.ExecutionEffortWeights + ContractRemovalEnabled bool + MinimumStorageReservation cadence.UFix64 + StorageMBPerFLOW cadence.UFix64 + Logger zerolog.Logger + ServerLogger zerolog.Logger + TransactionValidationEnabled bool + ChainID flowgo.ChainID + AutoMine bool + AccountStorageFormatV2Enabled bool } const defaultGenesisTokenSupply = "1000000000.0" @@ -272,3 +273,11 @@ func WithChainID(chainID flowgo.ChainID) Option { c.ChainID = chainID } } + +// WithAccountStorageFormatV2Enabled enabled/disables the account storage format V2. +// The default is false. +func WithAccountStorageFormatV2Enabled(enabled bool) Option { + return func(c *config) { + c.AccountStorageFormatV2Enabled = enabled + } +} diff --git a/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc b/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc index ef714ed20ba..3ca8c98555e 100644 --- a/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc +++ b/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc @@ -1,5 +1,6 @@ import RandomBeaconHistory from "RandomBeaconHistory" import EVM from "EVM" +import AccountV2Migration from "AccountV2Migration" transaction { prepare(serviceAccount: auth(BorrowValue) &Account) { @@ -12,5 +13,9 @@ transaction { .borrow<&EVM.Heartbeat>(from: /storage/EVMHeartbeat) ?? panic("Couldn't borrow EVM.Heartbeat Resource") evmHeartbeat.heartbeat() + + let accountV2MigrationAdmin = serviceAccount.storage + .borrow<&AccountV2Migration.Admin>(from: AccountV2Migration.adminStoragePath) + accountV2MigrationAdmin?.migrateNextBatch() } } diff --git a/integration/migration/accountV2_test.go b/integration/migration/accountV2_test.go new file mode 100644 index 00000000000..61835c8a79c --- /dev/null +++ b/integration/migration/accountV2_test.go @@ -0,0 +1,183 @@ +package migration + +import ( + "fmt" + "testing" + + "github.com/onflow/cadence" + "github.com/onflow/cadence/common" + "github.com/onflow/cadence/encoding/ccf" + sdkcrypto "github.com/onflow/flow-go-sdk/crypto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/onflow/flow-go/fvm/accountV2Migration" + "github.com/onflow/flow-go/integration/internal/emulator" + "github.com/onflow/flow-go/model/flow" +) + +func TestAccountV2Migration(t *testing.T) { + t.Parallel() + + chain := flow.Emulator.Chain() + serviceAddress := chain.ServiceAddress() + serviceAddressIndex, err := chain.IndexFromAddress(serviceAddress) + require.NoError(t, err) + + accountV2MigrationContractLocation := common.AddressLocation{ + Address: common.Address(serviceAddress), + Name: accountV2Migration.ContractName, + } + migratedEventTypeID := accountV2MigrationContractLocation. + TypeID(nil, accountV2Migration.MigratedEventTypeQualifiedIdentifier) + + storage := emulator.NewMemoryStore() + + newOptions := func(accountStorageFormatV2Enabled bool) []emulator.Option { + return []emulator.Option{ + emulator.WithStorageLimitEnabled(false), + emulator.WithStore(storage), + emulator.WithAccountStorageFormatV2Enabled(accountStorageFormatV2Enabled), + } + } + + // Ensure that the account V2 migration is disabled, + // and the service account is in V1 format after bootstrapping + + blockchain, err := emulator.New(newOptions(false)...) + require.NoError(t, err) + + block, _, err := blockchain.ExecuteAndCommitBlock() + require.NoError(t, err) + + blockEvents, err := blockchain.GetEventsForBlockIDs( + string(migratedEventTypeID), + []flow.Identifier{block.ID()}, + ) + require.NoError(t, err) + require.Len(t, blockEvents, 1) + assert.Empty(t, blockEvents[0].Events) + + checkServiceAccountStorageFormat(t, blockchain, "V1") + + // Enable the storage format V2 migration via system account transaction + + blockchain, err = emulator.New(newOptions(true)...) + require.NoError(t, err) + + batchSize := serviceAddressIndex + 1 + + setAccountV2MigrationBatchSize(t, blockchain, batchSize) + + block, results, err := blockchain.ExecuteAndCommitBlock() + require.NoError(t, err) + + require.Len(t, results, 1) + assert.NoError(t, results[0].Error) + + blockEvents, err = blockchain.GetEventsForBlockIDs( + string(migratedEventTypeID), + []flow.Identifier{block.ID()}, + ) + require.NoError(t, err) + require.Len(t, blockEvents, 1) + assert.Len(t, blockEvents[0].Events, 1) + + event := blockEvents[0].Events[0] + assert.Equal(t, + flow.EventType(migratedEventTypeID), + event.Type, + ) + + decodedEventPayload, err := ccf.Decode(nil, event.Payload) + require.NoError(t, err) + + require.IsType(t, cadence.Event{}, decodedEventPayload) + + eventFields := decodedEventPayload.(cadence.Composite).FieldsMappedByName() + assert.Equal(t, cadence.UInt64(1), eventFields["addressStartIndex"]) + assert.Equal(t, cadence.UInt64(batchSize), eventFields["count"]) + + // Ensure the service account is in V2 format after the migration + + checkServiceAccountStorageFormat(t, blockchain, "V2") +} + +func sendTransaction(t *testing.T, blockchain *emulator.Blockchain, script string) { + serviceAddress := blockchain.ServiceKey().Address + + tx := flow.NewTransactionBody(). + SetScript([]byte(script)). + SetComputeLimit(9999). + SetProposalKey(serviceAddress, 0, blockchain.ServiceKey().SequenceNumber). + AddAuthorizer(serviceAddress). + SetPayer(serviceAddress) + + serviceKey := blockchain.ServiceKey() + signer, err := sdkcrypto.NewInMemorySigner( + serviceKey.PrivateKey, + serviceKey.HashAlgo, + ) + require.NoError(t, err) + + err = tx.SignEnvelope(serviceAddress, 0, signer.PrivateKey, signer.Hasher) + assert.NoError(t, err) + + err = blockchain.SendTransaction(tx) + require.NoError(t, err) +} + +func setAccountV2MigrationBatchSize(t *testing.T, blockchain *emulator.Blockchain, batchSize uint64) { + serviceAddress := blockchain.ServiceKey().Address + + script := fmt.Sprintf( + ` + import AccountV2Migration from %[1]s + + transaction { + prepare(signer: auth(Storage) &Account) { + log("Enabling account V2 migration") + let admin = signer.storage + .borrow<&AccountV2Migration.Admin>( + from: AccountV2Migration.adminStoragePath + ) + ?? panic("missing account V2 migration admin resource") + admin.setBatchSize(%[2]d) + } + } + `, + serviceAddress.HexWithPrefix(), + batchSize, + ) + sendTransaction(t, blockchain, script) +} + +func executeScript(t *testing.T, blockchain *emulator.Blockchain, script string) { + result, err := blockchain.ExecuteScript([]byte(script), nil) + require.NoError(t, err) + require.NoError(t, result.Error) +} + +func checkServiceAccountStorageFormat( + t *testing.T, + blockchain *emulator.Blockchain, + storageFormatCaseName string, +) { + serviceAddress := blockchain.ServiceKey().Address + + executeScript(t, + blockchain, + fmt.Sprintf( + ` + import AccountV2Migration from %[1]s + + access(all) fun main() { + let storageFormat = AccountV2Migration.getAccountStorageFormat(address: %[1]s) + assert(storageFormat == AccountV2Migration.StorageFormat.%[2]s) + } + `, + serviceAddress.HexWithPrefix(), + storageFormatCaseName, + ), + ) +} From a57912f300104bd333695da943d0878f6c6e859d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 12 Dec 2024 15:19:23 -0800 Subject: [PATCH 20/21] add a new Migration system account contract, call it in system chunk tx --- fvm/accountV2Migration/AccountV2Migration.cdc | 2 +- .../systemChunkTransactionTemplate.cdc | 8 ++--- fvm/blueprints/system.go | 6 ++-- fvm/bootstrap.go | 15 +++++++++ fvm/migration/Migration.cdc | 32 +++++++++++++++++++ fvm/migration/migration.go | 24 ++++++++++++++ fvm/systemcontracts/system_contracts.go | 5 +++ integration/internal/emulator/blockchain.go | 6 ++-- .../systemChunkTransactionTemplate.cdc | 8 ++--- 9 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 fvm/migration/Migration.cdc create mode 100644 fvm/migration/migration.go diff --git a/fvm/accountV2Migration/AccountV2Migration.cdc b/fvm/accountV2Migration/AccountV2Migration.cdc index f5bc9aa7b46..798e8e44690 100644 --- a/fvm/accountV2Migration/AccountV2Migration.cdc +++ b/fvm/accountV2Migration/AccountV2Migration.cdc @@ -57,7 +57,7 @@ contract AccountV2Migration { ) } - access(contract) + access(account) fun migrateNextBatch() { let batchSize = self.batchSize if batchSize <= 0 { diff --git a/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc b/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc index 5e868aa66b7..a2e5b4e2f05 100644 --- a/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc +++ b/fvm/blueprints/scripts/systemChunkTransactionTemplate.cdc @@ -2,7 +2,7 @@ import FlowEpoch from "FlowEpoch" import NodeVersionBeacon from "NodeVersionBeacon" import RandomBeaconHistory from "RandomBeaconHistory" import EVM from "EVM" -import AccountV2Migration from "AccountV2Migration" +import Migration from "Migration" transaction { prepare(serviceAccount: auth(BorrowValue) &Account) { @@ -24,8 +24,8 @@ transaction { .borrow<&EVM.Heartbeat>(from: /storage/EVMHeartbeat) evmHeartbeat?.heartbeat() - let accountV2MigrationAdmin = serviceAccount.storage - .borrow<&AccountV2Migration.Admin>(from: AccountV2Migration.adminStoragePath) - accountV2MigrationAdmin?.migrateNextBatch() + let migrationAdmin = serviceAccount.storage + .borrow<&Migration.Admin>(from: Migration.adminStoragePath) + migrationAdmin?.migrate() } } diff --git a/fvm/blueprints/system.go b/fvm/blueprints/system.go index 46c5ffb61a7..f2631b6bbb2 100644 --- a/fvm/blueprints/system.go +++ b/fvm/blueprints/system.go @@ -23,7 +23,7 @@ var systemChunkTransactionTemplate string const placeholderEVMAddress = "\"EVM\"" -const placeholderAccountV2MigrationAddress = "\"AccountV2Migration\"" +const placeholderMigrationAddress = "\"Migration\"" func prepareSystemContractCode(chainID flow.ChainID) string { sc := systemcontracts.SystemContractsForChain(chainID) @@ -38,8 +38,8 @@ func prepareSystemContractCode(chainID flow.ChainID) string { ) code = strings.ReplaceAll( code, - placeholderAccountV2MigrationAddress, - sc.AccountV2Migration.Address.HexWithPrefix(), + placeholderMigrationAddress, + sc.Migration.Address.HexWithPrefix(), ) return code } diff --git a/fvm/bootstrap.go b/fvm/bootstrap.go index 10e89692cb8..a194a7818fa 100644 --- a/fvm/bootstrap.go +++ b/fvm/bootstrap.go @@ -14,6 +14,7 @@ import ( "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm/stdlib" "github.com/onflow/flow-go/fvm/meter" + "github.com/onflow/flow-go/fvm/migration" "github.com/onflow/flow-go/fvm/storage" "github.com/onflow/flow-go/fvm/storage/logical" "github.com/onflow/flow-go/fvm/systemcontracts" @@ -449,6 +450,7 @@ func (b *bootstrapExecutor) Execute() error { b.setStakingAllowlist(service, b.identities.NodeIDs()) b.deployAccountV2MigrationContract(service) + b.deployMigrationContract(service) return nil } @@ -1083,6 +1085,19 @@ func (b *bootstrapExecutor) deployAccountV2MigrationContract(deployTo flow.Addre panicOnMetaInvokeErrf("failed to deploy AccountV2Migration contract: %s", txError, err) } +func (b *bootstrapExecutor) deployMigrationContract(deployTo flow.Address) { + tx := blueprints.DeployContractTransaction( + deployTo, + migration.ContractCode(deployTo), + migration.ContractName, + ) + txError, err := b.invokeMetaTransaction( + b.ctx, + Transaction(tx, 0), + ) + panicOnMetaInvokeErrf("failed to deploy Migration contract: %s", txError, err) +} + func (b *bootstrapExecutor) setContractDeploymentRestrictions( service flow.Address, deployment *bool, diff --git a/fvm/migration/Migration.cdc b/fvm/migration/Migration.cdc new file mode 100644 index 00000000000..28879db3643 --- /dev/null +++ b/fvm/migration/Migration.cdc @@ -0,0 +1,32 @@ + +import "AccountV2Migration" + +access(all) +contract Migration { + + access(all) + resource Admin { + + access(all) + fun migrate() { + Migration.migrate() + } + } + + access(all) + let adminStoragePath: StoragePath + + init() { + self.adminStoragePath = /storage/migrationAdmin + + self.account.storage.save( + <-create Admin(), + to: self.adminStoragePath + ) + } + + access(contract) + fun migrate() { + AccountV2Migration.migrateNextBatch() + } +} diff --git a/fvm/migration/migration.go b/fvm/migration/migration.go new file mode 100644 index 00000000000..f7a9a17ee18 --- /dev/null +++ b/fvm/migration/migration.go @@ -0,0 +1,24 @@ +package migration + +import ( + _ "embed" + "fmt" + "regexp" + + "github.com/onflow/flow-go/model/flow" +) + +//go:embed Migration.cdc +var contractCode string + +const ContractName = "Migration" + +var accountV2MigrationImportPattern = regexp.MustCompile(`(?m)^import "AccountV2Migration"`) + +func ContractCode(accountV2MigrationAddress flow.Address) []byte { + evmContract := accountV2MigrationImportPattern.ReplaceAllString( + contractCode, + fmt.Sprintf("import AccountV2Migration from %s", accountV2MigrationAddress.HexWithPrefix()), + ) + return []byte(evmContract) +} diff --git a/fvm/systemcontracts/system_contracts.go b/fvm/systemcontracts/system_contracts.go index efb1d250678..3b63a86490d 100644 --- a/fvm/systemcontracts/system_contracts.go +++ b/fvm/systemcontracts/system_contracts.go @@ -44,6 +44,7 @@ const ( ContractNameEVM = "EVM" ContractNameBurner = "Burner" ContractNameCrypto = "Crypto" + ContractNameMigration = "Migration" ContractNameAccountV2Migration = "AccountV2Migration" // AccountNameEVMStorage is not a contract, but a special account that is used to store EVM state @@ -177,6 +178,7 @@ type SystemContracts struct { Crypto SystemContract // Migration contracts + Migration SystemContract AccountV2Migration SystemContract } @@ -238,6 +240,7 @@ func (c SystemContracts) All() []SystemContract { c.Burner, c.Crypto, + c.Migration, c.AccountV2Migration, } } @@ -378,6 +381,7 @@ func init() { ContractNameBurner: burnerAddressFunc, ContractNameCrypto: serviceAddressFunc, + ContractNameMigration: serviceAddressFunc, ContractNameAccountV2Migration: serviceAddressFunc, } @@ -436,6 +440,7 @@ func init() { Burner: addressOfContract(ContractNameBurner), Crypto: addressOfContract(ContractNameCrypto), + Migration: addressOfContract(ContractNameMigration), AccountV2Migration: addressOfContract(ContractNameAccountV2Migration), } diff --git a/integration/internal/emulator/blockchain.go b/integration/internal/emulator/blockchain.go index fcf38781931..949795ed877 100644 --- a/integration/internal/emulator/blockchain.go +++ b/integration/internal/emulator/blockchain.go @@ -1019,10 +1019,10 @@ func (b *Blockchain) systemChunkTransaction() (*flowgo.TransactionBody, error) { script = strings.ReplaceAll( script, - `import AccountV2Migration from "AccountV2Migration"`, + `import Migration from "Migration"`, fmt.Sprintf( - `import AccountV2Migration from %s`, - sc.AccountV2Migration.Address.HexWithPrefix(), + `import Migration from %s`, + sc.Migration.Address.HexWithPrefix(), ), ) diff --git a/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc b/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc index 3ca8c98555e..1c7f657406a 100644 --- a/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc +++ b/integration/internal/emulator/templates/systemChunkTransactionTemplate.cdc @@ -1,6 +1,6 @@ import RandomBeaconHistory from "RandomBeaconHistory" import EVM from "EVM" -import AccountV2Migration from "AccountV2Migration" +import Migration from "Migration" transaction { prepare(serviceAccount: auth(BorrowValue) &Account) { @@ -14,8 +14,8 @@ transaction { ?? panic("Couldn't borrow EVM.Heartbeat Resource") evmHeartbeat.heartbeat() - let accountV2MigrationAdmin = serviceAccount.storage - .borrow<&AccountV2Migration.Admin>(from: AccountV2Migration.adminStoragePath) - accountV2MigrationAdmin?.migrateNextBatch() + let migrationAdmin = serviceAccount.storage + .borrow<&Migration.Admin>(from: Migration.adminStoragePath) + migrationAdmin?.migrate() } } From d24f07e71f3f279823ce1cb28eda265e7a2e575d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 12 Dec 2024 15:27:06 -0800 Subject: [PATCH 21/21] adjust expected hashes --- engine/execution/state/bootstrap/bootstrap_test.go | 2 +- utils/unittest/execution_state.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/execution/state/bootstrap/bootstrap_test.go b/engine/execution/state/bootstrap/bootstrap_test.go index 5ee4bc54a61..8de70bd000e 100644 --- a/engine/execution/state/bootstrap/bootstrap_test.go +++ b/engine/execution/state/bootstrap/bootstrap_test.go @@ -53,7 +53,7 @@ func TestBootstrapLedger(t *testing.T) { } func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) { - expectedStateCommitmentBytes, _ := hex.DecodeString("947bc69537b9e5b5256b36c4e68097417348903727fde7a30dba34b3e1b5c42f") + expectedStateCommitmentBytes, _ := hex.DecodeString("0696f3e4336f3e4dbc1d4599e48b13ec27643111ef971a1ca630d89a0f051593") expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes) require.NoError(t, err) diff --git a/utils/unittest/execution_state.go b/utils/unittest/execution_state.go index 6af9904b3dd..e61c327c678 100644 --- a/utils/unittest/execution_state.go +++ b/utils/unittest/execution_state.go @@ -23,7 +23,7 @@ const ServiceAccountPrivateKeySignAlgo = crypto.ECDSAP256 const ServiceAccountPrivateKeyHashAlgo = hash.SHA2_256 // Pre-calculated state commitment with root account with the above private key -const GenesisStateCommitmentHex = "cc19c6f693542f77bfffb179ee7e15ab62a99c842fabc3e146c2b04c235f3460" +const GenesisStateCommitmentHex = "0fde9fb033b250966cae6d5c241a3036e1926daf026fc361d0e3f3e6c1fcecf5" var GenesisStateCommitment flow.StateCommitment @@ -87,10 +87,10 @@ func genesisCommitHexByChainID(chainID flow.ChainID) string { return GenesisStateCommitmentHex } if chainID == flow.Testnet { - return "c0404acd8d02516d35cf37e49183e57985d7eee9510fc53fd3e0066138702740" + return "1ac42950289199a8272c3975e9dccc3cc94db8ea42491192660cb89f4555aacd" } if chainID == flow.Sandboxnet { return "e1c08b17f9e5896f03fe28dd37ca396c19b26628161506924fbf785834646ea1" } - return "eb6a97d98d9260f04df1257b510c3ee41af3e04bd96dc54727de85cc5112bdaf" + return "5adde6c29a016ef167fbc0a5d18b533f5ae8e54a59da9466cfa61aa6b2e47daa" }