Merge pull request #682 from filecoin-project/feat/election-post-fallback

Feat/election post fallback
This commit is contained in:
Łukasz Magiera 2019-11-28 19:10:50 +01:00 committed by GitHub
commit 6098db4f51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 428 additions and 446 deletions

View File

@ -99,7 +99,7 @@ type FullNode interface {
StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error) StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error)
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error)
StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error)
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error) StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
StatePledgeCollateral(context.Context, *types.TipSet) (types.BigInt, error) StatePledgeCollateral(context.Context, *types.TipSet) (types.BigInt, error)
StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error) StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error)

View File

@ -89,7 +89,7 @@ type FullNodeStruct struct {
StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"`
StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"`
StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"`
StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` StateMinerElectionPeriodStart func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"`
StateMinerSectorSize func(context.Context, address.Address, *types.TipSet) (uint64, error) `perm:"read"` StateMinerSectorSize func(context.Context, address.Address, *types.TipSet) (uint64, error) `perm:"read"`
StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"`
StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"` StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"`
@ -362,8 +362,8 @@ func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address
return c.Internal.StateMinerPeerID(ctx, m, ts) return c.Internal.StateMinerPeerID(ctx, m, ts)
} }
func (c *FullNodeStruct) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { func (c *FullNodeStruct) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
return c.Internal.StateMinerProvingPeriodEnd(ctx, actor, ts) return c.Internal.StateMinerElectionPeriodStart(ctx, actor, ts)
} }
func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {

View File

@ -31,7 +31,7 @@ func SupportedSectorSize(ssize uint64) bool {
// ///// // /////
// Payments // Payments
// Blocks // Epochs
const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours
// ///// // /////
@ -40,13 +40,13 @@ const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours
// Seconds // Seconds
const AllowableClockDrift = BlockDelay * 2 const AllowableClockDrift = BlockDelay * 2
// Blocks // Epochs
const ForkLengthThreshold = Finality const ForkLengthThreshold = Finality
// Blocks (e) // Blocks (e)
const BlocksPerEpoch = 5 const BlocksPerEpoch = 5
// Blocks // Epochs
const Finality = 500 const Finality = 500
// constants for Weight calculation // constants for Weight calculation
@ -57,40 +57,45 @@ const WRatioDen = 2
// ///// // /////
// Proofs // Proofs
// PoStChallangeTime sets the window in which post computation should happen
// Blocks
const PoStChallangeTime = ProvingPeriodDuration - 6
// PoStRandomnessLookback is additional randomness lookback for PoSt computation // PoStRandomnessLookback is additional randomness lookback for PoSt computation
// To compute randomness epoch in a given proving period: // To compute randomness epoch in a given proving period:
// RandH = PPE - PoStChallangeTime - PoStRandomnessLookback // RandH = PPE - PoStChallangeTime - PoStRandomnessLookback
// //
// Blocks // Epochs
const PoStRandomnessLookback = 1 const PoStRandomnessLookback = 1
// Blocks // Epochs
const SealRandomnessLookback = Finality const SealRandomnessLookback = Finality
// Blocks // Epochs
const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000 const SealRandomnessLookbackLimit = SealRandomnessLookback + 2000
// 1 / n // 1 / n
const SectorChallengeRatioDiv = 25 const SectorChallengeRatioDiv = 25
const MaxFallbackPostChallengeCount = 10
// FallbackPoStDelay is the number of epochs the miner needs to wait after
// ElectionPeriodStart before starting fallback post computation
//
// Epochs
const FallbackPoStDelay = 1000
// SlashablePowerDelay is the number of epochs
// Epochs
const SlashablePowerDelay = 2000
// ///// // /////
// Mining // Mining
// Blocks // Epochs
const EcRandomnessLookback = 300 const EcRandomnessLookback = 300
const FallbackPoStBegin = 1000
const SlashablePowerDelay = 2000
const PowerCollateralProportion = 5 const PowerCollateralProportion = 5
const PerCapitaCollateralProportion = 1 const PerCapitaCollateralProportion = 1
const CollateralPrecision = 1000 const CollateralPrecision = 1000
// Blocks // Epochs
const InteractivePoRepDelay = 10 const InteractivePoRepDelay = 10
// ///// // /////
@ -106,8 +111,8 @@ var InitialReward *big.Int
const FilecoinPrecision = 1_000_000_000_000_000_000 const FilecoinPrecision = 1_000_000_000_000_000_000
// six years // six years
// Blocks // Epochs
const HalvingPeriodBlocks = 6 * 365 * 24 * 60 * 2 const HalvingPeriodEpochs = 6 * 365 * 24 * 60 * 2
// TODO: Move other important consts here // TODO: Move other important consts here
@ -125,6 +130,6 @@ func init() {
// Sync // Sync
const BadBlockCacheSize = 1 << 15 const BadBlockCacheSize = 1 << 15
// assuming 4000 blocks per round, this lets us not lose any messages across a // assuming 4000 messages per round, this lets us not lose any messages across a
// 10 block reorg. // 10 block reorg.
const BlsSignatureCacheSize = 40000 const BlsSignatureCacheSize = 40000

View File

@ -5,6 +5,7 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
ffi "github.com/filecoin-project/filecoin-ffi" ffi "github.com/filecoin-project/filecoin-ffi"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
@ -388,19 +389,12 @@ func (sma StorageMinerActor) ProveCommitSector(act *types.Actor, vmctx types.VMC
return nil, err return nil, err
} }
type SubmitPoStParams struct { type SubmitFallbackPoStParams struct {
Proof types.EPostProof Proof []byte
Candidates []types.EPostTicket
} }
func ProvingPeriodEnd(setPeriodEnd, height uint64) (uint64, uint64) { func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitFallbackPoStParams) ([]byte, ActorError) {
offset := setPeriodEnd % build.ProvingPeriodDuration
period := ((height - offset - 1) / build.ProvingPeriodDuration) + 1
end := (period * build.ProvingPeriodDuration) + offset
return end, period
}
func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VMContext, params *SubmitPoStParams) ([]byte, ActorError) {
oldstate, self, err := loadState(vmctx) oldstate, self, err := loadState(vmctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -433,7 +427,7 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
var seed [sectorbuilder.CommLen]byte var seed [sectorbuilder.CommLen]byte
{ {
randHeight := self.ElectionPeriodStart + build.FallbackPoStBegin randHeight := self.ElectionPeriodStart + build.FallbackPoStDelay
if vmctx.BlockHeight() <= randHeight { if vmctx.BlockHeight() <= randHeight {
// TODO: spec, retcode // TODO: spec, retcode
return nil, aerrors.Newf(1, "submit fallback PoSt called too early (%d < %d)", vmctx.BlockHeight(), randHeight) return nil, aerrors.Newf(1, "submit fallback PoSt called too early (%d < %d)", vmctx.BlockHeight(), randHeight)
@ -481,18 +475,21 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
faults := self.CurrentFaultSet.All() faults := self.CurrentFaultSet.All()
_ = faults _ = faults
_ = seed
//VerifyPoStRandomness()
convertToCandidates := func(wins []types.EPostTicket) []sectorbuilder.EPostCandidate {
panic("NYI")
}
winners := convertToCandidates(params.Proof.Winners)
proverID := vmctx.Message().To // TODO: normalize to ID address proverID := vmctx.Message().To // TODO: normalize to ID address
if ok, lerr := sectorbuilder.VerifyPost(vmctx.Context(), mi.SectorSize, var candidates []sectorbuilder.EPostCandidate
sectorbuilder.NewSortedPublicSectorInfo(sectorInfos), params.Proof.PostRand, params.Proof.Proof, winners, proverID); !ok || lerr != nil { for _, t := range params.Candidates {
var partial [32]byte
copy(partial[:], t.Partial)
candidates = append(candidates, sectorbuilder.EPostCandidate{
PartialTicket: partial,
SectorID: t.SectorID,
SectorChallengeIndex: t.ChallengeIndex,
})
}
if ok, lerr := sectorbuilder.VerifyFallbackPost(vmctx.Context(), mi.SectorSize,
sectorbuilder.NewSortedPublicSectorInfo(sectorInfos), seed[:], params.Proof, candidates, proverID); !ok || lerr != nil {
if lerr != nil { if lerr != nil {
// TODO: study PoST errors // TODO: study PoST errors
return nil, aerrors.Absorb(lerr, 4, "PoST error") return nil, aerrors.Absorb(lerr, 4, "PoST error")
@ -503,42 +500,10 @@ func (sma StorageMinerActor) SubmitFallbackPoSt(act *types.Actor, vmctx types.VM
} }
// Post submission is successful! // Post submission is successful!
self.CurrentFaultSet = self.NextFaultSet if err := onSuccessfulPoSt(self, vmctx); err != nil {
self.NextFaultSet = types.NewBitField()
oldPower := self.Power
self.Power = types.BigMul(types.NewInt(pss.Count-uint64(len(faults))),
types.NewInt(mi.SectorSize))
delta := types.BigSub(self.Power, oldPower)
if self.SlashedAt != 0 {
self.SlashedAt = 0
delta = self.Power
}
prevSlashingDeadline := self.ElectionPeriodStart + build.SlashablePowerDelay
if !self.Active {
self.Active = true
prevSlashingDeadline = 0
}
enc, err := SerializeParams(&UpdateStorageParams{
Delta: delta,
NextProvingPeriodEnd: vmctx.BlockHeight() + build.SlashablePowerDelay,
PreviousProvingPeriodEnd: prevSlashingDeadline,
})
if err != nil {
return nil, err return nil, err
} }
_, err = vmctx.Send(StoragePowerAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc)
if err != nil {
return nil, err
}
self.ProvingSet = self.Sectors
self.ElectionPeriodStart = vmctx.BlockHeight()
c, err := vmctx.Storage().Put(self) c, err := vmctx.Storage().Put(self)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -813,7 +813,7 @@ func (t *MinerInfo) UnmarshalCBOR(r io.Reader) error {
return nil return nil
} }
func (t *SubmitPoStParams) MarshalCBOR(w io.Writer) error { func (t *SubmitFallbackPoStParams) MarshalCBOR(w io.Writer) error {
if t == nil { if t == nil {
_, err := w.Write(cbg.CborNull) _, err := w.Write(cbg.CborNull)
return err return err
@ -823,13 +823,10 @@ func (t *SubmitPoStParams) MarshalCBOR(w io.Writer) error {
} }
// t.t.Proof (types.EPostProof) (struct) // t.t.Proof (types.EPostProof) (struct)
if err := t.Proof.MarshalCBOR(w); err != nil {
return err
}
return nil return nil
} }
func (t *SubmitPoStParams) UnmarshalCBOR(r io.Reader) error { func (t *SubmitFallbackPoStParams) UnmarshalCBOR(r io.Reader) error {
br := cbg.GetPeeker(r) br := cbg.GetPeeker(r)
maj, extra, err := cbg.CborReadHeader(br) maj, extra, err := cbg.CborReadHeader(br)
@ -848,10 +845,6 @@ func (t *SubmitPoStParams) UnmarshalCBOR(r io.Reader) error {
{ {
if err := t.Proof.UnmarshalCBOR(br); err != nil {
return err
}
} }
return nil return nil
} }

View File

@ -506,7 +506,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
PostRand: vrfout, PostRand: vrfout,
} }
for _, win := range winners { for _, win := range winners {
ept.Winners = append(ept.Winners, types.EPostTicket{ ept.Candidates = append(ept.Candidates, types.EPostTicket{
Partial: win.PartialTicket[:], Partial: win.PartialTicket[:],
SectorID: win.SectorID, SectorID: win.SectorID,
ChallengeIndex: win.SectorChallengeIndex, ChallengeIndex: win.SectorChallengeIndex,

View File

@ -149,15 +149,14 @@ func GetMinerWorker(ctx context.Context, sm *StateManager, ts *types.TipSet, mad
return address.NewFromBytes(recp.Return) return address.NewFromBytes(recp.Return)
} }
func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) { func GetMinerElectionPeriodStart(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
var mas actors.StorageMinerActorState var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts) _, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil { if err != nil {
return 0, xerrors.Errorf("failed to load miner actor state: %w", err) return 0, xerrors.Errorf("failed to load miner actor state: %w", err)
} }
panic("idk what to do") return mas.ElectionPeriodStart, nil
//return mas.ProvingPeriodEnd, nil
} }
func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.ChainSectorInfo, error) { func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.ChainSectorInfo, error) {

View File

@ -555,7 +555,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("failed to get sector size for block miner: %w", err) return xerrors.Errorf("failed to get sector size for block miner: %w", err)
} }
for _, t := range h.EPostProof.Winners { for _, t := range h.EPostProof.Candidates {
if !types.IsTicketWinner(t.Partial, ssize, tpow, 1) { if !types.IsTicketWinner(t.Partial, ssize, tpow, 1) {
return xerrors.Errorf("miner created a block but was not a winner") return xerrors.Errorf("miner created a block but was not a winner")
} }
@ -667,7 +667,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc
} }
var winners []sectorbuilder.EPostCandidate var winners []sectorbuilder.EPostCandidate
for _, t := range h.EPostProof.Winners { for _, t := range h.EPostProof.Candidates {
var partial [32]byte var partial [32]byte
copy(partial[:], t.Partial) copy(partial[:], t.Partial)
winners = append(winners, sectorbuilder.EPostCandidate{ winners = append(winners, sectorbuilder.EPostCandidate{
@ -689,7 +689,7 @@ func (syncer *Syncer) VerifyElectionPoStProof(ctx context.Context, h *types.Bloc
return xerrors.Errorf("[TESTING] election post was invalid") return xerrors.Errorf("[TESTING] election post was invalid")
} }
hvrf := sha256.Sum256(h.EPostProof.PostRand) hvrf := sha256.Sum256(h.EPostProof.PostRand)
ok, err := sectorbuilder.VerifyPost(ctx, ssize, *sectorInfo, hvrf[:], h.EPostProof.Proof, winners, h.Miner) ok, err := sectorbuilder.VerifyElectionPost(ctx, ssize, *sectorInfo, hvrf[:], h.EPostProof.Proof, winners, h.Miner)
if err != nil { if err != nil {
return xerrors.Errorf("failed to verify election post: %w", err) return xerrors.Errorf("failed to verify election post: %w", err)
} }

View File

@ -29,7 +29,7 @@ type EPostTicket struct {
type EPostProof struct { type EPostProof struct {
Proof []byte Proof []byte
PostRand []byte PostRand []byte
Winners []EPostTicket Candidates []EPostTicket
} }
type BlockHeader struct { type BlockHeader struct {

View File

@ -349,11 +349,11 @@ func (t *EPostProof) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.t.Winners ([]types.EPostTicket) (slice) // t.t.Candidates ([]types.EPostTicket) (slice)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Winners)))); err != nil { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Candidates)))); err != nil {
return err return err
} }
for _, v := range t.Winners { for _, v := range t.Candidates {
if err := v.MarshalCBOR(w); err != nil { if err := v.MarshalCBOR(w); err != nil {
return err return err
} }
@ -410,21 +410,21 @@ func (t *EPostProof) UnmarshalCBOR(r io.Reader) error {
if _, err := io.ReadFull(br, t.PostRand); err != nil { if _, err := io.ReadFull(br, t.PostRand); err != nil {
return err return err
} }
// t.t.Winners ([]types.EPostTicket) (slice) // t.t.Candidates ([]types.EPostTicket) (slice)
maj, extra, err = cbg.CborReadHeader(br) maj, extra, err = cbg.CborReadHeader(br)
if err != nil { if err != nil {
return err return err
} }
if extra > 8192 { if extra > 8192 {
return fmt.Errorf("t.Winners: array too large (%d)", extra) return fmt.Errorf("t.Candidates: array too large (%d)", extra)
} }
if maj != cbg.MajArray { if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array") return fmt.Errorf("expected cbor array")
} }
if extra > 0 { if extra > 0 {
t.Winners = make([]EPostTicket, extra) t.Candidates = make([]EPostTicket, extra)
} }
for i := 0; i < int(extra); i++ { for i := 0; i < int(extra); i++ {
@ -433,7 +433,7 @@ func (t *EPostProof) UnmarshalCBOR(r io.Reader) error {
return err return err
} }
t.Winners[i] = v t.Candidates[i] = v
} }
return nil return nil

View File

@ -159,7 +159,7 @@ func DumpActorState(code cid.Cid, b []byte) (interface{}, error) {
typ, ok := i.builtInState[code] typ, ok := i.builtInState[code]
if !ok { if !ok {
return nil, xerrors.New("state type for actor not found") return nil, xerrors.Errorf("state type for actor %s not found", code)
} }
rv := reflect.New(typ) rv := reflect.New(typ)

View File

@ -12,7 +12,7 @@ import (
func TestBlockReward(t *testing.T) { func TestBlockReward(t *testing.T) {
coffer := types.FromFil(build.MiningRewardTotal).Int coffer := types.FromFil(build.MiningRewardTotal).Int
sum := new(big.Int) sum := new(big.Int)
N := build.HalvingPeriodBlocks N := build.HalvingPeriodEpochs
for i := 0; i < N; i++ { for i := 0; i < N; i++ {
a := MiningReward(types.BigInt{coffer}) a := MiningReward(types.BigInt{coffer})
sum = sum.Add(sum, a.Int) sum = sum.Add(sum, a.Int)

View File

@ -192,7 +192,7 @@ func main() {
epost := time.Now() epost := time.Now()
ok, err := sectorbuilder.VerifyPost(context.TODO(), sectorSize, sinfos, challenge[:], proof, candidates[:1], maddr) ok, err := sectorbuilder.VerifyElectionPost(context.TODO(), sectorSize, sinfos, challenge[:], proof, candidates[:1], maddr)
if err != nil { if err != nil {
return err return err
} }

View File

@ -60,7 +60,7 @@ var infoCmd = &cli.Command{
} }
fmt.Printf("Worker use: %d / %d (+%d)\n", wstat.Total-wstat.Reserved-wstat.Free, wstat.Total, wstat.Reserved) fmt.Printf("Worker use: %d / %d (+%d)\n", wstat.Total-wstat.Reserved-wstat.Free, wstat.Total, wstat.Reserved)
ppe, err := api.StateMinerProvingPeriodEnd(ctx, maddr, nil) ppe, err := api.StateMinerElectionPeriodStart(ctx, maddr, nil)
if err != nil { if err != nil {
return err return err
} }

View File

@ -93,7 +93,7 @@ func main() {
actors.SectorPreCommitInfo{}, actors.SectorPreCommitInfo{},
actors.PreCommittedSector{}, actors.PreCommittedSector{},
actors.MinerInfo{}, actors.MinerInfo{},
actors.SubmitPoStParams{}, actors.SubmitFallbackPoStParams{},
actors.PaymentVerifyParams{}, actors.PaymentVerifyParams{},
actors.UpdatePeerIDParams{}, actors.UpdatePeerIDParams{},
actors.MultiSigActorState{}, actors.MultiSigActorState{},

View File

@ -299,7 +299,7 @@ func (sb *SectorBuilder) GenerateEPostCandidates(sectorInfo SortedPublicSectorIn
return nil, err return nil, err
} }
challengeCount := challangeCount(uint64(len(sectorInfo.Values()))) challengeCount := electionPostChallengeCount(uint64(len(sectorInfo.Values())))
proverID := addressToProverID(sb.Miner) proverID := addressToProverID(sb.Miner)
return sectorbuilder.GenerateCandidates(sb.ssize, proverID, challengeSeed, challengeCount, privsectors) return sectorbuilder.GenerateCandidates(sb.ssize, proverID, challengeSeed, challengeCount, privsectors)
@ -328,8 +328,22 @@ func (sb *SectorBuilder) pubSectorToPriv(sectorInfo SortedPublicSectorInfo) (Sor
return NewSortedPrivateSectorInfo(out), nil return NewSortedPrivateSectorInfo(out), nil
} }
func (sb *SectorBuilder) GenerateFallbackPoSt(sectorInfo SortedPrivateSectorInfo, challengeSeed [CommLen]byte, faults []uint64) ([]byte, error) { func (sb *SectorBuilder) GenerateFallbackPoSt(sectorInfo SortedPublicSectorInfo, challengeSeed [CommLen]byte, faults []uint64) ([]EPostCandidate, []byte, error) {
panic("NYI") privsectors, err := sb.pubSectorToPriv(sectorInfo)
if err != nil {
return nil, nil, err
}
challengeCount := fallbackPostChallengeCount(uint64(len(sectorInfo.Values())))
proverID := addressToProverID(sb.Miner)
candidates, err := sectorbuilder.GenerateCandidates(sb.ssize, proverID, challengeSeed, challengeCount, privsectors)
if err != nil {
return nil, nil, err
}
proof, err := sectorbuilder.GeneratePoSt(sb.ssize, proverID, privsectors, challengeSeed, candidates)
return candidates, proof, err
} }
var UserBytesForSectorSize = sectorbuilder.GetMaxUserBytesPerStagedSector var UserBytesForSectorSize = sectorbuilder.GetMaxUserBytesPerStagedSector
@ -353,16 +367,29 @@ func NewSortedPublicSectorInfo(sectors []sectorbuilder.PublicSectorInfo) SortedP
return sectorbuilder.NewSortedPublicSectorInfo(sectors...) return sectorbuilder.NewSortedPublicSectorInfo(sectors...)
} }
func VerifyPost(ctx context.Context, sectorSize uint64, sectorInfo SortedPublicSectorInfo, challengeSeed []byte, proof []byte, winners []EPostCandidate, proverID address.Address) (bool, error) { func VerifyElectionPost(ctx context.Context, sectorSize uint64, sectorInfo SortedPublicSectorInfo, challengeSeed []byte, proof []byte, candidates []EPostCandidate, proverID address.Address) (bool, error) {
challengeCount := electionPostChallengeCount(uint64(len(sectorInfo.Values())))
return verifyPost(ctx, sectorSize, sectorInfo, challengeCount, challengeSeed, proof, candidates, proverID)
}
func VerifyFallbackPost(ctx context.Context, sectorSize uint64, sectorInfo SortedPublicSectorInfo, challengeSeed []byte, proof []byte, candidates []EPostCandidate, proverID address.Address) (bool, error) {
challengeCount := fallbackPostChallengeCount(uint64(len(sectorInfo.Values())))
return verifyPost(ctx, sectorSize, sectorInfo, challengeCount, challengeSeed, proof, candidates, proverID)
}
func verifyPost(ctx context.Context, sectorSize uint64, sectorInfo SortedPublicSectorInfo, challengeCount uint64, challengeSeed []byte, proof []byte, candidates []EPostCandidate, proverID address.Address) (bool, error) {
if challengeCount != uint64(len(candidates)) {
log.Warnf("verifyPost with wrong candidate count: expected %d, got %d", challengeCount, len(candidates))
return false, nil // user input, dont't error
}
var challengeSeeda [CommLen]byte var challengeSeeda [CommLen]byte
copy(challengeSeeda[:], challengeSeed) copy(challengeSeeda[:], challengeSeed)
challengeCount := challangeCount(uint64(len(sectorInfo.Values())))
_, span := trace.StartSpan(ctx, "VerifyPoSt") _, span := trace.StartSpan(ctx, "VerifyPoSt")
defer span.End() defer span.End()
prover := addressToProverID(proverID) prover := addressToProverID(proverID)
return sectorbuilder.VerifyPoSt(sectorSize, sectorInfo, challengeSeeda, challengeCount, proof, winners, prover) return sectorbuilder.VerifyPoSt(sectorSize, sectorInfo, challengeSeeda, challengeCount, proof, candidates, prover)
} }
func GeneratePieceCommitment(piece io.Reader, pieceSize uint64) (commP [CommLen]byte, err error) { func GeneratePieceCommitment(piece io.Reader, pieceSize uint64) (commP [CommLen]byte, err error) {
@ -383,7 +410,15 @@ func GenerateDataCommitment(ssize uint64, pieces []PublicPieceInfo) ([CommLen]by
return sectorbuilder.GenerateDataCommitment(ssize, pieces) return sectorbuilder.GenerateDataCommitment(ssize, pieces)
} }
func challangeCount(sectors uint64) uint64 { func electionPostChallengeCount(sectors uint64) uint64 {
// ceil(sectors / build.SectorChallengeRatioDiv) // ceil(sectors / build.SectorChallengeRatioDiv)
return (sectors + build.SectorChallengeRatioDiv - 1) / build.SectorChallengeRatioDiv return (sectors + build.SectorChallengeRatioDiv - 1) / build.SectorChallengeRatioDiv
} }
func fallbackPostChallengeCount(sectors uint64) uint64 {
challengeCount := electionPostChallengeCount(sectors)
if challengeCount > build.MaxFallbackPostChallengeCount {
return build.MaxFallbackPostChallengeCount
}
return challengeCount
}

View File

@ -102,7 +102,7 @@ func (s *seal) post(t *testing.T, sb *sectorbuilder.SectorBuilder) time.Time {
t.Fatalf("%+v", err) t.Fatalf("%+v", err)
} }
ok, err := sectorbuilder.VerifyPost(context.TODO(), sb.SectorSize(), ssi, cSeed[:], postProof, candndates, sb.Miner) ok, err := sectorbuilder.VerifyElectionPost(context.TODO(), sb.SectorSize(), ssi, cSeed[:], postProof, candndates, sb.Miner)
if err != nil { if err != nil {
t.Fatalf("%+v", err) t.Fatalf("%+v", err)
} }

View File

@ -76,8 +76,8 @@ func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *
return stmgr.GetMinerPeerID(ctx, a.StateManager, ts, m) return stmgr.GetMinerPeerID(ctx, a.StateManager, ts, m)
} }
func (a *StateAPI) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { func (a *StateAPI) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {
return stmgr.GetMinerProvingPeriodEnd(ctx, a.StateManager, ts, actor) return stmgr.GetMinerElectionPeriodStart(ctx, a.StateManager, ts, actor)
} }
func (a *StateAPI) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { func (a *StateAPI) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) {

140
storage/fpost_run.go Normal file
View File

@ -0,0 +1,140 @@
package storage
import (
"context"
"time"
ffi "github.com/filecoin-project/filecoin-ffi"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sectorbuilder"
)
func (s *fpostScheduler) doPost(ctx context.Context, eps uint64, ts *types.TipSet) {
ctx, abort := context.WithCancel(ctx)
s.abort = abort
s.activeEPS = eps
go func() {
defer abort()
ctx, span := trace.StartSpan(ctx, "fpostScheduler.doPost")
defer span.End()
proof, err := s.runPost(ctx, eps, ts)
if err != nil {
log.Errorf("runPost failed: %+v", err)
return
}
if err := s.submitPost(ctx, proof); err != nil {
log.Errorf("submitPost failed: %+v", err)
return
}
}()
}
func (s *fpostScheduler) runPost(ctx context.Context, eps uint64, ts *types.TipSet) (*actors.SubmitFallbackPoStParams, error) {
ctx, span := trace.StartSpan(ctx, "storage.runPost")
defer span.End()
challengeRound := int64(eps + build.FallbackPoStDelay)
rand, err := s.api.ChainGetRandomness(ctx, ts.Key(), challengeRound)
if err != nil {
return nil, xerrors.Errorf("failed to get chain randomness for fpost (ts=%d; eps=%d): %w", ts.Height(), eps, err)
}
ssi, err := s.sortedSectorInfo(ctx, ts)
if err != nil {
return nil, xerrors.Errorf("getting sorted sector info: %w", err)
}
log.Infow("running fPoSt", "chain-random", rand, "eps", eps, "height", ts.Height())
tsStart := time.Now()
var faults []uint64 // TODO
var seed [32]byte
copy(seed[:], rand)
scandidates, proof, err := s.sb.GenerateFallbackPoSt(ssi, seed, faults)
if err != nil {
return nil, xerrors.Errorf("running post failed: %w", err)
}
elapsed := time.Since(tsStart)
log.Infow("submitting PoSt", "pLen", len(proof), "elapsed", elapsed)
candidates := make([]types.EPostTicket, len(scandidates))
for i, sc := range scandidates {
candidates[i] = types.EPostTicket{
Partial: sc.PartialTicket[:],
SectorID: sc.SectorID,
ChallengeIndex: sc.SectorChallengeIndex,
}
}
return &actors.SubmitFallbackPoStParams{
Proof: proof,
Candidates: candidates,
}, nil
}
func (s *fpostScheduler) sortedSectorInfo(ctx context.Context, ts *types.TipSet) (sectorbuilder.SortedPublicSectorInfo, error) {
sset, err := s.api.StateMinerProvingSet(ctx, s.actor, ts)
if err != nil {
return sectorbuilder.SortedPublicSectorInfo{}, xerrors.Errorf("failed to get proving set for miner (tsH: %d): %w", ts.Height(), err)
}
if len(sset) == 0 {
log.Warn("empty proving set! (ts.H: %d)", ts.Height())
}
sbsi := make([]ffi.PublicSectorInfo, len(sset))
for k, sector := range sset {
var commR [sectorbuilder.CommLen]byte
copy(commR[:], sector.CommR)
sbsi[k] = ffi.PublicSectorInfo{
SectorID: sector.SectorID,
CommR: commR,
}
}
return sectorbuilder.NewSortedPublicSectorInfo(sbsi), nil
}
func (s *fpostScheduler) submitPost(ctx context.Context, proof *actors.SubmitFallbackPoStParams) error {
ctx, span := trace.StartSpan(ctx, "storage.commitPost")
defer span.End()
enc, aerr := actors.SerializeParams(proof)
if aerr != nil {
return xerrors.Errorf("could not serialize submit post parameters: %w", aerr)
}
msg := &types.Message{
To: s.actor,
From: s.worker,
Method: actors.MAMethods.SubmitFallbackPoSt,
Params: enc,
Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late
GasLimit: types.NewInt(10000000), // i dont know help
GasPrice: types.NewInt(1),
}
// TODO: consider maybe caring about the output
sm, err := s.api.MpoolPushMessage(ctx, msg)
if err != nil {
return xerrors.Errorf("pushing message to mpool: %w", err)
}
log.Infof("Submitted fallback post: %s", sm.Cid())
return nil
}

141
storage/fpost_sched.go Normal file
View File

@ -0,0 +1,141 @@
package storage
import (
"context"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/address"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sectorbuilder"
)
const Inactive = 0
const StartConfidence = 4 // TODO: config
type fpostScheduler struct {
api storageMinerApi
sb *sectorbuilder.SectorBuilder
actor address.Address
worker address.Address
cur *types.TipSet
// if a post is in progress, this indicates for which ElectionPeriodStart
activeEPS uint64
abort context.CancelFunc
}
func (s *fpostScheduler) run(ctx context.Context) {
notifs, err := s.api.ChainNotify(ctx)
if err != nil {
return
}
current := <-notifs
if len(current) != 1 {
panic("expected first notif to have len = 1")
}
if current[0].Type != store.HCCurrent {
panic("expected first notif to tell current ts")
}
if err := s.update(ctx, current[0].Val); err != nil {
panic(err)
}
// not fine to panic after this point
for {
select {
case changes := <-notifs:
ctx, span := trace.StartSpan(ctx, "fpostScheduler.headChange")
var lowest, highest *types.TipSet = s.cur, nil
for _, change := range changes {
switch change.Type {
case store.HCRevert:
lowest = change.Val
case store.HCApply:
highest = change.Val
}
}
if err := s.revert(ctx, lowest); err != nil {
log.Error("handling head reverts in fallbackPost sched: %+v", err)
}
if err := s.update(ctx, highest); err != nil {
log.Error("handling head updates in fallbackPost sched: %+v", err)
}
span.End()
}
}
}
func (s *fpostScheduler) revert(ctx context.Context, newLowest *types.TipSet) error {
if s.cur == newLowest {
return nil
}
s.cur = newLowest
newEPS, _, err := s.shouldFallbackPost(ctx, newLowest)
if err != nil {
return err
}
if newEPS != s.activeEPS {
s.abortActivePoSt()
}
return nil
}
func (s *fpostScheduler) update(ctx context.Context, new *types.TipSet) error {
newEPS, start, err := s.shouldFallbackPost(ctx, new)
if err != nil {
return err
}
if newEPS != s.activeEPS {
s.abortActivePoSt()
}
if newEPS != Inactive && start {
s.doPost(ctx, newEPS, new)
}
return nil
}
func (s *fpostScheduler) abortActivePoSt() {
if s.activeEPS == Inactive {
return // noop
}
if s.abort != nil {
s.abort()
}
log.Warnf("Aborting Fallback PoSt (EPS: %d)", s.activeEPS)
s.activeEPS = 0
s.abort = nil
}
func (s *fpostScheduler) shouldFallbackPost(ctx context.Context, ts *types.TipSet) (uint64, bool, error) {
eps, err := s.api.StateMinerElectionPeriodStart(ctx, s.actor, ts)
if err != nil {
return 0, false, xerrors.Errorf("getting ElectionPeriodStart: %w", err)
}
if ts.Height() >= eps+build.FallbackPoStDelay {
return eps, ts.Height() >= eps+build.FallbackPoStDelay+StartConfidence, nil
}
return 0, false, nil
}

View File

@ -53,7 +53,7 @@ type storageMinerApi interface {
// Call a read only method on actors (no interaction with the chain required) // Call a read only method on actors (no interaction with the chain required)
StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error)
StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error)
StateMinerProvingPeriodEnd(context.Context, address.Address, *types.TipSet) (uint64, error) StateMinerElectionPeriodStart(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error)
StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error) StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error)
StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error) StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.ChainSectorInfo, error)
StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error) StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error)
@ -99,7 +99,14 @@ func (m *Miner) Run(ctx context.Context) error {
m.events = events.NewEvents(ctx, m.api) m.events = events.NewEvents(ctx, m.api)
go m.beginPosting(ctx) fps := &fpostScheduler{
api: m.api,
sb: m.sb,
actor: m.maddr,
worker: m.worker,
}
go fps.run(ctx)
go m.sectorStateLoop(ctx) go m.sectorStateLoop(ctx)
return nil return nil
} }

View File

@ -1,301 +0,0 @@
package storage
import (
"context"
ffi "github.com/filecoin-project/filecoin-ffi"
"time"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sectorbuilder"
)
const postMsgTimeout = 20
func (m *Miner) beginPosting(ctx context.Context) {
ts, err := m.api.ChainHead(context.TODO())
if err != nil {
log.Error(err)
return
}
sppe, err := m.api.StateMinerProvingPeriodEnd(ctx, m.maddr, ts)
if err != nil {
log.Errorf("failed to get proving period end for miner (ts h: %d): %s", ts.Height(), err)
return
}
if sppe == 0 {
log.Warn("Not proving yet")
return
}
m.postLk.Lock()
if m.schedPost > 0 {
log.Warnf("PoSts already running %d", m.schedPost)
m.postLk.Unlock()
return
}
// height needs to be +1, because otherwise we'd be trying to schedule PoSt
// at current block height
ppe, _ := actors.ProvingPeriodEnd(sppe, ts.Height()+1)
m.schedPost = ppe
m.postLk.Unlock()
if build.PoStChallangeTime > ppe {
ppe = build.PoStChallangeTime
}
log.Infof("Scheduling post at height %d (begin ts: %d, statePPE: %d)", ppe-build.PoStChallangeTime, ts.Height(), sppe)
err = m.events.ChainAt(m.computePost(m.schedPost), func(ctx context.Context, 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
}
headPPE, provingPeriod := actors.ProvingPeriodEnd(ppe, ts.Height())
if headPPE > ppe {
log.Warnw("PoSt computation running behind chain", "headPPE", headPPE, "ppe", ppe)
ppe = headPPE
}
m.postLk.Lock()
if m.schedPost >= ppe {
// this probably can't happen
log.Errorw("PoSt already scheduled", "schedPost", m.schedPost, "ppe", ppe)
m.postLk.Unlock()
return
}
m.schedPost = ppe
m.postLk.Unlock()
log.Infow("scheduling PoSt", "post-height", ppe-build.PoStChallangeTime,
"height", ts.Height(), "ppe", ppe, "proving-period", provingPeriod)
err = m.events.ChainAt(m.computePost(ppe), func(ctx context.Context, 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: %+v", err)
return
}
}
type post struct {
m *Miner
ppe uint64
ts *types.TipSet
// prep
sset []*api.ChainSectorInfo
r []byte
// run
proof []byte
// commit
smsg *types.SignedMessage
}
func (p *post) doPost(ctx context.Context) error {
ctx, span := trace.StartSpan(ctx, "storage.computePost")
defer span.End()
if err := p.preparePost(ctx); err != nil {
return xerrors.Errorf("prepare: %w", err)
}
if err := p.runPost(ctx); err != nil {
return xerrors.Errorf("run: %w", err)
}
if err := p.commitPost(ctx); err != nil {
return xerrors.Errorf("commit: %w", err)
}
if err := p.waitCommit(ctx); err != nil {
return xerrors.Errorf("wait: %w", err)
}
return nil
}
func (p *post) preparePost(ctx context.Context) error {
ctx, span := trace.StartSpan(ctx, "storage.preparePost")
defer span.End()
log.Info("preparePost")
sset, err := p.m.api.StateMinerProvingSet(ctx, p.m.maddr, p.ts)
if err != nil {
return xerrors.Errorf("failed to get proving set for miner (tsH: %d): %w", p.ts.Height(), err)
}
if len(sset) == 0 {
log.Warn("empty proving set! (ts.H: %d)", p.ts.Height())
}
p.sset = sset
challengeRound := int64(p.ppe) - int64(build.PoStChallangeTime+build.PoStRandomnessLookback)
r, err := p.m.api.ChainGetRandomness(ctx, p.ts.Key(), challengeRound)
if err != nil {
return xerrors.Errorf("failed to get chain randomness for post (ts=%d; ppe=%d): %w", p.ts.Height(), p.ppe, err)
}
p.r = r
return nil
}
func (p *post) sortedSectorInfo() sectorbuilder.SortedPrivateSectorInfo {
panic("NYI")
sbsi := make([]ffi.PrivateSectorInfo, len(p.sset))
for k, sector := range p.sset {
var commR [sectorbuilder.CommLen]byte
copy(commR[:], sector.CommR)
sbsi[k] = ffi.PrivateSectorInfo{
SectorID: sector.SectorID,
CommR: commR,
}
}
return sectorbuilder.NewSortedPrivateSectorInfo(sbsi)
}
func (p *post) runPost(ctx context.Context) error {
ctx, span := trace.StartSpan(ctx, "storage.runPost")
defer span.End()
log.Infow("running PoSt", "delayed-by",
int64(p.ts.Height())-(int64(p.ppe)-int64(build.PoStChallangeTime)),
"chain-random", p.r, "ppe", p.ppe, "height", p.ts.Height(), "sectors", len(p.sset))
tsStart := time.Now()
var faults []uint64 // TODO
var seed [32]byte
copy(seed[:], p.r)
proof, err := p.m.sb.GenerateFallbackPoSt(p.sortedSectorInfo(), seed, faults)
if err != nil {
return xerrors.Errorf("running post failed: %w", err)
}
elapsed := time.Since(tsStart)
p.proof = proof
log.Infow("submitting PoSt", "pLen", len(proof), "elapsed", elapsed)
return nil
}
func (p *post) commitPost(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "storage.commitPost")
defer span.End()
panic("NYI")
/*
params := &actors.SubmitPoStParams{
//Proof: p.proof,
}
enc, aerr := actors.SerializeParams(params)
if aerr != nil {
return xerrors.Errorf("could not serialize submit post parameters: %w", aerr)
}
msg := &types.Message{
To: p.m.maddr,
From: p.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(1000000), // i dont know help
GasPrice: types.NewInt(1),
}
log.Info("mpush")
p.smsg, err = p.m.api.MpoolPushMessage(ctx, msg)
if err != nil {
return xerrors.Errorf("pushing message to mpool: %w", err)
}
*/
return nil
}
func (p *post) waitCommit(ctx context.Context) error {
ctx, span := trace.StartSpan(ctx, "storage.waitPost")
defer span.End()
log.Infof("Waiting for post %s to appear on chain", p.smsg.Cid())
err := p.m.events.CalledMsg(ctx, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH uint64) (more bool, err error) {
if rec.ExitCode != 0 {
log.Warnf("SubmitPoSt EXIT: %d", rec.ExitCode)
}
log.Infof("Post made it on chain! (height=%d)", ts.Height())
return false, nil
}, func(ctx context.Context, ts *types.TipSet) error {
log.Warn("post message reverted")
return nil
}, 3, postMsgTimeout, p.smsg)
if err != nil {
return xerrors.Errorf("waiting for post to appear on chain: %w", err)
}
return nil
}
func (m *Miner) computePost(ppe uint64) func(ctx context.Context, ts *types.TipSet, curH uint64) error {
called := 0
return func(ctx context.Context, ts *types.TipSet, curH uint64) error {
called++
if called > 1 {
log.Errorw("BUG: computePost callback called again", "ppe", ppe,
"height", ts.Height(), "curH", curH, "called", called-1)
return nil
}
err := (&post{
m: m,
ppe: ppe,
ts: ts,
}).doPost(ctx)
m.scheduleNextPost(ppe + build.ProvingPeriodDuration)
if err != nil {
return xerrors.Errorf("doPost: %w", err)
}
return nil
}
}

View File

@ -220,8 +220,6 @@ func (m *Miner) committing(ctx context.Context, sector SectorInfo) (func(*Sector
return nil, xerrors.New("UNHANDLED: submitting sector proof failed") return nil, xerrors.New("UNHANDLED: submitting sector proof failed")
} }
m.beginPosting(ctx)
return func(info *SectorInfo) { return func(info *SectorInfo) {
mcid := smsg.Cid() mcid := smsg.Cid()
info.CommitMessage = &mcid info.CommitMessage = &mcid