2019-09-26 23:07:40 +00:00
package storage
import (
"context"
2019-10-10 23:41:48 +00:00
"time"
2019-09-26 23:07:40 +00:00
"golang.org/x/xerrors"
2019-10-18 04:47:41 +00:00
"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"
2019-09-26 23:07:40 +00:00
)
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
2019-09-30 22:56:23 +00:00
ppe , _ = actors . ProvingPeriodEnd ( ppe , ts . Height ( ) + 1 )
m . schedPost = ppe
2019-09-26 23:07:40 +00:00
m . schedLk . Unlock ( )
2019-10-28 08:15:08 +00:00
log . Infof ( "Scheduling post at height %d" , ppe - build . PoStChallangeTime )
2019-09-26 23:07:40 +00:00
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
2019-10-28 08:15:08 +00:00
} , PoStConfidence , ppe - build . PoStChallangeTime )
2019-09-26 23:07:40 +00:00
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 {
2019-10-10 23:41:48 +00:00
log . Warnw ( "PoSt computation running behind chain" , "headPPE" , headPPE , "ppe" , ppe )
2019-09-26 23:07:40 +00:00
ppe = headPPE
}
m . schedLk . Lock ( )
if m . schedPost >= ppe {
// this probably can't happen
2019-10-10 23:41:48 +00:00
log . Errorw ( "PoSt already scheduled" , "schedPost" , m . schedPost , "ppe" , ppe )
2019-09-26 23:07:40 +00:00
m . schedLk . Unlock ( )
return
}
m . schedPost = ppe
m . schedLk . Unlock ( )
2019-10-28 08:15:08 +00:00
log . Infow ( "scheduling PoSt" , "post-height" , ppe - build . PoStChallangeTime ,
2019-10-10 23:41:48 +00:00
"height" , ts . Height ( ) , "ppe" , ppe , "proving-period" , 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
2019-10-28 08:15:08 +00:00
} , PoStConfidence , ppe - build . PoStChallangeTime )
2019-09-26 23:07:40 +00:00
if err != nil {
// TODO: This is BAD, figure something out
2019-10-10 23:41:48 +00:00
log . Errorf ( "scheduling PoSt failed: %+v" , err )
2019-09-26 23:07:40 +00:00
return
}
}
func ( m * Miner ) computePost ( ppe uint64 ) func ( ts * types . TipSet , curH uint64 ) error {
2019-10-12 23:18:32 +00:00
called := 0
2019-09-26 23:07:40 +00:00
return func ( ts * types . TipSet , curH uint64 ) error {
2019-10-15 20:13:49 +00:00
called ++
if called > 1 {
2019-10-12 23:18:32 +00:00
log . Errorw ( "BUG: computePost callback called again" , "ppe" , ppe ,
2019-10-15 20:13:49 +00:00
"height" , ts . Height ( ) , "curH" , curH , "called" , called - 1 )
return nil
2019-10-12 23:18:32 +00:00
}
2019-09-26 23:07:40 +00:00
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 )
}
2019-10-28 08:15:08 +00:00
r , err := m . api . ChainGetRandomness ( ctx , ts , nil , int ( int64 ( ts . Height ( ) ) - int64 ( ppe ) + int64 ( build . PoStChallangeTime ) + int64 ( build . PoStRandomnessLookback ) ) ) // TODO: review: check math
2019-09-26 23:07:40 +00:00
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
}
2019-10-10 23:41:48 +00:00
log . Infow ( "running PoSt" , "delayed-by" ,
2019-10-28 08:15:08 +00:00
int64 ( ts . Height ( ) ) - ( int64 ( ppe ) - int64 ( build . PoStChallangeTime ) ) ,
2019-10-10 23:41:48 +00:00
"chain-random" , r , "ppe" , ppe , "height" , ts . Height ( ) )
tsStart := time . Now ( )
2019-09-26 23:07:40 +00:00
var faults [ ] uint64
proof , err := m . secst . RunPoSt ( ctx , sset , r , faults )
if err != nil {
return xerrors . Errorf ( "running post failed: %w" , err )
}
2019-10-10 23:41:48 +00:00
elapsed := time . Since ( tsStart )
2019-09-26 23:07:40 +00:00
2019-10-10 23:41:48 +00:00
log . Infow ( "submitting PoSt" , "pLen" , len ( proof ) , "elapsed" , elapsed )
2019-09-26 23:07:40 +00:00
params := & actors . SubmitPoStParams {
Proof : proof ,
2019-10-04 18:30:30 +00:00
DoneSet : types . BitFieldFromSet ( nil ) ,
2019-09-26 23:07:40 +00:00
}
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
2019-10-18 04:08:36 +00:00
GasLimit : types . NewInt ( 1000000 /* i dont know help */ ) ,
2019-09-26 23:07:40 +00:00
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...
2019-10-08 05:51:34 +00:00
rec , err := m . api . StateWaitMsg ( ctx , smsg . Cid ( ) )
2019-09-26 23:07:40 +00:00
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
}