lotus/node/impl/full/state.go

607 lines
18 KiB
Go
Raw Normal View History

2019-08-20 16:48:33 +00:00
package full
import (
"bytes"
2019-08-20 16:48:33 +00:00
"context"
"fmt"
"strconv"
2019-09-19 20:25:18 +00:00
cid "github.com/ipfs/go-cid"
2019-09-16 20:11:17 +00:00
"github.com/ipfs/go-hamt-ipld"
2020-02-04 22:19:05 +00:00
cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
2019-09-16 20:11:17 +00:00
"go.uber.org/fx"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
2020-02-25 20:54:58 +00:00
"github.com/filecoin-project/go-amt-ipld/v2"
"github.com/filecoin-project/lotus/api"
"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"
2020-04-13 21:05:34 +00:00
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/sector-storage/ffiwrapper"
2020-04-13 21:05:34 +00:00
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
2019-08-20 16:48:33 +00:00
)
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
2019-08-20 16:48:33 +00:00
}
2020-03-31 23:13:37 +00:00
func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) {
return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState())
}
2020-04-21 17:22:53 +00:00
func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
2020-04-21 17:22:53 +00:00
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, filter, filterOut)
2019-08-21 16:31:14 +00:00
}
2020-04-15 20:40:46 +00:00
func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
var mas miner.State
_, err = a.StateManager.LoadActorState(ctx, addr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
}
return stmgr.GetProvingSetRaw(ctx, a.StateManager, mas)
}
func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return miner.MinerInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.StateMinerInfo(ctx, a.StateManager, ts, actor)
}
func (a *StateAPI) StateMinerDeadlines(ctx context.Context, m address.Address, tsk types.TipSetKey) (*miner.Deadlines, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.GetMinerDeadlines(ctx, a.StateManager, ts, m)
}
func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]abi.SectorNumber, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
2020-01-30 00:50:58 +00:00
return stmgr.GetMinerFaults(ctx, a.StateManager, ts, addr)
}
2020-04-15 20:40:46 +00:00
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, err := stmgr.GetPower(ctx, a.StateManager, ts, addr)
if err != nil {
return nil, err
}
return &api.MinerPower{
MinerPower: m,
TotalPower: net,
}, nil
}
func (a *StateAPI) StatePledgeCollateral(ctx context.Context, 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)
}
param, err := actors.SerializeParams(&actors.PledgeCollateralParams{Size: types.NewInt(0)})
if err != nil {
return types.NewInt(0), err
}
ret, aerr := a.StateManager.Call(ctx, &types.Message{
2019-10-19 08:06:41 +00:00
From: actors.StoragePowerAddress,
To: actors.StoragePowerAddress,
Method: actors.SPAMethods.PledgeCollateralForSize,
Params: param,
}, ts)
if aerr != nil {
return types.NewInt(0), xerrors.Errorf("failed to get miner worker addr: %w", err)
}
if ret.MsgRct.ExitCode != 0 {
return types.NewInt(0), xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.MsgRct.ExitCode)
}
2020-02-12 23:52:36 +00:00
return types.BigFromBytes(ret.Return), nil*/
log.Error("TODO StatePledgeCollateral")
2020-02-12 23:52:36 +00:00
return big.Zero(), 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)
}
2019-09-09 20:03:10 +00:00
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)
}
2019-09-19 20:25:18 +00:00
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{
2020-03-08 00:46:12 +00:00
Msg: m,
MsgRct: &r.MessageReceipt,
InternalExecutions: r.InternalExecutions,
2020-03-08 00:46:12 +00:00
Error: errstr,
Duration: r.Duration,
2019-09-19 20:25:18 +00:00
}, nil
}
2019-10-10 11:13:26 +00:00
func (a *StateAPI) stateForTs(ctx context.Context, ts *types.TipSet) (*state.StateTree, error) {
if ts == nil {
ts = a.Chain.GetHeaviestTipSet()
}
2019-10-10 11:13:26 +00:00
st, _, err := a.StateManager.TipSetState(ctx, ts)
if err != nil {
return nil, err
}
buf := bufbstore.NewBufferedBstore(a.Chain.Blockstore())
2020-02-04 22:19:05 +00:00
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)
}
2019-10-10 11:13:26 +00:00
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)
}
2019-11-15 16:39:43 +00:00
state, err := a.stateForTs(ctx, ts)
if err != nil {
return address.Undef, err
}
return state.LookupID(addr)
}
2020-04-16 20:38:42 +00:00
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, act *types.Actor, 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)
}
2019-10-10 11:13:26 +00:00
state, err := a.stateForTs(ctx, ts)
if err != nil {
return nil, err
}
2020-02-04 22:19:05 +00:00
blk, err := state.Store.(*cbor.BasicIpldStore).Blocks.Get(act.Head)
if err != nil {
return nil, err
}
oif, err := vm.DumpActorState(act.Code, blk.RawData())
if err != nil {
return nil, 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, tsk, epoch, maddr, a.ProofVerifier)
}
2020-04-09 00:24:10 +00:00
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) (*api.MsgLookup, error) {
// TODO: consider using event system for this, expose confidence
ts, recpt, err := a.StateManager.WaitForMessage(ctx, msg)
if err != nil {
return nil, err
}
return &api.MsgLookup{
Receipt: *recpt,
TipSet: ts,
}, nil
}
func (a *StateAPI) StateSearchMsg(ctx context.Context, msg cid.Cid) (*api.MsgLookup, error) {
ts, recpt, err := a.StateManager.SearchForMessage(ctx, msg)
if err != nil {
return nil, err
}
if ts != nil {
return &api.MsgLookup{
Receipt: *recpt,
TipSet: ts,
}, nil
} else {
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)
}
2019-11-19 21:27:25 +00:00
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)
}
2019-10-22 10:09:36 +00:00
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)
2019-10-22 10:09:36 +00:00
}
func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSetKey) (map[string]api.MarketBalance, error) {
2020-02-08 02:18:32 +00:00
out := map[string]api.MarketBalance{}
2020-02-25 20:35:15 +00:00
var state market.State
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
2020-02-25 20:54:58 +00:00
if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err
}
2020-02-04 22:19:05 +00:00
cst := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore())
2020-02-14 14:14:39 +00:00
escrow, err := hamt.LoadNode(ctx, cst, state.EscrowTable, hamt.UseTreeBitWidth(5)) // todo: adt map
2020-02-08 02:18:32 +00:00
if err != nil {
return nil, err
}
2020-02-14 14:14:39 +00:00
locked, err := hamt.LoadNode(ctx, cst, state.EscrowTable, hamt.UseTreeBitWidth(5))
if err != nil {
return nil, err
}
2020-02-08 02:18:32 +00:00
err = escrow.ForEach(ctx, func(k string, val interface{}) error {
cv := val.(*cbg.Deferred)
a, err := address.NewFromBytes([]byte(k))
if err != nil {
return err
}
2020-02-08 02:18:32 +00:00
var es abi.TokenAmount
if err := es.UnmarshalCBOR(bytes.NewReader(cv.Raw)); err != nil {
return err
}
var lk abi.TokenAmount
if err := locked.Find(ctx, k, &es); err != nil {
return err
}
2020-02-08 02:18:32 +00:00
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{}
2020-02-25 20:35:15 +00:00
var state market.State
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
2020-02-25 20:54:58 +00:00
if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil {
return nil, err
}
blks := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore())
2020-02-08 02:18:32 +00:00
da, err := amt.LoadAMT(ctx, blks, state.Proposals)
if err != nil {
return nil, err
}
sa, err := amt.LoadAMT(ctx, blks, state.States)
if err != nil {
return nil, err
}
if err := da.ForEach(ctx, func(i uint64, v *cbg.Deferred) error {
2020-02-08 02:18:32 +00:00
var d market.DealProposal
if err := d.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil {
return err
}
var s market.DealState
if err := sa.Get(ctx, i, &s); err != nil {
return err
}
out[strconv.FormatInt(int64(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)
}
2019-11-15 18:38:09 +00:00
func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) {
2020-02-04 22:19:05 +00:00
cst := cbor.NewCborStore(a.Chain.Blockstore())
2019-11-15 18:38:09 +00:00
2020-02-14 14:14:39 +00:00
nh, err := hamt.LoadNode(ctx, cst, new, hamt.UseTreeBitWidth(5))
2019-11-15 18:38:09 +00:00
if err != nil {
return nil, err
}
2020-02-14 14:14:39 +00:00
oh, err := hamt.LoadNode(ctx, cst, old, hamt.UseTreeBitWidth(5))
2019-11-15 18:38:09 +00:00
if err != nil {
return nil, err
}
out := map[string]types.Actor{}
err = nh.ForEach(ctx, func(k string, nval interface{}) error {
ncval := nval.(*cbg.Deferred)
var act types.Actor
var ocval cbg.Deferred
switch err := oh.Find(ctx, k, &ocval); err {
case nil:
if bytes.Equal(ocval.Raw, ncval.Raw) {
return nil // not changed
}
fallthrough
case hamt.ErrNotFound:
if err := act.UnmarshalCBOR(bytes.NewReader(ncval.Raw)); err != nil {
return err
}
addr, err := address.NewFromBytes([]byte(k))
if err != nil {
return xerrors.Errorf("address in state tree was not valid: %w", err)
}
out[addr.String()] = act
default:
return err
}
return nil
})
if err != nil {
return nil, err
}
return out, nil
}
2019-12-11 23:31:59 +00:00
func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Address, tsk types.TipSetKey) (api.MinerSectors, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil {
return api.MinerSectors{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
2019-12-11 23:31:59 +00:00
return stmgr.SectorSetSizes(ctx, a.StateManager, addr, ts)
}
2020-01-07 19:03:11 +00:00
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 miner.SectorPreCommitOnChainInfo{}, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}
return stmgr.PreCommitInfo(ctx, a.StateManager, maddr, n, ts)
}
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)
}
2020-01-07 19:03:11 +00:00
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
}
2020-03-08 02:31:36 +00:00
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 {
2020-03-08 02:31:36 +00:00
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
}
2020-03-08 02:31:36 +00:00
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)
}
2020-02-08 02:18:32 +00:00
var st samsig.State
act, err := a.StateManager.LoadActorState(ctx, addr, &st, ts)
if err != nil {
return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state: %w", err)
}
2020-02-25 20:54:58 +00:00
if act.Code != builtin.MultisigActorCodeID {
return types.EmptyInt, fmt.Errorf("given actor was not a multisig")
}
if st.UnlockDuration == 0 {
return act.Balance, nil
}
2020-02-08 02:18:32 +00:00
offset := ts.Height() - st.StartEpoch
if offset > st.UnlockDuration {
return act.Balance, nil
}
2020-02-04 03:37:55 +00:00
minBalance := types.BigDiv(types.BigInt(st.InitialBalance), types.NewInt(uint64(st.UnlockDuration)))
2020-02-08 02:18:32 +00:00
minBalance = types.BigMul(minBalance, types.NewInt(uint64(offset)))
return types.BigSub(act.Balance, minBalance), nil
}