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, §orOnChain) 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, §orOnChain) 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 }