2019-09-06 06:26:02 +00:00
package stmgr
import (
2020-04-30 22:11:14 +00:00
"bytes"
2019-09-06 06:26:02 +00:00
"context"
2020-09-04 03:28:42 +00:00
"fmt"
2020-04-20 17:43:02 +00:00
"os"
2020-07-03 16:57:58 +00:00
"reflect"
2020-09-04 03:28:42 +00:00
"runtime"
"strings"
2020-04-17 23:36:54 +00:00
2020-10-06 08:33:55 +00:00
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/network"
2020-04-20 17:43:02 +00:00
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
2020-07-01 04:57:49 +00:00
"github.com/filecoin-project/go-bitfield"
2020-09-07 03:49:10 +00:00
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto"
2020-09-28 19:48:08 +00:00
"github.com/filecoin-project/go-state-types/rt"
2020-09-22 18:14:55 +00:00
2020-09-28 19:48:08 +00:00
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
2020-09-30 17:11:48 +00:00
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
2021-01-21 19:43:36 +00:00
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
2020-02-08 02:18:32 +00:00
2019-10-18 04:47:41 +00:00
"github.com/filecoin-project/lotus/api"
2020-10-08 20:32:54 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin"
2020-09-14 22:43:12 +00:00
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
2020-09-15 13:29:25 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
2020-09-14 22:43:12 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
2020-09-22 18:14:55 +00:00
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
2020-10-08 20:32:54 +00:00
"github.com/filecoin-project/lotus/chain/actors/policy"
2020-04-30 22:11:14 +00:00
"github.com/filecoin-project/lotus/chain/beacon"
2020-03-31 23:13:37 +00:00
"github.com/filecoin-project/lotus/chain/state"
2020-01-17 02:33:43 +00:00
"github.com/filecoin-project/lotus/chain/store"
2019-10-18 04:47:41 +00:00
"github.com/filecoin-project/lotus/chain/types"
2020-01-17 02:33:43 +00:00
"github.com/filecoin-project/lotus/chain/vm"
2020-09-22 18:14:55 +00:00
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
2020-03-31 23:13:37 +00:00
"github.com/filecoin-project/lotus/node/modules/dtypes"
2019-09-06 06:26:02 +00:00
)
2020-03-31 23:13:37 +00:00
func GetNetworkName ( ctx context . Context , sm * StateManager , st cid . Cid ) ( dtypes . NetworkName , error ) {
2020-09-14 22:43:12 +00:00
act , err := sm . LoadActorRaw ( ctx , init_ . Address , st )
if err != nil {
return "" , err
}
ias , err := init_ . Load ( sm . cs . Store ( ctx ) , act )
2020-03-31 23:13:37 +00:00
if err != nil {
2020-07-14 11:45:45 +00:00
return "" , err
2020-03-31 23:13:37 +00:00
}
2020-09-15 04:55:49 +00:00
return ias . NetworkName ( )
2020-03-31 23:13:37 +00:00
}
2019-10-23 17:39:14 +00:00
func GetMinerWorkerRaw ( ctx context . Context , sm * StateManager , st cid . Cid , maddr address . Address ) ( address . Address , error ) {
2020-09-15 04:55:49 +00:00
state , err := sm . StateTree ( st )
2019-09-06 06:26:02 +00:00
if err != nil {
2020-09-15 04:55:49 +00:00
return address . Undef , xerrors . Errorf ( "(get sset) failed to load state tree: %w" , err )
}
act , err := state . GetActor ( maddr )
if err != nil {
return address . Undef , xerrors . Errorf ( "(get sset) failed to load miner actor: %w" , err )
2019-09-06 06:26:02 +00:00
}
2020-09-14 22:43:12 +00:00
mas , err := miner . Load ( sm . cs . Store ( ctx ) , act )
2020-02-21 16:57:40 +00:00
if err != nil {
2020-09-15 04:55:49 +00:00
return address . Undef , xerrors . Errorf ( "(get sset) failed to load miner actor state: %w" , err )
2020-02-21 16:57:40 +00:00
}
2020-09-14 22:43:12 +00:00
info , err := mas . Info ( )
2020-07-01 11:47:40 +00:00
if err != nil {
2020-09-14 22:43:12 +00:00
return address . Undef , xerrors . Errorf ( "failed to load actor info: %w" , err )
2020-07-01 11:47:40 +00:00
}
2020-09-15 04:55:49 +00:00
return vm . ResolveToKeyAddr ( state , sm . cs . Store ( ctx ) , info . Worker )
2019-09-06 06:26:02 +00:00
}
2020-09-16 05:47:24 +00:00
func GetPower ( ctx context . Context , sm * StateManager , ts * types . TipSet , maddr address . Address ) ( power . Claim , power . Claim , bool , error ) {
2020-04-17 23:36:54 +00:00
return GetPowerRaw ( ctx , sm , ts . ParentState ( ) , maddr )
2020-04-02 01:25:58 +00:00
}
2020-09-16 05:47:24 +00:00
func GetPowerRaw ( ctx context . Context , sm * StateManager , st cid . Cid , maddr address . Address ) ( power . Claim , power . Claim , bool , error ) {
2020-09-22 04:12:07 +00:00
act , err := sm . LoadActorRaw ( ctx , power . Address , st )
2020-02-11 02:33:27 +00:00
if err != nil {
2020-09-16 05:47:24 +00:00
return power . Claim { } , power . Claim { } , false , xerrors . Errorf ( "(get sset) failed to load power actor state: %w" , err )
2020-02-11 02:33:27 +00:00
}
2019-09-09 20:03:10 +00:00
2020-09-16 05:47:24 +00:00
pas , err := power . Load ( sm . cs . Store ( ctx ) , act )
2020-09-14 22:43:12 +00:00
if err != nil {
2020-09-16 05:47:24 +00:00
return power . Claim { } , power . Claim { } , false , err
2020-09-14 22:43:12 +00:00
}
2020-09-16 05:47:24 +00:00
tpow , err := pas . TotalPower ( )
2020-09-14 22:43:12 +00:00
if err != nil {
2020-09-16 05:47:24 +00:00
return power . Claim { } , power . Claim { } , false , err
2020-09-14 22:43:12 +00:00
}
2020-04-17 22:02:04 +00:00
var mpow power . Claim
2020-09-26 16:06:16 +00:00
var minpow bool
2019-09-09 20:03:10 +00:00
if maddr != address . Undef {
2020-09-15 19:13:13 +00:00
var found bool
2020-09-16 05:47:24 +00:00
mpow , found , err = pas . MinerPower ( maddr )
2020-09-15 19:13:13 +00:00
if err != nil || ! found {
// TODO: return an error when not found?
2020-09-16 05:47:24 +00:00
return power . Claim { } , power . Claim { } , false , err
2020-04-13 21:05:34 +00:00
}
2019-09-09 20:03:10 +00:00
2020-09-26 16:06:16 +00:00
minpow , err = pas . MinerNominalPowerMeetsConsensusMinimum ( maddr )
if err != nil {
return power . Claim { } , power . Claim { } , false , err
}
2020-09-16 05:47:24 +00:00
}
return mpow , tpow , minpow , nil
2019-09-09 20:03:10 +00:00
}
2019-09-17 08:00:38 +00:00
2020-09-15 04:55:49 +00:00
func PreCommitInfo ( ctx context . Context , sm * StateManager , maddr address . Address , sid abi . SectorNumber , ts * types . TipSet ) ( * miner . SectorPreCommitOnChainInfo , error ) {
2020-09-14 22:43:12 +00:00
act , err := sm . LoadActor ( ctx , maddr , ts )
2020-04-04 02:55:19 +00:00
if err != nil {
2020-09-15 04:55:49 +00:00
return nil , xerrors . Errorf ( "(get sset) failed to load miner actor: %w" , err )
2020-04-04 02:55:19 +00:00
}
2020-09-15 04:55:49 +00:00
mas , err := miner . Load ( sm . cs . Store ( ctx ) , act )
2020-04-04 02:55:19 +00:00
if err != nil {
2020-09-15 04:55:49 +00:00
return nil , xerrors . Errorf ( "(get sset) failed to load miner actor state: %w" , err )
2020-04-04 02:55:19 +00:00
}
2020-09-15 04:55:49 +00:00
return mas . GetPrecommittedSector ( sid )
2020-04-04 02:55:19 +00:00
}
2020-05-28 00:06:29 +00:00
func MinerSectorInfo ( ctx context . Context , sm * StateManager , maddr address . Address , sid abi . SectorNumber , ts * types . TipSet ) ( * miner . SectorOnChainInfo , error ) {
2020-09-15 04:55:49 +00:00
act , err := sm . LoadActor ( ctx , maddr , ts )
2020-05-28 00:06:29 +00:00
if err != nil {
2020-09-15 04:55:49 +00:00
return nil , xerrors . Errorf ( "(get sset) failed to load miner actor: %w" , err )
2020-05-28 00:06:29 +00:00
}
2020-09-15 04:55:49 +00:00
mas , err := miner . Load ( sm . cs . Store ( ctx ) , act )
2020-05-28 00:06:29 +00:00
if err != nil {
2020-09-15 04:55:49 +00:00
return nil , xerrors . Errorf ( "(get sset) failed to load miner actor state: %w" , err )
2020-05-28 00:06:29 +00:00
}
2020-09-15 04:55:49 +00:00
return mas . GetSector ( sid )
2020-05-28 00:06:29 +00:00
}
2020-11-05 17:16:22 +00:00
func GetSectorsForWinningPoSt ( ctx context . Context , nv network . Version , pv ffiwrapper . Verifier , sm * StateManager , st cid . Cid , maddr address . Address , rand abi . PoStRandomness ) ( [ ] builtin . SectorInfo , error ) {
2020-09-15 11:04:45 +00:00
act , err := sm . LoadActorRaw ( ctx , maddr , st )
if err != nil {
return nil , xerrors . Errorf ( "failed to load miner actor: %w" , err )
}
2020-07-14 11:45:45 +00:00
2020-09-15 11:04:45 +00:00
mas , err := miner . Load ( sm . cs . Store ( ctx ) , act )
2020-07-01 04:57:49 +00:00
if err != nil {
2020-09-15 11:04:45 +00:00
return nil , xerrors . Errorf ( "failed to load miner actor state: %w" , err )
2020-07-01 04:57:49 +00:00
}
2020-11-05 17:16:22 +00:00
var provingSectors bitfield . BitField
if nv < network . Version7 {
allSectors , err := miner . AllPartSectors ( mas , miner . Partition . AllSectors )
if err != nil {
return nil , xerrors . Errorf ( "get all sectors: %w" , err )
}
2020-09-20 21:04:45 +00:00
2020-11-05 17:16:22 +00:00
faultySectors , err := miner . AllPartSectors ( mas , miner . Partition . FaultySectors )
if err != nil {
return nil , xerrors . Errorf ( "get faulty sectors: %w" , err )
}
2020-09-20 21:04:45 +00:00
2020-11-05 17:16:22 +00:00
provingSectors , err = bitfield . SubtractBitField ( allSectors , faultySectors )
if err != nil {
return nil , xerrors . Errorf ( "calc proving sectors: %w" , err )
}
} else {
provingSectors , err = miner . AllPartSectors ( mas , miner . Partition . ActiveSectors )
if err != nil {
return nil , xerrors . Errorf ( "get active sectors sectors: %w" , err )
}
2020-07-01 04:57:49 +00:00
}
numProvSect , err := provingSectors . Count ( )
2020-04-17 14:47:19 +00:00
if err != nil {
2020-07-01 04:57:49 +00:00
return nil , xerrors . Errorf ( "failed to count bits: %w" , err )
2020-04-17 14:47:19 +00:00
}
2020-07-01 04:57:49 +00:00
// TODO(review): is this right? feels fishy to me
if numProvSect == 0 {
2020-04-23 21:12:42 +00:00
return nil , nil
}
2020-09-15 11:04:45 +00:00
info , err := mas . Info ( )
if err != nil {
return nil , xerrors . Errorf ( "getting miner info: %w" , err )
}
2020-04-17 14:47:19 +00:00
mid , err := address . IDFromAddress ( maddr )
if err != nil {
return nil , xerrors . Errorf ( "getting miner ID: %w" , err )
}
2021-01-20 02:21:23 +00:00
proofType , err := miner . WinningPoStProofTypeFromWindowPoStProofType ( nv , info . WindowPoStProofType )
2020-04-17 14:47:19 +00:00
if err != nil {
2021-01-20 02:21:23 +00:00
return nil , xerrors . Errorf ( "determining winning post proof type: %w" , err )
2020-04-17 14:47:19 +00:00
}
2021-01-19 01:44:16 +00:00
ids , err := pv . GenerateWinningPoStSectorChallenge ( ctx , proofType , abi . ActorID ( mid ) , rand , numProvSect )
2020-04-17 14:47:19 +00:00
if err != nil {
return nil , xerrors . Errorf ( "generating winning post challenges: %w" , err )
}
2020-09-21 19:05:01 +00:00
iter , err := provingSectors . BitIterator ( )
2020-07-01 04:57:49 +00:00
if err != nil {
2020-09-21 19:05:01 +00:00
return nil , xerrors . Errorf ( "iterating over proving sectors: %w" , err )
2020-07-01 04:57:49 +00:00
}
2020-09-21 19:05:01 +00:00
// Select winning sectors by _index_ in the all-sectors bitfield.
selectedSectors := bitfield . New ( )
prev := uint64 ( 0 )
for _ , n := range ids {
sno , err := iter . Nth ( n - prev )
2020-09-17 06:34:15 +00:00
if err != nil {
2020-09-21 19:05:01 +00:00
return nil , xerrors . Errorf ( "iterating over proving sectors: %w" , err )
2020-09-17 06:34:15 +00:00
}
2020-09-21 19:05:01 +00:00
selectedSectors . Set ( sno )
prev = n
}
2020-09-17 06:34:15 +00:00
2020-09-21 19:05:01 +00:00
sectors , err := mas . LoadSectors ( & selectedSectors )
if err != nil {
return nil , xerrors . Errorf ( "loading proving sectors: %w" , err )
}
2020-07-01 04:57:49 +00:00
2020-10-08 01:09:33 +00:00
out := make ( [ ] builtin . SectorInfo , len ( sectors ) )
2020-09-21 19:05:01 +00:00
for i , sinfo := range sectors {
2020-10-08 01:09:33 +00:00
out [ i ] = builtin . SectorInfo {
2020-11-04 20:29:08 +00:00
SealProof : sinfo . SealProof ,
2020-09-17 06:34:15 +00:00
SectorNumber : sinfo . SectorNumber ,
SealedCID : sinfo . SealedCID ,
2020-04-17 14:47:19 +00:00
}
}
return out , nil
2020-04-17 05:39:55 +00:00
}
2020-03-02 01:09:38 +00:00
func GetMinerSlashed ( ctx context . Context , sm * StateManager , ts * types . TipSet , maddr address . Address ) ( bool , error ) {
2020-09-22 04:12:07 +00:00
act , err := sm . LoadActor ( ctx , power . Address , ts )
2020-09-15 11:04:45 +00:00
if err != nil {
return false , xerrors . Errorf ( "failed to load power actor: %w" , err )
}
spas , err := power . Load ( sm . cs . Store ( ctx ) , act )
2020-03-02 01:09:38 +00:00
if err != nil {
2020-09-15 11:04:45 +00:00
return false , xerrors . Errorf ( "failed to load power actor state: %w" , err )
2020-03-02 01:09:38 +00:00
}
2020-09-15 13:29:25 +00:00
_ , ok , err := spas . MinerPower ( maddr )
2020-04-21 14:32:17 +00:00
if err != nil {
2020-09-15 13:29:25 +00:00
return false , xerrors . Errorf ( "getting miner power: %w" , err )
2020-03-02 01:09:38 +00:00
}
2020-04-16 20:52:40 +00:00
2020-04-21 14:32:17 +00:00
if ! ok {
return true , nil
2020-03-02 01:09:38 +00:00
}
return false , nil
2019-11-15 01:01:53 +00:00
}
2020-06-02 14:29:39 +00:00
func GetStorageDeal ( ctx context . Context , sm * StateManager , dealID abi . DealID , ts * types . TipSet ) ( * api . MarketDeal , error ) {
2020-09-22 04:12:07 +00:00
act , err := sm . LoadActor ( ctx , market . Address , ts )
2020-09-15 11:04:45 +00:00
if err != nil {
return nil , xerrors . Errorf ( "failed to load market actor: %w" , err )
}
state , err := market . Load ( sm . cs . Store ( ctx ) , act )
if err != nil {
return nil , xerrors . Errorf ( "failed to load market actor state: %w" , err )
2019-11-07 07:57:10 +00:00
}
2020-09-15 11:04:45 +00:00
2020-09-17 07:32:10 +00:00
proposals , err := state . Proposals ( )
2019-11-07 07:57:10 +00:00
if err != nil {
return nil , err
}
2020-09-17 07:32:10 +00:00
proposal , found , err := proposals . Get ( dealID )
if err != nil {
2019-11-07 07:57:10 +00:00
return nil , err
2020-07-23 00:14:54 +00:00
} else if ! found {
2020-11-30 14:16:13 +00:00
return nil , xerrors . Errorf (
"deal %d not found " +
"- deal may not have completed sealing before deal proposal " +
"start epoch, or deal may have been slashed" ,
dealID )
2019-11-07 07:57:10 +00:00
}
2020-09-17 07:32:10 +00:00
states , err := state . States ( )
2020-04-13 21:05:34 +00:00
if err != nil {
return nil , err
}
2020-09-17 07:32:10 +00:00
st , found , err := states . Get ( dealID )
2020-02-09 06:06:32 +00:00
if err != nil {
return nil , err
}
2020-05-06 00:04:25 +00:00
if ! found {
2020-09-17 07:32:10 +00:00
st = market . EmptyDealState ( )
2020-05-06 00:04:25 +00:00
}
2020-02-09 06:06:32 +00:00
return & api . MarketDeal {
2020-09-17 07:32:10 +00:00
Proposal : * proposal ,
2020-02-23 15:50:36 +00:00
State : * st ,
2020-02-09 06:06:32 +00:00
} , nil
2019-11-07 07:57:10 +00:00
}
2019-12-17 06:51:41 +00:00
func ListMinerActors ( ctx context . Context , sm * StateManager , ts * types . TipSet ) ( [ ] address . Address , error ) {
2020-09-22 04:12:07 +00:00
act , err := sm . LoadActor ( ctx , power . Address , ts )
2020-09-15 11:04:45 +00:00
if err != nil {
return nil , xerrors . Errorf ( "failed to load power actor: %w" , err )
}
2020-09-16 05:00:00 +00:00
powState , err := power . Load ( sm . cs . Store ( ctx ) , act )
2020-09-15 11:04:45 +00:00
if err != nil {
return nil , xerrors . Errorf ( "failed to load power actor state: %w" , err )
2019-12-17 06:51:41 +00:00
}
2020-09-16 05:00:00 +00:00
return powState . ListAllMiners ( )
2019-09-17 22:43:47 +00:00
}
2020-01-17 02:33:43 +00:00
2020-03-08 02:31:36 +00:00
func ComputeState ( ctx context . Context , sm * StateManager , height abi . ChainEpoch , msgs [ ] * types . Message , ts * types . TipSet ) ( cid . Cid , [ ] * api . InvocResult , error ) {
2020-01-17 02:33:43 +00:00
if ts == nil {
ts = sm . cs . GetHeaviestTipSet ( )
}
2020-03-08 02:31:36 +00:00
base , trace , err := sm . ExecutionTrace ( ctx , ts )
2020-01-17 02:33:43 +00:00
if err != nil {
2020-03-08 02:31:36 +00:00
return cid . Undef , nil , err
2020-01-17 02:33:43 +00:00
}
2020-09-24 21:30:11 +00:00
for i := ts . Height ( ) ; i < height ; i ++ {
// handle state forks
base , err = sm . handleStateForks ( ctx , base , i , traceFunc ( & trace ) , ts )
if err != nil {
return cid . Undef , nil , xerrors . Errorf ( "error handling state forks: %w" , err )
}
// TODO: should we also run cron here?
}
2020-09-01 19:48:16 +00:00
r := store . NewChainRand ( sm . cs , ts . Cids ( ) )
2020-08-06 17:09:03 +00:00
vmopt := & vm . VMOpts {
2020-08-09 22:49:38 +00:00
StateBase : base ,
Epoch : height ,
Rand : r ,
Bstore : sm . cs . Blockstore ( ) ,
Syscalls : sm . cs . VMSys ( ) ,
2020-10-11 22:17:28 +00:00
CircSupplyCalc : sm . GetVMCirculatingSupply ,
2020-09-07 20:01:09 +00:00
NtwkVersion : sm . GetNtwkVersion ,
2020-08-09 22:49:38 +00:00
BaseFee : ts . Blocks ( ) [ 0 ] . ParentBaseFee ,
2020-10-24 09:57:17 +00:00
LookbackState : LookbackStateGetterForTipset ( sm , ts ) ,
2020-08-06 17:09:03 +00:00
}
2020-10-07 22:26:08 +00:00
vmi , err := sm . newVM ( ctx , vmopt )
2020-01-17 02:33:43 +00:00
if err != nil {
2020-03-08 02:31:36 +00:00
return cid . Undef , nil , err
2020-01-17 02:33:43 +00:00
}
for i , msg := range msgs {
2020-03-25 11:29:35 +00:00
// TODO: Use the signed message length for secp messages
2020-03-25 19:13:09 +00:00
ret , err := vmi . ApplyMessage ( ctx , msg )
2020-01-17 02:33:43 +00:00
if err != nil {
2020-03-08 02:31:36 +00:00
return cid . Undef , nil , xerrors . Errorf ( "applying message %s: %w" , msg . Cid ( ) , err )
2020-01-17 02:33:43 +00:00
}
if ret . ExitCode != 0 {
2020-01-17 06:14:00 +00:00
log . Infof ( "compute state apply message %d failed (exit: %d): %s" , i , ret . ExitCode , ret . ActorErr )
2020-01-17 02:33:43 +00:00
}
}
2020-03-08 02:31:36 +00:00
root , err := vmi . Flush ( ctx )
if err != nil {
return cid . Undef , nil , err
}
return root , trace , nil
2020-01-17 02:33:43 +00:00
}
2020-04-02 01:10:28 +00:00
2020-10-24 09:57:17 +00:00
func LookbackStateGetterForTipset ( sm * StateManager , ts * types . TipSet ) vm . LookbackStateGetter {
return func ( ctx context . Context , round abi . ChainEpoch ) ( * state . StateTree , error ) {
_ , st , err := GetLookbackTipSetForRound ( ctx , sm , ts , round )
if err != nil {
return nil , err
}
return sm . StateTree ( st )
}
}
2020-10-23 21:52:26 +00:00
func GetLookbackTipSetForRound ( ctx context . Context , sm * StateManager , ts * types . TipSet , round abi . ChainEpoch ) ( * types . TipSet , cid . Cid , error ) {
2020-04-17 23:36:54 +00:00
var lbr abi . ChainEpoch
2020-10-06 09:26:25 +00:00
lb := policy . GetWinningPoStSectorSetLookback ( sm . GetNtwkVersion ( ctx , round ) )
if round > lb {
lbr = round - lb
2020-04-17 23:36:54 +00:00
}
// more null blocks than our lookback
2020-10-23 21:52:26 +00:00
if lbr >= ts . Height ( ) {
// This should never happen at this point, but may happen before
// network version 3 (where the lookback was only 10 blocks).
st , _ , err := sm . TipSetState ( ctx , ts )
if err != nil {
return nil , cid . Undef , err
}
return ts , st , nil
}
// Get the tipset after the lookback tipset, or the next non-null one.
nextTs , err := sm . ChainStore ( ) . GetTipsetByHeight ( ctx , lbr + 1 , ts , false )
if err != nil {
return nil , cid . Undef , xerrors . Errorf ( "failed to get lookback tipset+1: %w" , err )
}
if lbr > nextTs . Height ( ) {
return nil , cid . Undef , xerrors . Errorf ( "failed to find non-null tipset %s (%d) which is known to exist, found %s (%d)" , ts . Key ( ) , ts . Height ( ) , nextTs . Key ( ) , nextTs . Height ( ) )
2020-04-17 23:36:54 +00:00
}
2020-10-23 21:52:26 +00:00
lbts , err := sm . ChainStore ( ) . GetTipSetFromKey ( nextTs . Parents ( ) )
2020-04-17 23:36:54 +00:00
if err != nil {
2020-10-23 21:52:26 +00:00
return nil , cid . Undef , xerrors . Errorf ( "failed to resolve lookback tipset: %w" , err )
2020-04-17 23:36:54 +00:00
}
2020-10-23 21:52:26 +00:00
return lbts , nextTs . ParentState ( ) , nil
2020-04-17 23:36:54 +00:00
}
2020-09-08 20:28:06 +00:00
func MinerGetBaseInfo ( ctx context . Context , sm * StateManager , bcs beacon . Schedule , tsk types . TipSetKey , round abi . ChainEpoch , maddr address . Address , pv ffiwrapper . Verifier ) ( * api . MiningBaseInfo , error ) {
2020-04-02 01:10:28 +00:00
ts , err := sm . ChainStore ( ) . LoadTipSet ( tsk )
if err != nil {
return nil , xerrors . Errorf ( "failed to load tipset for mining base: %w" , err )
}
2020-04-30 22:11:14 +00:00
prev , err := sm . ChainStore ( ) . GetLatestBeaconEntry ( ts )
if err != nil {
if os . Getenv ( "LOTUS_IGNORE_DRAND" ) != "_yes_" {
return nil , xerrors . Errorf ( "failed to get latest beacon entry: %w" , err )
}
prev = & types . BeaconEntry { }
}
2020-09-08 20:28:06 +00:00
entries , err := beacon . BeaconEntriesForBlock ( ctx , bcs , round , ts . Height ( ) , * prev )
2020-04-30 22:11:14 +00:00
if err != nil {
return nil , err
}
rbase := * prev
if len ( entries ) > 0 {
rbase = entries [ len ( entries ) - 1 ]
}
2020-10-23 21:52:26 +00:00
lbts , lbst , err := GetLookbackTipSetForRound ( ctx , sm , ts , round )
2020-04-17 23:36:54 +00:00
if err != nil {
return nil , xerrors . Errorf ( "getting lookback miner actor state: %w" , err )
}
2020-09-15 11:04:45 +00:00
act , err := sm . LoadActorRaw ( ctx , maddr , lbst )
2020-10-20 21:54:35 +00:00
if xerrors . Is ( err , types . ErrActorNotFound ) {
_ , err := sm . LoadActor ( ctx , maddr , ts )
if err != nil {
return nil , xerrors . Errorf ( "loading miner in current state: %w" , err )
}
return nil , nil
}
2020-09-15 11:04:45 +00:00
if err != nil {
return nil , xerrors . Errorf ( "failed to load miner actor: %w" , err )
}
mas , err := miner . Load ( sm . cs . Store ( ctx ) , act )
if err != nil {
return nil , xerrors . Errorf ( "failed to load miner actor state: %w" , err )
2020-04-17 23:36:54 +00:00
}
2020-04-30 22:11:14 +00:00
buf := new ( bytes . Buffer )
if err := maddr . MarshalCBOR ( buf ) ; err != nil {
return nil , xerrors . Errorf ( "failed to marshal miner address: %w" , err )
}
2020-05-01 19:42:59 +00:00
prand , err := store . DrawRandomness ( rbase . Data , crypto . DomainSeparationTag_WinningPoStChallengeSeed , round , buf . Bytes ( ) )
2020-04-02 01:10:28 +00:00
if err != nil {
2020-04-17 23:36:54 +00:00
return nil , xerrors . Errorf ( "failed to get randomness for winning post: %w" , err )
2020-04-02 01:10:28 +00:00
}
2020-11-05 17:16:22 +00:00
nv := sm . GetNtwkVersion ( ctx , ts . Height ( ) )
sectors , err := GetSectorsForWinningPoSt ( ctx , nv , pv , sm , lbst , maddr , prand )
2020-04-02 01:10:28 +00:00
if err != nil {
2020-09-16 01:19:27 +00:00
return nil , xerrors . Errorf ( "getting winning post proving set: %w" , err )
2020-04-02 01:10:28 +00:00
}
2020-04-23 21:12:42 +00:00
if len ( sectors ) == 0 {
return nil , nil
}
2020-10-06 08:33:55 +00:00
mpow , tpow , _ , err := GetPowerRaw ( ctx , sm , lbst , maddr )
2020-04-02 01:10:28 +00:00
if err != nil {
2020-04-15 19:59:11 +00:00
return nil , xerrors . Errorf ( "failed to get power: %w" , err )
2020-04-02 01:10:28 +00:00
}
2020-09-15 11:04:45 +00:00
info , err := mas . Info ( )
2020-07-01 11:47:40 +00:00
if err != nil {
return nil , err
}
worker , err := sm . ResolveToKeyAddress ( ctx , info . Worker , ts )
2020-04-16 17:17:56 +00:00
if err != nil {
return nil , xerrors . Errorf ( "resolving worker address: %w" , err )
}
2020-10-06 08:33:55 +00:00
// TODO: Not ideal performance...This method reloads miner and power state (already looked up here and in GetPowerRaw)
eligible , err := MinerEligibleToMine ( ctx , sm , maddr , ts , lbts )
if err != nil {
return nil , xerrors . Errorf ( "determining miner eligibility: %w" , err )
}
2020-04-02 01:10:28 +00:00
return & api . MiningBaseInfo {
2020-10-06 07:49:11 +00:00
MinerPower : mpow . QualityAdjPower ,
NetworkPower : tpow . QualityAdjPower ,
Sectors : sectors ,
WorkerKey : worker ,
SectorSize : info . SectorSize ,
PrevBeaconEntry : * prev ,
BeaconEntries : entries ,
2020-10-06 08:33:55 +00:00
EligibleForMining : eligible ,
2020-04-02 01:10:28 +00:00
} , nil
}
2020-06-26 13:49:39 +00:00
2020-09-04 03:28:42 +00:00
type MethodMeta struct {
2020-07-03 16:57:58 +00:00
Name string
Params reflect . Type
Ret reflect . Type
}
2020-09-04 03:28:42 +00:00
var MethodsMap = map [ cid . Cid ] map [ abi . MethodNum ] MethodMeta { }
2020-07-03 16:57:58 +00:00
func init ( ) {
2020-09-28 19:48:08 +00:00
// TODO: combine with the runtime actor registry.
var actors [ ] rt . VMActor
actors = append ( actors , exported0 . BuiltinActors ( ) ... )
2020-09-28 20:13:18 +00:00
actors = append ( actors , exported2 . BuiltinActors ( ) ... )
2021-01-21 19:43:36 +00:00
actors = append ( actors , exported3 . BuiltinActors ( ) ... )
2020-09-28 19:48:08 +00:00
for _ , actor := range actors {
exports := actor . Exports ( )
2020-09-04 03:28:42 +00:00
methods := make ( map [ abi . MethodNum ] MethodMeta , len ( exports ) )
2020-07-03 16:57:58 +00:00
2020-09-04 03:28:42 +00:00
// Explicitly add send, it's special.
2020-10-08 20:32:54 +00:00
methods [ builtin . MethodSend ] = MethodMeta {
2020-07-03 16:57:58 +00:00
Name : "Send" ,
2020-09-10 06:21:38 +00:00
Params : reflect . TypeOf ( new ( abi . EmptyValue ) ) ,
Ret : reflect . TypeOf ( new ( abi . EmptyValue ) ) ,
2020-09-04 03:28:42 +00:00
}
2020-07-03 16:57:58 +00:00
2020-09-04 03:28:42 +00:00
// Iterate over exported methods. Some of these _may_ be nil and
// must be skipped.
for number , export := range exports {
if export == nil {
continue
}
ev := reflect . ValueOf ( export )
et := ev . Type ( )
2020-09-28 19:48:08 +00:00
// Extract the method names using reflection. These
// method names always match the field names in the
// `builtin.Method*` structs (tested in the specs-actors
// tests).
2020-09-04 03:28:42 +00:00
fnName := runtime . FuncForPC ( ev . Pointer ( ) ) . Name ( )
fnName = strings . TrimSuffix ( fnName [ strings . LastIndexByte ( fnName , '.' ) + 1 : ] , "-fm" )
switch abi . MethodNum ( number ) {
2020-10-08 20:32:54 +00:00
case builtin . MethodSend :
2020-09-04 03:28:42 +00:00
panic ( "method 0 is reserved for Send" )
2020-10-08 20:32:54 +00:00
case builtin . MethodConstructor :
2020-09-04 03:28:42 +00:00
if fnName != "Constructor" {
panic ( "method 1 is reserved for Constructor" )
}
}
methods [ abi . MethodNum ( number ) ] = MethodMeta {
Name : fnName ,
Params : et . In ( 1 ) ,
Ret : et . Out ( 0 ) ,
}
2020-07-03 16:57:58 +00:00
}
2020-09-28 19:48:08 +00:00
MethodsMap [ actor . Code ( ) ] = methods
2020-07-03 16:57:58 +00:00
}
}
func GetReturnType ( ctx context . Context , sm * StateManager , to address . Address , method abi . MethodNum , ts * types . TipSet ) ( cbg . CBORUnmarshaler , error ) {
2020-09-15 11:04:45 +00:00
act , err := sm . LoadActor ( ctx , to , ts )
if err != nil {
return nil , xerrors . Errorf ( "(get sset) failed to load miner actor: %w" , err )
2020-07-03 16:57:58 +00:00
}
2020-09-04 03:28:42 +00:00
m , found := MethodsMap [ act . Code ] [ method ]
if ! found {
return nil , fmt . Errorf ( "unknown method %d for actor %s" , method , act . Code )
}
2020-07-03 16:57:58 +00:00
return reflect . New ( m . Ret . Elem ( ) ) . Interface ( ) . ( cbg . CBORUnmarshaler ) , nil
}
2020-07-27 23:51:30 +00:00
2020-09-29 07:01:52 +00:00
func GetParamType ( actCode cid . Cid , method abi . MethodNum ) ( cbg . CBORUnmarshaler , error ) {
m , found := MethodsMap [ actCode ] [ method ]
if ! found {
return nil , fmt . Errorf ( "unknown method %d for actor %s" , method , actCode )
}
return reflect . New ( m . Params . Elem ( ) ) . Interface ( ) . ( cbg . CBORUnmarshaler ) , nil
}
2020-10-06 08:33:55 +00:00
func minerHasMinPower ( ctx context . Context , sm * StateManager , addr address . Address , ts * types . TipSet ) ( bool , error ) {
2020-09-22 04:12:07 +00:00
pact , err := sm . LoadActor ( ctx , power . Address , ts )
2020-07-27 23:51:30 +00:00
if err != nil {
return false , xerrors . Errorf ( "loading power actor state: %w" , err )
}
2020-09-14 22:43:12 +00:00
ps , err := power . Load ( sm . cs . Store ( ctx ) , pact )
2020-09-14 12:17:45 +00:00
if err != nil {
return false , err
}
2020-09-14 22:43:12 +00:00
return ps . MinerNominalPowerMeetsConsensusMinimum ( addr )
2020-07-27 23:51:30 +00:00
}
2020-08-12 22:20:32 +00:00
2020-10-06 08:33:55 +00:00
func MinerEligibleToMine ( ctx context . Context , sm * StateManager , addr address . Address , baseTs * types . TipSet , lookbackTs * types . TipSet ) ( bool , error ) {
hmp , err := minerHasMinPower ( ctx , sm , addr , lookbackTs )
// TODO: We're blurring the lines between a "runtime network version" and a "Lotus upgrade epoch", is that unavoidable?
if sm . GetNtwkVersion ( ctx , baseTs . Height ( ) ) <= network . Version3 {
return hmp , err
}
if err != nil {
return false , err
}
if ! hmp {
return false , nil
}
// Post actors v2, also check MinerEligibleForElection with base ts
pact , err := sm . LoadActor ( ctx , power . Address , baseTs )
if err != nil {
return false , xerrors . Errorf ( "loading power actor state: %w" , err )
}
pstate , err := power . Load ( sm . cs . Store ( ctx ) , pact )
if err != nil {
return false , err
}
mact , err := sm . LoadActor ( ctx , addr , baseTs )
if err != nil {
return false , xerrors . Errorf ( "loading miner actor state: %w" , err )
}
mstate , err := miner . Load ( sm . cs . Store ( ctx ) , mact )
if err != nil {
return false , err
}
// Non-empty power claim.
if claim , found , err := pstate . MinerPower ( addr ) ; err != nil {
return false , err
} else if ! found {
return false , err
} else if claim . QualityAdjPower . LessThanEqual ( big . Zero ( ) ) {
return false , err
}
// No fee debt.
if debt , err := mstate . FeeDebt ( ) ; err != nil {
return false , err
} else if ! debt . IsZero ( ) {
return false , err
}
// No active consensus faults.
if mInfo , err := mstate . Info ( ) ; err != nil {
return false , err
} else if baseTs . Height ( ) <= mInfo . ConsensusFaultElapsed {
return false , nil
}
return true , nil
}
2020-08-12 22:20:32 +00:00
func CheckTotalFIL ( ctx context . Context , sm * StateManager , ts * types . TipSet ) ( abi . TokenAmount , error ) {
2020-09-14 22:43:12 +00:00
str , err := state . LoadStateTree ( sm . ChainStore ( ) . Store ( ctx ) , ts . ParentState ( ) )
2020-08-12 22:20:32 +00:00
if err != nil {
return abi . TokenAmount { } , err
}
sum := types . NewInt ( 0 )
err = str . ForEach ( func ( a address . Address , act * types . Actor ) error {
sum = types . BigAdd ( sum , act . Balance )
return nil
} )
if err != nil {
return abi . TokenAmount { } , err
}
return sum , nil
}
2020-10-15 22:48:51 +00:00
func MakeMsgGasCost ( msg * types . Message , ret * vm . ApplyRet ) api . MsgGasCost {
return api . MsgGasCost {
Message : msg . Cid ( ) ,
GasUsed : big . NewInt ( ret . GasUsed ) ,
BaseFeeBurn : ret . GasCosts . BaseFeeBurn ,
OverEstimationBurn : ret . GasCosts . OverEstimationBurn ,
MinerPenalty : ret . GasCosts . MinerPenalty ,
MinerTip : ret . GasCosts . MinerTip ,
Refund : ret . GasCosts . Refund ,
TotalCost : big . Sub ( msg . RequiredFunds ( ) , ret . GasCosts . Refund ) ,
}
}