Skip to content

Commit

Permalink
Merge pull request #6306 from onflow/bastian/fix-storage-cap-migration
Browse files Browse the repository at this point in the history
 Fix migration of storage path capabilities
  • Loading branch information
SupunS authored Aug 8, 2024
2 parents 1dd0921 + 97bc1d9 commit f4e316a
Show file tree
Hide file tree
Showing 10 changed files with 274 additions and 63 deletions.
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

0 comments on commit f4e316a

Please sign in to comment.