lotus/chain/stmgr/utils.go

516 lines
15 KiB
Go
Raw Normal View History

package stmgr
import (
2020-04-30 22:11:14 +00:00
"bytes"
"context"
2020-04-20 17:43:02 +00:00
"os"
2020-04-20 17:43:02 +00:00
cid "github.com/ipfs/go-cid"
blockstore "github.com/ipfs/go-ipfs-blockstore"
cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
amt "github.com/filecoin-project/go-amt-ipld/v2"
2020-04-17 14:47:19 +00:00
"github.com/filecoin-project/sector-storage/ffiwrapper"
2020-02-08 02:18:32 +00:00
"github.com/filecoin-project/specs-actors/actors/abi"
2020-02-19 20:39:10 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin"
2020-03-31 23:13:37 +00:00
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
2020-02-08 02:18:32 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin/market"
2020-02-11 02:33:27 +00:00
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/power"
2020-04-17 14:47:19 +00:00
"github.com/filecoin-project/specs-actors/actors/crypto"
2020-02-11 02:33:27 +00:00
"github.com/filecoin-project/specs-actors/actors/util/adt"
2020-02-08 02:18:32 +00:00
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
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"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
2020-03-31 23:13:37 +00:00
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
2020-03-31 23:13:37 +00:00
func GetNetworkName(ctx context.Context, sm *StateManager, st cid.Cid) (dtypes.NetworkName, error) {
var state init_.State
_, err := sm.LoadActorStateRaw(ctx, builtin.InitActorAddr, &state, st)
if err != nil {
return "", xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
}
return dtypes.NetworkName(state.NetworkName), nil
}
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
2020-02-11 02:33:27 +00:00
var mas miner.State
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st)
if err != nil {
2020-02-11 02:33:27 +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
cst := cbor.NewCborStore(sm.cs.Blockstore())
state, err := state.LoadStateTree(cst, st)
if err != nil {
return address.Undef, xerrors.Errorf("load state tree: %w", err)
}
return vm.ResolveToKeyAddr(state, cst, mas.Info.Worker)
}
2020-04-17 22:02:04 +00:00
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, error) {
return GetPowerRaw(ctx, sm, ts.ParentState(), maddr)
2020-04-02 01:25:58 +00:00
}
func GetPowerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (power.Claim, power.Claim, error) {
2020-02-11 02:33:27 +00:00
var ps power.State
2020-04-02 01:25:58 +00:00
_, err := sm.LoadActorStateRaw(ctx, builtin.StoragePowerActorAddr, &ps, st)
2020-02-11 02:33:27 +00:00
if err != nil {
2020-04-17 22:02:04 +00:00
return power.Claim{}, power.Claim{}, 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-04-17 22:02:04 +00:00
var mpow power.Claim
2019-09-09 20:03:10 +00:00
if maddr != address.Undef {
2020-04-13 21:05:34 +00:00
cm, err := adt.AsMap(sm.cs.Store(ctx), ps.Claims)
if err != nil {
2020-04-17 22:02:04 +00:00
return power.Claim{}, power.Claim{}, err
2020-04-13 21:05:34 +00:00
}
2020-02-11 02:33:27 +00:00
var claim power.Claim
2020-04-13 21:05:34 +00:00
if _, err := cm.Get(adt.AddrKey(maddr), &claim); err != nil {
2020-04-17 22:02:04 +00:00
return power.Claim{}, power.Claim{}, err
2019-09-09 20:03:10 +00:00
}
2020-04-17 22:02:04 +00:00
mpow = claim
2019-09-09 20:03:10 +00:00
}
2020-04-17 22:02:04 +00:00
return mpow, power.Claim{
RawBytePower: ps.TotalRawBytePower,
QualityAdjPower: ps.TotalQualityAdjPower,
}, nil
2019-09-09 20:03:10 +00:00
}
2019-09-17 08:00:38 +00:00
2019-12-11 23:31:59 +00:00
func SectorSetSizes(ctx context.Context, sm *StateManager, maddr address.Address, ts *types.TipSet) (api.MinerSectors, error) {
2020-02-25 20:35:15 +00:00
var mas miner.State
2019-12-11 23:31:59 +00:00
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return api.MinerSectors{}, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
}
2020-05-01 12:06:19 +00:00
notProving, err := abi.BitFieldUnion(mas.Faults, mas.Recoveries)
if err != nil {
return api.MinerSectors{}, err
}
npc, err := notProving.Count()
if err != nil {
return api.MinerSectors{}, err
}
blks := cbor.NewCborStore(sm.ChainStore().Blockstore())
ss, err := amt.LoadAMT(ctx, blks, mas.Sectors)
2019-12-11 23:31:59 +00:00
if err != nil {
return api.MinerSectors{}, err
}
return api.MinerSectors{
Sset: ss.Count,
2020-05-01 12:06:19 +00:00
Pset: ss.Count - npc,
2019-12-11 23:31:59 +00:00
}, nil
}
func PreCommitInfo(ctx context.Context, sm *StateManager, maddr address.Address, sid abi.SectorNumber, ts *types.TipSet) (miner.SectorPreCommitOnChainInfo, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return miner.SectorPreCommitOnChainInfo{}, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
}
i, ok, err := mas.GetPrecommittedSector(sm.cs.Store(ctx), sid)
if err != nil {
return miner.SectorPreCommitOnChainInfo{}, err
}
if !ok {
return miner.SectorPreCommitOnChainInfo{}, xerrors.New("precommit not found")
}
return *i, nil
}
2020-04-21 17:22:53 +00:00
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
2020-02-25 20:35:15 +00:00
var mas miner.State
2019-09-18 02:55:51 +00:00
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
2019-09-18 02:55:51 +00:00
}
2020-04-21 17:22:53 +00:00
return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors, filter, filterOut)
2019-09-18 02:55:51 +00:00
}
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]abi.SectorInfo, error) {
2020-04-17 14:47:19 +00:00
var mas miner.State
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, st)
2020-04-17 14:47:19 +00:00
if err != nil {
return nil, xerrors.Errorf("(get sectors) failed to load miner actor state: %w", err)
2020-04-17 14:47:19 +00:00
}
// TODO: Optimization: we could avoid loaditg the whole proving set here if we had AMT.GetNth with bitfield filtering
sectorSet, err := GetProvingSetRaw(ctx, sm, mas)
if err != nil {
return nil, xerrors.Errorf("getting proving set: %w", err)
}
2020-04-23 21:12:42 +00:00
if len(sectorSet) == 0 {
return nil, nil
}
2020-04-17 14:47:19 +00:00
spt, err := ffiwrapper.SealProofTypeFromSectorSize(mas.Info.SectorSize)
if err != nil {
return nil, xerrors.Errorf("getting seal proof type: %w", err)
}
wpt, err := spt.RegisteredWinningPoStProof()
if err != nil {
return nil, xerrors.Errorf("getting window proof type: %w", err)
}
mid, err := address.IDFromAddress(maddr)
if err != nil {
return nil, xerrors.Errorf("getting miner ID: %w", err)
}
ids, err := pv.GenerateWinningPoStSectorChallenge(ctx, wpt, abi.ActorID(mid), rand, uint64(len(sectorSet)))
if err != nil {
return nil, xerrors.Errorf("generating winning post challenges: %w", err)
}
out := make([]abi.SectorInfo, len(ids))
for i, n := range ids {
out[i] = abi.SectorInfo{
RegisteredProof: wpt,
SectorNumber: sectorSet[n].ID,
SealedCID: sectorSet[n].Info.Info.SealedCID,
}
}
return out, nil
}
func StateMinerInfo(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (miner.MinerInfo, error) {
var mas miner.State
_, err := sm.LoadActorStateRaw(ctx, maddr, &mas, ts.ParentState())
if err != nil {
return miner.MinerInfo{}, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
}
return mas.Info, nil
2020-04-02 01:25:58 +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) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return false, xerrors.Errorf("(get miner slashed) failed to load miner actor state")
}
var spas power.State
_, err = sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &spas, ts)
if err != nil {
return false, xerrors.Errorf("(get miner slashed) failed to load power actor state")
}
store := sm.cs.Store(ctx)
2020-04-13 21:05:34 +00:00
2020-04-21 14:32:17 +00:00
claims, err := adt.AsMap(store, spas.Claims)
if err != nil {
return false, 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
ok, err := claims.Get(power.AddrKey(maddr), nil)
if err != nil {
return false, err
}
if !ok {
return true, nil
2020-03-02 01:09:38 +00:00
}
return false, nil
}
func GetMinerDeadlines(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*miner.Deadlines, error) {
var mas miner.State
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
}
2020-04-21 14:32:17 +00:00
return mas.LoadDeadlines(sm.cs.Store(ctx))
}
func GetMinerFaults(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]abi.SectorNumber, error) {
2020-02-25 20:35:15 +00:00
var mas miner.State
2020-01-30 00:50:58 +00:00
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
}
2020-04-16 16:41:45 +00:00
faults, err := mas.Faults.All(miner.SectorsMax)
if err != nil {
return nil, xerrors.Errorf("reading fault bit set: %w", err)
}
out := make([]abi.SectorNumber, len(faults))
for i, fault := range faults {
out[i] = abi.SectorNumber(fault)
}
return out, nil
2020-01-30 00:50:58 +00:00
}
func GetStorageDeal(ctx context.Context, sm *StateManager, dealId abi.DealID, ts *types.TipSet) (*api.MarketDeal, error) {
2020-02-23 15:50:36 +00:00
var state market.State
2020-02-25 20:54:58 +00:00
if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err
}
2020-02-08 02:18:32 +00:00
da, err := amt.LoadAMT(ctx, cbor.NewCborStore(sm.ChainStore().Blockstore()), state.Proposals)
if err != nil {
return nil, err
}
var dp market.DealProposal
if err := da.Get(ctx, uint64(dealId), &dp); err != nil {
return nil, err
}
2020-04-13 21:05:34 +00:00
sa, err := market.AsDealStateArray(sm.ChainStore().Store(ctx), state.States)
if err != nil {
return nil, err
}
2020-02-23 15:50:36 +00:00
st, err := sa.Get(dealId)
if err != nil {
return nil, err
}
return &api.MarketDeal{
Proposal: dp,
2020-02-23 15:50:36 +00:00
State: *st,
}, nil
}
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
2020-02-25 20:35:15 +00:00
var state power.State
2020-02-25 20:54:58 +00:00
if _, err := sm.LoadActorState(ctx, builtin.StoragePowerActorAddr, &state, ts); err != nil {
return nil, err
}
2020-04-13 21:05:34 +00:00
m, err := adt.AsMap(sm.cs.Store(ctx), state.Claims)
if err != nil {
return nil, err
}
2020-02-11 02:33:27 +00:00
var miners []address.Address
2020-04-13 21:05:34 +00:00
err = m.ForEach(nil, func(k string) error {
2020-02-11 02:33:27 +00:00
a, err := address.NewFromBytes([]byte(k))
if err != nil {
return err
}
miners = append(miners, a)
return nil
})
if err != nil {
return nil, err
}
return miners, nil
}
2020-04-21 17:22:53 +00:00
func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) {
a, err := amt.LoadAMT(ctx, cbor.NewCborStore(bs), ssc)
2019-09-17 22:43:47 +00:00
if err != nil {
return nil, err
}
2019-11-08 18:15:13 +00:00
var sset []*api.ChainSectorInfo
if err := a.ForEach(ctx, func(i uint64, v *cbg.Deferred) error {
2020-04-15 19:59:11 +00:00
if filter != nil {
set, err := filter.IsSet(i)
if err != nil {
return xerrors.Errorf("filter check error: %w", err)
}
2020-04-21 17:22:53 +00:00
if set == filterOut {
2020-04-15 19:59:11 +00:00
return nil
}
}
2020-02-19 19:26:11 +00:00
var oci miner.SectorOnChainInfo
if err := cbor.DecodeInto(v.Raw, &oci); err != nil {
2019-09-17 22:43:47 +00:00
return err
}
2019-11-08 18:15:13 +00:00
sset = append(sset, &api.ChainSectorInfo{
2020-02-19 20:34:21 +00:00
Info: oci,
2020-02-21 19:28:20 +00:00
ID: abi.SectorNumber(i),
2019-09-17 22:43:47 +00:00
})
return nil
}); err != nil {
return nil, err
}
return sset, nil
}
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) {
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
}
2020-03-08 02:31:36 +00:00
base, trace, err := sm.ExecutionTrace(ctx, ts)
if err != nil {
2020-03-08 02:31:36 +00:00
return cid.Undef, nil, err
}
fstate, err := sm.handleStateForks(ctx, base, height, ts.Height())
if err != nil {
2020-03-08 02:31:36 +00:00
return cid.Undef, nil, err
}
r := store.NewChainRand(sm.cs, ts.Cids(), height)
2020-04-07 18:26:43 +00:00
vmi, err := vm.NewVM(fstate, height, r, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil {
2020-03-08 02:31:36 +00:00
return cid.Undef, nil, err
}
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)
if err != nil {
2020-03-08 02:31:36 +00:00
return cid.Undef, nil, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
}
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-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-04-15 20:40:46 +00:00
func GetProvingSetRaw(ctx context.Context, sm *StateManager, mas miner.State) ([]*api.ChainSectorInfo, error) {
2020-04-16 16:41:45 +00:00
notProving, err := abi.BitFieldUnion(mas.Faults, mas.Recoveries)
2020-04-15 20:40:46 +00:00
if err != nil {
return nil, err
}
2020-04-21 17:22:53 +00:00
provset, err := LoadSectorsFromSet(ctx, sm.cs.Blockstore(), mas.Sectors, notProving, true)
2020-04-15 20:40:46 +00:00
if err != nil {
return nil, xerrors.Errorf("failed to get proving set: %w", err)
}
return provset, nil
}
func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types.TipSet, round abi.ChainEpoch) (*types.TipSet, error) {
var lbr abi.ChainEpoch
if round > build.WinningPoStSectorSetLookback {
lbr = round - build.WinningPoStSectorSetLookback
}
// more null blocks than our lookback
if lbr > ts.Height() {
return ts, nil
}
lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, lbr, ts)
if err != nil {
return nil, xerrors.Errorf("failed to get lookback tipset: %w", err)
}
return lbts, nil
}
2020-04-30 22:11:14 +00:00
func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBeacon, 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)
}
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{}
}
entries, err := beacon.BeaconEntriesForBlock(ctx, bcn, round, *prev)
if err != nil {
return nil, err
}
rbase := *prev
if len(entries) > 0 {
rbase = entries[len(entries)-1]
}
lbts, err := GetLookbackTipSetForRound(ctx, sm, ts, round)
if err != nil {
return nil, xerrors.Errorf("getting lookback miner actor state: %w", err)
}
lbst, _, err := sm.TipSetState(ctx, lbts)
if err != nil {
return nil, err
}
2020-04-15 19:59:11 +00:00
var mas miner.State
if _, err := sm.LoadActorStateRaw(ctx, maddr, &mas, lbst); err != nil {
return nil, err
}
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)
}
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)
}
sectors, err := GetSectorsForWinningPoSt(ctx, pv, sm, lbst, maddr, prand)
if err != nil {
return nil, xerrors.Errorf("getting wpost proving set: %w", err)
}
2020-04-23 21:12:42 +00:00
if len(sectors) == 0 {
return nil, nil
}
mpow, tpow, err := GetPowerRaw(ctx, sm, lbst, maddr)
if err != nil {
2020-04-15 19:59:11 +00:00
return nil, xerrors.Errorf("failed to get power: %w", err)
}
2020-04-16 17:17:56 +00:00
worker, err := sm.ResolveToKeyAddress(ctx, mas.GetWorker(), ts)
if err != nil {
return nil, xerrors.Errorf("resolving worker address: %w", err)
}
return &api.MiningBaseInfo{
2020-04-17 22:02:04 +00:00
MinerPower: mpow.QualityAdjPower,
NetworkPower: tpow.QualityAdjPower,
Sectors: sectors,
2020-04-16 17:17:56 +00:00
WorkerKey: worker,
2020-04-15 19:59:11 +00:00
SectorSize: mas.Info.SectorSize,
2020-04-09 17:13:09 +00:00
PrevBeaconEntry: *prev,
2020-04-30 22:11:14 +00:00
BeaconEntries: entries,
}, nil
}