2024-03-15 21:38:13 +00:00
package seal
2024-01-11 18:24:28 +00:00
import (
"bytes"
"context"
2024-05-22 08:08:32 +00:00
"encoding/json"
2024-05-07 11:03:51 +00:00
"fmt"
2024-01-12 10:03:37 +00:00
"golang.org/x/xerrors"
2024-01-11 18:24:28 +00:00
"github.com/filecoin-project/go-address"
2024-05-22 08:08:32 +00:00
cborutil "github.com/filecoin-project/go-cbor-util"
2024-01-11 18:24:28 +00:00
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/builtin"
2024-05-22 08:08:32 +00:00
miner2 "github.com/filecoin-project/go-state-types/builtin/v13/miner"
verifreg13 "github.com/filecoin-project/go-state-types/builtin/v13/verifreg"
verifregtypes9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
2024-01-12 10:03:37 +00:00
2024-01-11 18:24:28 +00:00
"github.com/filecoin-project/lotus/api"
2024-05-22 08:08:32 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
2024-01-11 18:24:28 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types"
2024-03-15 21:38:13 +00:00
"github.com/filecoin-project/lotus/curiosrc/message"
"github.com/filecoin-project/lotus/curiosrc/multictladdr"
2024-01-11 18:24:28 +00:00
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/lib/harmony/harmonytask"
"github.com/filecoin-project/lotus/lib/harmony/resources"
2024-05-22 08:08:32 +00:00
"github.com/filecoin-project/lotus/node/config"
2024-01-11 18:24:28 +00:00
"github.com/filecoin-project/lotus/storage/ctladdr"
)
type SubmitCommitAPI interface {
ChainHead ( context . Context ) ( * types . TipSet , error )
StateMinerInfo ( context . Context , address . Address , types . TipSetKey ) ( api . MinerInfo , error )
StateMinerInitialPledgeCollateral ( context . Context , address . Address , miner . SectorPreCommitInfo , types . TipSetKey ) ( big . Int , error )
StateSectorPreCommitInfo ( context . Context , address . Address , abi . SectorNumber , types . TipSetKey ) ( * miner . SectorPreCommitOnChainInfo , error )
2024-05-22 08:08:32 +00:00
StateGetAllocation ( ctx context . Context , clientAddr address . Address , allocationId verifregtypes9 . AllocationId , tsk types . TipSetKey ) ( * verifregtypes9 . Allocation , error )
StateGetAllocationIdForPendingDeal ( ctx context . Context , dealId abi . DealID , tsk types . TipSetKey ) ( verifregtypes9 . AllocationId , error )
2024-01-11 18:24:28 +00:00
ctladdr . NodeApi
}
2024-05-22 08:08:32 +00:00
type commitConfig struct {
maxFee types . FIL
RequireActivationSuccess bool
RequireNotificationSuccess bool
}
2024-01-11 18:24:28 +00:00
type SubmitCommitTask struct {
sp * SealPoller
db * harmonydb . DB
api SubmitCommitAPI
2024-03-15 21:38:13 +00:00
sender * message . Sender
2024-02-16 20:27:15 +00:00
as * multictladdr . MultiAddressSelector
2024-05-22 08:08:32 +00:00
cfg commitConfig
2024-01-11 18:24:28 +00:00
}
2024-05-22 08:08:32 +00:00
func NewSubmitCommitTask ( sp * SealPoller , db * harmonydb . DB , api SubmitCommitAPI , sender * message . Sender , as * multictladdr . MultiAddressSelector , cfg * config . CurioConfig ) * SubmitCommitTask {
cnfg := commitConfig {
maxFee : cfg . Fees . MaxCommitGasFee ,
RequireActivationSuccess : cfg . Subsystems . RequireActivationSuccess ,
RequireNotificationSuccess : cfg . Subsystems . RequireNotificationSuccess ,
}
2024-01-11 18:24:28 +00:00
return & SubmitCommitTask {
sp : sp ,
db : db ,
api : api ,
sender : sender ,
as : as ,
2024-05-22 08:08:32 +00:00
cfg : cnfg ,
2024-01-11 18:24:28 +00:00
}
}
func ( s * SubmitCommitTask ) Do ( taskID harmonytask . TaskID , stillOwned func ( ) bool ) ( done bool , err error ) {
ctx := context . Background ( )
var sectorParamsArr [ ] struct {
SpID int64 ` db:"sp_id" `
SectorNumber int64 ` db:"sector_number" `
Proof [ ] byte ` db:"porep_proof" `
}
err = s . db . Select ( ctx , & sectorParamsArr , `
SELECT sp_id , sector_number , porep_proof
FROM sectors_sdr_pipeline
WHERE task_id_commit_msg = $ 1 ` , taskID )
if err != nil {
return false , xerrors . Errorf ( "getting sector params: %w" , err )
}
if len ( sectorParamsArr ) != 1 {
return false , xerrors . Errorf ( "expected 1 sector params, got %d" , len ( sectorParamsArr ) )
}
sectorParams := sectorParamsArr [ 0 ]
2024-05-22 08:08:32 +00:00
var pieces [ ] struct {
PieceIndex int64 ` db:"piece_index" `
PieceCID string ` db:"piece_cid" `
PieceSize int64 ` db:"piece_size" `
Proposal json . RawMessage ` db:"f05_deal_proposal" `
Manifest json . RawMessage ` db:"direct_piece_activation_manifest" `
DealID abi . DealID ` db:"f05_deal_id" `
2024-01-11 18:24:28 +00:00
}
2024-05-22 08:08:32 +00:00
err = s . db . Select ( ctx , & pieces , `
SELECT piece_index ,
piece_cid ,
piece_size ,
f05_deal_proposal ,
direct_piece_activation_manifest ,
COALESCE ( f05_deal_id , 0 ) AS f05_deal_id
FROM sectors_sdr_initial_pieces
WHERE sp_id = $ 1 AND sector_number = $ 2 ORDER BY piece_index ASC ` , sectorParams . SpID , sectorParams . SectorNumber )
if err != nil {
return false , xerrors . Errorf ( "getting pieces: %w" , err )
2024-01-11 18:24:28 +00:00
}
2024-05-22 08:08:32 +00:00
maddr , err := address . NewIDAddress ( uint64 ( sectorParams . SpID ) )
if err != nil {
return false , xerrors . Errorf ( "getting miner address: %w" , err )
2024-01-11 18:24:28 +00:00
}
ts , err := s . api . ChainHead ( ctx )
if err != nil {
return false , xerrors . Errorf ( "getting chain head: %w" , err )
}
pci , err := s . api . StateSectorPreCommitInfo ( ctx , maddr , abi . SectorNumber ( sectorParams . SectorNumber ) , ts . Key ( ) )
if err != nil {
return false , xerrors . Errorf ( "getting precommit info: %w" , err )
}
if pci == nil {
return false , xerrors . Errorf ( "precommit info not found on chain" )
}
2024-05-22 08:08:32 +00:00
mi , err := s . api . StateMinerInfo ( ctx , maddr , types . EmptyTSK )
if err != nil {
return false , xerrors . Errorf ( "getting miner info: %w" , err )
}
params := miner . ProveCommitSectors3Params {
RequireActivationSuccess : s . cfg . RequireActivationSuccess ,
RequireNotificationSuccess : s . cfg . RequireNotificationSuccess ,
}
var pams [ ] miner . PieceActivationManifest
for _ , piece := range pieces {
if piece . Proposal != nil {
var prop * market . DealProposal
err = json . Unmarshal ( piece . Proposal , & prop )
if err != nil {
return false , xerrors . Errorf ( "marshalling json to deal proposal: %w" , err )
}
alloc , err := s . api . StateGetAllocationIdForPendingDeal ( ctx , piece . DealID , types . EmptyTSK )
if err != nil {
return false , xerrors . Errorf ( "getting allocation for deal %d: %w" , piece . DealID , err )
}
clid , err := s . api . StateLookupID ( ctx , prop . Client , types . EmptyTSK )
if err != nil {
return false , xerrors . Errorf ( "getting client address for deal %d: %w" , piece . DealID , err )
}
clientId , err := address . IDFromAddress ( clid )
if err != nil {
return false , xerrors . Errorf ( "getting client address for deal %d: %w" , piece . DealID , err )
}
var vac * miner2 . VerifiedAllocationKey
if alloc != verifregtypes9 . NoAllocationID {
vac = & miner2 . VerifiedAllocationKey {
Client : abi . ActorID ( clientId ) ,
ID : verifreg13 . AllocationId ( alloc ) ,
}
}
payload , err := cborutil . Dump ( piece . DealID )
if err != nil {
return false , xerrors . Errorf ( "serializing deal id: %w" , err )
}
pams = append ( pams , miner . PieceActivationManifest {
CID : prop . PieceCID ,
Size : prop . PieceSize ,
VerifiedAllocationKey : vac ,
Notify : [ ] miner2 . DataActivationNotification {
{
Address : market . Address ,
Payload : payload ,
} ,
} ,
} )
} else {
var pam * miner . PieceActivationManifest
err = json . Unmarshal ( piece . Manifest , & pam )
if err != nil {
return false , xerrors . Errorf ( "marshalling json to PieceManifest: %w" , err )
}
err = s . allocationCheck ( ctx , pam , pci , abi . ActorID ( sectorParams . SpID ) , ts )
if err != nil {
return false , err
}
pams = append ( pams , * pam )
}
}
params . SectorActivations = append ( params . SectorActivations , miner . SectorActivationManifest {
SectorNumber : abi . SectorNumber ( sectorParams . SectorNumber ) ,
Pieces : pams ,
} )
params . SectorProofs = append ( params . SectorProofs , sectorParams . Proof )
enc := new ( bytes . Buffer )
if err := params . MarshalCBOR ( enc ) ; err != nil {
return false , xerrors . Errorf ( "could not serialize commit params: %w" , err )
}
2024-01-11 18:24:28 +00:00
collateral , err := s . api . StateMinerInitialPledgeCollateral ( ctx , maddr , pci . Info , ts . Key ( ) )
if err != nil {
return false , xerrors . Errorf ( "getting initial pledge collateral: %w" , err )
}
collateral = big . Sub ( collateral , pci . PreCommitDeposit )
if collateral . LessThan ( big . Zero ( ) ) {
collateral = big . Zero ( )
}
2024-02-16 20:27:15 +00:00
a , _ , err := s . as . AddressFor ( ctx , s . api , maddr , mi , api . CommitAddr , collateral , big . Zero ( ) )
2024-01-11 18:24:28 +00:00
if err != nil {
return false , xerrors . Errorf ( "getting address for precommit: %w" , err )
}
msg := & types . Message {
To : maddr ,
From : a ,
2024-05-22 08:08:32 +00:00
Method : builtin . MethodsMiner . ProveCommitSectors3 ,
2024-01-11 18:24:28 +00:00
Params : enc . Bytes ( ) ,
Value : collateral , // todo config for pulling from miner balance!!
}
mss := & api . MessageSendSpec {
2024-05-22 08:08:32 +00:00
MaxFee : abi . TokenAmount ( s . cfg . maxFee ) ,
2024-01-11 18:24:28 +00:00
}
mcid , err := s . sender . Send ( ctx , msg , mss , "commit" )
if err != nil {
return false , xerrors . Errorf ( "pushing message to mpool: %w" , err )
}
2024-05-15 15:40:40 +00:00
_ , err = s . db . Exec ( ctx , ` UPDATE sectors_sdr_pipeline SET commit_msg_cid = $1, after_commit_msg = TRUE, task_id_commit_msg = NULL WHERE sp_id = $2 AND sector_number = $3 ` , mcid , sectorParams . SpID , sectorParams . SectorNumber )
2024-01-11 18:24:28 +00:00
if err != nil {
return false , xerrors . Errorf ( "updating commit_msg_cid: %w" , err )
}
_ , err = s . db . Exec ( ctx , ` INSERT INTO message_waits (signed_message_cid) VALUES ($1) ` , mcid )
if err != nil {
return false , xerrors . Errorf ( "inserting into message_waits: %w" , err )
}
2024-05-07 11:03:51 +00:00
if err := s . transferFinalizedSectorData ( ctx , sectorParams . SpID , sectorParams . SectorNumber ) ; err != nil {
return false , xerrors . Errorf ( "transferring finalized sector data: %w" , err )
}
2024-01-11 18:24:28 +00:00
return true , nil
}
2024-05-07 11:03:51 +00:00
func ( s * SubmitCommitTask ) transferFinalizedSectorData ( ctx context . Context , spID , sectorNum int64 ) error {
if _ , err := s . db . Exec ( ctx , `
INSERT INTO sectors_meta (
sp_id ,
sector_num ,
reg_seal_proof ,
ticket_epoch ,
ticket_value ,
orig_sealed_cid ,
orig_unsealed_cid ,
cur_sealed_cid ,
cur_unsealed_cid ,
msg_cid_precommit ,
msg_cid_commit ,
seed_epoch ,
seed_value
)
SELECT
sp_id ,
sector_number as sector_num ,
reg_seal_proof ,
ticket_epoch ,
ticket_value ,
tree_r_cid as orig_sealed_cid ,
tree_d_cid as orig_unsealed_cid ,
tree_r_cid as cur_sealed_cid ,
tree_d_cid as cur_unsealed_cid ,
precommit_msg_cid ,
commit_msg_cid ,
seed_epoch ,
seed_value
FROM
sectors_sdr_pipeline
WHERE
sp_id = $ 1 AND
sector_number = $ 2
ON CONFLICT ( sp_id , sector_num ) DO UPDATE SET
reg_seal_proof = excluded . reg_seal_proof ,
ticket_epoch = excluded . ticket_epoch ,
ticket_value = excluded . ticket_value ,
orig_sealed_cid = excluded . orig_sealed_cid ,
cur_sealed_cid = excluded . cur_sealed_cid ,
msg_cid_precommit = excluded . msg_cid_precommit ,
msg_cid_commit = excluded . msg_cid_commit ,
seed_epoch = excluded . seed_epoch ,
seed_value = excluded . seed_value ;
` , spID , sectorNum ) ; err != nil {
return fmt . Errorf ( "failed to insert/update sectors_meta: %w" , err )
}
// Execute the query for piece metadata
if _ , err := s . db . Exec ( ctx , `
INSERT INTO sectors_meta_pieces (
sp_id ,
sector_num ,
piece_num ,
piece_cid ,
piece_size ,
requested_keep_data ,
raw_data_size ,
start_epoch ,
orig_end_epoch ,
f05_deal_id ,
ddo_pam
)
SELECT
sp_id ,
sector_number AS sector_num ,
piece_index AS piece_num ,
piece_cid ,
piece_size ,
not data_delete_on_finalize as requested_keep_data ,
data_raw_size ,
COALESCE ( f05_deal_start_epoch , direct_start_epoch ) as start_epoch ,
COALESCE ( f05_deal_end_epoch , direct_end_epoch ) as orig_end_epoch ,
f05_deal_id ,
direct_piece_activation_manifest as ddo_pam
FROM
sectors_sdr_initial_pieces
WHERE
sp_id = $ 1 AND
sector_number = $ 2
ON CONFLICT ( sp_id , sector_num , piece_num ) DO UPDATE SET
piece_cid = excluded . piece_cid ,
piece_size = excluded . piece_size ,
requested_keep_data = excluded . requested_keep_data ,
raw_data_size = excluded . raw_data_size ,
start_epoch = excluded . start_epoch ,
orig_end_epoch = excluded . orig_end_epoch ,
f05_deal_id = excluded . f05_deal_id ,
ddo_pam = excluded . ddo_pam ;
` , spID , sectorNum ) ; err != nil {
return fmt . Errorf ( "failed to insert/update sector_meta_pieces: %w" , err )
}
return nil
}
2024-01-11 18:24:28 +00:00
func ( s * SubmitCommitTask ) CanAccept ( ids [ ] harmonytask . TaskID , engine * harmonytask . TaskEngine ) ( * harmonytask . TaskID , error ) {
id := ids [ 0 ]
return & id , nil
}
func ( s * SubmitCommitTask ) TypeDetails ( ) harmonytask . TaskTypeDetails {
return harmonytask . TaskTypeDetails {
Max : 128 ,
Name : "CommitSubmit" ,
Cost : resources . Resources {
Cpu : 0 ,
Gpu : 0 ,
Ram : 1 << 20 ,
} ,
MaxFailures : 16 ,
}
}
func ( s * SubmitCommitTask ) Adder ( taskFunc harmonytask . AddTaskFunc ) {
s . sp . pollers [ pollerCommitMsg ] . Set ( taskFunc )
}
2024-05-22 08:08:32 +00:00
func ( s * SubmitCommitTask ) allocationCheck ( ctx context . Context , piece * miner . PieceActivationManifest , precomitInfo * miner . SectorPreCommitOnChainInfo , miner abi . ActorID , ts * types . TipSet ) error {
// skip pieces not claiming an allocation
if piece . VerifiedAllocationKey == nil {
return nil
}
addr , err := address . NewIDAddress ( uint64 ( piece . VerifiedAllocationKey . Client ) )
if err != nil {
return err
}
alloc , err := s . api . StateGetAllocation ( ctx , addr , verifregtypes9 . AllocationId ( piece . VerifiedAllocationKey . ID ) , ts . Key ( ) )
if err != nil {
return err
}
if alloc == nil {
return xerrors . Errorf ( "no allocation found for piece %s with allocation ID %d" , piece . CID . String ( ) , piece . VerifiedAllocationKey . ID )
}
if alloc . Provider != miner {
return xerrors . Errorf ( "provider id mismatch for piece %s: expected %d and found %d" , piece . CID . String ( ) , miner , alloc . Provider )
}
if alloc . Size != piece . Size {
return xerrors . Errorf ( "size mismatch for piece %s: expected %d and found %d" , piece . CID . String ( ) , piece . Size , alloc . Size )
}
if precomitInfo . Info . Expiration < ts . Height ( ) + alloc . TermMin {
return xerrors . Errorf ( "sector expiration %d is before than allocation TermMin %d for piece %s" , precomitInfo . Info . Expiration , ts . Height ( ) + alloc . TermMin , piece . CID . String ( ) )
}
if precomitInfo . Info . Expiration > ts . Height ( ) + alloc . TermMax {
return xerrors . Errorf ( "sector expiration %d is later than allocation TermMax %d for piece %s" , precomitInfo . Info . Expiration , ts . Height ( ) + alloc . TermMax , piece . CID . String ( ) )
}
return nil
}
2024-01-11 18:24:28 +00:00
var _ harmonytask . TaskInterface = & SubmitCommitTask { }