2019-07-29 18:57:23 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-11-22 16:20:56 +00:00
|
|
|
"errors"
|
2019-11-06 06:26:50 +00:00
|
|
|
"sync"
|
2019-12-03 00:08:08 +00:00
|
|
|
"time"
|
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"
|
2019-11-08 20:11:56 +00:00
|
|
|
"github.com/ipfs/go-datastore/namespace"
|
2019-07-29 18:57:23 +00:00
|
|
|
logging "github.com/ipfs/go-log"
|
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
|
|
|
|
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"
|
2019-10-18 04:47:41 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/address"
|
|
|
|
"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/store"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2019-11-08 20:11:56 +00:00
|
|
|
"github.com/filecoin-project/lotus/lib/sectorbuilder"
|
|
|
|
"github.com/filecoin-project/lotus/lib/statestore"
|
2019-07-29 18:57:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var log = logging.Logger("storageminer")
|
|
|
|
|
2019-11-29 19:11:01 +00:00
|
|
|
const SectorStorePrefix = "/sectors"
|
2019-09-18 13:32:21 +00:00
|
|
|
|
2019-07-29 18:57:23 +00:00
|
|
|
type Miner struct {
|
2019-09-18 11:45:52 +00:00
|
|
|
api storageMinerApi
|
|
|
|
events *events.Events
|
2019-11-01 13:58:48 +00:00
|
|
|
h host.Host
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2019-11-01 13:58:48 +00:00
|
|
|
maddr address.Address
|
2019-07-29 18:57:23 +00:00
|
|
|
worker address.Address
|
|
|
|
|
2019-11-01 13:58:48 +00:00
|
|
|
// PoSt
|
|
|
|
postLk sync.Mutex
|
|
|
|
schedPost uint64
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2019-11-01 13:58:48 +00:00
|
|
|
// Sealing
|
2019-11-07 18:43:15 +00:00
|
|
|
sb *sectorbuilder.SectorBuilder
|
2019-11-01 13:58:48 +00:00
|
|
|
sectors *statestore.StateStore
|
2019-11-07 18:43:15 +00:00
|
|
|
tktFn TicketFn
|
2019-09-19 16:17:49 +00:00
|
|
|
|
2019-11-01 13:58:48 +00:00
|
|
|
sectorIncoming chan *SectorInfo
|
|
|
|
sectorUpdated chan sectorUpdate
|
|
|
|
stop chan struct{}
|
|
|
|
stopped chan struct{}
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type storageMinerApi interface {
|
|
|
|
// Call a read only method on actors (no interaction with the chain required)
|
2019-09-06 06:26:02 +00:00
|
|
|
StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error)
|
2019-09-18 02:50:03 +00:00
|
|
|
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
2019-11-28 17:44:49 +00:00
|
|
|
StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error)
|
2019-11-08 18:15:13 +00:00
|
|
|
StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error)
|
|
|
|
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error)
|
2019-10-16 07:07:16 +00:00
|
|
|
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
|
2019-11-20 19:44:38 +00:00
|
|
|
StateWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) // TODO: removeme eventually
|
2019-11-19 21:27:25 +00:00
|
|
|
StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error)
|
|
|
|
StateGetReceipt(context.Context, cid.Cid, *types.TipSet) (*types.MessageReceipt, error)
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2019-09-19 16:17:49 +00:00
|
|
|
MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error)
|
2019-07-29 18:57:23 +00:00
|
|
|
|
2019-09-18 13:32:21 +00:00
|
|
|
ChainHead(context.Context) (*types.TipSet, error)
|
2019-09-18 11:01:52 +00:00
|
|
|
ChainNotify(context.Context) (<-chan []*store.HeadChange, error)
|
2019-11-19 15:53:00 +00:00
|
|
|
ChainGetRandomness(context.Context, types.TipSetKey, int64) ([]byte, error)
|
2019-09-18 00:08:49 +00:00
|
|
|
ChainGetTipSetByHeight(context.Context, uint64, *types.TipSet) (*types.TipSet, error)
|
2019-09-18 11:45:52 +00:00
|
|
|
ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error)
|
2019-08-08 04:24:49 +00:00
|
|
|
|
2019-11-01 23:43:54 +00:00
|
|
|
WalletSign(context.Context, address.Address, []byte) (*types.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
|
|
|
}
|
|
|
|
|
2019-11-07 18:22:59 +00:00
|
|
|
func NewMiner(api storageMinerApi, addr address.Address, h host.Host, ds datastore.Batching, sb *sectorbuilder.SectorBuilder, tktFn TicketFn) (*Miner, error) {
|
2019-07-29 18:57:23 +00:00
|
|
|
return &Miner{
|
2019-09-18 18:07:39 +00:00
|
|
|
api: api,
|
2019-09-18 11:45:52 +00:00
|
|
|
|
2019-07-29 18:57:23 +00:00
|
|
|
maddr: addr,
|
|
|
|
h: h,
|
2019-11-07 18:43:15 +00:00
|
|
|
sb: sb,
|
2019-11-07 18:22:59 +00:00
|
|
|
tktFn: tktFn,
|
2019-11-01 13:58:48 +00:00
|
|
|
|
2019-11-29 19:11:01 +00:00
|
|
|
sectors: statestore.New(namespace.Wrap(ds, datastore.NewKey(SectorStorePrefix))),
|
2019-11-01 22:44:55 +00:00
|
|
|
|
|
|
|
sectorIncoming: make(chan *SectorInfo),
|
|
|
|
sectorUpdated: make(chan sectorUpdate),
|
|
|
|
stop: make(chan struct{}),
|
|
|
|
stopped: make(chan struct{}),
|
2019-07-29 18:57:23 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-09-18 18:07:39 +00:00
|
|
|
m.events = events.NewEvents(ctx, m.api)
|
|
|
|
|
2019-11-28 17:44:49 +00:00
|
|
|
fps := &fpostScheduler{
|
|
|
|
api: m.api,
|
|
|
|
sb: m.sb,
|
|
|
|
actor: m.maddr,
|
|
|
|
worker: m.worker,
|
|
|
|
}
|
|
|
|
|
|
|
|
go fps.run(ctx)
|
2019-11-01 13:58:48 +00:00
|
|
|
go m.sectorStateLoop(ctx)
|
2019-07-29 18:57:23 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-11-01 13:58:48 +00:00
|
|
|
func (m *Miner) Stop(ctx context.Context) error {
|
|
|
|
close(m.stop)
|
|
|
|
select {
|
|
|
|
case <-m.stopped:
|
|
|
|
return nil
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
}
|
2019-07-29 18:57:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Miner) runPreflightChecks(ctx context.Context) error {
|
2019-09-18 00:08:49 +00:00
|
|
|
worker, err := m.api.StateMinerWorker(ctx, m.maddr, nil)
|
2019-07-29 18:57:23 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
m.worker = worker
|
|
|
|
|
2019-08-08 17:29:23 +00:00
|
|
|
has, err := m.api.WalletHas(ctx, worker)
|
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
|
|
|
}
|
|
|
|
|
2019-07-30 00:46:56 +00:00
|
|
|
log.Infof("starting up miner %s, worker addr %s", m.maddr, m.worker)
|
2019-07-29 18:57:23 +00:00
|
|
|
return nil
|
|
|
|
}
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2019-12-02 12:51:16 +00:00
|
|
|
type SectorBuilderEpp struct {
|
2019-11-25 04:45:13 +00:00
|
|
|
sb *sectorbuilder.SectorBuilder
|
|
|
|
}
|
|
|
|
|
2019-12-02 12:51:16 +00:00
|
|
|
func NewElectionPoStProver(sb *sectorbuilder.SectorBuilder) *SectorBuilderEpp {
|
|
|
|
return &SectorBuilderEpp{sb}
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 12:51:16 +00:00
|
|
|
var _ gen.ElectionPoStProver = (*SectorBuilderEpp)(nil)
|
2019-11-25 04:45:13 +00:00
|
|
|
|
2019-12-02 12:51:16 +00:00
|
|
|
func (epp *SectorBuilderEpp) GenerateCandidates(ctx context.Context, ssi sectorbuilder.SortedPublicSectorInfo, rand []byte) ([]sectorbuilder.EPostCandidate, error) {
|
2019-12-03 00:08:08 +00:00
|
|
|
start := time.Now()
|
2019-11-25 04:45:13 +00:00
|
|
|
var faults []uint64 // TODO
|
|
|
|
|
|
|
|
var randbuf [32]byte
|
|
|
|
copy(randbuf[:], rand)
|
2019-12-03 00:08:08 +00:00
|
|
|
cds, err := epp.sb.GenerateEPostCandidates(ssi, randbuf, faults)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
log.Infof("Generate candidates took %s", time.Since(start))
|
|
|
|
return cds, nil
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|
|
|
|
|
2019-12-02 12:51:16 +00:00
|
|
|
func (epp *SectorBuilderEpp) ComputeProof(ctx context.Context, ssi sectorbuilder.SortedPublicSectorInfo, rand []byte, winners []sectorbuilder.EPostCandidate) ([]byte, error) {
|
2019-11-30 23:17:50 +00:00
|
|
|
if build.InsecurePoStValidation {
|
|
|
|
log.Warn("Generating fake EPost proof! You should only see this while running tests!")
|
|
|
|
return []byte("valid proof"), nil
|
|
|
|
}
|
2019-12-03 00:08:08 +00:00
|
|
|
start := time.Now()
|
|
|
|
proof, err := epp.sb.ComputeElectionPoSt(ssi, rand, winners)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
log.Infof("ComputeElectionPost took %s", time.Since(start))
|
|
|
|
return proof, nil
|
2019-11-25 04:45:13 +00:00
|
|
|
}
|