diff --git a/builtin/v15/migration/system.go b/builtin/v15/migration/system.go new file mode 100644 index 00000000..552bae8b --- /dev/null +++ b/builtin/v15/migration/system.go @@ -0,0 +1,40 @@ +package migration + +import ( + "context" + + system15 "github.com/filecoin-project/go-state-types/builtin/v15/system" + + "github.com/filecoin-project/go-state-types/migration" + + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" +) + +// System Actor migrator +type systemActorMigrator struct { + OutCodeCID cid.Cid + ManifestData cid.Cid +} + +func (m systemActorMigrator) MigratedCodeCID() cid.Cid { + return m.OutCodeCID +} + +func (m systemActorMigrator) MigrateState(ctx context.Context, store cbor.IpldStore, in migration.ActorMigrationInput) (*migration.ActorMigrationResult, error) { + // The ManifestData itself is already in the blockstore + state := system15.State{BuiltinActors: m.ManifestData} + stateHead, err := store.Put(ctx, &state) + if err != nil { + return nil, err + } + + return &migration.ActorMigrationResult{ + NewCodeCID: m.OutCodeCID, + NewHead: stateHead, + }, nil +} + +func (m systemActorMigrator) Deferred() bool { + return false +} diff --git a/builtin/v15/migration/top.go b/builtin/v15/migration/top.go new file mode 100644 index 00000000..f2056827 --- /dev/null +++ b/builtin/v15/migration/top.go @@ -0,0 +1,104 @@ +package migration + +import ( + "context" + + adt15 "github.com/filecoin-project/go-state-types/builtin/v15/util/adt" + + system14 "github.com/filecoin-project/go-state-types/builtin/v14/system" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/go-state-types/migration" + + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "golang.org/x/xerrors" +) + +// MigrateStateTree Migrates the filecoin state tree starting from the global state tree and upgrading all actor state. +// The store must support concurrent writes (even if the configured worker count is 1). +func MigrateStateTree(ctx context.Context, store cbor.IpldStore, newManifestCID cid.Cid, actorsRootIn cid.Cid, priorEpoch abi.ChainEpoch, cfg migration.Config, log migration.Logger, cache migration.MigrationCache) (cid.Cid, error) { + if cfg.MaxWorkers <= 0 { + return cid.Undef, xerrors.Errorf("invalid migration config with %d workers", cfg.MaxWorkers) + } + + adtStore := adt15.WrapStore(ctx, store) + + // Load input and output state trees + actorsIn, err := builtin.LoadTree(adtStore, actorsRootIn) + if err != nil { + return cid.Undef, xerrors.Errorf("loading state tree: %w", err) + } + + // load old manifest data + systemActor, ok, err := actorsIn.GetActorV5(builtin.SystemActorAddr) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to get system actor: %w", err) + } + + if !ok { + return cid.Undef, xerrors.New("didn't find system actor") + } + + var systemState system14.State + if err := store.Get(ctx, systemActor.Head, &systemState); err != nil { + return cid.Undef, xerrors.Errorf("failed to get system actor state: %w", err) + } + + var oldManifestData manifest.ManifestData + if err := store.Get(ctx, systemState.BuiltinActors, &oldManifestData); err != nil { + return cid.Undef, xerrors.Errorf("failed to get old manifest data: %w", err) + } + + // load new manifest + var newManifest manifest.Manifest + if err := adtStore.Get(ctx, newManifestCID, &newManifest); err != nil { + return cid.Undef, xerrors.Errorf("error reading actor manifest: %w", err) + } + + if err := newManifest.Load(ctx, adtStore); err != nil { + return cid.Undef, xerrors.Errorf("error loading actor manifest: %w", err) + } + + // Maps prior version code CIDs to migration functions. + migrations := make(map[cid.Cid]migration.ActorMigration) + // Set of prior version code CIDs for actors to defer during iteration, for explicit migration afterwards. + deferredCodeIDs := make(map[cid.Cid]struct{}) + + for _, oldEntry := range oldManifestData.Entries { + newCodeCID, ok := newManifest.Get(oldEntry.Name) + if !ok { + return cid.Undef, xerrors.Errorf("code cid for %s actor not found in new manifest", oldEntry.Name) + } + migrations[oldEntry.Code] = migration.CachedMigration(cache, migration.CodeMigrator{OutCodeCID: newCodeCID}) + } + + // migrations that migrate both code and state, override entries in `migrations` + + // The System Actor + + newSystemCodeCID, ok := newManifest.Get(manifest.SystemKey) + if !ok { + return cid.Undef, xerrors.Errorf("code cid for system actor not found in new manifest") + } + + migrations[systemActor.Code] = systemActorMigrator{OutCodeCID: newSystemCodeCID, ManifestData: newManifest.Data} + + if len(migrations)+len(deferredCodeIDs) != len(oldManifestData.Entries) { + return cid.Undef, xerrors.Errorf("incomplete migration specification with %d code CIDs, need %d", len(migrations)+len(deferredCodeIDs), len(oldManifestData.Entries)) + } + + actorsOut, err := migration.RunMigration(ctx, cfg, cache, store, log, actorsIn, migrations) + if err != nil { + return cid.Undef, xerrors.Errorf("failed to run migration: %w", err) + } + + outCid, err := actorsOut.Flush() + if err != nil { + return cid.Undef, xerrors.Errorf("failed to flush actorsOut: %w", err) + } + + return outCid, nil +}