lotus/chain/stmgr/utils.go

350 lines
10 KiB
Go
Raw Normal View History

package stmgr
import (
"context"
ffi "github.com/filecoin-project/filecoin-ffi"
2020-01-07 16:23:12 +00:00
sectorbuilder "github.com/filecoin-project/go-sectorbuilder"
"github.com/filecoin-project/go-address"
2020-01-07 16:23:12 +00:00
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
2019-09-17 22:43:47 +00:00
amt "github.com/filecoin-project/go-amt-ipld"
cid "github.com/ipfs/go-cid"
hamt "github.com/ipfs/go-hamt-ipld"
2019-09-18 02:55:51 +00:00
blockstore "github.com/ipfs/go-ipfs-blockstore"
2019-09-17 22:43:47 +00:00
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
)
func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
2019-09-09 20:03:10 +00:00
recp, err := sm.CallRaw(ctx, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetWorkerAddr,
}, st, nil, 0)
if err != nil {
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner worker addr failed (exit code %d)", recp.ExitCode)
}
worker, err := address.NewFromBytes(recp.Return)
if err != nil {
return address.Undef, err
}
if worker.Protocol() == address.ID {
return address.Undef, xerrors.Errorf("need to resolve worker address to a pubkeyaddr")
}
return worker, nil
}
func GetMinerOwner(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) {
2019-09-09 20:03:10 +00:00
recp, err := sm.CallRaw(ctx, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetOwner,
}, st, nil, 0)
if err != nil {
return address.Undef, xerrors.Errorf("callRaw failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner owner addr failed (exit code %d)", recp.ExitCode)
}
owner, err := address.NewFromBytes(recp.Return)
if err != nil {
return address.Undef, err
}
if owner.Protocol() == address.ID {
return address.Undef, xerrors.Errorf("need to resolve owner address to a pubkeyaddr")
}
return owner, nil
}
2019-09-09 20:03:10 +00:00
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (types.BigInt, types.BigInt, error) {
var err error
var mpow types.BigInt
if maddr != address.Undef {
2019-10-15 14:59:31 +00:00
enc, aerr := actors.SerializeParams(&actors.PowerLookupParams{maddr})
if aerr != nil {
return types.EmptyInt, types.EmptyInt, aerr
}
2019-09-09 20:03:10 +00:00
ret, err := sm.Call(ctx, &types.Message{
From: maddr,
2019-10-19 08:06:41 +00:00
To: actors.StoragePowerAddress,
Method: actors.SPAMethods.PowerLookup,
2019-09-09 20:03:10 +00:00
Params: enc,
}, ts)
if err != nil {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get miner power from chain: %w", err)
}
if ret.ExitCode != 0 {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get miner power from chain (exit code %d)", ret.ExitCode)
}
mpow = types.BigFromBytes(ret.Return)
}
ret, err := sm.Call(ctx, &types.Message{
2019-10-19 08:06:41 +00:00
From: actors.StoragePowerAddress,
To: actors.StoragePowerAddress,
Method: actors.SPAMethods.GetTotalStorage,
2019-09-09 20:03:10 +00:00
}, ts)
if err != nil {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get total power from chain: %w", err)
}
if ret.ExitCode != 0 {
return types.EmptyInt, types.EmptyInt, xerrors.Errorf("failed to get total power from chain (exit code %d)", ret.ExitCode)
}
tpow := types.BigFromBytes(ret.Return)
return mpow, tpow, nil
}
2019-09-17 08:00:38 +00:00
func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (peer.ID, error) {
recp, err := sm.Call(ctx, &types.Message{
To: maddr,
From: maddr,
2019-09-17 08:34:41 +00:00
Method: actors.MAMethods.GetPeerID,
2019-09-17 08:00:38 +00:00
}, ts)
if err != nil {
return "", xerrors.Errorf("call failed: %w", err)
2019-09-17 08:00:38 +00:00
}
if recp.ExitCode != 0 {
return "", xerrors.Errorf("getting miner peer ID failed (exit code %d)", recp.ExitCode)
}
return peer.IDFromBytes(recp.Return)
}
2019-09-17 22:43:47 +00:00
func GetMinerWorker(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (address.Address, error) {
recp, err := sm.Call(ctx, &types.Message{
To: maddr,
From: maddr,
Method: actors.MAMethods.GetWorkerAddr,
}, ts)
if err != nil {
return address.Undef, xerrors.Errorf("call failed: %w", err)
}
if recp.ExitCode != 0 {
return address.Undef, xerrors.Errorf("getting miner peer ID failed (exit code %d)", recp.ExitCode)
}
return address.NewFromBytes(recp.Return)
}
func GetMinerElectionPeriodStart(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
2019-09-17 22:43:47 +00:00
var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return 0, xerrors.Errorf("(get eps) failed to load miner actor state: %w", err)
2019-09-17 22:43:47 +00:00
}
return mas.ElectionPeriodStart, nil
2019-09-17 22:43:47 +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) {
var mas actors.StorageMinerActorState
_, 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)
}
blks := amt.WrapBlockstore(sm.ChainStore().Blockstore())
ss, err := amt.LoadAMT(blks, mas.Sectors)
if err != nil {
return api.MinerSectors{}, err
}
ps, err := amt.LoadAMT(blks, mas.ProvingSet)
if err != nil {
return api.MinerSectors{}, err
}
return api.MinerSectors{
Pset: ps.Count,
Sset: ss.Count,
}, nil
}
2019-11-08 18:15:13 +00:00
func GetMinerProvingSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.ChainSectorInfo, error) {
2019-09-17 22:43:47 +00:00
var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return nil, xerrors.Errorf("(get pset) failed to load miner actor state: %w", err)
2019-09-17 22:43:47 +00:00
}
2019-09-18 02:55:51 +00:00
return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.ProvingSet)
}
2019-11-08 18:15:13 +00:00
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) ([]*api.ChainSectorInfo, error) {
2019-09-18 02:55:51 +00:00
var mas actors.StorageMinerActorState
_, 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
}
return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors)
}
2019-11-25 04:45:13 +00:00
func GetSectorsForElectionPost(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (*sectorbuilder.SortedPublicSectorInfo, error) {
sectors, err := GetMinerProvingSet(ctx, sm, ts, maddr)
2019-11-21 22:21:45 +00:00
if err != nil {
return nil, xerrors.Errorf("failed to get sector set for miner: %w", err)
}
var uselessOtherArray []ffi.PublicSectorInfo
2019-11-21 22:21:45 +00:00
for _, s := range sectors {
var uselessBuffer [32]byte
copy(uselessBuffer[:], s.CommR)
uselessOtherArray = append(uselessOtherArray, ffi.PublicSectorInfo{
2019-11-21 22:21:45 +00:00
SectorID: s.SectorID,
CommR: uselessBuffer,
})
}
2019-11-25 04:45:13 +00:00
ssi := sectorbuilder.NewSortedPublicSectorInfo(uselessOtherArray)
2019-11-21 22:21:45 +00:00
return &ssi, nil
}
func GetMinerSectorSize(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return 0, xerrors.Errorf("(get ssize) failed to load miner actor state: %w", err)
}
cst := hamt.CSTFromBstore(sm.cs.Blockstore())
var minfo actors.MinerInfo
if err := cst.Get(ctx, mas.Info, &minfo); err != nil {
return 0, xerrors.Errorf("failed to read miner info: %w", err)
}
return minfo.SectorSize, nil
}
func GetMinerSlashed(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) {
var mas actors.StorageMinerActorState
_, err := sm.LoadActorState(ctx, maddr, &mas, ts)
if err != nil {
return 0, xerrors.Errorf("(get mslash) failed to load miner actor state: %w", err)
}
return mas.SlashedAt, nil
}
func GetStorageDeal(ctx context.Context, sm *StateManager, dealId uint64, ts *types.TipSet) (*actors.OnChainDeal, error) {
var state actors.StorageMarketState
if _, err := sm.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil {
return nil, err
}
blks := amt.WrapBlockstore(sm.ChainStore().Blockstore())
da, err := amt.LoadAMT(blks, state.Deals)
if err != nil {
return nil, err
}
var ocd actors.OnChainDeal
if err := da.Get(dealId, &ocd); err != nil {
return nil, err
}
return &ocd, nil
}
func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([]address.Address, error) {
var state actors.StoragePowerState
if _, err := sm.LoadActorState(ctx, actors.StoragePowerAddress, &state, ts); err != nil {
return nil, err
}
cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore())
miners, err := actors.MinerSetList(ctx, cst, state.Miners)
if err != nil {
return nil, err
}
return miners, nil
}
2019-11-08 18:15:13 +00:00
func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid) ([]*api.ChainSectorInfo, error) {
2019-09-18 02:55:51 +00:00
blks := amt.WrapBlockstore(bs)
a, err := amt.LoadAMT(blks, 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
2019-09-17 22:43:47 +00:00
if err := a.ForEach(func(i uint64, v *cbg.Deferred) error {
var comms [][]byte
if err := cbor.DecodeInto(v.Raw, &comms); err != nil {
return err
}
2019-11-08 18:15:13 +00:00
sset = append(sset, &api.ChainSectorInfo{
2019-09-17 22:43:47 +00:00
SectorID: i,
CommR: comms[0],
CommD: comms[1],
})
return nil
}); err != nil {
return nil, err
}
return sset, nil
}
func ComputeState(ctx context.Context, sm *StateManager, height uint64, msgs []*types.Message, ts *types.TipSet) (cid.Cid, error) {
if ts == nil {
ts = sm.cs.GetHeaviestTipSet()
}
base, _, err := sm.TipSetState(ctx, ts)
if err != nil {
return cid.Undef, err
}
fstate, err := sm.handleStateForks(ctx, base, height, ts.Height())
if err != nil {
return cid.Undef, err
}
r := store.NewChainRand(sm.cs, ts.Cids(), height)
vmi, err := vm.NewVM(fstate, height, r, actors.NetworkAddress, sm.cs.Blockstore(), sm.cs.VMSys())
if err != nil {
return cid.Undef, err
}
for i, msg := range msgs {
ret, err := vmi.ApplyMessage(ctx, msg)
if err != nil {
return cid.Undef, xerrors.Errorf("applying message %s: %w", msg.Cid(), err)
}
if ret.ExitCode != 0 {
log.Info("compute state apply message %d failed (exit: %d): %s", i, ret.ExitCode, ret.ActorErr)
}
}
return vmi.Flush(ctx)
}