2019-07-29 18:57:23 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-11-22 16:20:56 +00:00
|
|
|
"errors"
|
2019-12-03 00:08:08 +00:00
|
|
|
"time"
|
2019-11-06 06:26:50 +00:00
|
|
|
|
2020-09-17 02:34:13 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/network"
|
|
|
|
|
2020-09-10 06:30:47 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/dline"
|
|
|
|
|
2020-09-07 03:49:10 +00:00
|
|
|
"github.com/filecoin-project/go-bitfield"
|
2019-11-06 06:26:50 +00:00
|
|
|
|
2019-07-29 18:57:23 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
"github.com/ipfs/go-datastore"
|
2020-01-08 19:10:57 +00:00
|
|
|
logging "github.com/ipfs/go-log/v2"
|
2019-09-18 13:32:21 +00:00
|
|
|
"github.com/libp2p/go-libp2p-core/host"
|
2019-11-22 16:20:56 +00:00
|
|
|
"golang.org/x/xerrors"
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2020-04-06 18:07:26 +00:00
|
|
|
"github.com/filecoin-project/go-address"
|
2020-09-07 03:49:10 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
2020-08-17 13:39:33 +00:00
|
|
|
sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage"
|
2020-08-17 13:26:18 +00:00
|
|
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
2020-04-06 18:07:26 +00:00
|
|
|
"github.com/filecoin-project/specs-storage/storage"
|
2020-02-08 02:18:32 +00:00
|
|
|
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2019-11-30 23:17:50 +00:00
|
|
|
"github.com/filecoin-project/lotus/build"
|
2020-10-08 01:09:33 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
2020-09-15 19:09:39 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
2020-10-08 01:09:33 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/events"
|
2019-11-25 04:45:13 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/gen"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2020-08-17 13:39:33 +00:00
|
|
|
sealing "github.com/filecoin-project/lotus/extern/storage-sealing"
|
2020-07-21 12:02:51 +00:00
|
|
|
"github.com/filecoin-project/lotus/journal"
|
2020-08-12 17:47:00 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/config"
|
2020-04-04 02:55:19 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
2019-07-29 18:57:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var log = logging.Logger("storageminer")
|
|
|
|
|
|
|
|
type Miner struct {
|
2020-12-02 20:47:45 +00:00
|
|
|
api storageMinerApi
|
|
|
|
feeCfg config.MinerFeeConfig
|
|
|
|
h host.Host
|
|
|
|
sealer sectorstorage.SectorManager
|
|
|
|
ds datastore.Batching
|
|
|
|
sc sealing.SectorIDCounter
|
|
|
|
verif ffiwrapper.Verifier
|
|
|
|
addrSel *AddressSelector
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2020-10-21 03:35:18 +00:00
|
|
|
maddr address.Address
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2020-08-18 14:20:31 +00:00
|
|
|
getSealConfig dtypes.GetSealingConfigFunc
|
|
|
|
sealing *sealing.Sealing
|
2020-07-21 12:02:51 +00:00
|
|
|
|
|
|
|
sealingEvtType journal.EventType
|
2020-10-09 19:52:04 +00:00
|
|
|
|
|
|
|
journal journal.Journal
|
2020-07-21 12:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SealingStateEvt is a journal event that records a sector state transition.
|
|
|
|
type SealingStateEvt struct {
|
|
|
|
SectorNumber abi.SectorNumber
|
|
|
|
SectorType abi.RegisteredSealProof
|
|
|
|
From sealing.SectorState
|
|
|
|
After sealing.SectorState
|
|
|
|
Error string
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type storageMinerApi interface {
|
|
|
|
// Call a read only method on actors (no interaction with the chain required)
|
2020-03-03 23:32:17 +00:00
|
|
|
StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error)
|
2020-09-21 19:05:01 +00:00
|
|
|
StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error)
|
2020-04-04 02:55:19 +00:00
|
|
|
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
|
2020-05-28 00:06:29 +00:00
|
|
|
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
|
2020-09-15 19:09:39 +00:00
|
|
|
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error)
|
2020-09-17 02:34:13 +00:00
|
|
|
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error)
|
2020-09-17 15:30:15 +00:00
|
|
|
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]api.Deadline, error)
|
2020-09-18 22:40:49 +00:00
|
|
|
StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]api.Partition, error)
|
2020-09-10 06:30:47 +00:00
|
|
|
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error)
|
2020-07-28 18:55:20 +00:00
|
|
|
StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error)
|
2020-06-26 15:59:34 +00:00
|
|
|
StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error)
|
2020-10-13 19:35:29 +00:00
|
|
|
StateMinerSectorAllocated(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (bool, error)
|
2020-08-18 16:02:13 +00:00
|
|
|
StateSearchMsg(context.Context, cid.Cid) (*api.MsgLookup, error)
|
2020-06-03 21:42:06 +00:00
|
|
|
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) // TODO: removeme eventually
|
2020-02-24 17:32:02 +00:00
|
|
|
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
|
2020-02-11 23:29:45 +00:00
|
|
|
StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error)
|
2020-02-24 17:32:02 +00:00
|
|
|
StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error)
|
2020-09-07 03:49:10 +00:00
|
|
|
StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error)
|
|
|
|
StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error)
|
2020-08-19 20:08:04 +00:00
|
|
|
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
2020-09-17 02:34:13 +00:00
|
|
|
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
|
2020-12-02 18:58:00 +00:00
|
|
|
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2020-08-12 20:17:21 +00:00
|
|
|
MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error)
|
2020-08-19 21:25:58 +00:00
|
|
|
|
|
|
|
GasEstimateMessageGas(context.Context, *types.Message, *api.MessageSendSpec, types.TipSetKey) (*types.Message, error)
|
2020-10-07 17:41:07 +00:00
|
|
|
GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error)
|
|
|
|
GasEstimateGasPremium(_ context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2020-02-24 17:45:25 +00:00
|
|
|
ChainHead(context.Context) (*types.TipSet, error)
|
2020-04-23 22:15:00 +00:00
|
|
|
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
|
2020-08-11 23:58:35 +00:00
|
|
|
ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
|
|
|
ChainGetRandomnessFromBeacon(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error)
|
2020-02-24 17:32:02 +00:00
|
|
|
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
|
2019-09-18 11:45:52 +00:00
|
|
|
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
2021-01-25 10:28:39 +00:00
|
|
|
ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error)
|
2020-01-23 17:34:04 +00:00
|
|
|
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
|
2020-02-13 03:50:37 +00:00
|
|
|
ChainHasObj(context.Context, cid.Cid) (bool, error)
|
2020-05-13 22:48:36 +00:00
|
|
|
ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error)
|
2019-08-08 04:24:49 +00:00
|
|
|
|
2020-02-25 21:09:22 +00:00
|
|
|
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
2019-08-08 04:24:49 +00:00
|
|
|
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
2019-08-08 17:29:23 +00:00
|
|
|
WalletHas(context.Context, address.Address) (bool, error)
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 20:47:45 +00:00
|
|
|
func NewMiner(api storageMinerApi, maddr address.Address, h host.Host, ds datastore.Batching, sealer sectorstorage.SectorManager, sc sealing.SectorIDCounter, verif ffiwrapper.Verifier, gsd dtypes.GetSealingConfigFunc, feeCfg config.MinerFeeConfig, journal journal.Journal, as *AddressSelector) (*Miner, error) {
|
2020-01-10 02:11:00 +00:00
|
|
|
m := &Miner{
|
2020-12-02 20:47:45 +00:00
|
|
|
api: api,
|
|
|
|
feeCfg: feeCfg,
|
|
|
|
h: h,
|
|
|
|
sealer: sealer,
|
|
|
|
ds: ds,
|
|
|
|
sc: sc,
|
|
|
|
verif: verif,
|
|
|
|
addrSel: as,
|
2019-11-01 13:58:48 +00:00
|
|
|
|
2020-08-26 15:38:23 +00:00
|
|
|
maddr: maddr,
|
|
|
|
getSealConfig: gsd,
|
2020-10-09 19:52:04 +00:00
|
|
|
journal: journal,
|
|
|
|
sealingEvtType: journal.RegisterEventType("storage", "sealing_states"),
|
2020-01-10 02:11:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return m, nil
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Miner) Run(ctx context.Context) error {
|
|
|
|
if err := m.runPreflightChecks(ctx); err != nil {
|
2019-11-22 16:20:56 +00:00
|
|
|
return xerrors.Errorf("miner preflight checks failed: %w", err)
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
2020-04-24 17:12:30 +00:00
|
|
|
md, err := m.api.StateMinerProvingDeadline(ctx, m.maddr, types.EmptyTSK)
|
2020-04-17 19:49:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("getting miner info: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-08-12 17:47:00 +00:00
|
|
|
fc := sealing.FeeConfig{
|
|
|
|
MaxPreCommitGasFee: abi.TokenAmount(m.feeCfg.MaxPreCommitGasFee),
|
|
|
|
MaxCommitGasFee: abi.TokenAmount(m.feeCfg.MaxCommitGasFee),
|
2021-01-12 23:42:01 +00:00
|
|
|
MaxTerminateGasFee: abi.TokenAmount(m.feeCfg.MaxTerminateGasFee),
|
2020-08-12 17:47:00 +00:00
|
|
|
}
|
|
|
|
|
2020-01-15 20:49:11 +00:00
|
|
|
evts := events.NewEvents(ctx, m.api)
|
2020-04-07 22:34:30 +00:00
|
|
|
adaptedAPI := NewSealingAPIAdapter(m.api)
|
2020-09-17 02:34:13 +00:00
|
|
|
// TODO: Maybe we update this policy after actor upgrades?
|
2020-10-08 01:09:33 +00:00
|
|
|
pcp := sealing.NewBasicPreCommitPolicy(adaptedAPI, policy.GetMaxSectorExpirationExtension()-(md.WPoStProvingPeriod*2), md.PeriodStart%md.WPoStProvingPeriod)
|
2020-12-02 20:47:45 +00:00
|
|
|
|
|
|
|
as := func(ctx context.Context, mi miner.MinerInfo, use api.AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) {
|
|
|
|
return m.addrSel.AddressFor(ctx, m.api, mi, use, goodFunds, minFunds)
|
|
|
|
}
|
|
|
|
|
|
|
|
m.sealing = sealing.New(adaptedAPI, fc, NewEventsAdapter(evts), m.maddr, m.ds, m.sealer, m.sc, m.verif, &pcp, sealing.GetSealingConfigFunc(m.getSealConfig), m.handleSealingNotifications, as)
|
2019-12-04 22:14:50 +00:00
|
|
|
|
2020-05-27 20:53:20 +00:00
|
|
|
go m.sealing.Run(ctx) //nolint:errcheck // logged intside the function
|
2020-01-20 08:23:56 +00:00
|
|
|
|
2019-07-29 18:57:23 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-21 12:02:51 +00:00
|
|
|
func (m *Miner) handleSealingNotifications(before, after sealing.SectorInfo) {
|
2020-10-09 19:52:04 +00:00
|
|
|
m.journal.RecordEvent(m.sealingEvtType, func() interface{} {
|
2020-07-21 12:02:51 +00:00
|
|
|
return SealingStateEvt{
|
|
|
|
SectorNumber: before.SectorNumber,
|
|
|
|
SectorType: before.SectorType,
|
|
|
|
From: before.State,
|
|
|
|
After: after.State,
|
|
|
|
Error: after.LastErr,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-11-01 13:58:48 +00:00
|
|
|
func (m *Miner) Stop(ctx context.Context) error {
|
2020-05-27 20:53:20 +00:00
|
|
|
return m.sealing.Stop(ctx)
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Miner) runPreflightChecks(ctx context.Context) error {
|
2020-10-21 03:35:18 +00:00
|
|
|
mi, err := m.api.StateMinerInfo(ctx, m.maddr, types.EmptyTSK)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to resolve miner info: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
workerKey, err := m.api.StateAccountKey(ctx, mi.Worker, types.EmptyTSK)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to resolve worker key: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
has, err := m.api.WalletHas(ctx, workerKey)
|
2019-07-30 00:46:56 +00:00
|
|
|
if err != nil {
|
2019-11-22 16:20:56 +00:00
|
|
|
return xerrors.Errorf("failed to check wallet for worker key: %w", err)
|
2019-07-30 00:46:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !has {
|
|
|
|
return errors.New("key for worker not found in local wallet")
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 03:35:18 +00:00
|
|
|
log.Infof("starting up miner %s, worker addr %s", m.maddr, workerKey)
|
2019-07-29 18:57:23 +00:00
|
|
|
return nil
|
|
|
|
}
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2020-04-10 21:07:18 +00:00
|
|
|
type StorageWpp struct {
|
2020-04-17 22:02:43 +00:00
|
|
|
prover storage.Prover
|
2020-04-17 14:47:19 +00:00
|
|
|
verifier ffiwrapper.Verifier
|
2020-04-17 22:02:43 +00:00
|
|
|
miner abi.ActorID
|
2020-06-15 16:30:49 +00:00
|
|
|
winnRpt abi.RegisteredPoStProof
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2020-04-17 14:47:19 +00:00
|
|
|
func NewWinningPoStProver(api api.FullNode, prover storage.Prover, verifier ffiwrapper.Verifier, miner dtypes.MinerID) (*StorageWpp, error) {
|
2020-04-13 21:25:38 +00:00
|
|
|
ma, err := address.NewIDAddress(uint64(miner))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-04-16 17:36:36 +00:00
|
|
|
mi, err := api.StateMinerInfo(context.TODO(), ma, types.EmptyTSK)
|
2020-04-13 21:25:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, xerrors.Errorf("getting sector size: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-11-04 20:29:08 +00:00
|
|
|
wpt, err := mi.SealProofType.RegisteredWinningPoStProof()
|
2020-04-13 21:25:38 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-07 13:53:55 +00:00
|
|
|
if build.InsecurePoStValidation {
|
|
|
|
log.Warn("*****************************************************************************")
|
|
|
|
log.Warn(" Generating fake PoSt proof! You should only see this while running tests! ")
|
|
|
|
log.Warn("*****************************************************************************")
|
|
|
|
}
|
|
|
|
|
2020-04-17 22:02:43 +00:00
|
|
|
return &StorageWpp{prover, verifier, abi.ActorID(miner), wpt}, nil
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 21:07:18 +00:00
|
|
|
var _ gen.WinningPoStProver = (*StorageWpp)(nil)
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2020-04-10 21:07:18 +00:00
|
|
|
func (wpp *StorageWpp) GenerateCandidates(ctx context.Context, randomness abi.PoStRandomness, eligibleSectorCount uint64) ([]uint64, error) {
|
2020-07-10 14:43:14 +00:00
|
|
|
start := build.Clock.Now()
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2020-04-17 14:47:19 +00:00
|
|
|
cds, err := wpp.verifier.GenerateWinningPoStSectorChallenge(ctx, wpp.winnRpt, wpp.miner, randomness, eligibleSectorCount)
|
2019-12-03 00:08:08 +00:00
|
|
|
if err != nil {
|
2020-02-28 18:01:43 +00:00
|
|
|
return nil, xerrors.Errorf("failed to generate candidates: %w", err)
|
2019-12-03 00:08:08 +00:00
|
|
|
}
|
2020-04-17 19:49:32 +00:00
|
|
|
log.Infof("Generate candidates took %s (C: %+v)", time.Since(start), cds)
|
2019-12-03 00:08:08 +00:00
|
|
|
return cds, nil
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2020-10-08 01:09:33 +00:00
|
|
|
func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []builtin.SectorInfo, rand abi.PoStRandomness) ([]builtin.PoStProof, error) {
|
2019-11-30 23:17:50 +00:00
|
|
|
if build.InsecurePoStValidation {
|
2020-10-08 01:09:33 +00:00
|
|
|
return []builtin.PoStProof{{ProofBytes: []byte("valid proof")}}, nil
|
2019-11-30 23:17:50 +00:00
|
|
|
}
|
2020-02-27 21:45:31 +00:00
|
|
|
|
2020-04-17 19:49:32 +00:00
|
|
|
log.Infof("Computing WinningPoSt ;%+v; %v", ssi, rand)
|
|
|
|
|
2020-07-10 14:43:14 +00:00
|
|
|
start := build.Clock.Now()
|
2020-04-10 21:07:18 +00:00
|
|
|
proof, err := wpp.prover.GenerateWinningPoSt(ctx, wpp.miner, ssi, rand)
|
2019-12-03 00:08:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-04-10 22:20:48 +00:00
|
|
|
log.Infof("GenerateWinningPoSt took %s", time.Since(start))
|
2019-12-03 00:08:08 +00:00
|
|
|
return proof, nil
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|