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

Improve Cadence 1.0 migration #5388

Merged
merged 23 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ba2e543
add support for localnet
turbolent Feb 13, 2024
47f788f
do not update FT switchboard on localnet
turbolent Feb 13, 2024
f1f58e6
update Cadence
turbolent Feb 13, 2024
3e3b847
fix static binary
turbolent Feb 14, 2024
3684bcc
Assert FlowToken.Vault migration in tests
SupunS Feb 14, 2024
513285a
fix burner contract deployment and imports in updated system contracts
turbolent Feb 14, 2024
ae6ceb5
Merge remote-tracking branch 'origin/auto-update-onflow-cadence-v1.0.…
turbolent Feb 14, 2024
c81e215
Merge branch 'feature/stable-cadence' into bastian/cadence-1-migratio…
turbolent Feb 14, 2024
4a88ae3
update Cadence
turbolent Feb 15, 2024
7fa4b7d
add TODO
turbolent Feb 15, 2024
5f79437
remove unused/unnecessary GetOrLoadProgramFunc field
turbolent Feb 15, 2024
99af973
update to latest fixed Cadence
turbolent Feb 15, 2024
7e09edd
generate contract map from all payloads instead of full payload snapshot
turbolent Feb 15, 2024
5e8b0d9
update Cadence
turbolent Feb 16, 2024
c19d5b4
test contract update for missing contract is rejected
turbolent Feb 16, 2024
1dbb4bf
only report program loading errors once, omit full message for subseq…
turbolent Feb 16, 2024
4faf9bf
go mod tidy
turbolent Feb 16, 2024
ae39304
share error message handling, cache program loading errors
turbolent Feb 16, 2024
4198bc7
remove log statements
turbolent Feb 17, 2024
97b6f10
Merge branch 'feature/stable-cadence' into bastian/cadence-1-migratio…
turbolent Feb 22, 2024
faad624
Merge branch 'feature/stable-cadence' into bastian/cadence-1-migratio…
turbolent Feb 23, 2024
388a112
simplify
turbolent Feb 26, 2024
1bc3c79
Merge branch 'feature/stable-cadence' into bastian/cadence-1-migratio…
turbolent Feb 26, 2024
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
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,
),
)
}
136 changes: 103 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,59 @@ 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 {
var message 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 {
message = "error getting program"
}
}

if message == "" {
message = err.Error()
}

return message
}

// 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 +313,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 +326,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 +343,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 +354,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 +364,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
Loading