2020-01-23 15:38:01 +00:00
|
|
|
package sealing
|
|
|
|
|
|
|
|
import (
|
2020-01-23 17:34:04 +00:00
|
|
|
"bytes"
|
2020-01-23 15:38:01 +00:00
|
|
|
"fmt"
|
2020-02-11 23:29:45 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2020-01-23 15:38:01 +00:00
|
|
|
"time"
|
|
|
|
|
2020-01-23 17:34:04 +00:00
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
2020-01-23 15:38:01 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2020-01-23 17:34:04 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors"
|
2020-01-23 15:38:01 +00:00
|
|
|
"github.com/filecoin-project/lotus/lib/statemachine"
|
|
|
|
)
|
|
|
|
|
|
|
|
const minRetryTime = 1 * time.Minute
|
|
|
|
|
|
|
|
func failedCooldown(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
retryStart := time.Unix(int64(sector.Log[len(sector.Log)-1].Timestamp), 0).Add(minRetryTime)
|
|
|
|
if len(sector.Log) > 0 && !time.Now().After(retryStart) {
|
2020-01-23 15:57:14 +00:00
|
|
|
log.Infof("%s(%d), waiting %s before retrying", api.SectorStates[sector.State], sector.SectorID, time.Until(retryStart))
|
2020-01-23 15:38:01 +00:00
|
|
|
select {
|
|
|
|
case <-time.After(time.Until(retryStart)):
|
|
|
|
case <-ctx.Context().Done():
|
|
|
|
return ctx.Context().Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-01-23 17:34:04 +00:00
|
|
|
func (m *Sealing) checkPreCommitted(ctx statemachine.Context, sector SectorInfo) (*actors.PreCommittedSector, bool) {
|
2020-02-11 23:29:45 +00:00
|
|
|
act, err := m.api.StateGetActor(ctx.Context(), m.maddr, types.EmptyTSK)
|
2020-01-23 15:38:01 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("handleSealFailed(%d): temp error: %+v", sector.SectorID, err)
|
2020-01-23 17:34:04 +00:00
|
|
|
return nil, true
|
2020-01-23 15:38:01 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 17:34:04 +00:00
|
|
|
st, err := m.api.ChainReadObj(ctx.Context(), act.Head)
|
2020-01-23 15:38:01 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Errorf("handleSealFailed(%d): temp error: %+v", sector.SectorID, err)
|
2020-01-23 17:34:04 +00:00
|
|
|
return nil, true
|
|
|
|
}
|
|
|
|
|
|
|
|
var state actors.StorageMinerActorState
|
|
|
|
if err := state.UnmarshalCBOR(bytes.NewReader(st)); err != nil {
|
|
|
|
log.Errorf("handleSealFailed(%d): temp error: unmarshaling miner state: %+v", sector.SectorID, err)
|
|
|
|
return nil, true
|
2020-01-23 15:38:01 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 17:34:04 +00:00
|
|
|
pci, found := state.PreCommittedSectors[fmt.Sprint(sector.SectorID)]
|
2020-01-23 15:38:01 +00:00
|
|
|
if found {
|
|
|
|
// TODO: If not expired yet, we can just try reusing sealticket
|
2020-01-24 00:53:52 +00:00
|
|
|
log.Warnf("sector %d found in miner preseal array", sector.SectorID)
|
2020-01-23 17:34:04 +00:00
|
|
|
return pci, true
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Sealing) handleSealFailed(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
|
|
|
|
if _, is := m.checkPreCommitted(ctx, sector); is {
|
|
|
|
// TODO: Remove this after we can re-precommit
|
|
|
|
return nil // noop, for now
|
2020-01-23 15:38:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := failedCooldown(ctx, sector); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorRetrySeal{})
|
|
|
|
}
|
2020-01-23 17:34:04 +00:00
|
|
|
|
|
|
|
func (m *Sealing) handlePreCommitFailed(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
if err := checkSeal(ctx.Context(), m.maddr, sector, m.api); err != nil {
|
|
|
|
switch err.(type) {
|
|
|
|
case *ErrApi:
|
|
|
|
log.Errorf("handlePreCommitFailed: api error, not proceeding: %+v", err)
|
|
|
|
return nil
|
|
|
|
case *ErrBadCommD: // TODO: Should this just back to packing? (not really needed since handleUnsealed will do that too)
|
|
|
|
return ctx.Send(SectorSealFailed{xerrors.Errorf("bad CommD error: %w", err)})
|
|
|
|
case *ErrExpiredTicket:
|
2020-01-23 17:45:57 +00:00
|
|
|
return ctx.Send(SectorSealFailed{xerrors.Errorf("ticket expired error: %w", err)})
|
2020-01-23 17:34:04 +00:00
|
|
|
default:
|
|
|
|
return xerrors.Errorf("checkSeal sanity check error: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if pci, is := m.checkPreCommitted(ctx, sector); is && pci != nil {
|
|
|
|
if sector.PreCommitMessage != nil {
|
|
|
|
log.Warn("sector %d is precommitted on chain, but we don't have precommit message", sector.SectorID)
|
|
|
|
return nil // TODO: SeedWait needs this currently
|
|
|
|
}
|
|
|
|
|
|
|
|
if string(pci.Info.CommR) != string(sector.CommR) {
|
|
|
|
log.Warn("sector %d is precommitted on chain, with different CommR: %x != %x", sector.SectorID, pci.Info.CommR, sector.CommR)
|
|
|
|
return nil // TODO: remove when the actor allows re-precommit
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: we could compare more things, but I don't think we really need to
|
|
|
|
// CommR tells us that CommD (and CommPs), and the ticket are all matching
|
|
|
|
|
|
|
|
if err := failedCooldown(ctx, sector); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorRetryWaitSeed{})
|
|
|
|
}
|
|
|
|
|
|
|
|
if sector.PreCommitMessage != nil {
|
|
|
|
log.Warn("retrying precommit even though the message failed to apply")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := failedCooldown(ctx, sector); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorRetryPreCommit{})
|
|
|
|
}
|