github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/cmd/util/ledger/migrations/cadence_values_migration.go (about)

     1  package migrations
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"sync"
     9  
    10  	"errors"
    11  
    12  	"github.com/onflow/cadence/migrations"
    13  	"github.com/onflow/cadence/migrations/capcons"
    14  	"github.com/onflow/cadence/migrations/entitlements"
    15  	"github.com/onflow/cadence/migrations/statictypes"
    16  	"github.com/onflow/cadence/migrations/string_normalization"
    17  	"github.com/onflow/cadence/runtime"
    18  	"github.com/onflow/cadence/runtime/common"
    19  	cadenceErrors "github.com/onflow/cadence/runtime/errors"
    20  	"github.com/onflow/cadence/runtime/interpreter"
    21  	"github.com/rs/zerolog"
    22  
    23  	"github.com/onflow/flow-go/cmd/util/ledger/reporters"
    24  	"github.com/onflow/flow-go/cmd/util/ledger/util"
    25  	"github.com/onflow/flow-go/cmd/util/ledger/util/registers"
    26  	"github.com/onflow/flow-go/fvm/environment"
    27  	"github.com/onflow/flow-go/fvm/tracing"
    28  	"github.com/onflow/flow-go/ledger"
    29  	"github.com/onflow/flow-go/model/flow"
    30  )
    31  
    32  type CadenceBaseMigration struct {
    33  	name                              string
    34  	log                               zerolog.Logger
    35  	reporter                          reporters.ReportWriter
    36  	diffReporter                      reporters.ReportWriter
    37  	logVerboseDiff                    bool
    38  	verboseErrorOutput                bool
    39  	checkStorageHealthBeforeMigration bool
    40  	valueMigrations                   func(
    41  		inter *interpreter.Interpreter,
    42  		accounts environment.Accounts,
    43  		reporter *cadenceValueMigrationReporter,
    44  	) []migrations.ValueMigration
    45  	interpreterMigrationRuntimeConfig InterpreterMigrationRuntimeConfig
    46  	errorMessageHandler               *errorMessageHandler
    47  	programs                          map[runtime.Location]*interpreter.Program
    48  	chainID                           flow.ChainID
    49  	nWorkers                          int
    50  }
    51  
    52  var _ AccountBasedMigration = (*CadenceBaseMigration)(nil)
    53  var _ io.Closer = (*CadenceBaseMigration)(nil)
    54  
    55  func (m *CadenceBaseMigration) Close() error {
    56  	// Close the report writer so it flushes to file.
    57  	m.reporter.Close()
    58  
    59  	if m.diffReporter != nil {
    60  		m.diffReporter.Close()
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  func (m *CadenceBaseMigration) InitMigration(
    67  	log zerolog.Logger,
    68  	_ *registers.ByAccount,
    69  	nWorkers int,
    70  ) error {
    71  	m.log = log.With().Str("migration", m.name).Logger()
    72  	m.nWorkers = nWorkers
    73  
    74  	// During the migration, we only provide already checked programs,
    75  	// no parsing/checking of contracts is expected.
    76  
    77  	m.interpreterMigrationRuntimeConfig = InterpreterMigrationRuntimeConfig{
    78  		GetOrLoadProgram: func(
    79  			location runtime.Location,
    80  			_ func() (*interpreter.Program, error),
    81  		) (*interpreter.Program, error) {
    82  			program, ok := m.programs[location]
    83  			if !ok {
    84  				return nil, fmt.Errorf("program not found: %s", location)
    85  			}
    86  			return program, nil
    87  		},
    88  		GetCode: func(_ common.AddressLocation) ([]byte, error) {
    89  			return nil, fmt.Errorf("unexpected call to GetCode")
    90  		},
    91  		GetContractNames: func(address flow.Address) ([]string, error) {
    92  			return nil, fmt.Errorf("unexpected call to GetContractNames")
    93  		},
    94  	}
    95  
    96  	return nil
    97  }
    98  
    99  func (m *CadenceBaseMigration) MigrateAccount(
   100  	_ context.Context,
   101  	address common.Address,
   102  	accountRegisters *registers.AccountRegisters,
   103  ) error {
   104  	var oldPayloadsForDiff []*ledger.Payload
   105  	if m.diffReporter != nil {
   106  		oldPayloadsForDiff = accountRegisters.Payloads()
   107  	}
   108  
   109  	// Create all the runtime components we need for the migration
   110  	migrationRuntime, err := NewInterpreterMigrationRuntime(
   111  		accountRegisters,
   112  		m.chainID,
   113  		m.interpreterMigrationRuntimeConfig,
   114  	)
   115  	if err != nil {
   116  		return fmt.Errorf("failed to create interpreter migration runtime: %w", err)
   117  	}
   118  
   119  	storage := migrationRuntime.Storage
   120  
   121  	// Check storage health before migration, if enabled.
   122  	var storageHealthErrorBefore error
   123  	if m.checkStorageHealthBeforeMigration {
   124  
   125  		storageHealthErrorBefore = checkStorageHealth(address, storage, accountRegisters, m.nWorkers)
   126  		if storageHealthErrorBefore != nil {
   127  			m.log.Warn().
   128  				Err(storageHealthErrorBefore).
   129  				Str("account", address.HexWithPrefix()).
   130  				Msg("storage health check before migration failed")
   131  		}
   132  	}
   133  
   134  	migration, err := migrations.NewStorageMigration(
   135  		migrationRuntime.Interpreter,
   136  		storage,
   137  		m.name,
   138  		address,
   139  	)
   140  	if err != nil {
   141  		return fmt.Errorf("failed to create storage migration: %w", err)
   142  	}
   143  
   144  	reporter := newValueMigrationReporter(
   145  		m.reporter,
   146  		m.log,
   147  		m.errorMessageHandler,
   148  		m.verboseErrorOutput,
   149  	)
   150  
   151  	valueMigrations := m.valueMigrations(
   152  		migrationRuntime.Interpreter,
   153  		migrationRuntime.Accounts,
   154  		reporter,
   155  	)
   156  
   157  	migration.Migrate(
   158  		migration.NewValueMigrationsPathMigrator(
   159  			reporter,
   160  			valueMigrations...,
   161  		),
   162  	)
   163  
   164  	err = migration.Commit()
   165  	if err != nil {
   166  		return fmt.Errorf("failed to commit changes: %w", err)
   167  	}
   168  
   169  	// Check storage health after migration.
   170  	// If the storage health check failed before the migration, we don't need to check it again.
   171  	if storageHealthErrorBefore == nil {
   172  		storageHealthErrorAfter := storage.CheckHealth()
   173  		if storageHealthErrorAfter != nil {
   174  			m.log.Err(storageHealthErrorAfter).
   175  				Str("account", address.HexWithPrefix()).
   176  				Msg("storage health check after migration failed")
   177  		}
   178  	}
   179  
   180  	// finalize the transaction
   181  	result, err := migrationRuntime.TransactionState.FinalizeMainTransaction()
   182  	if err != nil {
   183  		return fmt.Errorf("failed to finalize main transaction: %w", err)
   184  	}
   185  
   186  	// Merge the changes into the registers
   187  	expectedAddresses := map[flow.Address]struct{}{
   188  		flow.Address(address): {},
   189  	}
   190  
   191  	err = registers.ApplyChanges(
   192  		accountRegisters,
   193  		result.WriteSet,
   194  		expectedAddresses,
   195  		m.log,
   196  	)
   197  	if err != nil {
   198  		return fmt.Errorf("failed to apply changes: %w", err)
   199  	}
   200  
   201  	if m.diffReporter != nil {
   202  		newPayloadsForDiff := accountRegisters.Payloads()
   203  
   204  		accountDiffReporter := NewCadenceValueDiffReporter(
   205  			address,
   206  			m.chainID,
   207  			m.diffReporter,
   208  			m.logVerboseDiff,
   209  			m.nWorkers,
   210  		)
   211  
   212  		accountDiffReporter.DiffStates(
   213  			oldPayloadsForDiff,
   214  			newPayloadsForDiff,
   215  			allStorageMapDomains,
   216  		)
   217  	}
   218  
   219  	return nil
   220  }
   221  
   222  const cadenceValueMigrationReporterName = "cadence-value-migration"
   223  
   224  // NewCadence1ValueMigration creates a new CadenceBaseMigration
   225  // which runs some of the Cadence value migrations (static types, entitlements, strings)
   226  func NewCadence1ValueMigration(
   227  	rwf reporters.ReportWriterFactory,
   228  	errorMessageHandler *errorMessageHandler,
   229  	programs map[runtime.Location]*interpreter.Program,
   230  	compositeTypeConverter statictypes.CompositeTypeConverterFunc,
   231  	interfaceTypeConverter statictypes.InterfaceTypeConverterFunc,
   232  	staticTypeCache migrations.StaticTypeCache,
   233  	opts Options,
   234  ) *CadenceBaseMigration {
   235  
   236  	var diffReporter reporters.ReportWriter
   237  	if opts.DiffMigrations {
   238  		diffReporter = rwf.ReportWriter("cadence-value-migration-diff")
   239  	}
   240  
   241  	return &CadenceBaseMigration{
   242  		name:                              "cadence_value_migration",
   243  		reporter:                          rwf.ReportWriter(cadenceValueMigrationReporterName),
   244  		diffReporter:                      diffReporter,
   245  		logVerboseDiff:                    opts.LogVerboseDiff,
   246  		verboseErrorOutput:                opts.VerboseErrorOutput,
   247  		checkStorageHealthBeforeMigration: opts.CheckStorageHealthBeforeMigration,
   248  		valueMigrations: func(
   249  			inter *interpreter.Interpreter,
   250  			_ environment.Accounts,
   251  			reporter *cadenceValueMigrationReporter,
   252  		) []migrations.ValueMigration {
   253  			return []migrations.ValueMigration{
   254  				statictypes.NewStaticTypeMigration().
   255  					WithCompositeTypeConverter(compositeTypeConverter).
   256  					WithInterfaceTypeConverter(interfaceTypeConverter),
   257  				entitlements.NewEntitlementsMigrationWithCache(inter, staticTypeCache),
   258  				string_normalization.NewStringNormalizingMigration(),
   259  			}
   260  		},
   261  		errorMessageHandler: errorMessageHandler,
   262  		programs:            programs,
   263  		chainID:             opts.ChainID,
   264  	}
   265  }
   266  
   267  // NewCadence1LinkValueMigration creates a new CadenceBaseMigration
   268  // which migrates links to capability controllers.
   269  // It populates the given map with the IDs of the capability controller it issues.
   270  func NewCadence1LinkValueMigration(
   271  	rwf reporters.ReportWriterFactory,
   272  	errorMessageHandler *errorMessageHandler,
   273  	programs map[runtime.Location]*interpreter.Program,
   274  	capabilityMapping *capcons.CapabilityMapping,
   275  	opts Options,
   276  ) *CadenceBaseMigration {
   277  	var diffReporter reporters.ReportWriter
   278  	if opts.DiffMigrations {
   279  		diffReporter = rwf.ReportWriter("cadence-link-value-migration-diff")
   280  	}
   281  
   282  	return &CadenceBaseMigration{
   283  		name:                              "cadence_link_value_migration",
   284  		reporter:                          rwf.ReportWriter("cadence-link-value-migration"),
   285  		diffReporter:                      diffReporter,
   286  		logVerboseDiff:                    opts.LogVerboseDiff,
   287  		verboseErrorOutput:                opts.VerboseErrorOutput,
   288  		checkStorageHealthBeforeMigration: opts.CheckStorageHealthBeforeMigration,
   289  		valueMigrations: func(
   290  			_ *interpreter.Interpreter,
   291  			accounts environment.Accounts,
   292  			reporter *cadenceValueMigrationReporter,
   293  		) []migrations.ValueMigration {
   294  			idGenerator := environment.NewAccountLocalIDGenerator(
   295  				tracing.NewMockTracerSpan(),
   296  				util.NopMeter{},
   297  				accounts,
   298  			)
   299  			return []migrations.ValueMigration{
   300  				&capcons.LinkValueMigration{
   301  					CapabilityMapping:  capabilityMapping,
   302  					AccountIDGenerator: idGenerator,
   303  					Reporter:           reporter,
   304  				},
   305  			}
   306  		},
   307  		errorMessageHandler: errorMessageHandler,
   308  		programs:            programs,
   309  		chainID:             opts.ChainID,
   310  	}
   311  }
   312  
   313  // NewCadence1CapabilityValueMigration creates a new CadenceBaseMigration
   314  // which migrates path capability values to ID capability values.
   315  // It requires a map the IDs of the capability controllers,
   316  // generated by the link value migration.
   317  func NewCadence1CapabilityValueMigration(
   318  	rwf reporters.ReportWriterFactory,
   319  	errorMessageHandler *errorMessageHandler,
   320  	programs map[runtime.Location]*interpreter.Program,
   321  	capabilityMapping *capcons.CapabilityMapping,
   322  	opts Options,
   323  ) *CadenceBaseMigration {
   324  	var diffReporter reporters.ReportWriter
   325  	if opts.DiffMigrations {
   326  		diffReporter = rwf.ReportWriter("cadence-capability-value-migration-diff")
   327  	}
   328  
   329  	return &CadenceBaseMigration{
   330  		name:                              "cadence_capability_value_migration",
   331  		reporter:                          rwf.ReportWriter("cadence-capability-value-migration"),
   332  		diffReporter:                      diffReporter,
   333  		logVerboseDiff:                    opts.LogVerboseDiff,
   334  		verboseErrorOutput:                opts.VerboseErrorOutput,
   335  		checkStorageHealthBeforeMigration: opts.CheckStorageHealthBeforeMigration,
   336  		valueMigrations: func(
   337  			_ *interpreter.Interpreter,
   338  			_ environment.Accounts,
   339  			reporter *cadenceValueMigrationReporter,
   340  		) []migrations.ValueMigration {
   341  			return []migrations.ValueMigration{
   342  				&capcons.CapabilityValueMigration{
   343  					CapabilityMapping: capabilityMapping,
   344  					Reporter:          reporter,
   345  				},
   346  			}
   347  		},
   348  		errorMessageHandler: errorMessageHandler,
   349  		programs:            programs,
   350  		chainID:             opts.ChainID,
   351  	}
   352  }
   353  
   354  // errorMessageHandler formats error messages from errors.
   355  // It only reports program loading errors once.
   356  type errorMessageHandler struct {
   357  	// common.Location -> struct{}
   358  	reportedProgramLoadingErrors sync.Map
   359  }
   360  
   361  func (t *errorMessageHandler) FormatError(err error) (message string, showStack bool) {
   362  
   363  	// Only report program loading errors once,
   364  	// omit full error message for subsequent occurrences
   365  
   366  	var programLoadingError environment.ProgramLoadingError
   367  	if errors.As(err, &programLoadingError) {
   368  		location := programLoadingError.Location
   369  		_, ok := t.reportedProgramLoadingErrors.LoadOrStore(location, struct{}{})
   370  		if ok {
   371  			return "error getting program", false
   372  		}
   373  
   374  		return err.Error(), false
   375  	}
   376  
   377  	return err.Error(), true
   378  }
   379  
   380  // cadenceValueMigrationReporter is the reporter for cadence value migrations
   381  type cadenceValueMigrationReporter struct {
   382  	reportWriter        reporters.ReportWriter
   383  	log                 zerolog.Logger
   384  	errorMessageHandler *errorMessageHandler
   385  	verboseErrorOutput  bool
   386  }
   387  
   388  var _ capcons.LinkMigrationReporter = &cadenceValueMigrationReporter{}
   389  var _ capcons.CapabilityMigrationReporter = &cadenceValueMigrationReporter{}
   390  var _ migrations.Reporter = &cadenceValueMigrationReporter{}
   391  
   392  func newValueMigrationReporter(
   393  	reportWriter reporters.ReportWriter,
   394  	log zerolog.Logger,
   395  	errorMessageHandler *errorMessageHandler,
   396  	verboseErrorOutput bool,
   397  ) *cadenceValueMigrationReporter {
   398  	return &cadenceValueMigrationReporter{
   399  		reportWriter:        reportWriter,
   400  		log:                 log,
   401  		errorMessageHandler: errorMessageHandler,
   402  		verboseErrorOutput:  verboseErrorOutput,
   403  	}
   404  }
   405  
   406  func (t *cadenceValueMigrationReporter) Migrated(
   407  	storageKey interpreter.StorageKey,
   408  	storageMapKey interpreter.StorageMapKey,
   409  	migration string,
   410  ) {
   411  	t.reportWriter.Write(cadenceValueMigrationEntry{
   412  		StorageKey:    storageKey,
   413  		StorageMapKey: storageMapKey,
   414  		Migration:     migration,
   415  	})
   416  }
   417  
   418  func (t *cadenceValueMigrationReporter) Error(err error) {
   419  
   420  	var migrationErr migrations.StorageMigrationError
   421  
   422  	if !errors.As(err, &migrationErr) {
   423  		panic(cadenceErrors.NewUnreachableError())
   424  	}
   425  
   426  	message, showStack := t.errorMessageHandler.FormatError(migrationErr.Err)
   427  
   428  	storageKey := migrationErr.StorageKey
   429  	storageMapKey := migrationErr.StorageMapKey
   430  	migration := migrationErr.Migration
   431  
   432  	if showStack && len(migrationErr.Stack) > 0 {
   433  		message = fmt.Sprintf("%s\n%s", message, migrationErr.Stack)
   434  	}
   435  
   436  	if t.verboseErrorOutput {
   437  		t.reportWriter.Write(cadenceValueMigrationFailureEntry{
   438  			StorageKey:    storageKey,
   439  			StorageMapKey: storageMapKey,
   440  			Migration:     migration,
   441  			Message:       message,
   442  		})
   443  	}
   444  }
   445  
   446  func (t *cadenceValueMigrationReporter) MigratedPathCapability(
   447  	accountAddress common.Address,
   448  	addressPath interpreter.AddressPath,
   449  	borrowType *interpreter.ReferenceStaticType,
   450  ) {
   451  	t.reportWriter.Write(capabilityMigrationEntry{
   452  		AccountAddress: accountAddress,
   453  		AddressPath:    addressPath,
   454  		BorrowType:     borrowType,
   455  	})
   456  }
   457  
   458  func (t *cadenceValueMigrationReporter) MissingCapabilityID(
   459  	accountAddress common.Address,
   460  	addressPath interpreter.AddressPath,
   461  ) {
   462  	t.reportWriter.Write(capabilityMissingCapabilityIDEntry{
   463  		AccountAddress: accountAddress,
   464  		AddressPath:    addressPath,
   465  	})
   466  }
   467  
   468  func (t *cadenceValueMigrationReporter) MigratedLink(
   469  	accountAddressPath interpreter.AddressPath,
   470  	capabilityID interpreter.UInt64Value,
   471  ) {
   472  	t.reportWriter.Write(linkMigrationEntry{
   473  		AccountAddressPath: accountAddressPath,
   474  		CapabilityID:       uint64(capabilityID),
   475  	})
   476  }
   477  
   478  func (t *cadenceValueMigrationReporter) CyclicLink(err capcons.CyclicLinkError) {
   479  	t.reportWriter.Write(err)
   480  }
   481  
   482  func (t *cadenceValueMigrationReporter) MissingTarget(accountAddressPath interpreter.AddressPath) {
   483  	t.reportWriter.Write(linkMissingTargetEntry{
   484  		AddressPath: accountAddressPath,
   485  	})
   486  }
   487  
   488  func (t *cadenceValueMigrationReporter) DictionaryKeyConflict(accountAddressPath interpreter.AddressPath) {
   489  	t.reportWriter.Write(dictionaryKeyConflictEntry{
   490  		AddressPath: accountAddressPath,
   491  	})
   492  }
   493  
   494  type valueMigrationReportEntry interface {
   495  	accountAddress() common.Address
   496  }
   497  
   498  // cadenceValueMigrationReportEntry
   499  
   500  type cadenceValueMigrationEntry struct {
   501  	StorageKey    interpreter.StorageKey
   502  	StorageMapKey interpreter.StorageMapKey
   503  	Migration     string
   504  }
   505  
   506  var _ valueMigrationReportEntry = cadenceValueMigrationEntry{}
   507  
   508  func (e cadenceValueMigrationEntry) accountAddress() common.Address {
   509  	return e.StorageKey.Address
   510  }
   511  
   512  var _ json.Marshaler = cadenceValueMigrationEntry{}
   513  
   514  func (e cadenceValueMigrationEntry) MarshalJSON() ([]byte, error) {
   515  	return json.Marshal(struct {
   516  		Kind           string `json:"kind"`
   517  		AccountAddress string `json:"account_address"`
   518  		StorageDomain  string `json:"domain"`
   519  		Key            string `json:"key"`
   520  		Migration      string `json:"migration"`
   521  	}{
   522  		Kind:           "cadence-value-migration-success",
   523  		AccountAddress: e.StorageKey.Address.HexWithPrefix(),
   524  		StorageDomain:  e.StorageKey.Key,
   525  		Key:            fmt.Sprintf("%s", e.StorageMapKey),
   526  		Migration:      e.Migration,
   527  	})
   528  }
   529  
   530  // cadenceValueMigrationFailureEntry
   531  
   532  type cadenceValueMigrationFailureEntry struct {
   533  	StorageKey    interpreter.StorageKey
   534  	StorageMapKey interpreter.StorageMapKey
   535  	Migration     string
   536  	Message       string
   537  }
   538  
   539  var _ valueMigrationReportEntry = cadenceValueMigrationFailureEntry{}
   540  
   541  func (e cadenceValueMigrationFailureEntry) accountAddress() common.Address {
   542  	return e.StorageKey.Address
   543  }
   544  
   545  var _ json.Marshaler = cadenceValueMigrationFailureEntry{}
   546  
   547  func (e cadenceValueMigrationFailureEntry) MarshalJSON() ([]byte, error) {
   548  	return json.Marshal(struct {
   549  		Kind           string `json:"kind"`
   550  		AccountAddress string `json:"account_address"`
   551  		StorageDomain  string `json:"domain"`
   552  		Key            string `json:"key"`
   553  		Migration      string `json:"migration"`
   554  		Message        string `json:"message"`
   555  	}{
   556  		Kind:           "cadence-value-migration-failure",
   557  		AccountAddress: e.StorageKey.Address.HexWithPrefix(),
   558  		StorageDomain:  e.StorageKey.Key,
   559  		Key:            fmt.Sprintf("%s", e.StorageMapKey),
   560  		Migration:      e.Migration,
   561  		Message:        e.Message,
   562  	})
   563  }
   564  
   565  // linkMigrationEntry
   566  
   567  type linkMigrationEntry struct {
   568  	AccountAddressPath interpreter.AddressPath
   569  	CapabilityID       uint64
   570  }
   571  
   572  var _ valueMigrationReportEntry = linkMigrationEntry{}
   573  
   574  func (e linkMigrationEntry) accountAddress() common.Address {
   575  	return e.AccountAddressPath.Address
   576  }
   577  
   578  var _ json.Marshaler = linkMigrationEntry{}
   579  
   580  func (e linkMigrationEntry) MarshalJSON() ([]byte, error) {
   581  	return json.Marshal(struct {
   582  		Kind           string `json:"kind"`
   583  		AccountAddress string `json:"account_address"`
   584  		Path           string `json:"path"`
   585  		CapabilityID   uint64 `json:"capability_id"`
   586  	}{
   587  		Kind:           "link-migration-success",
   588  		AccountAddress: e.AccountAddressPath.Address.HexWithPrefix(),
   589  		Path:           e.AccountAddressPath.Path.String(),
   590  		CapabilityID:   e.CapabilityID,
   591  	})
   592  }
   593  
   594  // capabilityMigrationEntry
   595  
   596  type capabilityMigrationEntry struct {
   597  	AccountAddress common.Address
   598  	AddressPath    interpreter.AddressPath
   599  	BorrowType     *interpreter.ReferenceStaticType
   600  }
   601  
   602  var _ valueMigrationReportEntry = capabilityMigrationEntry{}
   603  
   604  func (e capabilityMigrationEntry) accountAddress() common.Address {
   605  	return e.AccountAddress
   606  }
   607  
   608  var _ json.Marshaler = capabilityMigrationEntry{}
   609  
   610  func (e capabilityMigrationEntry) MarshalJSON() ([]byte, error) {
   611  	return json.Marshal(struct {
   612  		Kind           string `json:"kind"`
   613  		AccountAddress string `json:"account_address"`
   614  		Address        string `json:"address"`
   615  		Path           string `json:"path"`
   616  		BorrowType     string `json:"borrow_type"`
   617  	}{
   618  		Kind:           "capability-migration-success",
   619  		AccountAddress: e.AccountAddress.HexWithPrefix(),
   620  		Address:        e.AddressPath.Address.HexWithPrefix(),
   621  		Path:           e.AddressPath.Path.String(),
   622  		BorrowType:     string(e.BorrowType.ID()),
   623  	})
   624  }
   625  
   626  // capabilityMissingCapabilityIDEntry
   627  
   628  type capabilityMissingCapabilityIDEntry struct {
   629  	AccountAddress common.Address
   630  	AddressPath    interpreter.AddressPath
   631  }
   632  
   633  var _ valueMigrationReportEntry = capabilityMissingCapabilityIDEntry{}
   634  
   635  func (e capabilityMissingCapabilityIDEntry) accountAddress() common.Address {
   636  	return e.AccountAddress
   637  }
   638  
   639  var _ json.Marshaler = capabilityMissingCapabilityIDEntry{}
   640  
   641  func (e capabilityMissingCapabilityIDEntry) MarshalJSON() ([]byte, error) {
   642  	return json.Marshal(struct {
   643  		Kind           string `json:"kind"`
   644  		AccountAddress string `json:"account_address"`
   645  		Address        string `json:"address"`
   646  		Path           string `json:"path"`
   647  	}{
   648  		Kind:           "capability-missing-capability-id",
   649  		AccountAddress: e.AccountAddress.HexWithPrefix(),
   650  		Address:        e.AddressPath.Address.HexWithPrefix(),
   651  		Path:           e.AddressPath.Path.String(),
   652  	})
   653  }
   654  
   655  // linkMissingTargetEntry
   656  
   657  type linkMissingTargetEntry struct {
   658  	AddressPath interpreter.AddressPath
   659  }
   660  
   661  var _ valueMigrationReportEntry = linkMissingTargetEntry{}
   662  
   663  func (e linkMissingTargetEntry) accountAddress() common.Address {
   664  	return e.AddressPath.Address
   665  }
   666  
   667  var _ json.Marshaler = linkMissingTargetEntry{}
   668  
   669  func (e linkMissingTargetEntry) MarshalJSON() ([]byte, error) {
   670  	return json.Marshal(struct {
   671  		Kind           string `json:"kind"`
   672  		AccountAddress string `json:"account_address"`
   673  		Path           string `json:"path"`
   674  	}{
   675  		Kind:           "link-missing-target",
   676  		AccountAddress: e.AddressPath.Address.HexWithPrefix(),
   677  		Path:           e.AddressPath.Path.String(),
   678  	})
   679  }
   680  
   681  // dictionaryKeyConflictEntry
   682  
   683  type dictionaryKeyConflictEntry struct {
   684  	AddressPath interpreter.AddressPath
   685  }
   686  
   687  var _ json.Marshaler = dictionaryKeyConflictEntry{}
   688  
   689  func (e dictionaryKeyConflictEntry) MarshalJSON() ([]byte, error) {
   690  	return json.Marshal(struct {
   691  		Kind           string `json:"kind"`
   692  		AccountAddress string `json:"account_address"`
   693  		Path           string `json:"path"`
   694  	}{
   695  		Kind:           "dictionary-key-conflict",
   696  		AccountAddress: e.AddressPath.Address.HexWithPrefix(),
   697  		Path:           e.AddressPath.Path.String(),
   698  	})
   699  }