Skip to content

Commit

Permalink
Merge pull request #5388 from onflow/bastian/cadence-1-migration-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Feb 26, 2024
2 parents 0776bdc + 1bc3c79 commit b9c9109
Show file tree
Hide file tree
Showing 11 changed files with 386 additions and 153 deletions.
30 changes: 26 additions & 4 deletions cmd/util/ledger/migrations/cadence.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,25 @@ func NewCadence1ValueMigrations(
// used by CadenceCapabilityValueMigrator
capabilityMapping := &capcons.CapabilityMapping{}

errorMessageHandler := &errorMessageHandler{}

for _, accountBasedMigration := range []AccountBasedMigration{
NewCadence1ValueMigrator(
rwf,
errorMessageHandler,
NewCadence1CompositeStaticTypeConverter(chainID),
NewCadence1InterfaceStaticTypeConverter(chainID),
),
NewCadence1LinkValueMigrator(rwf, capabilityMapping),
NewCadence1CapabilityValueMigrator(rwf, capabilityMapping),
NewCadence1LinkValueMigrator(
rwf,
errorMessageHandler,
capabilityMapping,
),
NewCadence1CapabilityValueMigrator(
rwf,
errorMessageHandler,
capabilityMapping,
),
} {
migrations = append(
migrations,
Expand Down Expand Up @@ -236,7 +247,18 @@ func NewCadence1Migrations(
stagedContracts []StagedContract,
) []ledger.Migration {
return common.Concat(
NewCadence1ContractsMigrations(log, nWorker, chainID, evmContractChange, stagedContracts),
NewCadence1ValueMigrations(log, rwf, nWorker, chainID),
NewCadence1ContractsMigrations(
log,
nWorker,
chainID,
evmContractChange,
stagedContracts,
),
NewCadence1ValueMigrations(
log,
rwf,
nWorker,
chainID,
),
)
}
131 changes: 98 additions & 33 deletions cmd/util/ledger/migrations/cadence_values_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import (
"context"
"fmt"
"io"
"sync"

"errors"

"github.com/onflow/cadence/migrations/statictypes"
"github.com/onflow/cadence/runtime"
Expand All @@ -21,6 +24,7 @@ import (
"github.com/onflow/flow-go/fvm/environment"
"github.com/onflow/flow-go/fvm/tracing"
"github.com/onflow/flow-go/ledger"
"github.com/onflow/flow-go/ledger/common/convert"
"github.com/onflow/flow-go/model/flow"
)

Expand All @@ -34,6 +38,7 @@ type CadenceBaseMigrator struct {
reporter *cadenceValueMigrationReporter,
) []migrations.ValueMigration
runtimeInterfaceConfig util.RuntimeInterfaceConfig
errorMessageHandler *errorMessageHandler
}

var _ AccountBasedMigration = (*CadenceBaseMigrator)(nil)
Expand All @@ -55,33 +60,58 @@ func (m *CadenceBaseMigrator) InitMigration(
// The MigrateAccount function is only given the payloads for the account to be migrated.
// However, the migration needs to be able to get the code for contracts of any account.

fullPayloadSnapshot, err := util.NewPayloadSnapshot(allPayloads)
contracts, err := getContractMap(allPayloads)
if err != nil {
return err
}

m.runtimeInterfaceConfig = util.RuntimeInterfaceConfig{
m.runtimeInterfaceConfig.GetContractCodeFunc = func(location runtime.Location) ([]byte, error) {
addressLocation, ok := location.(common.AddressLocation)
if !ok {
return nil, nil
}

GetContractCodeFunc: func(location runtime.Location) ([]byte, error) {
addressLocation, ok := location.(common.AddressLocation)
if !ok {
return nil, nil
}
contractRegisterID := flow.ContractRegisterID(
flow.Address(addressLocation.Address),
addressLocation.Name,
)
contract, err := fullPayloadSnapshot.Get(contractRegisterID)
if err != nil {
return nil, fmt.Errorf("failed to get contract code: %w", err)
}
return contract, nil
},
contract, ok := contracts[addressLocation]
if !ok {
return nil, fmt.Errorf("failed to get contract code for location %s", location)
}

return contract, nil
}

return nil
}

func getContractMap(allPayloads []*ledger.Payload) (map[common.AddressLocation][]byte, error) {
contracts := make(map[common.AddressLocation][]byte)

for _, payload := range allPayloads {
registerID, registerValue, err := convert.PayloadToRegister(payload)
if err != nil {
return nil, fmt.Errorf("failed to convert payload to register: %w", err)
}

contractName := flow.RegisterIDContractName(registerID)
if contractName == "" {
continue
}

address, err := common.BytesToAddress([]byte(registerID.Owner))
if err != nil {
return nil, fmt.Errorf("failed to convert register owner to address: %w", err)
}

addressLocation := common.AddressLocation{
Address: address,
Name: contractName,
}

contracts[addressLocation] = registerValue
}

return contracts, nil
}

func (m *CadenceBaseMigrator) MigrateAccount(
_ context.Context,
address common.Address,
Expand All @@ -104,9 +134,7 @@ func (m *CadenceBaseMigrator) MigrateAccount(
migrationRuntime.Storage,
)

reporter := newValueMigrationReporter(m.reporter, m.log)

m.log.Info().Msg("Migrating cadence values")
reporter := newValueMigrationReporter(m.reporter, m.log, m.errorMessageHandler)

migration.Migrate(
&migrations.AddressSliceIterator{
Expand All @@ -120,7 +148,6 @@ func (m *CadenceBaseMigrator) MigrateAccount(
),
)

m.log.Info().Msg("Committing changes")
err = migration.Commit()
if err != nil {
return nil, fmt.Errorf("failed to commit changes: %w", err)
Expand All @@ -144,6 +171,7 @@ func (m *CadenceBaseMigrator) MigrateAccount(
// which runs some of the Cadence value migrations (static types, entitlements, strings)
func NewCadence1ValueMigrator(
rwf reporters.ReportWriterFactory,
errorMessageHandler *errorMessageHandler,
compositeTypeConverter statictypes.CompositeTypeConverterFunc,
interfaceTypeConverter statictypes.InterfaceTypeConverterFunc,
) *CadenceBaseMigrator {
Expand All @@ -163,6 +191,7 @@ func NewCadence1ValueMigrator(
string_normalization.NewStringNormalizingMigration(),
}
},
errorMessageHandler: errorMessageHandler,
}
}

Expand All @@ -171,6 +200,7 @@ func NewCadence1ValueMigrator(
// It populates the given map with the IDs of the capability controller it issues.
func NewCadence1LinkValueMigrator(
rwf reporters.ReportWriterFactory,
errorMessageHandler *errorMessageHandler,
capabilityMapping *capcons.CapabilityMapping,
) *CadenceBaseMigrator {
return &CadenceBaseMigrator{
Expand All @@ -194,6 +224,7 @@ func NewCadence1LinkValueMigrator(
},
}
},
errorMessageHandler: errorMessageHandler,
}
}

Expand All @@ -203,6 +234,7 @@ func NewCadence1LinkValueMigrator(
// generated by the link value migration.
func NewCadence1CapabilityValueMigrator(
rwf reporters.ReportWriterFactory,
errorMessageHandler *errorMessageHandler,
capabilityMapping *capcons.CapabilityMapping,
) *CadenceBaseMigrator {
return &CadenceBaseMigrator{
Expand All @@ -220,23 +252,54 @@ func NewCadence1CapabilityValueMigrator(
},
}
},
errorMessageHandler: errorMessageHandler,
}
}

// errorMessageHandler formats error messages from errors.
// It only reports program loading errors once.
type errorMessageHandler struct {
// common.Location -> struct{}
reportedProgramLoadingErrors sync.Map
}

func (t *errorMessageHandler) FormatError(err error) string {

// Only report program loading errors once,
// omit full error message for subsequent occurrences

var programLoadingError environment.ProgramLoadingError
if errors.As(err, &programLoadingError) {
location := programLoadingError.Location
_, ok := t.reportedProgramLoadingErrors.LoadOrStore(location, struct{}{})
if ok {
return "error getting program"
}
}

return err.Error()
}

// cadenceValueMigrationReporter is the reporter for cadence value migrations
type cadenceValueMigrationReporter struct {
rw reporters.ReportWriter
log zerolog.Logger
reportWriter reporters.ReportWriter
log zerolog.Logger
errorMessageHandler *errorMessageHandler
}

var _ capcons.LinkMigrationReporter = &cadenceValueMigrationReporter{}
var _ capcons.CapabilityMigrationReporter = &cadenceValueMigrationReporter{}
var _ migrations.Reporter = &cadenceValueMigrationReporter{}

func newValueMigrationReporter(rw reporters.ReportWriter, log zerolog.Logger) *cadenceValueMigrationReporter {
func newValueMigrationReporter(
reportWriter reporters.ReportWriter,
log zerolog.Logger,
errorMessageHandler *errorMessageHandler,
) *cadenceValueMigrationReporter {
return &cadenceValueMigrationReporter{
rw: rw,
log: log,
reportWriter: reportWriter,
log: log,
errorMessageHandler: errorMessageHandler,
}
}

Expand All @@ -245,7 +308,7 @@ func (t *cadenceValueMigrationReporter) Migrated(
storageMapKey interpreter.StorageMapKey,
migration string,
) {
t.rw.Write(cadenceValueMigrationReportEntry{
t.reportWriter.Write(cadenceValueMigrationReportEntry{
StorageKey: storageKey,
StorageMapKey: storageMapKey,
Migration: migration,
Expand All @@ -258,13 +321,15 @@ func (t *cadenceValueMigrationReporter) Error(
migration string,
err error,
) {
message := t.errorMessageHandler.FormatError(err)

t.log.Error().Msgf(
"failed to run %s in account %s, domain %s, key %s: %s",
migration,
storageKey.Address,
storageKey.Key,
storageMapKey,
err,
message,
)
}

Expand All @@ -273,7 +338,7 @@ func (t *cadenceValueMigrationReporter) MigratedPathCapability(
addressPath interpreter.AddressPath,
borrowType *interpreter.ReferenceStaticType,
) {
t.rw.Write(capConsPathCapabilityMigrationEntry{
t.reportWriter.Write(capConsPathCapabilityMigrationEntry{
AccountAddress: accountAddress,
AddressPath: addressPath,
BorrowType: borrowType,
Expand All @@ -284,7 +349,7 @@ func (t *cadenceValueMigrationReporter) MissingCapabilityID(
accountAddress common.Address,
addressPath interpreter.AddressPath,
) {
t.rw.Write(capConsMissingCapabilityIDEntry{
t.reportWriter.Write(capConsMissingCapabilityIDEntry{
AccountAddress: accountAddress,
AddressPath: addressPath,
})
Expand All @@ -294,18 +359,18 @@ func (t *cadenceValueMigrationReporter) MigratedLink(
accountAddressPath interpreter.AddressPath,
capabilityID interpreter.UInt64Value,
) {
t.rw.Write(capConsLinkMigrationEntry{
t.reportWriter.Write(capConsLinkMigrationEntry{
AccountAddressPath: accountAddressPath,
CapabilityID: capabilityID,
})
}

func (t *cadenceValueMigrationReporter) CyclicLink(err capcons.CyclicLinkError) {
t.rw.Write(err)
t.reportWriter.Write(err)
}

func (t *cadenceValueMigrationReporter) MissingTarget(accountAddressPath interpreter.AddressPath) {
t.rw.Write(capConsMissingTargetEntry{
t.reportWriter.Write(capConsMissingTargetEntry{
AddressPath: accountAddressPath,
})
}
Expand Down
Loading

0 comments on commit b9c9109

Please sign in to comment.