diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 42425e782..73511e057 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -3,7 +3,6 @@ package sealing import ( "bytes" "context" - "github.com/filecoin-project/lotus/chain/actors/policy" proof2 "github.com/filecoin-project/specs-actors/v2/actors/runtime/proof" @@ -80,6 +79,24 @@ func checkPieces(ctx context.Context, maddr address.Address, si SectorInfo, api return nil } +func checkDealExpiration(ctx context.Context, sector SectorInfo, api SealingAPI) error { + tok, height, err := api.ChainHead(ctx) + if err != nil { + return &ErrApi{xerrors.Errorf("getting chain head: %w", err)} + } + + for i, p := range sector.Pieces { + proposal, err := api.StateMarketStorageDealProposal(ctx, p.DealInfo.DealID, tok) + if err != nil { + return &ErrInvalidDeals{xerrors.Errorf("getting deal %d for piece %d: %w", p.DealInfo.DealID, i, err)} + } + if height >= proposal.StartEpoch { + return &ErrExpiredDeals{xerrors.Errorf("piece %d (of %d) of sector %d refers expired deal %d - should start at %d, head %d", i, len(sector.Pieces), sector.SectorNumber, p.DealInfo.DealID, proposal.StartEpoch, height)} + } + } + return nil +} + // checkPrecommit checks that data commitment generated in the sealing process // matches pieces, and that the seal ticket isn't expired func checkPrecommit(ctx context.Context, maddr address.Address, si SectorInfo, tok TipSetToken, height abi.ChainEpoch, api SealingAPI) (err error) { diff --git a/extern/storage-sealing/states_replica_update.go b/extern/storage-sealing/states_replica_update.go index 28c5ede0b..7c237add5 100644 --- a/extern/storage-sealing/states_replica_update.go +++ b/extern/storage-sealing/states_replica_update.go @@ -2,7 +2,6 @@ package sealing import ( "bytes" - "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" statemachine "github.com/filecoin-project/go-statemachine" @@ -13,18 +12,7 @@ import ( func (m *Sealing) handleReplicaUpdate(ctx statemachine.Context, sector SectorInfo) error { if err := checkPieces(ctx.Context(), m.maddr, sector, m.Api); err != nil { // Sanity check state - switch err.(type) { - case *ErrApi: - log.Errorf("handleReplicaUpdate: api error, not proceeding: %+v", err) - return nil - case *ErrInvalidDeals: - log.Warnf("invalid deals in sector %d: %v", sector.SectorNumber, err) - return ctx.Send(SectorInvalidDealIDs{}) - case *ErrExpiredDeals: // Probably not much we can do here, maybe re-pack the sector? - return ctx.Send(SectorDealsExpired{xerrors.Errorf("expired dealIDs in sector: %w", err)}) - default: - return xerrors.Errorf("checkPieces sanity check error: %w", err) - } + return handleErrors(ctx, err, sector) } out, err := m.sealer.ReplicaUpdate(sector.sealingCtx(ctx.Context()), m.minerSector(sector.SectorType, sector.SectorNumber), sector.pieceInfos()) if err != nil { @@ -42,6 +30,11 @@ func (m *Sealing) handleProveReplicaUpdate(ctx statemachine.Context, sector Sect if sector.CommR == nil { return xerrors.Errorf("invalid sector %d with nil CommR", sector.SectorNumber) } + + if err := checkDealExpiration(ctx.Context(), sector, m.Api); err != nil { // Sanity check state + return handleErrors(ctx, err, sector) + } + vanillaProofs, err := m.sealer.ProveReplicaUpdate1(sector.sealingCtx(ctx.Context()), m.minerSector(sector.SectorType, sector.SectorNumber), *sector.CommR, *sector.UpdateSealed, *sector.UpdateUnsealed) if err != nil { return ctx.Send(SectorProveReplicaUpdateFailed{xerrors.Errorf("prove replica update (1) failed: %w", err)}) @@ -65,6 +58,10 @@ func (m *Sealing) handleSubmitReplicaUpdate(ctx statemachine.Context, sector Sec return nil } + if err := checkDealExpiration(ctx.Context(), sector, m.Api); err != nil { // Sanity check state + return handleErrors(ctx, err, sector) + } + if err := checkReplicaUpdate(ctx.Context(), m.maddr, sector, tok, m.Api); err != nil { return ctx.Send(SectorSubmitReplicaUpdateFailed{}) } @@ -207,3 +204,18 @@ func (m *Sealing) handleReplicaUpdateWait(ctx statemachine.Context, sector Secto func (m *Sealing) handleFinalizeReplicaUpdate(ctx statemachine.Context, sector SectorInfo) error { return ctx.Send(SectorFinalized{}) } + +func handleErrors(ctx statemachine.Context, err error, sector SectorInfo) error { + switch err.(type) { + case *ErrApi: + log.Errorf("handleReplicaUpdate: api error, not proceeding: %+v", err) + return nil + case *ErrInvalidDeals: + log.Warnf("invalid deals in sector %d: %v", sector.SectorNumber, err) + return ctx.Send(SectorInvalidDealIDs{}) + case *ErrExpiredDeals: // Probably not much we can do here, maybe re-pack the sector? + return ctx.Send(SectorDealsExpired{xerrors.Errorf("expired dealIDs in sector: %w", err)}) + default: + return xerrors.Errorf("checkPieces sanity check error: %w", err) + } +}