github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/sectors.go (about)

     1  package miner
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/filecoin-project/go-bitfield"
     7  	"github.com/filecoin-project/go-state-types/abi"
     8  	xc "github.com/filecoin-project/go-state-types/exitcode"
     9  	"github.com/ipfs/go-cid"
    10  	"golang.org/x/xerrors"
    11  
    12  	"github.com/filecoin-project/specs-actors/v4/actors/util/adt"
    13  )
    14  
    15  func LoadSectors(store adt.Store, root cid.Cid) (Sectors, error) {
    16  	sectorsArr, err := adt.AsArray(store, root, SectorsAmtBitwidth)
    17  	if err != nil {
    18  		return Sectors{}, err
    19  	}
    20  	return Sectors{sectorsArr}, nil
    21  }
    22  
    23  // Sectors is a helper type for accessing/modifying a miner's sectors. It's safe
    24  // to pass this object around as needed.
    25  type Sectors struct {
    26  	*adt.Array
    27  }
    28  
    29  func (sa Sectors) Load(sectorNos bitfield.BitField) ([]*SectorOnChainInfo, error) {
    30  	var sectorInfos []*SectorOnChainInfo
    31  	if err := sectorNos.ForEach(func(i uint64) error {
    32  		var sectorOnChain SectorOnChainInfo
    33  		found, err := sa.Array.Get(i, &sectorOnChain)
    34  		if err != nil {
    35  			return xc.ErrIllegalState.Wrapf("failed to load sector %v: %w", abi.SectorNumber(i), err)
    36  		} else if !found {
    37  			return xc.ErrNotFound.Wrapf("can't find sector %d", i)
    38  		}
    39  		sectorInfos = append(sectorInfos, &sectorOnChain)
    40  		return nil
    41  	}); err != nil {
    42  		// Keep the underlying error code, unless the error was from
    43  		// traversing the bitfield. In that case, it's an illegal
    44  		// argument error.
    45  		return nil, xc.Unwrap(err, xc.ErrIllegalArgument).Wrapf("failed to load sectors: %w", err)
    46  	}
    47  	return sectorInfos, nil
    48  }
    49  
    50  func (sa Sectors) Get(sectorNumber abi.SectorNumber) (info *SectorOnChainInfo, found bool, err error) {
    51  	var res SectorOnChainInfo
    52  	if found, err := sa.Array.Get(uint64(sectorNumber), &res); err != nil {
    53  		return nil, false, xerrors.Errorf("failed to get sector %d: %w", sectorNumber, err)
    54  	} else if !found {
    55  		return nil, false, nil
    56  	}
    57  	return &res, true, nil
    58  }
    59  
    60  func (sa Sectors) Store(infos ...*SectorOnChainInfo) error {
    61  	for _, info := range infos {
    62  		if info == nil {
    63  			return xerrors.Errorf("nil sector info")
    64  		}
    65  		if info.SectorNumber > abi.MaxSectorNumber {
    66  			return fmt.Errorf("sector number %d out of range", info.SectorNumber)
    67  		}
    68  		if err := sa.Set(uint64(info.SectorNumber), info); err != nil {
    69  			return fmt.Errorf("failed to store sector %d: %w", info.SectorNumber, err)
    70  		}
    71  	}
    72  	return nil
    73  }
    74  
    75  func (sa Sectors) MustGet(sectorNumber abi.SectorNumber) (info *SectorOnChainInfo, err error) {
    76  	if info, found, err := sa.Get(sectorNumber); err != nil {
    77  		return nil, err
    78  	} else if !found {
    79  		return nil, fmt.Errorf("sector %d not found", sectorNumber)
    80  	} else {
    81  		return info, nil
    82  	}
    83  }
    84  
    85  // Loads info for a set of sectors to be proven.
    86  // If any of the sectors are declared faulty and not to be recovered, info for the first non-faulty sector is substituted instead.
    87  // If any of the sectors are declared recovered, they are returned from this method.
    88  func (sa Sectors) LoadForProof(provenSectors, expectedFaults bitfield.BitField) ([]*SectorOnChainInfo, error) {
    89  	nonFaults, err := bitfield.SubtractBitField(provenSectors, expectedFaults)
    90  	if err != nil {
    91  		return nil, xerrors.Errorf("failed to diff bitfields: %w", err)
    92  	}
    93  
    94  	// Return empty if no non-faults
    95  	if empty, err := nonFaults.IsEmpty(); err != nil {
    96  		return nil, xerrors.Errorf("failed to check if bitfield was empty: %w", err)
    97  	} else if empty {
    98  		return nil, nil
    99  	}
   100  
   101  	// Select a non-faulty sector as a substitute for faulty ones.
   102  	goodSectorNo, err := nonFaults.First()
   103  	if err != nil {
   104  		return nil, xerrors.Errorf("failed to get first good sector: %w", err)
   105  	}
   106  
   107  	// Load sector infos
   108  	sectorInfos, err := sa.LoadWithFaultMask(provenSectors, expectedFaults, abi.SectorNumber(goodSectorNo))
   109  	if err != nil {
   110  		return nil, xerrors.Errorf("failed to load sector infos: %w", err)
   111  	}
   112  	return sectorInfos, nil
   113  }
   114  
   115  // Loads sector info for a sequence of sectors, substituting info for a stand-in sector for any that are faulty.
   116  func (sa Sectors) LoadWithFaultMask(sectors bitfield.BitField, faults bitfield.BitField, faultStandIn abi.SectorNumber) ([]*SectorOnChainInfo, error) {
   117  	standInInfo, err := sa.MustGet(faultStandIn)
   118  	if err != nil {
   119  		return nil, fmt.Errorf("failed to load stand-in sector %d: %v", faultStandIn, err)
   120  	}
   121  
   122  	// Expand faults into a map for quick lookups.
   123  	// The faults bitfield should already be a subset of the sectors bitfield.
   124  	sectorCount, err := sectors.Count()
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	faultSet, err := faults.AllMap(sectorCount)
   129  	if err != nil {
   130  		return nil, fmt.Errorf("failed to expand faults: %w", err)
   131  	}
   132  
   133  	// Load the sector infos, masking out fault sectors with a good one.
   134  	sectorInfos := make([]*SectorOnChainInfo, 0, sectorCount)
   135  	err = sectors.ForEach(func(i uint64) error {
   136  		sector := standInInfo
   137  		faulty := faultSet[i]
   138  		if !faulty {
   139  			sectorOnChain, err := sa.MustGet(abi.SectorNumber(i))
   140  			if err != nil {
   141  				return xerrors.Errorf("failed to load sector %d: %w", i, err)
   142  			}
   143  			sector = sectorOnChain
   144  		}
   145  		sectorInfos = append(sectorInfos, sector)
   146  		return nil
   147  	})
   148  	return sectorInfos, err
   149  }
   150  
   151  func selectSectors(sectors []*SectorOnChainInfo, field bitfield.BitField) ([]*SectorOnChainInfo, error) {
   152  	toInclude, err := field.AllMap(uint64(len(sectors)))
   153  	if err != nil {
   154  		return nil, xerrors.Errorf("failed to expand bitfield when selecting sectors: %w", err)
   155  	}
   156  
   157  	included := make([]*SectorOnChainInfo, 0, len(toInclude))
   158  	for _, s := range sectors {
   159  		if !toInclude[uint64(s.SectorNumber)] {
   160  			continue
   161  		}
   162  		included = append(included, s)
   163  		delete(toInclude, uint64(s.SectorNumber))
   164  	}
   165  	if len(toInclude) > 0 {
   166  		return nil, xerrors.Errorf("failed to find %d expected sectors", len(toInclude))
   167  	}
   168  	return included, nil
   169  }