stmgr: Put actor state accessors in actors.go
This commit is contained in:
parent
e7d73cbe56
commit
ce82f2827b
551
chain/stmgr/actors.go
Normal file
551
chain/stmgr/actors.go
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
package stmgr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-bitfield"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
|
cid "github.com/ipfs/go-cid"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||||
|
"github.com/filecoin-project/lotus/chain/beacon"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
|
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
||||||
|
state, err := sm.StateTree(st)
|
||||||
|
if err != nil {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := mas.Info()
|
||||||
|
if err != nil {
|
||||||
|
return address.Undef, xerrors.Errorf("failed to load actor info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm.ResolveToKeyAddr(state, sm.cs.ActorStore(ctx), info.Worker)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||||
|
return GetPowerRaw(ctx, sm, ts.ParentState(), maddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||||
|
act, err := sm.LoadActorRaw(ctx, power.Address, st)
|
||||||
|
if err != nil {
|
||||||
|
return power.Claim{}, power.Claim{}, false, xerrors.Errorf("(get sset) failed to load power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return power.Claim{}, power.Claim{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tpow, err := pas.TotalPower()
|
||||||
|
if err != nil {
|
||||||
|
return power.Claim{}, power.Claim{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var mpow power.Claim
|
||||||
|
var minpow bool
|
||||||
|
if maddr != address.Undef {
|
||||||
|
var found bool
|
||||||
|
mpow, found, err = pas.MinerPower(maddr)
|
||||||
|
if err != nil || !found {
|
||||||
|
return power.Claim{}, tpow, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
minpow, err = pas.MinerNominalPowerMeetsConsensusMinimum(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return power.Claim{}, power.Claim{}, false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mpow, tpow, minpow, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorPreCommitOnChainInfo, error) {
|
||||||
|
act, err := sm.LoadActor(ctx, maddr, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mas.GetPrecommittedSector(sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) {
|
||||||
|
act, err := sm.LoadActor(ctx, maddr, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mas.GetSector(sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
faultySectors, err := miner.AllPartSectors(mas, miner.Partition.FaultySectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("get faulty sectors: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numProvSect, err := provingSectors.Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to count bits: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(review): is this right? feels fishy to me
|
||||||
|
if numProvSect == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := mas.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting miner info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mid, err := address.IDFromAddress(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
proofType, err := miner.WinningPoStProofTypeFromWindowPoStProofType(nv, info.WindowPoStProofType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("determining winning post proof type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, proofType, abi.ActorID(mid), rand, numProvSect)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
iter, err := provingSectors.BitIterator()
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
||||||
|
}
|
||||||
|
selectedSectors.Set(sno)
|
||||||
|
prev = n
|
||||||
|
}
|
||||||
|
|
||||||
|
sectors, err := mas.LoadSectors(&selectedSectors)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("loading proving sectors: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]builtin.SectorInfo, len(sectors))
|
||||||
|
for i, sinfo := range sectors {
|
||||||
|
out[i] = builtin.SectorInfo{
|
||||||
|
SealProof: sinfo.SealProof,
|
||||||
|
SectorNumber: sinfo.SectorNumber,
|
||||||
|
SealedCID: sinfo.SealedCID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
||||||
|
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("failed to load power actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("failed to load power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok, err := spas.MinerPower(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("getting miner power: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
||||||
|
act, err := sm.LoadActor(ctx, market.Address, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load market actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := market.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load market actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
proposals, err := state.Proposals()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
proposal, found, err := proposals.Get(dealID)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !found {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
states, err := state.States()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
st, found, err := states.Get(dealID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
st = market.EmptyDealState()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.MarketDeal{
|
||||||
|
Proposal: *proposal,
|
||||||
|
State: *st,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
|
||||||
|
act, err := sm.LoadActor(ctx, power.Address, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load power actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
powState, err := power.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return powState.ListAllMiners()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
ts, err := sm.ChainStore().LoadTipSet(tsk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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{}
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rbase := *prev
|
||||||
|
if len(entries) > 0 {
|
||||||
|
rbase = entries[len(entries)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
lbts, lbst, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
act, err := sm.LoadActorRaw(ctx, maddr, lbst)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := maddr.MarshalCBOR(buf); err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to marshal miner address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nv := sm.GetNtwkVersion(ctx, ts.Height())
|
||||||
|
|
||||||
|
sectors, err := GetSectorsForWinningPoSt(ctx, nv, pv, sm, lbst, maddr, prand)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("getting winning post proving set: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sectors) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to get power: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := mas.Info()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.MiningBaseInfo{
|
||||||
|
MinerPower: mpow.QualityAdjPower,
|
||||||
|
NetworkPower: tpow.QualityAdjPower,
|
||||||
|
Sectors: sectors,
|
||||||
|
WorkerKey: worker,
|
||||||
|
SectorSize: info.SectorSize,
|
||||||
|
PrevBeaconEntry: *prev,
|
||||||
|
BeaconEntries: entries,
|
||||||
|
EligibleForMining: eligible,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func minerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
||||||
|
pact, err := sm.LoadActor(ctx, power.Address, ts)
|
||||||
|
if err != nil {
|
||||||
|
return false, xerrors.Errorf("loading power actor state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ps, err := power.Load(sm.cs.ActorStore(ctx), pact)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ActorStore(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.ActorStore(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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
||||||
|
st, err := sm.ParentState(ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
act, err := st.GetActor(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
actState, err := paych.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return act, actState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (market.State, error) {
|
||||||
|
st, err := sm.ParentState(ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
act, err := st.GetActor(market.Address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
actState, err := market.Load(sm.cs.ActorStore(ctx), act)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return actState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (api.MarketBalance, error) {
|
||||||
|
mstate, err := sm.GetMarketState(ctx, ts)
|
||||||
|
if err != nil {
|
||||||
|
return api.MarketBalance{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err = sm.LookupID(ctx, addr, ts)
|
||||||
|
if err != nil {
|
||||||
|
return api.MarketBalance{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var out api.MarketBalance
|
||||||
|
|
||||||
|
et, err := mstate.EscrowTable()
|
||||||
|
if err != nil {
|
||||||
|
return api.MarketBalance{}, err
|
||||||
|
}
|
||||||
|
out.Escrow, err = et.Get(addr)
|
||||||
|
if err != nil {
|
||||||
|
return api.MarketBalance{}, xerrors.Errorf("getting escrow balance: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lt, err := mstate.LockedTable()
|
||||||
|
if err != nil {
|
||||||
|
return api.MarketBalance{}, err
|
||||||
|
}
|
||||||
|
out.Locked, err = lt.Get(addr)
|
||||||
|
if err != nil {
|
||||||
|
return api.MarketBalance{}, xerrors.Errorf("getting locked balance: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ StateManagerAPI = (*StateManager)(nil)
|
@ -1,52 +1,124 @@
|
|||||||
package stmgr
|
package stmgr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
|
||||||
|
|
||||||
cid "github.com/ipfs/go-cid"
|
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-bitfield"
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/rt"
|
"github.com/filecoin-project/go-state-types/rt"
|
||||||
|
|
||||||
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
exported0 "github.com/filecoin-project/specs-actors/actors/builtin/exported"
|
||||||
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
exported2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/exported"
|
||||||
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
|
exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
|
||||||
exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported"
|
exported4 "github.com/filecoin-project/specs-actors/v4/actors/builtin/exported"
|
||||||
|
exported5 "github.com/filecoin-project/specs-actors/v5/actors/builtin/exported"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||||
"github.com/filecoin-project/lotus/chain/beacon"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
"github.com/filecoin-project/lotus/chain/state"
|
||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper"
|
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type MethodMeta struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
Params reflect.Type
|
||||||
|
Ret reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// TODO: combine with the runtime actor registry.
|
||||||
|
var actors []rt.VMActor
|
||||||
|
actors = append(actors, exported0.BuiltinActors()...)
|
||||||
|
actors = append(actors, exported2.BuiltinActors()...)
|
||||||
|
actors = append(actors, exported3.BuiltinActors()...)
|
||||||
|
actors = append(actors, exported4.BuiltinActors()...)
|
||||||
|
actors = append(actors, exported5.BuiltinActors()...)
|
||||||
|
|
||||||
|
for _, actor := range actors {
|
||||||
|
exports := actor.Exports()
|
||||||
|
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
||||||
|
|
||||||
|
// Explicitly add send, it's special.
|
||||||
|
methods[builtin.MethodSend] = MethodMeta{
|
||||||
|
Name: "Send",
|
||||||
|
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
||||||
|
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
||||||
|
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
||||||
|
|
||||||
|
switch abi.MethodNum(number) {
|
||||||
|
case builtin.MethodSend:
|
||||||
|
panic("method 0 is reserved for Send")
|
||||||
|
case builtin.MethodConstructor:
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MethodsMap[actor.Code()] = methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
||||||
|
act, err := sm.LoadActor(ctx, to, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m, found := MethodsMap[act.Code][method]
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
||||||
|
}
|
||||||
|
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) {
|
func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) {
|
||||||
act, err := sm.LoadActorRaw(ctx, init_.Address, st)
|
act, err := sm.LoadActorRaw(ctx, init_.Address, st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,277 +132,6 @@ func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.N
|
|||||||
return ias.NetworkName()
|
return ias.NetworkName()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
|
|
||||||
state, err := sm.StateTree(st)
|
|
||||||
if err != nil {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := mas.Info()
|
|
||||||
if err != nil {
|
|
||||||
return address.Undef, xerrors.Errorf("failed to load actor info: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return vm.ResolveToKeyAddr(state, sm.cs.ActorStore(ctx), info.Worker)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
|
||||||
return GetPowerRaw(ctx, sm, ts.ParentState(), maddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
|
||||||
act, err := sm.LoadActorRaw(ctx, power.Address, st)
|
|
||||||
if err != nil {
|
|
||||||
return power.Claim{}, power.Claim{}, false, xerrors.Errorf("(get sset) failed to load power actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return power.Claim{}, power.Claim{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tpow, err := pas.TotalPower()
|
|
||||||
if err != nil {
|
|
||||||
return power.Claim{}, power.Claim{}, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var mpow power.Claim
|
|
||||||
var minpow bool
|
|
||||||
if maddr != address.Undef {
|
|
||||||
var found bool
|
|
||||||
mpow, found, err = pas.MinerPower(maddr)
|
|
||||||
if err != nil || !found {
|
|
||||||
return power.Claim{}, tpow, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
minpow, err = pas.MinerNominalPowerMeetsConsensusMinimum(maddr)
|
|
||||||
if err != nil {
|
|
||||||
return power.Claim{}, power.Claim{}, false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mpow, tpow, minpow, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorPreCommitOnChainInfo, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mas.GetPrecommittedSector(sid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (*miner.SectorOnChainInfo, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, maddr, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mas.GetSector(sid)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
act, err := sm.LoadActorRaw(ctx, maddr, st)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
faultySectors, err := miner.AllPartSectors(mas, miner.Partition.FaultySectors)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("get faulty sectors: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
numProvSect, err := provingSectors.Count()
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to count bits: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(review): is this right? feels fishy to me
|
|
||||||
if numProvSect == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := mas.Info()
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("getting miner info: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mid, err := address.IDFromAddress(maddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("getting miner ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
proofType, err := miner.WinningPoStProofTypeFromWindowPoStProofType(nv, info.WindowPoStProofType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("determining winning post proof type: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, proofType, abi.ActorID(mid), rand, numProvSect)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
iter, err := provingSectors.BitIterator()
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("iterating over proving sectors: %w", err)
|
|
||||||
}
|
|
||||||
selectedSectors.Set(sno)
|
|
||||||
prev = n
|
|
||||||
}
|
|
||||||
|
|
||||||
sectors, err := mas.LoadSectors(&selectedSectors)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("loading proving sectors: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
out := make([]builtin.SectorInfo, len(sectors))
|
|
||||||
for i, sinfo := range sectors {
|
|
||||||
out[i] = builtin.SectorInfo{
|
|
||||||
SealProof: sinfo.SealProof,
|
|
||||||
SectorNumber: sinfo.SectorNumber,
|
|
||||||
SealedCID: sinfo.SealedCID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (bool, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
|
||||||
if err != nil {
|
|
||||||
return false, xerrors.Errorf("failed to load power actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
spas, err := power.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return false, xerrors.Errorf("failed to load power actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, ok, err := spas.MinerPower(maddr)
|
|
||||||
if err != nil {
|
|
||||||
return false, xerrors.Errorf("getting miner power: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, market.Address, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load market actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
state, err := market.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load market actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
proposals, err := state.Proposals()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
proposal, found, err := proposals.Get(dealID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if !found {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
states, err := state.States()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
st, found, err := states.Get(dealID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
st = market.EmptyDealState()
|
|
||||||
}
|
|
||||||
|
|
||||||
return &api.MarketDeal{
|
|
||||||
Proposal: *proposal,
|
|
||||||
State: *st,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, power.Address, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load power actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
powState, err := power.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load power actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return powState.ListAllMiners()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, msgs []*types.Message, ts *types.TipSet) (cid.Cid, []*api.InvocResult, error) {
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
ts = sm.cs.GetHeaviestTipSet()
|
ts = sm.cs.GetHeaviestTipSet()
|
||||||
@ -434,272 +235,6 @@ func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.
|
|||||||
return lbts, nextTs.ParentState(), nil
|
return lbts, nextTs.ParentState(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
ts, err := sm.ChainStore().LoadTipSet(tsk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
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{}
|
|
||||||
}
|
|
||||||
|
|
||||||
entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rbase := *prev
|
|
||||||
if len(entries) > 0 {
|
|
||||||
rbase = entries[len(entries)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
lbts, lbst, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
act, err := sm.LoadActorRaw(ctx, maddr, lbst)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mas, err := miner.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := maddr.MarshalCBOR(buf); err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to marshal miner address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
prand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_WinningPoStChallengeSeed, round, buf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to get randomness for winning post: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
nv := sm.GetNtwkVersion(ctx, ts.Height())
|
|
||||||
|
|
||||||
sectors, err := GetSectorsForWinningPoSt(ctx, nv, pv, sm, lbst, maddr, prand)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("getting winning post proving set: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(sectors) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
mpow, tpow, _, err := GetPowerRaw(ctx, sm, lbst, maddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to get power: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := mas.Info()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &api.MiningBaseInfo{
|
|
||||||
MinerPower: mpow.QualityAdjPower,
|
|
||||||
NetworkPower: tpow.QualityAdjPower,
|
|
||||||
Sectors: sectors,
|
|
||||||
WorkerKey: worker,
|
|
||||||
SectorSize: info.SectorSize,
|
|
||||||
PrevBeaconEntry: *prev,
|
|
||||||
BeaconEntries: entries,
|
|
||||||
EligibleForMining: eligible,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type MethodMeta struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
Params reflect.Type
|
|
||||||
Ret reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// TODO: combine with the runtime actor registry.
|
|
||||||
var actors []rt.VMActor
|
|
||||||
actors = append(actors, exported0.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported2.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported3.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported4.BuiltinActors()...)
|
|
||||||
actors = append(actors, exported5.BuiltinActors()...)
|
|
||||||
|
|
||||||
for _, actor := range actors {
|
|
||||||
exports := actor.Exports()
|
|
||||||
methods := make(map[abi.MethodNum]MethodMeta, len(exports))
|
|
||||||
|
|
||||||
// Explicitly add send, it's special.
|
|
||||||
methods[builtin.MethodSend] = MethodMeta{
|
|
||||||
Name: "Send",
|
|
||||||
Params: reflect.TypeOf(new(abi.EmptyValue)),
|
|
||||||
Ret: reflect.TypeOf(new(abi.EmptyValue)),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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()
|
|
||||||
|
|
||||||
// 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).
|
|
||||||
fnName := runtime.FuncForPC(ev.Pointer()).Name()
|
|
||||||
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
|
|
||||||
|
|
||||||
switch abi.MethodNum(number) {
|
|
||||||
case builtin.MethodSend:
|
|
||||||
panic("method 0 is reserved for Send")
|
|
||||||
case builtin.MethodConstructor:
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MethodsMap[actor.Code()] = methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
|
||||||
act, err := sm.LoadActor(ctx, to, ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
m, found := MethodsMap[act.Code][method]
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
|
||||||
}
|
|
||||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func minerHasMinPower(ctx context.Context, sm *StateManager, addr address.Address, ts *types.TipSet) (bool, error) {
|
|
||||||
pact, err := sm.LoadActor(ctx, power.Address, ts)
|
|
||||||
if err != nil {
|
|
||||||
return false, xerrors.Errorf("loading power actor state: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ps, err := power.Load(sm.cs.ActorStore(ctx), pact)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ps.MinerNominalPowerMeetsConsensusMinimum(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
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.ActorStore(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.ActorStore(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
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckTotalFIL(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) (abi.TokenAmount, error) {
|
func CheckTotalFIL(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) (abi.TokenAmount, error) {
|
||||||
str, err := state.LoadStateTree(cs.ActorStore(ctx), ts.ParentState())
|
str, err := state.LoadStateTree(cs.ActorStore(ctx), ts.ParentState())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -748,75 +283,3 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([]
|
|||||||
|
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
|
|
||||||
st, err := sm.ParentState(ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
act, err := st.GetActor(addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
actState, err := paych.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return act, actState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *StateManager) GetMarketState(ctx context.Context, ts *types.TipSet) (market.State, error) {
|
|
||||||
st, err := sm.ParentState(ts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
act, err := st.GetActor(market.Address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
actState, err := market.Load(sm.cs.ActorStore(ctx), act)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return actState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (api.MarketBalance, error) {
|
|
||||||
mstate, err := sm.GetMarketState(ctx, ts)
|
|
||||||
if err != nil {
|
|
||||||
return api.MarketBalance{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err = sm.LookupID(ctx, addr, ts)
|
|
||||||
if err != nil {
|
|
||||||
return api.MarketBalance{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var out api.MarketBalance
|
|
||||||
|
|
||||||
et, err := mstate.EscrowTable()
|
|
||||||
if err != nil {
|
|
||||||
return api.MarketBalance{}, err
|
|
||||||
}
|
|
||||||
out.Escrow, err = et.Get(addr)
|
|
||||||
if err != nil {
|
|
||||||
return api.MarketBalance{}, xerrors.Errorf("getting escrow balance: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
lt, err := mstate.LockedTable()
|
|
||||||
if err != nil {
|
|
||||||
return api.MarketBalance{}, err
|
|
||||||
}
|
|
||||||
out.Locked, err = lt.Get(addr)
|
|
||||||
if err != nil {
|
|
||||||
return api.MarketBalance{}, xerrors.Errorf("getting locked balance: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ StateManagerAPI = (*StateManager)(nil)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user