From 10d4c252e648f2df002c381ad07a64a68973922c Mon Sep 17 00:00:00 2001 From: simlecode <69969590+simlecode@users.noreply.github.com> Date: Thu, 9 Nov 2023 09:43:53 +0800 Subject: [PATCH] fix: nv21fix migration: correctly upgrade system actor --- pkg/fork/fork.go | 34 +++++++++++++++++++++++++--------- pkg/fvm/fvm.go | 18 ++++++++++++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/pkg/fork/fork.go b/pkg/fork/fork.go index 0151f2f279..0aac30c3bb 100644 --- a/pkg/fork/fork.go +++ b/pkg/fork/fork.go @@ -643,16 +643,19 @@ func (c *ChainFork) HandleStateForks(ctx context.Context, root cid.Cid, height a retCid := root u := c.stateMigrations[height] if u != nil && u.upgrade != nil { - migCid, ok, err := u.migrationResultCache.Get(ctx, root) - if err == nil && ok && !constants.NoMigrationResultCache { - log.Infow("CACHED migration", "height", height, "from", root, "to", migCid) - return migCid, nil - } else if !errors.Is(err, dstore.ErrNotFound) { - log.Errorw("failed to lookup previous migration result", "err", err) - } else { - log.Debug("no cached migration found, migrating from scratch") + if height != c.forkUpgrade.UpgradeWatermelonFixHeight { + migCid, ok, err := u.migrationResultCache.Get(ctx, root) + if err == nil && ok && !constants.NoMigrationResultCache { + log.Infow("CACHED migration", "height", height, "from", root, "to", migCid) + return migCid, nil + } else if !errors.Is(err, dstore.ErrNotFound) { + log.Errorw("failed to lookup previous migration result", "err", err) + } else { + log.Debug("no cached migration found, migrating from scratch") + } } + var err error startTime := time.Now() log.Warnw("STARTING migration", "height", height, "from", root) // Yes, we clone the cache, even for the final upgrade epoch. Why? Reverts. We may @@ -2907,6 +2910,19 @@ func (c *ChainFork) upgradeActorsV12Fix(ctx context.Context, return cid.Undef, fmt.Errorf("failed to perform migration: %w", err) } + systemState.BuiltinActors = newManifest.Data + newSystemHead, err := adtStore.Put(ctx, &systemState) + if err != nil { + return cid.Undef, fmt.Errorf("failed to put new system state: %w", err) + } + + systemActor.Head = newSystemHead + if err = actorsOut.SetActor(ctx, builtin.SystemActorAddr, systemActor); err != nil { + return cid.Undef, fmt.Errorf("failed to put new system actor: %w", err) + } + + // Sanity checking + err = actorsIn.ForEach(func(a address.Address, inActor *types.Actor) error { outActor, found, err := actorsOut.GetActor(ctx, a) if err != nil { @@ -2928,7 +2944,7 @@ func (c *ChainFork) upgradeActorsV12Fix(ctx context.Context, return fmt.Errorf("mismatched address for actor %s: %s != %s", a, inActor.Address, outActor.Address) } - if inActor.Head != outActor.Head { + if inActor.Head != outActor.Head && a != builtin.SystemActorAddr { return fmt.Errorf("mismatched head for actor %s", a) } diff --git a/pkg/fvm/fvm.go b/pkg/fvm/fvm.go index 9b74fcfd95..af1a0d3dc7 100644 --- a/pkg/fvm/fvm.go +++ b/pkg/fvm/fvm.go @@ -20,6 +20,7 @@ import ( "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/venus/pkg/config" "github.com/filecoin-project/venus/pkg/constants" "github.com/filecoin-project/venus/pkg/crypto" "github.com/filecoin-project/venus/pkg/state/tree" @@ -70,6 +71,11 @@ func (x *FvmExtern) TipsetCid(ctx context.Context, epoch abi.ChainEpoch) (cid.Ci return tsk.Cid() } +// todo: remove after nv21? +// https://github.com/filecoin-project/lotus/pull/11399 +var upgradeWatermelonFixHeight = abi.ChainEpoch(-1) +var setUpgradeWatermelonFixHeightOnce sync.Once + // VerifyConsensusFault is similar to the one in syscalls.go used by the LegacyVM, except it never errors // Errors are logged and "no fault" is returned, which is functionally what go-actors does anyway func (x *FvmExtern) VerifyConsensusFault(ctx context.Context, a, b, extra []byte) (*ffi_cgo.ConsensusFault, int64) { @@ -102,6 +108,14 @@ func (x *FvmExtern) VerifyConsensusFault(ctx context.Context, a, b, extra []byte fvmLog.Infof("invalid consensus fault: submitted blocks are the same") return ret, totalGas } + + if config.IsNearUpgrade(blockA.Height, upgradeWatermelonFixHeight) { + return ret, totalGas + } + if config.IsNearUpgrade(blockB.Height, upgradeWatermelonFixHeight) { + return ret, totalGas + } + // (1) check conditions necessary to any consensus fault // were blocks mined by same miner? @@ -288,6 +302,10 @@ func defaultFVMOpts(ctx context.Context, opts *vm.VmOption) (*ffi.FVMOpts, error } func NewFVM(ctx context.Context, opts *vm.VmOption) (*FVM, error) { + setUpgradeWatermelonFixHeightOnce.Do(func() { + upgradeWatermelonFixHeight = opts.Fork.GetForkUpgrade().UpgradeWatermelonFixHeight + }) + fvmOpts, err := defaultFVMOpts(ctx, opts) if err != nil { return nil, fmt.Errorf("creating fvm opts: %w", err)