lotus/storage/miner.go

304 lines
13 KiB
Go
Raw Normal View History

2019-07-29 18:57:23 +00:00
package storage
import (
"context"
"errors"
2019-12-03 00:08:08 +00:00
"time"
blocks "github.com/ipfs/go-block-format"
2019-07-29 18:57:23 +00:00
"github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
logging "github.com/ipfs/go-log/v2"
"golang.org/x/xerrors"
2019-07-29 18:57:23 +00:00
"github.com/filecoin-project/go-address"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/go-bitfield"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
2022-06-14 15:00:51 +00:00
"github.com/filecoin-project/go-state-types/builtin/v8/miner"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/crypto"
2021-05-14 18:46:41 +00:00
"github.com/filecoin-project/go-state-types/dline"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/specs-storage/storage"
"github.com/filecoin-project/lotus/api"
2021-04-06 11:36:16 +00:00
"github.com/filecoin-project/lotus/api/v1api"
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"
2022-04-20 21:34:28 +00:00
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/events"
2019-11-25 04:45:13 +00:00
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/types"
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"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/storage/ctladdr"
2022-06-14 18:31:17 +00:00
pipeline "github.com/filecoin-project/lotus/storage/pipeline"
"github.com/filecoin-project/lotus/storage/sealer"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
2019-07-29 18:57:23 +00:00
)
var log = logging.Logger("storageminer")
2021-05-14 18:45:47 +00:00
// Miner is the central miner entrypoint object inside Lotus. It is
// instantiated in the node builder, along with the WindowPoStScheduler.
//
// This object is the owner of the sealing pipeline. Most of the actual logic
// lives in the pipeline module (sealing.Sealing), and the Miner object
2021-05-14 18:45:47 +00:00
// exposes it to the rest of the system by proxying calls.
//
// Miner#Run starts the sealing FSM.
2019-07-29 18:57:23 +00:00
type Miner struct {
api fullNodeFilteredAPI
2020-12-02 20:47:45 +00:00
feeCfg config.MinerFeeConfig
sealer sealer.SectorManager
2020-12-02 20:47:45 +00:00
ds datastore.Batching
2022-06-14 18:31:17 +00:00
sc pipeline.SectorIDCounter
2020-12-02 20:47:45 +00:00
verif ffiwrapper.Verifier
2021-05-19 13:20:23 +00:00
prover ffiwrapper.Prover
addrSel *ctladdr.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
2022-06-14 18:31:17 +00:00
sealing *pipeline.Sealing
2020-07-21 12:02:51 +00:00
sealingEvtType journal.EventType
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
2022-06-14 18:31:17 +00:00
From pipeline.SectorState
After pipeline.SectorState
2020-07-21 12:02:51 +00:00
Error string
2019-07-29 18:57:23 +00:00
}
// fullNodeFilteredAPI is the subset of the full node API the Miner needs from
// a Lotus full node.
type fullNodeFilteredAPI interface {
2019-07-29 18:57:23 +00:00
// Call a read only method on actors (no interaction with the chain required)
StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error)
StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error)
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
2022-04-20 21:34:28 +00:00
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*lminer.SectorLocation, error)
StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error)
StateMinerAvailableBalance(ctx context.Context, maddr address.Address, tok types.TipSetKey) (types.BigInt, error)
StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*miner.SectorOnChainInfo, error)
2020-09-17 15:30:15 +00:00
StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]api.Deadline, error)
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)
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)
2021-04-05 17:56:53 +00:00
StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error)
StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error)
StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error)
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)
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)
StateComputeDataCID(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, deals []abi.DealID, tsk types.TipSetKey) (cid.Cid, error)
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
2019-07-29 18:57:23 +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)
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)
ChainNotify(context.Context) (<-chan []*api.HeadChange, error)
StateGetRandomnessFromTickets(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error)
StateGetRandomnessFromBeacon(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte, tsk types.TipSetKey) (abi.Randomness, error)
ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
ChainGetTipSetAfterHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error)
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error)
2021-08-04 00:10:30 +00:00
ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, 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)
ChainPutObj(context.Context, blocks.Block) error
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
}
2021-05-14 18:45:47 +00:00
// NewMiner creates a new Miner object.
func NewMiner(api fullNodeFilteredAPI,
maddr address.Address,
ds datastore.Batching,
sealer sealer.SectorManager,
2022-06-14 18:31:17 +00:00
sc pipeline.SectorIDCounter,
2021-05-14 18:45:47 +00:00
verif ffiwrapper.Verifier,
2021-05-27 10:27:47 +00:00
prover ffiwrapper.Prover,
2021-05-14 18:45:47 +00:00
gsd dtypes.GetSealingConfigFunc,
feeCfg config.MinerFeeConfig,
journal journal.Journal,
as *ctladdr.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,
sealer: sealer,
ds: ds,
sc: sc,
verif: verif,
2021-05-19 13:20:23 +00:00
prover: prover,
2020-12-02 20:47:45 +00:00
addrSel: as,
2019-11-01 13:58:48 +00:00
maddr: maddr,
getSealConfig: gsd,
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
}
2021-05-14 18:45:47 +00:00
// Run starts the sealing FSM in the background, running preliminary checks first.
2019-07-29 18:57:23 +00:00
func (m *Miner) Run(ctx context.Context) error {
if err := m.runPreflightChecks(ctx); err != nil {
return xerrors.Errorf("miner preflight checks failed: %w", err)
2019-07-29 18:57:23 +00:00
}
md, err := m.api.StateMinerProvingDeadline(ctx, m.maddr, types.EmptyTSK)
if err != nil {
return xerrors.Errorf("getting miner info: %w", err)
}
2021-08-04 00:10:30 +00:00
// consumer of chain head changes.
evts, err := events.NewEvents(ctx, m.api)
if err != nil {
return xerrors.Errorf("failed to subscribe to events: %w", err)
}
evtsAdapter := NewEventsAdapter(evts)
2020-12-02 20:47:45 +00:00
2021-08-04 00:10:30 +00:00
// Create a shim to glue the API required by the sealing component
// with the API that Lotus is capable of providing.
// The shim translates between "tipset tokens" and tipset keys, and
// provides extra methods.
adaptedAPI := NewSealingAPIAdapter(m.api)
2021-08-04 00:10:30 +00:00
// Instantiate a precommit policy.
2022-06-14 18:31:17 +00:00
cfg := pipeline.GetSealingConfigFunc(m.getSealConfig)
2021-08-04 00:10:30 +00:00
provingBuffer := md.WPoStProvingPeriod * 2
2022-06-14 18:31:17 +00:00
pcp := pipeline.NewBasicPreCommitPolicy(adaptedAPI, cfg, provingBuffer)
2021-08-04 00:10:30 +00:00
// address selector.
2022-04-20 21:34:28 +00:00
as := func(ctx context.Context, mi api.MinerInfo, use api.AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) {
2021-08-04 00:10:30 +00:00
return m.addrSel.AddressFor(ctx, m.api, mi, use, goodFunds, minFunds)
}
2020-12-02 20:47:45 +00:00
// Instantiate the sealing FSM.
2022-06-14 18:31:17 +00:00
m.sealing = pipeline.New(ctx, adaptedAPI, m.feeCfg, evtsAdapter, m.maddr, m.ds, m.sealer, m.sc, m.verif, m.prover, &pcp, cfg, m.handleSealingNotifications, as)
2019-12-04 22:14:50 +00:00
// Run the sealing FSM.
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
}
2022-06-14 18:31:17 +00:00
func (m *Miner) handleSealingNotifications(before, after pipeline.SectorInfo) {
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 {
return m.sealing.Stop(ctx)
2019-07-29 18:57:23 +00:00
}
2021-05-14 18:45:47 +00:00
// runPreflightChecks verifies that preconditions to run the miner are satisfied.
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)
if err != nil {
return xerrors.Errorf("failed to check wallet for worker key: %w", err)
}
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
}
2021-04-05 17:56:53 +00:00
func NewWinningPoStProver(api v1api.FullNode, prover storage.Prover, verifier ffiwrapper.Verifier, miner dtypes.MinerID) (*StorageWpp, error) {
ma, err := address.NewIDAddress(uint64(miner))
if err != nil {
return nil, err
}
mi, err := api.StateMinerInfo(context.TODO(), ma, types.EmptyTSK)
if err != nil {
return nil, xerrors.Errorf("getting sector size: %w", 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("*****************************************************************************")
}
return &StorageWpp{prover, verifier, abi.ActorID(miner), mi.WindowPoStProofType}, 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 {
return nil, xerrors.Errorf("failed to generate candidates: %w", err)
2019-12-03 00:08:08 +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
}
func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, currEpoch abi.ChainEpoch, nv network.Version) ([]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
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
}
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
}