2019-09-26 23:07:40 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/base64"
|
|
|
|
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/go-lotus/api"
|
|
|
|
"github.com/filecoin-project/go-lotus/build"
|
|
|
|
"github.com/filecoin-project/go-lotus/chain/actors"
|
|
|
|
"github.com/filecoin-project/go-lotus/chain/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (m *Miner) beginPosting(ctx context.Context) {
|
|
|
|
ts, err := m.api.ChainHead(context.TODO())
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ppe, err := m.api.StateMinerProvingPeriodEnd(ctx, m.maddr, ts)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("failed to get proving period end for miner: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if ppe == 0 {
|
|
|
|
log.Errorf("Proving period end == 0")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
m.schedLk.Lock()
|
|
|
|
if m.schedPost > 0 {
|
|
|
|
log.Warnf("PoSts already running %d", m.schedPost)
|
|
|
|
m.schedLk.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-09-27 23:00:00 +00:00
|
|
|
// height needs to be +1, because otherwise we'd be trying to schedule PoSt
|
|
|
|
// at current block height
|
|
|
|
m.schedPost, _ = actors.ProvingPeriodEnd(ppe, ts.Height()+1)
|
2019-09-26 23:07:40 +00:00
|
|
|
|
|
|
|
m.schedLk.Unlock()
|
|
|
|
|
|
|
|
log.Infof("Scheduling post at height %d", ppe-build.PoSTChallangeTime)
|
|
|
|
err = m.events.ChainAt(m.computePost(m.schedPost), func(ts *types.TipSet) error { // Revert
|
|
|
|
// TODO: Cancel post
|
|
|
|
log.Errorf("TODO: Cancel PoSt, re-run")
|
|
|
|
return nil
|
|
|
|
}, PoStConfidence, ppe-build.PoSTChallangeTime)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: This is BAD, figure something out
|
|
|
|
log.Errorf("scheduling PoSt failed: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Miner) scheduleNextPost(ppe uint64) {
|
|
|
|
ts, err := m.api.ChainHead(context.TODO())
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
|
|
|
// TODO: retry
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-09-27 19:47:47 +00:00
|
|
|
headPPE, provingPeriod := actors.ProvingPeriodEnd(ppe, ts.Height())
|
2019-09-26 23:07:40 +00:00
|
|
|
if headPPE > ppe {
|
|
|
|
log.Warn("PoSt computation running behind chain")
|
|
|
|
ppe = headPPE
|
|
|
|
}
|
|
|
|
|
|
|
|
m.schedLk.Lock()
|
|
|
|
if m.schedPost >= ppe {
|
|
|
|
// this probably can't happen
|
|
|
|
log.Error("PoSt already scheduled: %d >= %d", m.schedPost, ppe)
|
|
|
|
m.schedLk.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
m.schedPost = ppe
|
|
|
|
m.schedLk.Unlock()
|
|
|
|
|
2019-09-27 12:35:09 +00:00
|
|
|
log.Infof("Scheduling post at height %d (head=%d; ppe=%d, period=%d)", ppe-build.PoSTChallangeTime, ts.Height(), ppe, provingPeriod)
|
2019-09-26 23:07:40 +00:00
|
|
|
err = m.events.ChainAt(m.computePost(ppe), func(ts *types.TipSet) error { // Revert
|
|
|
|
// TODO: Cancel post
|
|
|
|
log.Errorf("TODO: Cancel PoSt, re-run")
|
|
|
|
return nil
|
|
|
|
}, PoStConfidence, ppe-build.PoSTChallangeTime)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: This is BAD, figure something out
|
|
|
|
log.Errorf("scheduling PoSt failed: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Miner) computePost(ppe uint64) func(ts *types.TipSet, curH uint64) error {
|
|
|
|
return func(ts *types.TipSet, curH uint64) error {
|
|
|
|
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
sset, err := m.api.StateMinerProvingSet(ctx, m.maddr, ts)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("failed to get proving set for miner: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(int64(ts.Height())-int64(ppe)+int64(build.PoSTChallangeTime))) // TODO: review: check math
|
|
|
|
if err != nil {
|
2019-09-27 12:35:09 +00:00
|
|
|
return xerrors.Errorf("failed to get chain randomness for post (ts=%d; ppe=%d): %w", ts.Height(), ppe, err)
|
2019-09-26 23:07:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("running PoSt computation, rh=%d r=%s, ppe=%d, h=%d", int64(ts.Height())-int64(ppe)+int64(build.PoSTChallangeTime), base64.StdEncoding.EncodeToString(r), ppe, ts.Height())
|
|
|
|
var faults []uint64
|
|
|
|
proof, err := m.secst.RunPoSt(ctx, sset, r, faults)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("running post failed: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("submitting PoSt pLen=%d", len(proof))
|
|
|
|
|
|
|
|
params := &actors.SubmitPoStParams{
|
|
|
|
Proof: proof,
|
|
|
|
DoneSet: types.BitFieldFromSet(sectorIdList(sset)),
|
|
|
|
}
|
|
|
|
|
|
|
|
enc, aerr := actors.SerializeParams(params)
|
|
|
|
if aerr != nil {
|
|
|
|
return xerrors.Errorf("could not serialize submit post parameters: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
msg := &types.Message{
|
|
|
|
To: m.maddr,
|
|
|
|
From: m.worker,
|
|
|
|
Method: actors.MAMethods.SubmitPoSt,
|
|
|
|
Params: enc,
|
|
|
|
Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late
|
|
|
|
GasLimit: types.NewInt(100000 /* i dont know help */),
|
|
|
|
GasPrice: types.NewInt(1),
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("mpush")
|
|
|
|
|
|
|
|
smsg, err := m.api.MpoolPushMessage(ctx, msg)
|
|
|
|
if err != nil {
|
|
|
|
return xerrors.Errorf("pushing message to mpool: %w", err)
|
|
|
|
}
|
|
|
|
|
2019-09-27 12:35:09 +00:00
|
|
|
log.Infof("Waiting for post %s to appear on chain", smsg.Cid())
|
2019-09-26 23:07:40 +00:00
|
|
|
|
|
|
|
// make sure it succeeds...
|
|
|
|
rec, err := m.api.ChainWaitMsg(ctx, smsg.Cid())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if rec.Receipt.ExitCode != 0 {
|
|
|
|
log.Warnf("SubmitPoSt EXIT: %d", rec.Receipt.ExitCode)
|
|
|
|
// TODO: Do something
|
|
|
|
}
|
|
|
|
|
|
|
|
m.scheduleNextPost(ppe + build.ProvingPeriodDuration)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func sectorIdList(si []*api.SectorInfo) []uint64 {
|
|
|
|
out := make([]uint64, len(si))
|
|
|
|
for i, s := range si {
|
|
|
|
out[i] = s.SectorID
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|