2024-01-19 15:07:06 +00:00
package fakelm
import (
"context"
2024-02-02 17:21:50 +00:00
"encoding/base64"
2024-01-20 14:52:38 +00:00
"net/http"
"net/url"
2024-02-11 13:08:54 +00:00
"github.com/BurntSushi/toml"
"github.com/gbrlsnchs/jwt/v3"
2024-01-20 14:52:38 +00:00
"github.com/google/uuid"
"golang.org/x/xerrors"
2024-01-19 15:07:06 +00:00
"github.com/filecoin-project/go-address"
2024-02-11 13:08:54 +00:00
"github.com/filecoin-project/go-jsonrpc/auth"
2024-01-19 15:07:06 +00:00
"github.com/filecoin-project/go-state-types/abi"
2024-02-11 13:08:54 +00:00
"github.com/filecoin-project/go-state-types/big"
2024-02-20 16:06:54 +00:00
"github.com/filecoin-project/go-state-types/network"
2024-01-20 14:52:38 +00:00
2024-01-19 15:07:06 +00:00
"github.com/filecoin-project/lotus/api"
2024-02-20 16:06:54 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
2024-02-11 13:08:54 +00:00
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/harmony/harmonydb"
"github.com/filecoin-project/lotus/node/config"
2024-01-20 14:52:38 +00:00
"github.com/filecoin-project/lotus/provider/lpmarket"
2024-01-19 15:07:06 +00:00
"github.com/filecoin-project/lotus/storage/paths"
sealing "github.com/filecoin-project/lotus/storage/pipeline"
"github.com/filecoin-project/lotus/storage/sealer/storiface"
)
type LMRPCProvider struct {
2024-02-11 12:40:25 +00:00
si paths . SectorIndex
full api . FullNode
2024-01-19 15:07:06 +00:00
maddr address . Address // lotus-miner RPC is single-actor
minerID abi . ActorID
ssize abi . SectorSize
2024-01-20 14:52:38 +00:00
2024-02-02 17:21:50 +00:00
pi lpmarket . Ingester
db * harmonydb . DB
confLayer string
2024-01-19 15:07:06 +00:00
}
2024-02-11 12:40:25 +00:00
func NewLMRPCProvider ( si paths . SectorIndex , full api . FullNode , maddr address . Address , minerID abi . ActorID , ssize abi . SectorSize , pi lpmarket . Ingester , db * harmonydb . DB , confLayer string ) * LMRPCProvider {
2024-02-01 19:44:29 +00:00
return & LMRPCProvider {
2024-02-02 17:21:50 +00:00
si : si ,
2024-02-11 12:40:25 +00:00
full : full ,
2024-02-02 17:21:50 +00:00
maddr : maddr ,
minerID : minerID ,
ssize : ssize ,
pi : pi ,
db : db ,
confLayer : confLayer ,
2024-02-01 19:44:29 +00:00
}
}
2024-01-19 15:07:06 +00:00
func ( l * LMRPCProvider ) ActorAddress ( ctx context . Context ) ( address . Address , error ) {
return l . maddr , nil
}
func ( l * LMRPCProvider ) WorkerJobs ( ctx context . Context ) ( map [ uuid . UUID ] [ ] storiface . WorkerJob , error ) {
// correct enough
return map [ uuid . UUID ] [ ] storiface . WorkerJob { } , nil
}
func ( l * LMRPCProvider ) SectorsStatus ( ctx context . Context , sid abi . SectorNumber , showOnChainInfo bool ) ( api . SectorInfo , error ) {
si , err := l . si . StorageFindSector ( ctx , abi . SectorID { Miner : l . minerID , Number : sid } , storiface . FTSealed | storiface . FTCache , 0 , false )
if err != nil {
return api . SectorInfo { } , err
}
2024-02-11 12:40:25 +00:00
var ssip [ ] struct {
PieceCID * string ` db:"piece_cid" `
DealID * int64 ` db:"f05_deal_id" `
}
err = l . db . Select ( ctx , & ssip , "select ssip.piece_cid, ssip.f05_deal_id from sectors_sdr_pipeline p left join sectors_sdr_initial_pieces ssip on p.sp_id = ssip.sp_id and p.sector_number = ssip.sector_number where p.sp_id = $1 and p.sector_number = $2" , l . minerID , sid )
if err != nil {
return api . SectorInfo { } , err
}
var deals [ ] abi . DealID
if len ( ssip ) > 0 {
for _ , d := range ssip {
if d . DealID != nil {
deals = append ( deals , abi . DealID ( * d . DealID ) )
}
}
} else {
osi , err := l . full . StateSectorGetInfo ( ctx , l . maddr , sid , types . EmptyTSK )
if err != nil {
return api . SectorInfo { } , err
}
if osi != nil {
deals = osi . DealIDs
}
}
2024-02-19 17:08:08 +00:00
spt , err := miner . SealProofTypeFromSectorSize ( l . ssize , network . Version20 , false ) // good enough, just need this for ssize anyways
if err != nil {
return api . SectorInfo { } , err
}
2024-01-19 15:07:06 +00:00
if len ( si ) == 0 {
2024-02-11 12:40:25 +00:00
state := api . SectorState ( sealing . UndefinedSectorState )
if len ( ssip ) > 0 {
state = api . SectorState ( sealing . PreCommit1 )
}
2024-01-19 15:07:06 +00:00
return api . SectorInfo {
SectorID : sid ,
2024-02-11 12:40:25 +00:00
State : state ,
2024-01-19 15:07:06 +00:00
CommD : nil ,
CommR : nil ,
Proof : nil ,
2024-02-11 12:40:25 +00:00
Deals : deals ,
2024-01-19 15:07:06 +00:00
Pieces : nil ,
Ticket : api . SealTicket { } ,
Seed : api . SealSeed { } ,
PreCommitMsg : nil ,
CommitMsg : nil ,
Retries : 0 ,
ToUpgrade : false ,
ReplicaUpdateMessage : nil ,
LastErr : "" ,
Log : nil ,
2024-02-19 17:08:08 +00:00
SealProof : spt ,
2024-01-19 15:07:06 +00:00
Activation : 0 ,
Expiration : 0 ,
2024-02-08 22:47:17 +00:00
DealWeight : big . Zero ( ) ,
VerifiedDealWeight : big . Zero ( ) ,
InitialPledge : big . Zero ( ) ,
2024-01-19 15:07:06 +00:00
OnTime : 0 ,
Early : 0 ,
} , nil
}
2024-02-11 12:40:25 +00:00
var state = api . SectorState ( sealing . Proving )
2024-01-19 15:07:06 +00:00
if ! si [ 0 ] . CanStore {
2024-02-11 12:40:25 +00:00
state = api . SectorState ( sealing . PreCommit2 )
2024-01-19 15:07:06 +00:00
}
// todo improve this with on-chain info
return api . SectorInfo {
SectorID : sid ,
State : state ,
CommD : nil ,
CommR : nil ,
Proof : nil ,
2024-02-11 12:40:25 +00:00
Deals : deals ,
2024-01-19 15:07:06 +00:00
Pieces : nil ,
Ticket : api . SealTicket { } ,
Seed : api . SealSeed { } ,
PreCommitMsg : nil ,
CommitMsg : nil ,
Retries : 0 ,
ToUpgrade : false ,
ReplicaUpdateMessage : nil ,
LastErr : "" ,
Log : nil ,
2024-02-19 17:08:08 +00:00
SealProof : spt ,
2024-01-19 15:07:06 +00:00
Activation : 0 ,
Expiration : 0 ,
2024-02-08 22:47:17 +00:00
DealWeight : big . Zero ( ) ,
VerifiedDealWeight : big . Zero ( ) ,
InitialPledge : big . Zero ( ) ,
2024-01-19 15:07:06 +00:00
OnTime : 0 ,
Early : 0 ,
} , nil
}
func ( l * LMRPCProvider ) SectorsList ( ctx context . Context ) ( [ ] abi . SectorNumber , error ) {
decls , err := l . si . StorageList ( ctx )
if err != nil {
return nil , err
}
var out [ ] abi . SectorNumber
for _ , decl := range decls {
for _ , s := range decl {
if s . Miner != l . minerID {
continue
}
out = append ( out , s . SectorID . Number )
}
}
return out , nil
}
type sectorParts struct {
sealed , unsealed , cache bool
inStorage bool
}
func ( l * LMRPCProvider ) SectorsSummary ( ctx context . Context ) ( map [ api . SectorState ] int , error ) {
decls , err := l . si . StorageList ( ctx )
if err != nil {
return nil , err
}
states := map [ abi . SectorID ] sectorParts { }
for si , decll := range decls {
sinfo , err := l . si . StorageInfo ( ctx , si )
if err != nil {
return nil , err
}
for _ , decl := range decll {
if decl . Miner != l . minerID {
continue
}
state := states [ abi . SectorID { Miner : decl . Miner , Number : decl . SectorID . Number } ]
state . sealed = state . sealed || decl . Has ( storiface . FTSealed )
state . unsealed = state . unsealed || decl . Has ( storiface . FTUnsealed )
state . cache = state . cache || decl . Has ( storiface . FTCache )
state . inStorage = state . inStorage || sinfo . CanStore
states [ abi . SectorID { Miner : decl . Miner , Number : decl . SectorID . Number } ] = state
}
}
out := map [ api . SectorState ] int { }
for _ , state := range states {
switch {
case state . sealed && state . inStorage :
out [ api . SectorState ( sealing . Proving ) ] ++
default :
// not even close to correct, but good enough for now
out [ api . SectorState ( sealing . PreCommit1 ) ] ++
}
}
return out , nil
}
func ( l * LMRPCProvider ) SectorsListInStates ( ctx context . Context , want [ ] api . SectorState ) ( [ ] abi . SectorNumber , error ) {
2024-02-01 19:44:29 +00:00
decls , err := l . si . StorageList ( ctx )
2024-01-19 15:07:06 +00:00
if err != nil {
return nil , err
}
wantProving , wantPrecommit1 := false , false
for _ , s := range want {
switch s {
case api . SectorState ( sealing . Proving ) :
wantProving = true
case api . SectorState ( sealing . PreCommit1 ) :
wantPrecommit1 = true
}
}
states := map [ abi . SectorID ] sectorParts { }
for si , decll := range decls {
sinfo , err := l . si . StorageInfo ( ctx , si )
if err != nil {
return nil , err
}
for _ , decl := range decll {
if decl . Miner != l . minerID {
continue
}
state := states [ abi . SectorID { Miner : decl . Miner , Number : decl . SectorID . Number } ]
state . sealed = state . sealed || decl . Has ( storiface . FTSealed )
state . unsealed = state . unsealed || decl . Has ( storiface . FTUnsealed )
state . cache = state . cache || decl . Has ( storiface . FTCache )
state . inStorage = state . inStorage || sinfo . CanStore
states [ abi . SectorID { Miner : decl . Miner , Number : decl . SectorID . Number } ] = state
}
}
var out [ ] abi . SectorNumber
for id , state := range states {
switch {
case state . sealed && state . inStorage :
if wantProving {
out = append ( out , id . Number )
}
default :
// not even close to correct, but good enough for now
if wantPrecommit1 {
out = append ( out , id . Number )
}
}
}
return out , nil
}
func ( l * LMRPCProvider ) StorageRedeclareLocal ( ctx context . Context , id * storiface . ID , b bool ) error {
// so this rescans and redeclares sectors on lotus-miner; whyyy is boost even calling this?
return nil
}
func ( l * LMRPCProvider ) IsUnsealed ( ctx context . Context , sectorNum abi . SectorNumber , offset abi . UnpaddedPieceSize , length abi . UnpaddedPieceSize ) ( bool , error ) {
sectorID := abi . SectorID { Miner : l . minerID , Number : sectorNum }
si , err := l . si . StorageFindSector ( ctx , sectorID , storiface . FTUnsealed , 0 , false )
if err != nil {
return false , err
}
// yes, yes, technically sectors can be partially unsealed, but that is never done in practice
// and can't even be easily done with the current implementation
return len ( si ) > 0 , nil
}
func ( l * LMRPCProvider ) ComputeDataCid ( ctx context . Context , pieceSize abi . UnpaddedPieceSize , pieceData storiface . Data ) ( abi . PieceInfo , error ) {
return abi . PieceInfo { } , xerrors . Errorf ( "not supported" )
}
func ( l * LMRPCProvider ) SectorAddPieceToAny ( ctx context . Context , size abi . UnpaddedPieceSize , r storiface . Data , d api . PieceDealInfo ) ( api . SectorOffset , error ) {
if d . DealProposal . PieceSize != abi . PaddedPieceSize ( l . ssize ) {
return api . SectorOffset { } , xerrors . Errorf ( "only full-sector pieces are supported" )
}
2024-01-20 14:52:38 +00:00
return api . SectorOffset { } , xerrors . Errorf ( "not supported, use AllocatePieceToSector" )
}
func ( l * LMRPCProvider ) AllocatePieceToSector ( ctx context . Context , maddr address . Address , piece api . PieceDealInfo , rawSize int64 , source url . URL , header http . Header ) ( api . SectorOffset , error ) {
return l . pi . AllocatePieceToSector ( ctx , maddr , piece , rawSize , source , header )
2024-01-19 15:07:06 +00:00
}
2024-02-02 17:21:50 +00:00
func ( l * LMRPCProvider ) AuthNew ( ctx context . Context , perms [ ] auth . Permission ) ( [ ] byte , error ) {
var cs [ ] struct {
Config string
}
err := l . db . Select ( ctx , & cs , "select config from harmony_config where title = $1" , l . confLayer )
if err != nil {
return nil , err
}
if len ( cs ) == 0 {
return nil , xerrors . Errorf ( "no harmony config found" )
}
lp := config . DefaultLotusProvider ( )
if _ , err := toml . Decode ( cs [ 0 ] . Config , lp ) ; err != nil {
return nil , xerrors . Errorf ( "decode harmony config: %w" , err )
}
type jwtPayload struct {
Allow [ ] auth . Permission
}
p := jwtPayload {
Allow : perms ,
}
sk , err := base64 . StdEncoding . DecodeString ( lp . Apis . StorageRPCSecret )
if err != nil {
return nil , xerrors . Errorf ( "decode secret: %w" , err )
}
return jwt . Sign ( & p , jwt . NewHS256 ( sk ) )
}
2024-01-19 15:07:06 +00:00
var _ MinimalLMApi = & LMRPCProvider { }