2020-01-20 22:03:50 +00:00
package sealing
import (
2020-02-23 00:47:47 +00:00
"bytes"
2020-01-20 22:03:50 +00:00
"context"
2020-02-25 20:35:15 +00:00
"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
2020-01-20 22:03:50 +00:00
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
2020-02-25 20:35:15 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
2020-01-23 14:05:44 +00:00
"github.com/filecoin-project/lotus/build"
2020-01-20 22:03:50 +00:00
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
2020-02-25 20:35:15 +00:00
"github.com/filecoin-project/lotus/lib/zerocomm"
2020-01-20 22:03:50 +00:00
)
2020-01-23 15:38:01 +00:00
// TODO: For now we handle this by halting state execution, when we get jsonrpc reconnecting
// We should implement some wait-for-api logic
2020-01-23 16:15:45 +00:00
type ErrApi struct { error }
2020-01-23 12:17:45 +00:00
2020-01-23 16:15:45 +00:00
type ErrInvalidDeals struct { error }
2020-02-23 00:47:47 +00:00
type ErrInvalidPiece struct { error }
2020-01-23 16:15:45 +00:00
type ErrExpiredDeals struct { error }
2020-01-23 12:17:45 +00:00
2020-01-23 16:15:45 +00:00
type ErrBadCommD struct { error }
type ErrExpiredTicket struct { error }
2020-01-23 14:05:44 +00:00
2020-01-24 20:15:02 +00:00
// checkPieces validates that:
// - Each piece han a corresponding on chain deal
// - Piece commitments match with on chain deals
// - Piece sizes match
// - Deals aren't expired
2020-01-22 19:47:29 +00:00
func checkPieces ( ctx context . Context , si SectorInfo , api sealingApi ) error {
2020-01-23 12:17:45 +00:00
head , err := api . ChainHead ( ctx )
if err != nil {
2020-01-23 15:57:14 +00:00
return & ErrApi { xerrors . Errorf ( "getting chain head: %w" , err ) }
2020-01-23 12:17:45 +00:00
}
2020-01-20 22:03:50 +00:00
for i , piece := range si . Pieces {
2020-02-23 00:47:47 +00:00
if piece . DealID == nil {
exp := zerocomm . ForSize ( piece . Size )
2020-02-27 00:42:39 +00:00
if piece . CommP != exp {
2020-02-23 00:47:47 +00:00
return & ErrInvalidPiece { xerrors . Errorf ( "deal %d piece %d had non-zero CommP %+v" , piece . DealID , i , piece . CommP ) }
}
continue
}
2020-02-24 17:32:02 +00:00
deal , err := api . StateMarketStorageDeal ( ctx , * piece . DealID , types . EmptyTSK )
2020-01-20 22:03:50 +00:00
if err != nil {
2020-01-23 15:57:14 +00:00
return & ErrApi { xerrors . Errorf ( "getting deal %d for piece %d: %w" , piece . DealID , i , err ) }
2020-01-20 22:03:50 +00:00
}
2020-02-27 00:42:39 +00:00
if deal . Proposal . PieceCID != piece . CommP {
return & ErrInvalidDeals { xerrors . Errorf ( "piece %d (or %d) of sector %d refers deal %d with wrong CommP: %x != %x" , i , len ( si . Pieces ) , si . SectorID , piece . DealID , piece . CommP , deal . Proposal . PieceCID ) }
2020-01-20 22:03:50 +00:00
}
2020-02-09 06:06:32 +00:00
if piece . Size != deal . Proposal . PieceSize . Unpadded ( ) {
return & ErrInvalidDeals { xerrors . Errorf ( "piece %d (or %d) of sector %d refers deal %d with different size: %d != %d" , i , len ( si . Pieces ) , si . SectorID , piece . DealID , piece . Size , deal . Proposal . PieceSize ) }
2020-01-23 12:17:45 +00:00
}
2020-02-09 06:06:32 +00:00
if head . Height ( ) >= deal . Proposal . StartEpoch {
return & ErrExpiredDeals { xerrors . Errorf ( "piece %d (or %d) of sector %d refers expired deal %d - should start at %d, head %d" , i , len ( si . Pieces ) , si . SectorID , piece . DealID , deal . Proposal . StartEpoch , head . Height ( ) ) }
2020-01-20 22:03:50 +00:00
}
}
return nil
}
2020-01-24 20:15:02 +00:00
// checkSeal checks that data commitment generated in the sealing process
// matches pieces, and that the seal ticket isn't expired
2020-01-22 19:47:29 +00:00
func checkSeal ( ctx context . Context , maddr address . Address , si SectorInfo , api sealingApi ) ( err error ) {
2020-01-23 14:05:44 +00:00
head , err := api . ChainHead ( ctx )
2020-01-20 22:03:50 +00:00
if err != nil {
2020-01-23 15:57:14 +00:00
return & ErrApi { xerrors . Errorf ( "getting chain head: %w" , err ) }
2020-01-23 14:05:44 +00:00
}
2020-02-25 20:35:15 +00:00
ccparams , err := actors . SerializeParams ( & market . ComputeDataCommitmentParams {
2020-01-20 22:03:50 +00:00
DealIDs : si . deals ( ) ,
2020-02-27 00:42:39 +00:00
SectorType : si . SectorType ,
2020-01-20 22:03:50 +00:00
} )
if err != nil {
return xerrors . Errorf ( "computing params for ComputeDataCommitment: %w" , err )
}
ccmt := & types . Message {
2020-02-25 20:54:58 +00:00
To : builtin . StorageMarketActorAddr ,
2020-01-22 19:47:29 +00:00
From : maddr ,
2020-01-20 22:03:50 +00:00
Value : types . NewInt ( 0 ) ,
GasPrice : types . NewInt ( 0 ) ,
GasLimit : types . NewInt ( 9999999999 ) ,
2020-02-11 02:33:27 +00:00
Method : builtin . MethodsMarket . ComputeDataCommitment ,
2020-01-20 22:03:50 +00:00
Params : ccparams ,
}
2020-02-11 23:29:45 +00:00
r , err := api . StateCall ( ctx , ccmt , types . EmptyTSK )
2020-01-20 22:03:50 +00:00
if err != nil {
2020-01-23 15:57:14 +00:00
return & ErrApi { xerrors . Errorf ( "calling ComputeDataCommitment: %w" , err ) }
2020-01-20 22:03:50 +00:00
}
if r . ExitCode != 0 {
2020-01-23 15:57:14 +00:00
return & ErrBadCommD { xerrors . Errorf ( "receipt for ComputeDataCommitment had exit code %d" , r . ExitCode ) }
2020-01-20 22:03:50 +00:00
}
2020-02-23 00:47:47 +00:00
var c cbg . CborCid
if err := c . UnmarshalCBOR ( bytes . NewReader ( r . Return ) ) ; err != nil {
return err
}
2020-02-27 00:42:39 +00:00
if cid . Cid ( c ) != * si . CommD {
2020-01-23 15:57:14 +00:00
return & ErrBadCommD { xerrors . Errorf ( "on chain CommD differs from sector: %x != %x" , r . Return , si . CommD ) }
2020-01-23 14:05:44 +00:00
}
2020-02-27 21:45:31 +00:00
if int64 ( head . Height ( ) ) - int64 ( si . Ticket . Epoch + build . SealRandomnessLookback ) > build . SealRandomnessLookbackLimit {
return & ErrExpiredTicket { xerrors . Errorf ( "ticket expired: seal height: %d, head: %d" , si . Ticket . Epoch + build . SealRandomnessLookback , head . Height ( ) ) }
2020-01-20 22:03:50 +00:00
}
return nil
}