Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cadence 1.0 Migration] Fix migration of storage path capabilities #6306

Merged
merged 5 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 157 additions & 9 deletions cmd/util/ledger/migrations/cadence.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package migrations

import (
"context"
_ "embed"
"fmt"

"github.com/onflow/cadence/migrations/capcons"
"github.com/onflow/cadence/migrations/statictypes"
"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/interpreter"
"github.com/rs/zerolog"

"github.com/onflow/flow-go/cmd/util/ledger/reporters"
"github.com/onflow/flow-go/cmd/util/ledger/util"
"github.com/onflow/flow-go/cmd/util/ledger/util/registers"
"github.com/onflow/flow-go/fvm/environment"
"github.com/onflow/flow-go/fvm/systemcontracts"
"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/model/flow"
)

Expand Down Expand Up @@ -214,6 +220,129 @@ type NamedMigration struct {
Migrate RegistersMigration
}

type IssueStorageCapConMigration struct {
name string
chainID flow.ChainID
accountsCapabilities *capcons.AccountsCapabilities
interpreterMigrationRuntimeConfig InterpreterMigrationRuntimeConfig
programs map[runtime.Location]*interpreter.Program
mapping *capcons.CapabilityMapping
reporter reporters.ReportWriter
}

const issueStorageCapConMigrationReporterName = "cadence-storage-capcon-issue-migration"

func NewIssueStorageCapConMigration(
rwf reporters.ReportWriterFactory,
chainID flow.ChainID,
storageDomainCapabilities *capcons.AccountsCapabilities,
programs map[runtime.Location]*interpreter.Program,
capabilityMapping *capcons.CapabilityMapping,
) *IssueStorageCapConMigration {
return &IssueStorageCapConMigration{
name: "cadence_storage_cap_con_issue_migration",
reporter: rwf.ReportWriter(issueStorageCapConMigrationReporterName),
chainID: chainID,
accountsCapabilities: storageDomainCapabilities,
programs: programs,
mapping: capabilityMapping,
}
}

func (m *IssueStorageCapConMigration) InitMigration(
_ zerolog.Logger,
_ *registers.ByAccount,
_ int,
) error {
// During the migration, we only provide already checked programs,
// no parsing/checking of contracts is expected.

m.interpreterMigrationRuntimeConfig = InterpreterMigrationRuntimeConfig{
GetOrLoadProgram: func(
location runtime.Location,
_ func() (*interpreter.Program, error),
) (*interpreter.Program, error) {
program, ok := m.programs[location]
if !ok {
return nil, fmt.Errorf("program not found: %s", location)
}
return program, nil
},
GetCode: func(_ common.AddressLocation) ([]byte, error) {
return nil, fmt.Errorf("unexpected call to GetCode")
},
GetContractNames: func(address flow.Address) ([]string, error) {
return nil, fmt.Errorf("unexpected call to GetContractNames")
},
}

return nil
}

func (m *IssueStorageCapConMigration) MigrateAccount(
_ context.Context,
address common.Address,
accountRegisters *registers.AccountRegisters,
) error {
accountCapabilities := m.accountsCapabilities.Get(address)
if accountCapabilities == nil {
return nil
}

// Create all the runtime components we need for the migration
migrationRuntime, err := NewInterpreterMigrationRuntime(
accountRegisters,
m.chainID,
m.interpreterMigrationRuntimeConfig,
)
if err != nil {
return fmt.Errorf("failed to create interpreter migration runtime: %w", err)
}

idGenerator := environment.NewAccountLocalIDGenerator(
tracing.NewMockTracerSpan(),
util.NopMeter{},
migrationRuntime.Accounts,
)

handler := capabilityControllerHandler{
idGenerator: idGenerator,
}

capcons.IssueAccountCapabilities(
migrationRuntime.Interpreter,
address,
accountCapabilities,
handler,
m.mapping,
)

// It would be ideal to do the reporting inside `IssueAccountCapabilities` function above.
// However, that doesn't have the access to the reporter. So doing it here.
for _, capability := range accountCapabilities.Capabilities {
id, _, _ := m.mapping.Get(interpreter.AddressPath{
Address: address,
Path: capability.Path,
})

m.reporter.Write(storageCapconIssuedEntry{
AccountAddress: address,
Path: capability.Path,
BorrowType: capability.BorrowType,
CapabilityID: id,
})
}

return nil
}

func (m *IssueStorageCapConMigration) Close() error {
m.reporter.Close()
return nil
}

var _ AccountBasedMigration = &IssueStorageCapConMigration{}

func NewCadence1ValueMigrations(
log zerolog.Logger,
rwf reporters.ReportWriterFactory,
Expand All @@ -225,6 +354,10 @@ func NewCadence1ValueMigrations(
// used by CadenceCapabilityValueMigration
capabilityMapping := &capcons.CapabilityMapping{}

// Populated by StorageCapMigration,
// used by IssueStorageCapConMigration
storageDomainCapabilities := &capcons.AccountsCapabilities{}

errorMessageHandler := &errorMessageHandler{}

// The value migrations are run as account-based migrations,
Expand Down Expand Up @@ -260,46 +393,61 @@ func NewCadence1ValueMigrations(
},
}

for index, migrationConstructor := range []func(opts Options) *CadenceBaseMigration{
func(opts Options) *CadenceBaseMigration {
return NewCadence1ValueMigration(
for index, migrationConstructor := range []func(opts Options) (string, AccountBasedMigration){
func(opts Options) (string, AccountBasedMigration) {
migration := NewCadence1ValueMigration(
rwf,
errorMessageHandler,
programs,
NewCadence1CompositeStaticTypeConverter(opts.ChainID),
NewCadence1InterfaceStaticTypeConverter(opts.ChainID),
storageDomainCapabilities,
opts,
)
return migration.name, migration
},
func(opts Options) (string, AccountBasedMigration) {
migration := NewIssueStorageCapConMigration(
rwf,
opts.ChainID,
storageDomainCapabilities,
programs,
capabilityMapping,
)
return migration.name, migration

},
func(opts Options) *CadenceBaseMigration {
return NewCadence1LinkValueMigration(
func(opts Options) (string, AccountBasedMigration) {
migration := NewCadence1LinkValueMigration(
rwf,
errorMessageHandler,
programs,
capabilityMapping,
opts,
)
return migration.name, migration
},
func(opts Options) *CadenceBaseMigration {
return NewCadence1CapabilityValueMigration(
func(opts Options) (string, AccountBasedMigration) {
migration := NewCadence1CapabilityValueMigration(
rwf,
errorMessageHandler,
programs,
capabilityMapping,
opts,
)
return migration.name, migration
},
} {
opts := opts
// Only check storage health before the first migration
opts.CheckStorageHealthBeforeMigration = opts.CheckStorageHealthBeforeMigration && index == 0

accountBasedMigration := migrationConstructor(opts)
name, accountBasedMigration := migrationConstructor(opts)

migs = append(
migs,
NamedMigration{
Name: accountBasedMigration.name,
Name: name,
Migrate: NewAccountBasedMigration(
log,
opts.NWorker,
Expand Down
49 changes: 37 additions & 12 deletions cmd/util/ledger/migrations/cadence_values_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ func NewCadence1ValueMigration(
programs map[runtime.Location]*interpreter.Program,
compositeTypeConverter statictypes.CompositeTypeConverterFunc,
interfaceTypeConverter statictypes.InterfaceTypeConverterFunc,
storageDomainCapabilities *capcons.AccountsCapabilities,
opts Options,
) *CadenceBaseMigration {

Expand Down Expand Up @@ -285,6 +286,9 @@ func NewCadence1ValueMigration(
// and the mutating iterator of the inlined version of atree
type_keys.NewTypeKeyMigration(),
string_normalization.NewStringNormalizingMigration(),
&capcons.StorageCapMigration{
StorageDomainCapabilities: storageDomainCapabilities,
},
}
},
errorMessageHandler: errorMessageHandler,
Expand Down Expand Up @@ -396,22 +400,10 @@ func NewCadence1CapabilityValueMigration(
accounts environment.Accounts,
reporter *cadenceValueMigrationReporter,
) []migrations.ValueMigration {

idGenerator := environment.NewAccountLocalIDGenerator(
tracing.NewMockTracerSpan(),
util.NopMeter{},
accounts,
)

handler := capabilityControllerHandler{
idGenerator: idGenerator,
}

return []migrations.ValueMigration{
&capcons.CapabilityValueMigration{
CapabilityMapping: capabilityMapping,
Reporter: reporter,
IssueHandler: handler,
},
}
},
Expand Down Expand Up @@ -808,3 +800,36 @@ func (e dictionaryKeyConflictEntry) MarshalJSON() ([]byte, error) {
Path: e.AddressPath.Path.String(),
})
}

// storageCapconIssuedEntry

type storageCapconIssuedEntry struct {
AccountAddress common.Address
Path interpreter.PathValue
BorrowType interpreter.StaticType
CapabilityID interpreter.UInt64Value
}

var _ valueMigrationReportEntry = storageCapconIssuedEntry{}

func (e storageCapconIssuedEntry) accountAddress() common.Address {
return e.AccountAddress
}

var _ json.Marshaler = storageCapconIssuedEntry{}

func (e storageCapconIssuedEntry) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Kind string `json:"kind"`
AccountAddress string `json:"account_address"`
Path string `json:"path"`
BorrowType string `json:"borrow_type"`
CapabilityID string `json:"capability_id"`
}{
Kind: "storage-capcon-issued",
AccountAddress: e.AccountAddress.HexWithPrefix(),
Path: e.Path.String(),
BorrowType: string(e.BorrowType.ID()),
CapabilityID: e.CapabilityID.String(),
})
}
Loading
Loading