optimize sector loading

And avoid exposing "arrays" via the miner abstraction. We may change these
structures later.
This commit is contained in:
Steven Allen 2020-09-21 12:05:01 -07:00
parent 025663118f
commit 4cf0c105eb
13 changed files with 81 additions and 159 deletions

View File

@ -313,11 +313,9 @@ type FullNode interface {
// StateNetworkName returns the name of the network the node is synced to // StateNetworkName returns the name of the network the node is synced to
StateNetworkName(context.Context) (dtypes.NetworkName, error) StateNetworkName(context.Context) (dtypes.NetworkName, error)
// StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. // StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included.
// If the filterOut boolean is set to true, any sectors in the filter are excluded. StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error)
// If false, only those sectors in the filter are included.
StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*miner.ChainSectorInfo, error)
// StateMinerActiveSectors returns info about sectors that a given miner is actively proving. // StateMinerActiveSectors returns info about sectors that a given miner is actively proving.
StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*miner.ChainSectorInfo, error) StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*miner.SectorOnChainInfo, error)
// StateMinerProvingDeadline calculates the deadline at some epoch for a proving period // StateMinerProvingDeadline calculates the deadline at some epoch for a proving period
// and returns the deadline-related calculations. // and returns the deadline-related calculations.
StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error)

View File

@ -162,8 +162,8 @@ type FullNodeStruct struct {
ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"` ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"`
StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"`
StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*miner.ChainSectorInfo, error) `perm:"read"` StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"`
StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*miner.ChainSectorInfo, error) `perm:"read"` StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*miner.SectorOnChainInfo, error) `perm:"read"`
StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) `perm:"read"` StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) `perm:"read"`
StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"` StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"`
StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) `perm:"read"` StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (miner.MinerInfo, error) `perm:"read"`
@ -734,11 +734,11 @@ func (c *FullNodeStruct) StateNetworkName(ctx context.Context) (dtypes.NetworkNa
return c.Internal.StateNetworkName(ctx) return c.Internal.StateNetworkName(ctx)
} }
func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*miner.ChainSectorInfo, error) { func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, sectorNos *bitfield.BitField, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {
return c.Internal.StateMinerSectors(ctx, addr, filter, filterOut, tsk) return c.Internal.StateMinerSectors(ctx, addr, sectorNos, tsk)
} }
func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*miner.ChainSectorInfo, error) { func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr address.Address, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {
return c.Internal.StateMinerActiveSectors(ctx, addr, tsk) return c.Internal.StateMinerActiveSectors(ctx, addr, tsk)
} }

View File

@ -55,20 +55,3 @@ func AsArray(store Store, root cid.Cid, version network.Version) (Array, error)
} }
return nil, xerrors.Errorf("unknown network version: %d", version) return nil, xerrors.Errorf("unknown network version: %d", version)
} }
type ROnlyArray interface {
Get(idx uint64, v cbor.Unmarshaler) (bool, error)
ForEach(v cbor.Unmarshaler, fn func(idx int64) error) error
}
type ProxyArray struct {
GetFunc func(idx uint64, v cbor.Unmarshaler) (bool, error)
ForEachFunc func(v cbor.Unmarshaler, fn func(idx int64) error) error
}
func (a *ProxyArray) Get(idx uint64, v cbor.Unmarshaler) (bool, error) {
return a.GetFunc(idx, v)
}
func (a *ProxyArray) ForEach(v cbor.Unmarshaler, fn func(idx int64) error) error {
return a.ForEachFunc(v, fn)
}

View File

@ -47,7 +47,7 @@ type State interface {
FindSector(abi.SectorNumber) (*SectorLocation, error) FindSector(abi.SectorNumber) (*SectorLocation, error)
GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error) GetSectorExpiration(abi.SectorNumber) (*SectorExpiration, error)
GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error) GetPrecommittedSector(abi.SectorNumber) (*SectorPreCommitOnChainInfo, error)
LoadSectorsFromSet(filter *bitfield.BitField, filterOut bool) (adt.ROnlyArray, error) LoadSectors(sectorNos *bitfield.BitField) ([]*SectorOnChainInfo, error)
IsAllocated(abi.SectorNumber) (bool, error) IsAllocated(abi.SectorNumber) (bool, error)
LoadDeadline(idx uint64) (Deadline, error) LoadDeadline(idx uint64) (Deadline, error)
@ -129,11 +129,6 @@ type MinerInfo struct {
WindowPoStPartitionSectors uint64 WindowPoStPartitionSectors uint64
} }
type ChainSectorInfo struct {
Info SectorOnChainInfo
ID abi.SectorNumber
}
type SectorExpiration struct { type SectorExpiration struct {
OnTime abi.ChainEpoch OnTime abi.ChainEpoch

View File

@ -6,12 +6,10 @@ import (
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"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-bitfield"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/go-state-types/dline" "github.com/filecoin-project/go-state-types/dline"
miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner" miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
adt0 "github.com/filecoin-project/specs-actors/actors/util/adt" adt0 "github.com/filecoin-project/specs-actors/actors/util/adt"
@ -163,59 +161,37 @@ func (s *state0) GetPrecommittedSector(num abi.SectorNumber) (*SectorPreCommitOn
return &ret, nil return &ret, nil
} }
func (s *state0) LoadSectorsFromSet(filter *bitfield.BitField, filterOut bool) (adt.ROnlyArray, error) { func (s *state0) LoadSectors(snos *bitfield.BitField) ([]*SectorOnChainInfo, error) {
a, err := adt0.AsArray(s.store, s.State.Sectors) sectors, err := miner0.LoadSectors(s.store, s.State.Sectors)
if err != nil { if err != nil {
return nil, err return nil, err
} }
incl := func(i uint64) (bool, error) { // If no sector numbers are specified, load all.
include := true if snos == nil {
if filter != nil { infos := make([]*SectorOnChainInfo, 0, sectors.Length())
set, err := filter.IsSet(i) var info0 miner0.SectorOnChainInfo
if err != nil { if err := sectors.ForEach(&info0, func(i int64) error {
return false, xerrors.Errorf("filter check error: %w", err) info := fromV0SectorOnChainInfo(info0)
} infos[i] = &info
if set == filterOut { return nil
include = false }); err != nil {
} return nil, err
} }
return include, nil return infos, nil
} }
return &adt.ProxyArray{ // Otherwise, load selected.
GetFunc: func(idx uint64, v cbor.Unmarshaler) (bool, error) { infos0, err := sectors.Load(*snos)
i, err := incl(idx) if err != nil {
if err != nil { return nil, err
return false, err }
} infos := make([]*SectorOnChainInfo, len(infos0))
if !i { for i, info0 := range infos0 {
return false, nil info := fromV0SectorOnChainInfo(*info0)
} infos[i] = &info
}
// TODO: ActorUpgrade potentially convert return infos, nil
return a.Get(idx, v)
},
ForEachFunc: func(v cbor.Unmarshaler, fn func(int64) error) error {
// TODO: ActorUpgrade potentially convert the output
return a.ForEach(v, func(i int64) error {
include, err := incl(uint64(i))
if err != nil {
return err
}
if !include {
return nil
}
return fn(i)
})
},
}, nil
}
func (s *state0) LoadPreCommittedSectors() (adt.Map, error) {
return adt0.AsMap(s.store, s.State.PreCommittedSectors)
} }
func (s *state0) IsAllocated(num abi.SectorNumber) (bool, error) { func (s *state0) IsAllocated(num abi.SectorNumber) (bool, error) {

View File

@ -150,7 +150,7 @@ func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Addres
return mas.GetSector(sid) return mas.GetSector(sid)
} }
func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *bitfield.BitField, filterOut bool) ([]*miner.ChainSectorInfo, error) { func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, snos *bitfield.BitField) ([]*miner.SectorOnChainInfo, error) {
act, err := sm.LoadActor(ctx, maddr, ts) act, err := sm.LoadActor(ctx, maddr, ts)
if err != nil { if err != nil {
return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err) return nil, xerrors.Errorf("(get sset) failed to load miner actor: %w", err)
@ -161,29 +161,7 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet,
return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err) return nil, xerrors.Errorf("(get sset) failed to load miner actor state: %w", err)
} }
sectors, err := mas.LoadSectorsFromSet(filter, filterOut) return mas.LoadSectors(snos)
if err != nil {
return nil, xerrors.Errorf("(get sset) failed to load sectors: %w", err)
}
var sset []*miner.ChainSectorInfo
var v cbg.Deferred
if err := sectors.ForEach(&v, func(i int64) error {
var oci miner.SectorOnChainInfo
if err := oci.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil {
return err
}
sset = append(sset, &miner.ChainSectorInfo{
Info: oci,
ID: abi.SectorNumber(i),
})
return nil
}); err != nil {
return nil, err
}
return sset, nil
} }
func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof.SectorInfo, error) { func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof.SectorInfo, error) {
@ -249,35 +227,30 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S
return nil, xerrors.Errorf("generating winning post challenges: %w", err) return nil, xerrors.Errorf("generating winning post challenges: %w", err)
} }
// we don't need to filter here (and it's **very** slow) iter, err := provingSectors.BitIterator()
sectors, err := mas.LoadSectorsFromSet(nil, false) 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 { if err != nil {
return nil, xerrors.Errorf("loading proving sectors: %w", err) return nil, xerrors.Errorf("loading proving sectors: %w", err)
} }
out := make([]proof.SectorInfo, len(ids)) out := make([]proof.SectorInfo, len(sectors))
for i, n := range ids { for i, sinfo := range sectors {
sb, err := provingSectors.Slice(n, 1)
if err != nil {
return nil, err
}
sid, err := sb.First()
if err != nil {
return nil, err
}
var sinfo miner.SectorOnChainInfo
found, err := sectors.Get(sid, &sinfo)
if err != nil {
return nil, xerrors.Errorf("loading sector info: %w", err)
}
if !found {
return nil, xerrors.Errorf("didn't find sector info for sector %d", n)
}
out[i] = proof.SectorInfo{ out[i] = proof.SectorInfo{
SealProof: spt, SealProof: spt,
SectorNumber: sinfo.SectorNumber, SectorNumber: sinfo.SectorNumber,

View File

@ -259,13 +259,13 @@ var stateSectorsCmd = &cli.Command{
return err return err
} }
sectors, err := api.StateMinerSectors(ctx, maddr, nil, true, ts.Key()) sectors, err := api.StateMinerSectors(ctx, maddr, nil, ts.Key())
if err != nil { if err != nil {
return err return err
} }
for _, s := range sectors { for _, s := range sectors {
fmt.Printf("%d: %x\n", s.Info.SectorNumber, s.Info.SealedCID) fmt.Printf("%d: %x\n", s.SectorNumber, s.SealedCID)
} }
return nil return nil
@ -305,7 +305,7 @@ var stateActiveSectorsCmd = &cli.Command{
} }
for _, s := range sectors { for _, s := range sectors {
fmt.Printf("%d: %x\n", s.Info.SectorNumber, s.Info.SealedCID) fmt.Printf("%d: %x\n", s.SectorNumber, s.SealedCID)
} }
return nil return nil

View File

@ -176,16 +176,16 @@ var sectorsListCmd = &cli.Command{
} }
activeIDs := make(map[abi.SectorNumber]struct{}, len(activeSet)) activeIDs := make(map[abi.SectorNumber]struct{}, len(activeSet))
for _, info := range activeSet { for _, info := range activeSet {
activeIDs[info.ID] = struct{}{} activeIDs[info.SectorNumber] = struct{}{}
} }
sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, true, types.EmptyTSK) sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, types.EmptyTSK)
if err != nil { if err != nil {
return err return err
} }
commitedIDs := make(map[abi.SectorNumber]struct{}, len(activeSet)) commitedIDs := make(map[abi.SectorNumber]struct{}, len(activeSet))
for _, info := range sset { for _, info := range sset {
commitedIDs[info.ID] = struct{}{} commitedIDs[info.SectorNumber] = struct{}{}
} }
sort.Slice(list, func(i, j int) bool { sort.Slice(list, func(i, j int) bool {

View File

@ -3714,8 +3714,6 @@ Response:
### StateMinerSectors ### StateMinerSectors
StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included.
If the filterOut boolean is set to true, any sectors in the filter are excluded.
If false, only those sectors in the filter are included.
Perms: read Perms: read
@ -3727,7 +3725,6 @@ Inputs:
[ [
0 0
], ],
true,
[ [
{ {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"

View File

@ -64,15 +64,15 @@ func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, er
return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState()) 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) { func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, sectorNos *bitfield.BitField, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
} }
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, filter, filterOut) return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr, sectorNos)
} }
func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*miner.ChainSectorInfo, error) { // TODO: only used in cli func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Address, tsk types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { // TODO: only used in cli
ts, err := a.Chain.GetTipSetFromKey(tsk) ts, err := a.Chain.GetTipSetFromKey(tsk)
if err != nil { if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
@ -93,7 +93,7 @@ func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Ad
return nil, xerrors.Errorf("merge partition active sets: %w", err) return nil, xerrors.Errorf("merge partition active sets: %w", err)
} }
return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, maddr, &activeSectors, false) return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, maddr, &activeSectors)
} }
func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) { func (a *StateAPI) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (miner.MinerInfo, error) {

View File

@ -71,7 +71,7 @@ type SealingStateEvt struct {
type storageMinerApi interface { type storageMinerApi interface {
// Call a read only method on actors (no interaction with the chain required) // Call a read only method on actors (no interaction with the chain required)
StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error)
StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*miner.ChainSectorInfo, error) StateMinerSectors(context.Context, address.Address, *bitfield.BitField, types.TipSetKey) ([]*miner.SectorOnChainInfo, error)
StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error)
StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error)
StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error)

View File

@ -594,7 +594,7 @@ func (s *WindowPoStScheduler) batchPartitions(partitions []api.Partition) ([][]a
} }
func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors bitfield.BitField, ts *types.TipSet) ([]proof.SectorInfo, error) { func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors bitfield.BitField, ts *types.TipSet) ([]proof.SectorInfo, error) {
sset, err := s.api.StateMinerSectors(ctx, s.actor, &goodSectors, false, ts.Key()) sset, err := s.api.StateMinerSectors(ctx, s.actor, &goodSectors, ts.Key())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -604,17 +604,17 @@ func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors,
} }
substitute := proof.SectorInfo{ substitute := proof.SectorInfo{
SectorNumber: sset[0].ID, SectorNumber: sset[0].SectorNumber,
SealedCID: sset[0].Info.SealedCID, SealedCID: sset[0].SealedCID,
SealProof: sset[0].Info.SealProof, SealProof: sset[0].SealProof,
} }
sectorByID := make(map[uint64]proof.SectorInfo, len(sset)) sectorByID := make(map[uint64]proof.SectorInfo, len(sset))
for _, sector := range sset { for _, sector := range sset {
sectorByID[uint64(sector.ID)] = proof.SectorInfo{ sectorByID[uint64(sector.SectorNumber)] = proof.SectorInfo{
SectorNumber: sector.ID, SectorNumber: sector.SectorNumber,
SealedCID: sector.Info.SealedCID, SealedCID: sector.SealedCID,
SealProof: sector.Info.SealProof, SealProof: sector.SealProof,
} }
} }

View File

@ -65,14 +65,14 @@ func (m *mockStorageMinerAPI) StateMinerPartitions(ctx context.Context, a addres
return m.partitions, nil return m.partitions, nil
} }
func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, field *bitfield.BitField, b bool, key types.TipSetKey) ([]*miner.ChainSectorInfo, error) { func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, snos *bitfield.BitField, key types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {
var sis []*miner.ChainSectorInfo var sis []*miner.SectorOnChainInfo
_ = field.ForEach(func(i uint64) error { if snos == nil {
sis = append(sis, &miner.ChainSectorInfo{ panic("unsupported")
Info: miner.SectorOnChainInfo{ }
SectorNumber: abi.SectorNumber(i), _ = snos.ForEach(func(i uint64) error {
}, sis = append(sis, &miner.SectorOnChainInfo{
ID: abi.SectorNumber(i), SectorNumber: abi.SectorNumber(i),
}) })
return nil return nil
}) })