lotus/node/impl/full/state.go
2020-09-16 21:56:02 -04:00

1133 lines
35 KiB
Go

package full
import (
"bytes"
"context"
"errors"
"fmt"
"github.com/filecoin-project/go-state-types/network"
"strconv"
"github.com/filecoin-project/go-state-types/dline"
cid "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
"go.uber.org/fx"
"golang.org/x/xerrors"
"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/lotus/extern/sector-storage/ffiwrapper"
"github.com/filecoin-project/specs-actors/actors/builtin"
v0miner "github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/specs-actors/actors/util/smoothing"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/builtin/multisig"
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/gen"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr"
"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/chain/wallet"
"github.com/filecoin-project/lotus/lib/bufbstore"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/chain/actors/builtin/market"
)
var errBreakForeach = errors.New("break")
type StateAPI struct {
fx.In
// TODO: the wallet here is only needed because we have the MinerCreateBlock
// API attached to the state API. It probably should live somewhere better
Wallet *wallet.Wallet
ProofVerifier ffiwrapper.Verifier
StateManager *stmgr.StateManager
Chain *store.ChainStore
Beacon beacon.Schedule
}
func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState())
}
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*miner.ChainSectorInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, filter, filterOut)
}
func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*miner.ChainSectorInfo, error) { // TODO: only used in cli
act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
}
activeSectors, err := miner.AllPartSectors(mas, miner.Partition.ActiveSectors)
if err != nil {
return nil, xerrors.Errorf("merge partition active sets: %w", err)
}
return mas.LoadSectorsFromSet(&activeSectors, false)
}
func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
act, err := a.StateManager.LoadActorTsk(ctx, actor, tsk)
if err != nil {
return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return miner.MinerInfo{}, xerrors.Errorf("failed to load miner actor state: %w", err)
}
return mas.Info()
}
func (a *StateAPI) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) ([]miner.Deadline, error) {
act, err := a.StateManager.LoadActorTsk(ctx, m, tsk)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
}
deadlines, err := mas.NumDeadlines()
if err != nil {
return nil, xerrors.Errorf("getting deadline count: %w", err)
}
out := make([]miner.Deadline, deadlines)
if err := mas.ForEachDeadline(func(i uint64, dl miner.Deadline) error {
out[i] = dl
return nil
}); err != nil {
return nil, err
}
return out, nil
}
func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address, dlIdx uint64, tsk types.TipSetKey) ([]*miner.Partition, error) {
act, err := a.StateManager.LoadActorTsk(ctx, m, tsk)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
}
dl, err := mas.LoadDeadline(dlIdx)
if err != nil {
return nil, xerrors.Errorf("failed to load the deadline: %w", err)
}
var out []*miner.Partition
err = dl.ForEachPartition(func(_ uint64, part miner.Partition) error {
p := part
out = append(out, &p)
return nil
})
return out, err
}
func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) {
ts, err := a.StateManager.ChainStore().GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
act, err := a.StateManager.LoadActor(ctx, addr, ts)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
}
return mas.DeadlineInfo(ts.Height()).NextNotElapsed(), nil
}
func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk)
if err != nil {
return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor state: %w", err)
}
return miner.AllPartSectors(mas, miner.Partition.FaultySectors)
}
func (a *StateAPI) StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, endTsk types.TipSetKey) ([]*api.Fault, error) {
return nil, xerrors.Errorf("fixme")
/*endTs, err := a.Chain.GetTipSetFromKey(endTsk)
if err != nil {
return nil, xerrors.Errorf("loading end tipset %s: %w", endTsk, err)
}
cutoff := endTs.Height() - lookback
miners, err := stmgr.ListMinerActors(ctx, a.StateManager, endTs)
if err != nil {
return nil, xerrors.Errorf("loading miners: %w", err)
}
var allFaults []*api.Fault
for _, m := range miners {
var mas miner.State
_, err := a.StateManager.LoadActorState(ctx, m, &mas, endTs)
if err != nil {
return nil, xerrors.Errorf("failed to load miner actor state %s: %w", m, err)
}
err = mas.ForEachFaultEpoch(a.Chain.Store(ctx), func(faultStart abi.ChainEpoch, faults abi.BitField) error {
if faultStart >= cutoff {
allFaults = append(allFaults, &api.Fault{
Miner: m,
Epoch: faultStart,
})
return nil
}
return nil
})
if err != nil {
return nil, xerrors.Errorf("failure when iterating over miner states: %w", err)
}
}
return allFaults, nil*/
}
func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {
act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk)
if err != nil {
return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor: %w", err)
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return bitfield.BitField{}, xerrors.Errorf("failed to load miner actor state: %w", err)
}
return miner.AllPartSectors(mas, miner.Partition.RecoveringSectors)
}
func (a *StateAPI) StateMinerPower(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*api.MinerPower, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
m, net, hmp, err := stmgr.GetPower(ctx, a.StateManager, ts, addr)
if err != nil {
return nil, err
}
return &api.MinerPower{
MinerPower: m,
TotalPower: net,
HasMinPower: hmp,
}, nil
}
func (a *StateAPI) StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (*api.InvocResult, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.Call(ctx, msg, ts)
}
func (a *StateAPI) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.Cid) (*api.InvocResult, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
m, r, err := a.StateManager.Replay(ctx, ts, mc)
if err != nil {
return nil, err
}
var errstr string
if r.ActorErr != nil {
errstr = r.ActorErr.Error()
}
return &api.InvocResult{
Msg: m,
MsgRct: &r.MessageReceipt,
ExecutionTrace: r.ExecutionTrace,
Error: errstr,
Duration: r.Duration,
}, nil
}
func (a *StateAPI) stateForTs(ctx context.Context, ts *types.TipSet) (*state.StateTree, error) {
if ts == nil {
ts = a.Chain.GetHeaviestTipSet()
}
st, _, err := a.StateManager.TipSetState(ctx, ts)
if err != nil {
return nil, err
}
buf := bufbstore.NewBufferedBstore(a.Chain.Blockstore())
cst := cbor.NewCborStore(buf)
return state.LoadStateTree(cst, st)
}
func (a *StateAPI) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
state, err := a.stateForTs(ctx, ts)
if err != nil {
return nil, xerrors.Errorf("computing tipset state failed: %w", err)
}
return state.GetActor(actor)
}
func (a *StateAPI) StateLookupID(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
state, err := a.stateForTs(ctx, ts)
if err != nil {
return address.Undef, err
}
return state.LookupID(addr)
}
func (a *StateAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.ResolveToKeyAddress(ctx, addr, ts)
}
func (a *StateAPI) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
state, err := a.stateForTs(ctx, ts)
if err != nil {
return nil, xerrors.Errorf("getting state for tipset: %w", err)
}
act, err := state.GetActor(actor)
if err != nil {
return nil, xerrors.Errorf("getting actor: %w", err)
}
blk, err := state.Store.(*cbor.BasicIpldStore).Blocks.Get(act.Head)
if err != nil {
return nil, xerrors.Errorf("getting actor head: %w", err)
}
oif, err := vm.DumpActorState(act.Code, blk.RawData())
if err != nil {
return nil, xerrors.Errorf("dumping actor state (a:%s): %w", actor, err)
}
return &api.ActorState{
Balance: act.Balance,
State: oif,
}, nil
}
// This is on StateAPI because miner.Miner requires this, and MinerAPI requires miner.Miner
func (a *StateAPI) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return stmgr.MinerGetBaseInfo(ctx, a.StateManager, a.Beacon, tsk, epoch, maddr, a.ProofVerifier)
}
func (a *StateAPI) MinerCreateBlock(ctx context.Context, bt *api.BlockTemplate) (*types.BlockMsg, error) {
fblk, err := gen.MinerCreateBlock(ctx, a.StateManager, a.Wallet, bt)
if err != nil {
return nil, err
}
var out types.BlockMsg
out.Header = fblk.Header
for _, msg := range fblk.BlsMessages {
out.BlsMessages = append(out.BlsMessages, msg.Cid())
}
for _, msg := range fblk.SecpkMessages {
out.SecpkMessages = append(out.SecpkMessages, msg.Cid())
}
return &out, nil
}
func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error) {
ts, recpt, found, err := a.StateManager.WaitForMessage(ctx, msg, confidence)
if err != nil {
return nil, err
}
var returndec interface{}
if recpt.ExitCode == 0 && len(recpt.Return) > 0 {
cmsg, err := a.Chain.GetCMessage(msg)
if err != nil {
return nil, xerrors.Errorf("failed to load message after successful receipt search: %w", err)
}
vmsg := cmsg.VMMessage()
t, err := stmgr.GetReturnType(ctx, a.StateManager, vmsg.To, vmsg.Method, ts)
if err != nil {
return nil, xerrors.Errorf("failed to get return type: %w", err)
}
if err := t.UnmarshalCBOR(bytes.NewReader(recpt.Return)); err != nil {
return nil, err
}
returndec = t
}
return &api.MsgLookup{
Message: found,
Receipt: *recpt,
ReturnDec: returndec,
TipSet: ts.Key(),
Height: ts.Height(),
}, nil
}
func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) {
ts, recpt, found, err := a.StateManager.SearchForMessage(ctx, msg)
if err != nil {
return nil, err
}
if ts != nil {
return &api.MsgLookup{
Message: found,
Receipt: *recpt,
TipSet: ts.Key(),
Height: ts.Height(),
}, nil
}
return nil, nil
}
func (a *StateAPI) StateGetReceipt(ctx context.Context, msg cid.Cid, tsk types.TipSetKey) (*types.MessageReceipt, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.GetReceipt(ctx, msg, ts)
}
func (a *StateAPI) StateListMiners(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.ListMinerActors(ctx, a.StateManager, ts)
}
func (a *StateAPI) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.ListAllActors(ctx, ts)
}
func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MarketBalance, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return api.MarketBalance{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.MarketBalance(ctx, addr, ts)
}
func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketBalance, error) {
out := map[string]api.MarketBalance{}
var state market.State
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err
}
store := a.StateManager.ChainStore().Store(ctx)
escrow, err := adt.AsMap(store, state.EscrowTable)
if err != nil {
return nil, err
}
locked, err := adt.AsMap(store, state.LockedTable)
if err != nil {
return nil, err
}
var es, lk abi.TokenAmount
err = escrow.ForEach(&es, func(k string) error {
a, err := address.NewFromBytes([]byte(k))
if err != nil {
return err
}
if found, err := locked.Get(abi.AddrKey(a), &lk); err != nil {
return err
} else if !found {
return fmt.Errorf("locked funds not found")
}
out[a.String()] = api.MarketBalance{
Escrow: es,
Locked: lk,
}
return nil
})
if err != nil {
return nil, err
}
return out, nil
}
func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketDeal, error) {
out := map[string]api.MarketDeal{}
var state market.State
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err
}
store := a.StateManager.ChainStore().Store(ctx)
da, err := adt.AsArray(store, state.Proposals)
if err != nil {
return nil, err
}
sa, err := adt.AsArray(store, state.States)
if err != nil {
return nil, err
}
var d market.DealProposal
if err := da.ForEach(&d, func(i int64) error {
var s market.DealState
if found, err := sa.Get(uint64(i), &s); err != nil {
return xerrors.Errorf("failed to get state for deal in proposals array: %w", err)
} else if !found {
s.SectorStartEpoch = -1
}
out[strconv.FormatInt(i, 10)] = api.MarketDeal{
Proposal: d,
State: s,
}
return nil
}); err != nil {
return nil, err
}
return out, nil
}
func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*api.MarketDeal, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.GetStorageDeal(ctx, a.StateManager, dealId, ts)
}
func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) {
store := adt.WrapStore(ctx, cbor.NewCborStore(a.Chain.Blockstore()))
nh, err := adt.AsMap(store, new)
if err != nil {
return nil, err
}
oh, err := adt.AsMap(store, old)
if err != nil {
return nil, err
}
out := map[string]types.Actor{}
var (
ncval, ocval cbg.Deferred
buf = bytes.NewReader(nil)
)
err = nh.ForEach(&ncval, func(k string) error {
var act types.Actor
addr, err := address.NewFromBytes([]byte(k))
if err != nil {
return xerrors.Errorf("address in state tree was not valid: %w", err)
}
found, err := oh.Get(abi.AddrKey(addr), &ocval)
if err != nil {
return err
}
if found && bytes.Equal(ocval.Raw, ncval.Raw) {
return nil // not changed
}
buf.Reset(ncval.Raw)
err = act.UnmarshalCBOR(buf)
buf.Reset(nil)
if err != nil {
return err
}
out[addr.String()] = act
return nil
})
if err != nil {
return nil, err
}
return out, nil
}
func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MinerSectors, error) {
act, err := a.StateManager.LoadActorTsk(ctx, addr, tsk)
if err != nil {
return api.MinerSectors{}, err
}
mas, err := miner.Load(a.Chain.Store(ctx), act)
if err != nil {
return api.MinerSectors{}, err
}
var activeCount, liveCount, faultyCount uint64
if err := mas.ForEachDeadline(func(_ uint64, dl miner.Deadline) error {
return dl.ForEachPartition(func(_ uint64, part miner.Partition) error {
if active, err := part.ActiveSectors(); err != nil {
return err
} else if count, err := active.Count(); err != nil {
return err
} else {
activeCount += count
}
if live, err := part.LiveSectors(); err != nil {
return err
} else if count, err := live.Count(); err != nil {
return err
} else {
liveCount += count
}
if faulty, err := part.FaultySectors(); err != nil {
return err
} else if count, err := faulty.Count(); err != nil {
return err
} else {
faultyCount += count
}
return nil
})
}); err != nil {
return api.MinerSectors{}, err
}
return api.MinerSectors{Live: liveCount, Active: activeCount, Faulty: faultyCount}, nil
}
func (a *StateAPI) StateSectorPreCommitInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.PreCommitInfo(ctx, a.StateManager, maddr, n, ts)
}
func (a *StateAPI) StateSectorGetInfo(ctx context.Context, maddr address.Address, n abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.MinerSectorInfo(ctx, a.StateManager, maddr, n, ts)
}
func (a *StateAPI) StateSectorExpiration(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorExpiration, error) {
act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk)
if err != nil {
return nil, err
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return nil, err
}
return mas.GetSectorExpiration(sectorNumber)
}
func (a *StateAPI) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorLocation, error) {
act, err := a.StateManager.LoadActorTsk(ctx, maddr, tsk)
if err != nil {
return nil, err
}
mas, err := miner.Load(a.StateManager.ChainStore().Store(ctx), act)
if err != nil {
return nil, err
}
return mas.FindSector(sectorNumber)
}
func (a *StateAPI) StateListMessages(ctx context.Context, match *types.Message, tsk types.TipSetKey, toheight abi.ChainEpoch) ([]cid.Cid, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
if ts == nil {
ts = a.Chain.GetHeaviestTipSet()
}
if match.To == address.Undef && match.From == address.Undef {
return nil, xerrors.Errorf("must specify at least To or From in message filter")
}
matchFunc := func(msg *types.Message) bool {
if match.From != address.Undef && match.From != msg.From {
return false
}
if match.To != address.Undef && match.To != msg.To {
return false
}
return true
}
var out []cid.Cid
for ts.Height() >= toheight {
msgs, err := a.Chain.MessagesForTipset(ts)
if err != nil {
return nil, xerrors.Errorf("failed to get messages for tipset (%s): %w", ts.Key(), err)
}
for _, msg := range msgs {
if matchFunc(msg.VMMessage()) {
out = append(out, msg.Cid())
}
}
if ts.Height() == 0 {
break
}
next, err := a.Chain.LoadTipSet(ts.Parents())
if err != nil {
return nil, xerrors.Errorf("loading next tipset: %w", err)
}
ts = next
}
return out, nil
}
func (a *StateAPI) StateCompute(ctx context.Context, height abi.ChainEpoch, msgs []*types.Message, tsk types.TipSetKey) (*api.ComputeStateOutput, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
st, t, err := stmgr.ComputeState(ctx, a.StateManager, height, msgs, ts)
if err != nil {
return nil, err
}
return &api.ComputeStateOutput{
Root: st,
Trace: t,
}, nil
}
func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
act, err := a.StateManager.LoadActor(ctx, addr, ts)
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to load multisig actor: %w", err)
}
msas, err := multisig.Load(a.Chain.Store(ctx), act)
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state: %w", err)
}
locked, err := msas.LockedBalance(ts.Height())
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to compute locked multisig balance: %w", err)
}
return types.BigSub(act.Balance, locked), nil
}
func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) {
startTs, err := a.Chain.GetTipSetFromKey(start)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading start tipset %s: %w", start, err)
}
endTs, err := a.Chain.GetTipSetFromKey(end)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading end tipset %s: %w", end, err)
}
if startTs.Height() > endTs.Height() {
return types.EmptyInt, xerrors.Errorf("start tipset %d is after end tipset %d", startTs.Height(), endTs.Height())
} else if startTs.Height() == endTs.Height() {
return big.Zero(), nil
}
act, err := a.StateManager.LoadActor(ctx, addr, endTs)
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to load multisig actor at end epoch: %w", err)
}
msas, err := multisig.Load(a.Chain.Store(ctx), act)
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state: %w", err)
}
startLk, err := msas.LockedBalance(startTs.Height())
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to compute locked balance at start height: %w", err)
}
endLk, err := msas.LockedBalance(endTs.Height())
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to compute locked balance at end height: %w", err)
}
return types.BigSub(startLk, endLk), nil
}
var initialPledgeNum = types.NewInt(110)
var initialPledgeDen = types.NewInt(100)
func (a *StateAPI) StateMinerPreCommitDepositForPower(ctx context.Context, maddr address.Address, pci miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
state, err := a.StateManager.ParentState(ts)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading state %s: %w", tsk, err)
}
ssize, err := pci.SealProof.SectorSize()
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to get resolve size: %w", err)
}
store := a.Chain.Store(ctx)
var sectorWeight abi.StoragePower
if act, err := state.GetActor(market.Address); err != nil {
return types.EmptyInt, xerrors.Errorf("loading miner actor %s: %w", maddr, err)
} else s, err := market.Load(store, act); err != nil {
return types.EmptyInt, xerrors.Errorf("loading market actor state %s: %w", maddr, err)
} else if w, vw, err := s.VerifyDealsForActivation(maddr, pci.DealIDs, ts.Height(), pci.Expiration); err != nil {
return types.EmptyInt, xerrors.Errorf("verifying deals for activation: %w", err)
} else {
// NB: not exactly accurate, but should always lead us to *over* estimate, not under
duration := pci.Expiration - ts.Height()
// TODO: handle changes to this function across actor upgrades.
sectorWeight = v0miner.QAPowerForWeight(ssize, duration, w, vw)
}
var powerSmoothed smoothing.FilterEstimate
if act, err := state.GetActor(power.Address); err != nil {
return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err)
} else s, err := power.Load(store, act); err != nil {
return types.EmptyInt, xerrors.Errorf("loading power actor state: %w", err)
} else p, err := s.TotalPowerSmoothed(); err != nil {
return types.EmptyInt, xerrors.Errorf("failed to determine total power: %w", err)
} else {
powerSmoothed = p
}
var rewardSmoothed smoothing.FilterEstimate
if act, err := state.GetActor(reward.Address); err != nil {
return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err)
} else s, err := reward.Load(store, act); err != nil {
return types.EmptyInt, xerrors.Errorf("loading reward actor state: %w", err)
} else r, err := s.RewardSmoothed(); err != nil {
return types.EmptyInt, xerrors.Errorf("failed to determine total reward: %w", err)
} else {
rewardSmoothed = r
}
// TODO: abstract over network upgrades.
deposit := v0miner.PreCommitDepositForPower(rewardSmoothed, powerSmoothed, sectorWeight)
return types.BigDiv(types.BigMul(deposit, initialPledgeNum), initialPledgeDen), nil
}
func (a *StateAPI) StateMinerInitialPledgeCollateral(ctx context.Context, maddr address.Address, pci miner.SectorPreCommitInfo, tsk types.TipSetKey) (types.BigInt, error) {
// TODO: this repeats a lot of the previous function. Fix that.
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
state, err := a.StateManager.ParentState(ts)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading state %s: %w", tsk, err)
}
ssize, err := pci.SealProof.SectorSize()
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to get resolve size: %w", err)
}
store := a.Chain.Store(ctx)
var sectorWeight abi.StoragePower
if act, err := state.GetActor(market.Address); err != nil {
return types.EmptyInt, xerrors.Errorf("loading miner actor %s: %w", maddr, err)
} else s, err := market.Load(store, act); err != nil {
return types.EmptyInt, xerrors.Errorf("loading market actor state %s: %w", maddr, err)
} else if w, vw, err := s.VerifyDealsForActivation(maddr, pci.DealIDs, ts.Height(), pci.Expiration); err != nil {
return types.EmptyInt, xerrors.Errorf("verifying deals for activation: %w", err)
} else {
// NB: not exactly accurate, but should always lead us to *over* estimate, not under
duration := pci.Expiration - ts.Height()
// TODO: handle changes to this function across actor upgrades.
sectorWeight = v0miner.QAPowerForWeight(ssize, duration, w, vw)
}
var (
powerSmoothed smoothing.FilterEstimate
pledgeCollerateral abi.TokenAmount
)
if act, err := state.GetActor(power.Address); err != nil {
return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err)
} else s, err := power.Load(store, act); err != nil {
return types.EmptyInt, xerrors.Errorf("loading power actor state: %w", err)
} else p, err := s.TotalPowerSmoothed(); err != nil {
return types.EmptyInt, xerrors.Errorf("failed to determine total power: %w", err)
} else c, err := s.TotalLocked(); err != nil {
return types.EmptyInt, xerrors.Errorf("failed to determine pledge collateral: %w", err)
} else {
powerSmoothed = p
pledgeCollateral = c
}
var (
rewardSmoothed smoothing.FilterEstimate
baselinePower abi.StoragePower
)
if act, err := state.GetActor(reward.Address); err != nil {
return types.EmptyInt, xerrors.Errorf("loading miner actor: %w", err)
} else s, err := reward.Load(store, act); err != nil {
return types.EmptyInt, xerrors.Errorf("loading reward actor state: %w", err)
} else r, err := s.RewardSmoothed(); err != nil {
return types.EmptyInt, xerrors.Errorf("failed to determine total reward: %w", err)
} else p, err := s.BaselinePower(); err != nil {
return types.EmptyInt, xerrors.Errorf("failed to determine baseline power: %w", err)
} else {
rewardSmoothed = r
baselinePower = p
}
// TODO: abstract over network upgrades.
circSupply, err := a.StateCirculatingSupply(ctx, ts.Key())
if err != nil {
return big.Zero(), xerrors.Errorf("getting circulating supply: %w", err)
}
initialPledge := miner.InitialPledgeForPower(
sectorWeight,
baselinePower,
pledgeCollateral,
rewardSmoothed,
powerSmoothed,
circSupply.FilCirculating,
)
return types.BigDiv(types.BigMul(initialPledge, initialPledgeNum), initialPledgeDen), nil
}
func (a *StateAPI) StateMinerAvailableBalance(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (types.BigInt, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return types.EmptyInt, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
var act *types.Actor
var mas miner.State
if err := a.StateManager.WithParentState(ts, a.StateManager.WithActor(maddr, func(actor *types.Actor) error {
act = actor
return a.StateManager.WithActorState(ctx, &mas)(actor)
})); err != nil {
return types.BigInt{}, xerrors.Errorf("getting miner state: %w", err)
}
as := store.ActorStore(ctx, a.Chain.Blockstore())
vested, err := mas.CheckVestedFunds(as, ts.Height())
if err != nil {
return types.EmptyInt, err
}
return types.BigAdd(mas.GetAvailableBalance(act.Balance), vested), nil
}
// StateVerifiedClientStatus returns the data cap for the given address.
// Returns nil if there is no entry in the data cap table for the
// address.
func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*verifreg.DataCap, error) {
act, err := a.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, tsk)
if err != nil {
return nil, err
}
aid, err := a.StateLookupID(ctx, addr, tsk)
if err != nil {
log.Warnf("lookup failure %v", err)
return nil, err
}
store := a.StateManager.ChainStore().Store(ctx)
var st verifreg.State
if err := store.Get(ctx, act.Head, &st); err != nil {
return nil, err
}
vh, err := adt.AsMap(store, st.VerifiedClients)
if err != nil {
return nil, err
}
var dcap verifreg.DataCap
if found, err := vh.Get(abi.AddrKey(aid), &dcap); err != nil {
return nil, err
} else if !found {
return nil, nil
}
return &dcap, nil
}
var dealProviderCollateralNum = types.NewInt(110)
var dealProviderCollateralDen = types.NewInt(100)
// StateDealProviderCollateralBounds returns the min and max collateral a storage provider
// can issue. It takes the deal size and verified status as parameters.
func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size abi.PaddedPieceSize, verified bool, tsk types.TipSetKey) (api.DealCollateralBounds, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
var powerState power.State
var rewardState reward.State
err = a.StateManager.WithParentStateTsk(ts.Key(), func(state *state.StateTree) error {
if err := a.StateManager.WithActor(builtin.StoragePowerActorAddr, a.StateManager.WithActorState(ctx, &powerState))(state); err != nil {
return xerrors.Errorf("getting power state: %w", err)
}
if err := a.StateManager.WithActor(builtin.RewardActorAddr, a.StateManager.WithActorState(ctx, &rewardState))(state); err != nil {
return xerrors.Errorf("getting reward state: %w", err)
}
return nil
})
if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("getting power and reward actor states: %w", err)
}
circ, err := a.StateCirculatingSupply(ctx, ts.Key())
if err != nil {
return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err)
}
min, max := market.DealProviderCollateralBounds(size,
verified,
powerState.TotalRawBytePower,
powerState.ThisEpochQualityAdjPower,
rewardState.ThisEpochBaselinePower,
circ.FilCirculating,
a.StateManager.GetNtwkVersion(ctx, ts.Height()))
return api.DealCollateralBounds{
Min: types.BigDiv(types.BigMul(min, dealProviderCollateralNum), dealProviderCollateralDen),
Max: max,
}, nil
}
func (a *StateAPI) StateCirculatingSupply(ctx context.Context, tsk types.TipSetKey) (api.CirculatingSupply, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return api.CirculatingSupply{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
sTree, err := a.stateForTs(ctx, ts)
if err != nil {
return api.CirculatingSupply{}, err
}
return a.StateManager.GetCirculatingSupplyDetailed(ctx, ts.Height(), sTree)
}
func (a *StateAPI) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return -1, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return a.StateManager.GetNtwkVersion(ctx, ts.Height()), nil
}