2019-07-24 01:13:56 +00:00
|
|
|
package impl
|
2019-07-24 00:58:31 +00:00
|
|
|
|
|
|
|
import (
|
2019-07-27 01:54:03 +00:00
|
|
|
"context"
|
2019-11-21 14:10:51 +00:00
|
|
|
"encoding/json"
|
2019-12-05 04:43:54 +00:00
|
|
|
"net/http"
|
|
|
|
"os"
|
2020-01-24 20:19:52 +00:00
|
|
|
"strconv"
|
2019-12-06 00:27:32 +00:00
|
|
|
|
2020-02-08 00:18:14 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
"golang.org/x/xerrors"
|
2020-02-27 21:45:31 +00:00
|
|
|
|
2019-12-19 20:13:17 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2020-02-08 00:18:14 +00:00
|
|
|
storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket"
|
2020-04-06 18:07:26 +00:00
|
|
|
sectorstorage "github.com/filecoin-project/sector-storage"
|
|
|
|
"github.com/filecoin-project/sector-storage/ffiwrapper"
|
|
|
|
"github.com/filecoin-project/sector-storage/stores"
|
2020-03-03 22:19:22 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
2020-02-04 06:17:18 +00:00
|
|
|
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2020-01-28 23:08:02 +00:00
|
|
|
"github.com/filecoin-project/lotus/api/apistruct"
|
2020-03-04 05:37:11 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2019-11-25 04:45:13 +00:00
|
|
|
"github.com/filecoin-project/lotus/miner"
|
2020-03-19 02:31:53 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/impl/common"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/storage"
|
|
|
|
"github.com/filecoin-project/lotus/storage/sectorblocks"
|
2020-04-07 00:41:33 +00:00
|
|
|
sealing "github.com/filecoin-project/storage-fsm"
|
2019-07-24 00:58:31 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type StorageMinerAPI struct {
|
2020-03-19 02:31:53 +00:00
|
|
|
common.CommonAPI
|
2019-07-27 00:45:27 +00:00
|
|
|
|
2020-03-26 19:34:38 +00:00
|
|
|
ProofsConfig *ffiwrapper.Config
|
2020-03-05 19:21:06 +00:00
|
|
|
SectorBlocks *sectorblocks.SectorBlocks
|
2019-07-30 00:46:56 +00:00
|
|
|
|
2020-02-08 00:18:14 +00:00
|
|
|
StorageProvider storagemarket.StorageProvider
|
|
|
|
Miner *storage.Miner
|
|
|
|
BlockMiner *miner.Miner
|
|
|
|
Full api.FullNode
|
2020-03-23 11:40:02 +00:00
|
|
|
StorageMgr *sectorstorage.Manager `optional:"true"`
|
2020-03-13 16:54:55 +00:00
|
|
|
*stores.Index
|
2019-07-24 00:58:31 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 14:10:51 +00:00
|
|
|
func (sm *StorageMinerAPI) ServeRemote(w http.ResponseWriter, r *http.Request) {
|
2019-12-09 17:08:32 +00:00
|
|
|
if !apistruct.HasPerm(r.Context(), apistruct.PermAdmin) {
|
2019-11-21 14:10:51 +00:00
|
|
|
w.WriteHeader(401)
|
|
|
|
json.NewEncoder(w).Encode(struct{ Error string }{"unauthorized: missing write permission"})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-03-11 05:49:17 +00:00
|
|
|
sm.StorageMgr.ServeHTTP(w, r)
|
2019-11-21 14:10:51 +00:00
|
|
|
}
|
2020-03-05 19:21:06 +00:00
|
|
|
|
2020-03-27 20:08:06 +00:00
|
|
|
func (sm *StorageMinerAPI) WorkerStats(context.Context) (map[uint64]sectorstorage.WorkerStats, error) {
|
2020-03-23 14:56:22 +00:00
|
|
|
return sm.StorageMgr.WorkerStats(), nil
|
|
|
|
}
|
2019-11-08 18:15:13 +00:00
|
|
|
|
2019-10-14 02:32:32 +00:00
|
|
|
func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error) {
|
2020-03-17 20:19:52 +00:00
|
|
|
return sm.Miner.Address(), nil
|
2019-08-10 01:54:45 +00:00
|
|
|
}
|
|
|
|
|
2020-02-09 06:06:32 +00:00
|
|
|
func (sm *StorageMinerAPI) ActorSectorSize(ctx context.Context, addr address.Address) (abi.SectorSize, error) {
|
2020-04-16 17:36:36 +00:00
|
|
|
mi, err := sm.Full.StateMinerInfo(ctx, addr, types.EmptyTSK)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
return mi.SectorSize, nil
|
2019-11-21 14:10:51 +00:00
|
|
|
}
|
|
|
|
|
2019-12-08 21:48:20 +00:00
|
|
|
func (sm *StorageMinerAPI) PledgeSector(ctx context.Context) error {
|
|
|
|
return sm.Miner.PledgeSector()
|
2019-07-27 01:54:03 +00:00
|
|
|
}
|
|
|
|
|
2020-02-09 06:06:32 +00:00
|
|
|
func (sm *StorageMinerAPI) SectorsStatus(ctx context.Context, sid abi.SectorNumber) (api.SectorInfo, error) {
|
2019-11-08 18:15:13 +00:00
|
|
|
info, err := sm.Miner.GetSectorInfo(sid)
|
|
|
|
if err != nil {
|
|
|
|
return api.SectorInfo{}, err
|
|
|
|
}
|
|
|
|
|
2020-02-09 06:06:32 +00:00
|
|
|
deals := make([]abi.DealID, len(info.Pieces))
|
2019-11-08 18:15:13 +00:00
|
|
|
for i, piece := range info.Pieces {
|
2020-04-07 22:34:30 +00:00
|
|
|
if piece.DealInfo == nil {
|
2020-02-23 00:47:47 +00:00
|
|
|
continue
|
|
|
|
}
|
2020-04-07 22:34:30 +00:00
|
|
|
deals[i] = piece.DealInfo.DealID
|
2019-11-08 18:15:13 +00:00
|
|
|
}
|
|
|
|
|
2020-01-23 14:18:05 +00:00
|
|
|
log := make([]api.SectorLog, len(info.Log))
|
|
|
|
for i, l := range info.Log {
|
|
|
|
log[i] = api.SectorLog{
|
|
|
|
Kind: l.Kind,
|
|
|
|
Timestamp: l.Timestamp,
|
|
|
|
Trace: l.Trace,
|
|
|
|
Message: l.Message,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-08 18:15:13 +00:00
|
|
|
return api.SectorInfo{
|
|
|
|
SectorID: sid,
|
|
|
|
State: info.State,
|
|
|
|
CommD: info.CommD,
|
|
|
|
CommR: info.CommR,
|
|
|
|
Proof: info.Proof,
|
|
|
|
Deals: deals,
|
2020-04-06 18:07:26 +00:00
|
|
|
Ticket: api.SealTicket{
|
|
|
|
Value: info.TicketValue,
|
|
|
|
Epoch: info.TicketEpoch,
|
|
|
|
},
|
|
|
|
Seed: api.SealSeed{
|
|
|
|
Value: info.SeedValue,
|
|
|
|
Epoch: info.SeedEpoch,
|
|
|
|
},
|
|
|
|
Retries: info.Nonce,
|
2019-12-04 00:44:29 +00:00
|
|
|
|
|
|
|
LastErr: info.LastErr,
|
2020-01-23 14:18:05 +00:00
|
|
|
Log: log,
|
2019-11-08 18:15:13 +00:00
|
|
|
}, nil
|
2019-07-27 21:08:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// List all staged sectors
|
2020-02-09 06:06:32 +00:00
|
|
|
func (sm *StorageMinerAPI) SectorsList(context.Context) ([]abi.SectorNumber, error) {
|
2019-11-08 18:15:13 +00:00
|
|
|
sectors, err := sm.Miner.ListSectors()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-02-09 06:06:32 +00:00
|
|
|
out := make([]abi.SectorNumber, len(sectors))
|
2019-11-08 18:15:13 +00:00
|
|
|
for i, sector := range sectors {
|
2020-04-06 22:31:33 +00:00
|
|
|
out[i] = sector.SectorNumber
|
2019-11-08 18:15:13 +00:00
|
|
|
}
|
|
|
|
return out, nil
|
2019-07-27 21:08:10 +00:00
|
|
|
}
|
|
|
|
|
2020-03-19 19:51:33 +00:00
|
|
|
func (sm *StorageMinerAPI) StorageLocal(ctx context.Context) (map[stores.ID]string, error) {
|
|
|
|
return sm.StorageMgr.StorageLocal(ctx)
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
func (sm *StorageMinerAPI) SectorsRefs(context.Context) (map[string][]api.SealedRef, error) {
|
|
|
|
// json can't handle cids as map keys
|
|
|
|
out := map[string][]api.SealedRef{}
|
|
|
|
|
|
|
|
refs, err := sm.SectorBlocks.List()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for k, v := range refs {
|
2020-01-24 20:19:52 +00:00
|
|
|
out[strconv.FormatUint(k, 10)] = v
|
2019-08-26 10:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2020-03-23 22:43:38 +00:00
|
|
|
func (sm *StorageMinerAPI) StorageStat(ctx context.Context, id stores.ID) (stores.FsStat, error) {
|
|
|
|
return sm.StorageMgr.FsStat(ctx, id)
|
|
|
|
}
|
|
|
|
|
2020-04-06 20:23:37 +00:00
|
|
|
func (sm *StorageMinerAPI) SectorsUpdate(ctx context.Context, id abi.SectorNumber, state sealing.SectorState) error {
|
2020-01-10 02:11:00 +00:00
|
|
|
return sm.Miner.ForceSectorState(ctx, id, state)
|
2019-12-05 04:43:54 +00:00
|
|
|
}
|
2020-03-05 19:21:06 +00:00
|
|
|
|
2020-03-11 01:57:52 +00:00
|
|
|
func (sm *StorageMinerAPI) WorkerConnect(ctx context.Context, url string) error {
|
2020-03-27 20:08:06 +00:00
|
|
|
w, err := connectRemoteWorker(ctx, sm, url)
|
2020-03-11 01:57:52 +00:00
|
|
|
if err != nil {
|
2020-03-18 23:23:28 +00:00
|
|
|
return xerrors.Errorf("connecting remote storage failed: %w", err)
|
2020-03-11 01:57:52 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 23:23:28 +00:00
|
|
|
log.Infof("Connected to a remote worker at %s", url)
|
|
|
|
|
2020-03-20 22:30:17 +00:00
|
|
|
return sm.StorageMgr.AddWorker(ctx, w)
|
2020-03-11 01:57:52 +00:00
|
|
|
}
|
|
|
|
|
2020-02-08 00:18:14 +00:00
|
|
|
func (sm *StorageMinerAPI) MarketImportDealData(ctx context.Context, propCid cid.Cid, path string) error {
|
|
|
|
fi, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to open file: %w", err)
|
|
|
|
}
|
|
|
|
defer fi.Close()
|
|
|
|
|
|
|
|
return sm.StorageProvider.ImportDataForDeal(ctx, propCid, fi)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sm *StorageMinerAPI) MarketListDeals(ctx context.Context) ([]storagemarket.StorageDeal, error) {
|
|
|
|
return sm.StorageProvider.ListDeals(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sm *StorageMinerAPI) MarketListIncompleteDeals(ctx context.Context) ([]storagemarket.MinerDeal, error) {
|
2020-04-07 02:17:02 +00:00
|
|
|
return sm.StorageProvider.ListLocalDeals()
|
2020-02-08 00:18:14 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 18:00:08 +00:00
|
|
|
func (sm *StorageMinerAPI) MarketSetPrice(ctx context.Context, p types.BigInt) error {
|
2020-02-08 00:18:14 +00:00
|
|
|
return sm.StorageProvider.AddAsk(abi.TokenAmount(p), 60*60*24*100) // lasts for 100 days?
|
|
|
|
}
|
|
|
|
|
2020-03-04 02:49:00 +00:00
|
|
|
func (sm *StorageMinerAPI) DealsList(ctx context.Context) ([]storagemarket.StorageDeal, error) {
|
|
|
|
return sm.StorageProvider.ListDeals(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sm *StorageMinerAPI) DealsImportData(ctx context.Context, deal cid.Cid, fname string) error {
|
|
|
|
fi, err := os.Open(fname)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to open given file: %w", err)
|
|
|
|
}
|
|
|
|
defer fi.Close()
|
|
|
|
|
|
|
|
return sm.StorageProvider.ImportDataForDeal(ctx, deal, fi)
|
|
|
|
}
|
|
|
|
|
2020-03-05 22:02:01 +00:00
|
|
|
func (sm *StorageMinerAPI) StorageAddLocal(ctx context.Context, path string) error {
|
|
|
|
if sm.StorageMgr == nil {
|
|
|
|
return xerrors.Errorf("no storage manager")
|
|
|
|
}
|
|
|
|
|
2020-03-19 15:10:19 +00:00
|
|
|
return sm.StorageMgr.AddLocalStorage(ctx, path)
|
2020-03-05 22:02:01 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 00:58:31 +00:00
|
|
|
var _ api.StorageMiner = &StorageMinerAPI{}
|