diff --git a/pkg/chainsync/syncer/syncer.go b/pkg/chainsync/syncer/syncer.go index bcf0dbe55b..ced8977138 100644 --- a/pkg/chainsync/syncer/syncer.go +++ b/pkg/chainsync/syncer/syncer.go @@ -7,9 +7,11 @@ import ( "sync/atomic" "time" + "github.com/filecoin-project/venus/pkg/consensus" "github.com/filecoin-project/venus/pkg/crypto" "github.com/filecoin-project/venus/pkg/repo" "github.com/filecoin-project/venus/pkg/statemanger" + "github.com/hashicorp/go-multierror" "github.com/ipfs-force-community/metrics" "golang.org/x/sync/errgroup" @@ -216,6 +218,24 @@ func (syncer *Syncer) syncOne(ctx context.Context, parent, next *types.TipSet) e } err = wg.Wait() if err != nil { + var rootNotMatch bool // nolint + + if merr, isok := err.(*multierror.Error); isok { + for _, e := range merr.Errors { + if isRootNotMatch(e) { + rootNotMatch = true + break + } + } + } else { + rootNotMatch = isRootNotMatch(err) // nolint + } + + if rootNotMatch { // nolint + // todo: should here rollback, and re-compute? + _ = syncer.stmgr.Rollback(ctx, parent, next) + } + return fmt.Errorf("validate mining failed %w", err) } } @@ -241,6 +261,10 @@ func (syncer *Syncer) syncOne(ctx context.Context, parent, next *types.TipSet) e return nil } +func isRootNotMatch(err error) bool { + return errors.Is(err, consensus.ErrStateRootMismatch) || errors.Is(err, consensus.ErrReceiptRootMismatch) +} + // HandleNewTipSet validates and syncs the chain rooted at the provided tipset // to a chain bsstore. Iff catchup is false then the syncer will set the head. func (syncer *Syncer) HandleNewTipSet(ctx context.Context, target *syncTypes.Target) (err error) { diff --git a/pkg/statemanger/state_manger.go b/pkg/statemanger/state_manger.go index aa6741d1b0..eebb769ebc 100644 --- a/pkg/statemanger/state_manger.go +++ b/pkg/statemanger/state_manger.go @@ -228,28 +228,17 @@ func (s *Stmgr) TipsetState(ctx context.Context, ts *types.TipSet) (*tree.State, // deprecated: this implementation needs more considerations func (s *Stmgr) Rollback(ctx context.Context, pts, cts *types.TipSet) error { - log.Infof("rollback chain head from(%d) to a valid tipset", pts.Height()) -redo: + log.Infof("rollback chain head from(%d)", pts.Height()) s.stLk.Lock() + defer s.stLk.Unlock() + if err := s.cs.DeleteTipSetMetadata(ctx, pts); err != nil { - s.stLk.Unlock() return err } if err := s.cs.SetHead(ctx, pts); err != nil { - s.stLk.Unlock() return err } - s.stLk.Unlock() - if root, _, err := s.RunStateTransition(ctx, pts, nil, false); err != nil { - return err - } else if !root.Equals(cts.At(0).ParentStateRoot) { - cts = pts - if pts, err = s.cs.GetTipSet(ctx, cts.Parents()); err != nil { - return err - } - goto redo - } return nil }