2020-06-22 16:42:38 +00:00
|
|
|
package sealing
|
|
|
|
|
|
|
|
import (
|
2021-01-12 23:42:01 +00:00
|
|
|
"time"
|
|
|
|
|
2020-06-22 16:42:38 +00:00
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
2021-01-12 23:42:01 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/exitcode"
|
2020-06-22 16:42:38 +00:00
|
|
|
"github.com/filecoin-project/go-statemachine"
|
2021-01-12 23:42:01 +00:00
|
|
|
"github.com/filecoin-project/lotus/build"
|
|
|
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
2020-06-22 16:42:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (m *Sealing) handleFaulty(ctx statemachine.Context, sector SectorInfo) error {
|
2020-06-22 16:44:28 +00:00
|
|
|
// TODO: noop because this is now handled by the PoSt scheduler. We can reuse
|
|
|
|
// this state for tracking faulty sectors, or remove it when that won't be
|
|
|
|
// a breaking change
|
|
|
|
return nil
|
2020-06-22 16:42:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Sealing) handleFaultReported(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
if sector.FaultReportMsg == nil {
|
|
|
|
return xerrors.Errorf("entered fault reported state without a FaultReportMsg cid")
|
|
|
|
}
|
|
|
|
|
|
|
|
mw, err := m.api.StateWaitMsg(ctx.Context(), *sector.FaultReportMsg)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to wait for fault declaration: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if mw.Receipt.ExitCode != 0 {
|
|
|
|
log.Errorf("UNHANDLED: declaring sector fault failed (exit=%d, msg=%s) (id: %d)", mw.Receipt.ExitCode, *sector.FaultReportMsg, sector.SectorNumber)
|
|
|
|
return xerrors.Errorf("UNHANDLED: submitting fault declaration failed (exit %d)", mw.Receipt.ExitCode)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorFaultedFinal{})
|
|
|
|
}
|
|
|
|
|
2021-01-12 23:42:01 +00:00
|
|
|
func (m *Sealing) handleTerminating(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
// First step of sector termination
|
|
|
|
// * See if sector is live
|
|
|
|
// * If not, goto removing
|
|
|
|
// * Add to termination queue
|
|
|
|
// * Wait for message to land on-chain
|
|
|
|
// * Check for correct termination
|
|
|
|
// * wait for expiration (+winning lookback?)
|
|
|
|
|
|
|
|
si, err := m.api.StateSectorGetInfo(ctx.Context(), m.maddr, sector.SectorNumber, nil)
|
|
|
|
if err != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("getting sector info: %w", err)})
|
|
|
|
}
|
|
|
|
|
|
|
|
if si == nil {
|
|
|
|
// either already terminated or not committed yet
|
2021-01-14 14:46:57 +00:00
|
|
|
|
2021-01-14 15:13:32 +00:00
|
|
|
pci, err := m.api.StateSectorPreCommitInfo(ctx.Context(), m.maddr, sector.SectorNumber, nil)
|
2021-01-14 14:46:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("checking precommit presence: %w", err)})
|
|
|
|
}
|
|
|
|
if pci != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("sector was precommitted but not proven, remove instead of terminating")})
|
|
|
|
}
|
|
|
|
|
2021-01-13 23:11:41 +00:00
|
|
|
return ctx.Send(SectorRemove{})
|
2021-01-12 23:42:01 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 16:14:26 +00:00
|
|
|
termCid, terminated, err := m.terminator.AddTermination(ctx.Context(), m.minerSectorID(sector.SectorNumber))
|
2021-01-12 23:42:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("queueing termination: %w", err)})
|
|
|
|
}
|
|
|
|
|
2021-01-14 16:14:26 +00:00
|
|
|
if terminated {
|
|
|
|
return ctx.Send(SectorTerminating{Message: nil})
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorTerminating{Message: &termCid})
|
2021-01-12 23:42:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Sealing) handleTerminateWait(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
if sector.TerminateMessage == nil {
|
|
|
|
return xerrors.New("entered TerminateWait with nil TerminateMessage")
|
|
|
|
}
|
|
|
|
|
|
|
|
mw, err := m.api.StateWaitMsg(ctx.Context(), *sector.TerminateMessage)
|
|
|
|
if err != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("waiting for terminate message to land on chain: %w", err)})
|
|
|
|
}
|
|
|
|
|
|
|
|
if mw.Receipt.ExitCode != exitcode.Ok {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("terminate message failed to execute: exit %d: %w", mw.Receipt.ExitCode, err)})
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorTerminated{TerminatedAt: mw.Height})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Sealing) handleTerminateFinality(ctx statemachine.Context, sector SectorInfo) error {
|
|
|
|
for {
|
|
|
|
tok, epoch, err := m.api.ChainHead(ctx.Context())
|
|
|
|
if err != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("getting chain head: %w", err)})
|
|
|
|
}
|
|
|
|
|
|
|
|
nv, err := m.api.StateNetworkVersion(ctx.Context(), tok)
|
|
|
|
if err != nil {
|
|
|
|
return ctx.Send(SectorTerminateFailed{xerrors.Errorf("getting network version: %w", err)})
|
|
|
|
}
|
|
|
|
|
|
|
|
if epoch >= sector.TerminatedAt+policy.GetWinningPoStSectorSetLookback(nv) {
|
|
|
|
return ctx.Send(SectorRemove{})
|
|
|
|
}
|
|
|
|
|
|
|
|
toWait := time.Duration(epoch-sector.TerminatedAt+policy.GetWinningPoStSectorSetLookback(nv)) * time.Duration(build.BlockDelaySecs) * time.Second
|
|
|
|
select {
|
|
|
|
case <-time.After(toWait):
|
|
|
|
continue
|
|
|
|
case <-ctx.Context().Done():
|
|
|
|
return ctx.Context().Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-22 16:42:38 +00:00
|
|
|
func (m *Sealing) handleRemoving(ctx statemachine.Context, sector SectorInfo) error {
|
2020-11-04 20:29:08 +00:00
|
|
|
if err := m.sealer.Remove(ctx.Context(), m.minerSector(sector.SectorType, sector.SectorNumber)); err != nil {
|
2020-06-22 16:42:38 +00:00
|
|
|
return ctx.Send(SectorRemoveFailed{err})
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx.Send(SectorRemoved{})
|
|
|
|
}
|