github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/partition_state.go (about) 1 package miner 2 3 import ( 4 "errors" 5 6 "github.com/filecoin-project/go-bitfield" 7 "github.com/filecoin-project/go-state-types/abi" 8 "github.com/filecoin-project/go-state-types/big" 9 xc "github.com/filecoin-project/go-state-types/exitcode" 10 "github.com/ipfs/go-cid" 11 "golang.org/x/xerrors" 12 13 "github.com/filecoin-project/specs-actors/v4/actors/util" 14 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 15 ) 16 17 type Partition struct { 18 // Sector numbers in this partition, including faulty, unproven, and terminated sectors. 19 Sectors bitfield.BitField 20 // Unproven sectors in this partition. This bitfield will be cleared on 21 // a successful window post (or at the end of the partition's next 22 // deadline). At that time, any still unproven sectors will be added to 23 // the faulty sector bitfield. 24 Unproven bitfield.BitField 25 // Subset of sectors detected/declared faulty and not yet recovered (excl. from PoSt). 26 // Faults ∩ Terminated = ∅ 27 Faults bitfield.BitField 28 // Subset of faulty sectors expected to recover on next PoSt 29 // Recoveries ∩ Terminated = ∅ 30 Recoveries bitfield.BitField 31 // Subset of sectors terminated but not yet removed from partition (excl. from PoSt) 32 Terminated bitfield.BitField 33 // Maps epochs sectors that expire in or before that epoch. 34 // An expiration may be an "on-time" scheduled expiration, or early "faulty" expiration. 35 // Keys are quantized to last-in-deadline epochs. 36 ExpirationsEpochs cid.Cid // AMT[ChainEpoch]ExpirationSet 37 // Subset of terminated that were before their committed expiration epoch, by termination epoch. 38 // Termination fees have not yet been calculated or paid and associated deals have not yet been 39 // canceled but effective power has already been adjusted. 40 // Not quantized. 41 EarlyTerminated cid.Cid // AMT[ChainEpoch]BitField 42 43 // Power of not-yet-terminated sectors (incl faulty & unproven). 44 LivePower PowerPair 45 // Power of yet-to-be-proved sectors (never faulty). 46 UnprovenPower PowerPair 47 // Power of currently-faulty sectors. FaultyPower <= LivePower. 48 FaultyPower PowerPair 49 // Power of expected-to-recover sectors. RecoveringPower <= FaultyPower. 50 RecoveringPower PowerPair 51 } 52 53 // Bitwidth of AMTs determined empirically from mutation patterns and projections of mainnet data. 54 const PartitionExpirationAmtBitwidth = 4 55 const PartitionEarlyTerminationArrayAmtBitwidth = 3 56 57 // Value type for a pair of raw and QA power. 58 type PowerPair struct { 59 Raw abi.StoragePower 60 QA abi.StoragePower 61 } 62 63 // A set of sectors associated with a given epoch. 64 func ConstructPartition(store adt.Store) (*Partition, error) { 65 emptyExpirationArrayRoot, err := adt.StoreEmptyArray(store, PartitionExpirationAmtBitwidth) 66 if err != nil { 67 return nil, err 68 } 69 emptyEarlyTerminationArrayRoot, err := adt.StoreEmptyArray(store, PartitionEarlyTerminationArrayAmtBitwidth) 70 if err != nil { 71 return nil, err 72 } 73 74 return &Partition{ 75 Sectors: bitfield.New(), 76 Unproven: bitfield.New(), 77 Faults: bitfield.New(), 78 Recoveries: bitfield.New(), 79 Terminated: bitfield.New(), 80 ExpirationsEpochs: emptyExpirationArrayRoot, 81 EarlyTerminated: emptyEarlyTerminationArrayRoot, 82 LivePower: NewPowerPairZero(), 83 UnprovenPower: NewPowerPairZero(), 84 FaultyPower: NewPowerPairZero(), 85 RecoveringPower: NewPowerPairZero(), 86 }, nil 87 } 88 89 // Live sectors are those that are not terminated (but may be faulty). 90 func (p *Partition) LiveSectors() (bitfield.BitField, error) { 91 live, err := bitfield.SubtractBitField(p.Sectors, p.Terminated) 92 if err != nil { 93 return bitfield.BitField{}, xerrors.Errorf("failed to compute live sectors: %w", err) 94 } 95 return live, nil 96 97 } 98 99 // Active sectors are those that are neither terminated nor faulty nor unproven, i.e. actively contributing power. 100 func (p *Partition) ActiveSectors() (bitfield.BitField, error) { 101 live, err := p.LiveSectors() 102 if err != nil { 103 return bitfield.BitField{}, err 104 } 105 nonFaulty, err := bitfield.SubtractBitField(live, p.Faults) 106 if err != nil { 107 return bitfield.BitField{}, xerrors.Errorf("failed to compute active sectors: %w", err) 108 } 109 active, err := bitfield.SubtractBitField(nonFaulty, p.Unproven) 110 if err != nil { 111 return bitfield.BitField{}, xerrors.Errorf("failed to compute active sectors: %w", err) 112 } 113 return active, err 114 } 115 116 // Active power is power of non-faulty sectors. 117 func (p *Partition) ActivePower() PowerPair { 118 return p.LivePower.Sub(p.FaultyPower).Sub(p.UnprovenPower) 119 } 120 121 // AddSectors adds new sectors to the partition. 122 // The sectors are "live", neither faulty, recovering, nor terminated. 123 // Each new sector's expiration is scheduled shortly after its target expiration epoch. 124 // If proven is false, the sectors are added to the partition's unproven set. 125 // Returns the total power of the added sectors. 126 func (p *Partition) AddSectors( 127 store adt.Store, proven bool, sectors []*SectorOnChainInfo, ssize abi.SectorSize, quant QuantSpec, 128 ) (PowerPair, error) { 129 expirations, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 130 if err != nil { 131 return NewPowerPairZero(), xerrors.Errorf("failed to load sector expirations: %w", err) 132 } 133 snos, power, _, err := expirations.AddActiveSectors(sectors, ssize) 134 if err != nil { 135 return NewPowerPairZero(), xerrors.Errorf("failed to record new sector expirations: %w", err) 136 } 137 if p.ExpirationsEpochs, err = expirations.Root(); err != nil { 138 return NewPowerPairZero(), xerrors.Errorf("failed to store sector expirations: %w", err) 139 } 140 141 if contains, err := util.BitFieldContainsAny(p.Sectors, snos); err != nil { 142 return NewPowerPairZero(), xerrors.Errorf("failed to check if any new sector was already in the partition: %w", err) 143 } else if contains { 144 return NewPowerPairZero(), xerrors.Errorf("not all added sectors are new") 145 } 146 147 // Update other metadata using the calculated totals. 148 if p.Sectors, err = bitfield.MergeBitFields(p.Sectors, snos); err != nil { 149 return NewPowerPairZero(), xerrors.Errorf("failed to record new sector numbers: %w", err) 150 } 151 p.LivePower = p.LivePower.Add(power) 152 153 if !proven { 154 if p.Unproven, err = bitfield.MergeBitFields(p.Unproven, snos); err != nil { 155 return NewPowerPairZero(), xerrors.Errorf("failed to update unproven sectors bitfield: %w", err) 156 } 157 p.UnprovenPower = p.UnprovenPower.Add(power) 158 } 159 160 // check invariants 161 if err := p.ValidateState(); err != nil { 162 return NewPowerPairZero(), err 163 } 164 165 // No change to faults, recoveries, or terminations. 166 // No change to faulty or recovering power. 167 return power, nil 168 } 169 170 // marks a set of sectors faulty 171 func (p *Partition) addFaults( 172 store adt.Store, sectorNos bitfield.BitField, sectors []*SectorOnChainInfo, faultExpiration abi.ChainEpoch, 173 ssize abi.SectorSize, quant QuantSpec, 174 ) (powerDelta, newFaultyPower PowerPair, err error) { 175 // Load expiration queue 176 queue, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 177 if err != nil { 178 return NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to load partition queue: %w", err) 179 } 180 181 // Reschedule faults 182 newFaultyPower, err = queue.RescheduleAsFaults(faultExpiration, sectors, ssize) 183 if err != nil { 184 return NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to add faults to partition queue: %w", err) 185 } 186 187 // Save expiration queue 188 if p.ExpirationsEpochs, err = queue.Root(); err != nil { 189 return NewPowerPairZero(), NewPowerPairZero(), err 190 } 191 192 // Update partition metadata 193 if p.Faults, err = bitfield.MergeBitFields(p.Faults, sectorNos); err != nil { 194 return NewPowerPairZero(), NewPowerPairZero(), err 195 } 196 197 // The sectors must not have been previously faulty or recovering. 198 // No change to recoveries or terminations. 199 p.FaultyPower = p.FaultyPower.Add(newFaultyPower) 200 201 // Once marked faulty, sectors are moved out of the unproven set. 202 unproven, err := bitfield.IntersectBitField(sectorNos, p.Unproven) 203 if err != nil { 204 return NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to intersect faulty sector IDs with unproven sector IDs: %w", err) 205 } 206 p.Unproven, err = bitfield.SubtractBitField(p.Unproven, unproven) 207 if err != nil { 208 return NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to subtract faulty sectors from unproven sector IDs: %w", err) 209 } 210 211 powerDelta = newFaultyPower.Neg() 212 if unprovenInfos, err := selectSectors(sectors, unproven); err != nil { 213 return NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to select unproven sectors: %w", err) 214 } else if len(unprovenInfos) > 0 { 215 lostUnprovenPower := PowerForSectors(ssize, unprovenInfos) 216 p.UnprovenPower = p.UnprovenPower.Sub(lostUnprovenPower) 217 powerDelta = powerDelta.Add(lostUnprovenPower) 218 } 219 220 // check invariants 221 if err := p.ValidateState(); err != nil { 222 return NewPowerPairZero(), NewPowerPairZero(), err 223 } 224 225 // No change to live or recovering power. 226 return powerDelta, newFaultyPower, nil 227 } 228 229 // Declares a set of sectors faulty. Already faulty sectors are ignored, 230 // terminated sectors are skipped, and recovering sectors are reverted to 231 // faulty. 232 // 233 // - New faults are added to the Faults bitfield and the FaultyPower is increased. 234 // - The sectors' expirations are rescheduled to the fault expiration epoch, as "early" (if not expiring earlier). 235 // 236 // Returns the power of the now-faulty sectors. 237 func (p *Partition) RecordFaults( 238 store adt.Store, sectors Sectors, sectorNos bitfield.BitField, faultExpirationEpoch abi.ChainEpoch, 239 ssize abi.SectorSize, quant QuantSpec, 240 ) (newFaults bitfield.BitField, powerDelta, newFaultyPower PowerPair, err error) { 241 err = validatePartitionContainsSectors(p, sectorNos) 242 if err != nil { 243 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xc.ErrIllegalArgument.Wrapf("failed fault declaration: %w", err) 244 } 245 246 // Split declarations into declarations of new faults, and retraction of declared recoveries. 247 retractedRecoveries, err := bitfield.IntersectBitField(p.Recoveries, sectorNos) 248 if err != nil { 249 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to intersect sectors with recoveries: %w", err) 250 } 251 252 newFaults, err = bitfield.SubtractBitField(sectorNos, retractedRecoveries) 253 if err != nil { 254 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to subtract recoveries from sectors: %w", err) 255 } 256 257 // Ignore any terminated sectors and previously declared or detected faults 258 newFaults, err = bitfield.SubtractBitField(newFaults, p.Terminated) 259 if err != nil { 260 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to subtract terminations from faults: %w", err) 261 } 262 newFaults, err = bitfield.SubtractBitField(newFaults, p.Faults) 263 if err != nil { 264 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to subtract existing faults from faults: %w", err) 265 } 266 267 // Add new faults to state. 268 newFaultyPower = NewPowerPairZero() 269 powerDelta = NewPowerPairZero() 270 if newFaultSectors, err := sectors.Load(newFaults); err != nil { 271 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to load fault sectors: %w", err) 272 } else if len(newFaultSectors) > 0 { 273 powerDelta, newFaultyPower, err = p.addFaults(store, newFaults, newFaultSectors, faultExpirationEpoch, ssize, quant) 274 if err != nil { 275 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to add faults: %w", err) 276 } 277 } 278 279 // Remove faulty recoveries from state. 280 if retractedRecoverySectors, err := sectors.Load(retractedRecoveries); err != nil { 281 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to load recovery sectors: %w", err) 282 } else if len(retractedRecoverySectors) > 0 { 283 retractedRecoveryPower := PowerForSectors(ssize, retractedRecoverySectors) 284 err = p.removeRecoveries(retractedRecoveries, retractedRecoveryPower) 285 if err != nil { 286 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to remove recoveries: %w", err) 287 } 288 } 289 290 // check invariants 291 if err := p.ValidateState(); err != nil { 292 return bitfield.BitField{}, NewPowerPairZero(), NewPowerPairZero(), err 293 } 294 295 return newFaults, powerDelta, newFaultyPower, nil 296 } 297 298 // Removes sector numbers from faults and thus from recoveries. 299 // The sectors are removed from the Faults and Recovering bitfields, and FaultyPower and RecoveringPower reduced. 300 // The sectors are re-scheduled for expiration shortly after their target expiration epoch. 301 // Returns the power of the now-recovered sectors. 302 func (p *Partition) RecoverFaults(store adt.Store, sectors Sectors, ssize abi.SectorSize, quant QuantSpec) (PowerPair, error) { 303 // Process recoveries, assuming the proof will be successful. 304 // This similarly updates state. 305 recoveredSectors, err := sectors.Load(p.Recoveries) 306 if err != nil { 307 return NewPowerPairZero(), xerrors.Errorf("failed to load recovered sectors: %w", err) 308 } 309 // Load expiration queue 310 queue, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 311 if err != nil { 312 return NewPowerPairZero(), xerrors.Errorf("failed to load partition queue: %w", err) 313 } 314 // Reschedule recovered 315 power, err := queue.RescheduleRecovered(recoveredSectors, ssize) 316 if err != nil { 317 return NewPowerPairZero(), xerrors.Errorf("failed to reschedule faults in partition queue: %w", err) 318 } 319 // Save expiration queue 320 if p.ExpirationsEpochs, err = queue.Root(); err != nil { 321 return NewPowerPairZero(), err 322 } 323 324 // Update partition metadata 325 if newFaults, err := bitfield.SubtractBitField(p.Faults, p.Recoveries); err != nil { 326 return NewPowerPairZero(), err 327 } else { 328 p.Faults = newFaults 329 } 330 p.Recoveries = bitfield.New() 331 332 // No change to live power. 333 // No change to unproven sectors. 334 p.FaultyPower = p.FaultyPower.Sub(power) 335 p.RecoveringPower = p.RecoveringPower.Sub(power) 336 337 // check invariants 338 if err := p.ValidateState(); err != nil { 339 return NewPowerPairZero(), err 340 } 341 342 return power, err 343 } 344 345 // Activates unproven sectors, returning the activated power. 346 func (p *Partition) ActivateUnproven() PowerPair { 347 newPower := p.UnprovenPower 348 p.UnprovenPower = NewPowerPairZero() 349 p.Unproven = bitfield.New() 350 return newPower 351 } 352 353 // Declares sectors as recovering. Non-faulty and already recovering sectors will be skipped. 354 func (p *Partition) DeclareFaultsRecovered(sectors Sectors, ssize abi.SectorSize, sectorNos bitfield.BitField) (err error) { 355 // Check that the declared sectors are actually assigned to the partition. 356 err = validatePartitionContainsSectors(p, sectorNos) 357 if err != nil { 358 return xc.ErrIllegalArgument.Wrapf("failed fault declaration: %w", err) 359 } 360 361 // Ignore sectors not faulty or already declared recovered 362 recoveries, err := bitfield.IntersectBitField(sectorNos, p.Faults) 363 if err != nil { 364 return xerrors.Errorf("failed to intersect recoveries with faults: %w", err) 365 } 366 recoveries, err = bitfield.SubtractBitField(recoveries, p.Recoveries) 367 if err != nil { 368 return xerrors.Errorf("failed to subtract existing recoveries: %w", err) 369 } 370 371 // Record the new recoveries for processing at Window PoSt or deadline cron. 372 recoverySectors, err := sectors.Load(recoveries) 373 if err != nil { 374 return xerrors.Errorf("failed to load recovery sectors: %w", err) 375 } 376 377 p.Recoveries, err = bitfield.MergeBitFields(p.Recoveries, recoveries) 378 if err != nil { 379 return err 380 } 381 382 power := PowerForSectors(ssize, recoverySectors) 383 p.RecoveringPower = p.RecoveringPower.Add(power) 384 385 // check invariants 386 if err := p.ValidateState(); err != nil { 387 return err 388 } 389 390 // No change to faults, or terminations. 391 // No change to faulty power. 392 // No change to unproven power/sectors. 393 return nil 394 } 395 396 // Removes sectors from recoveries and recovering power. Assumes sectors are currently faulty and recovering.. 397 func (p *Partition) removeRecoveries(sectorNos bitfield.BitField, power PowerPair) (err error) { 398 empty, err := sectorNos.IsEmpty() 399 if err != nil { 400 return err 401 } 402 if empty { 403 return nil 404 } 405 p.Recoveries, err = bitfield.SubtractBitField(p.Recoveries, sectorNos) 406 if err != nil { 407 return err 408 } 409 p.RecoveringPower = p.RecoveringPower.Sub(power) 410 // No change to faults, or terminations. 411 // No change to faulty power. 412 // No change to unproven or unproven power. 413 return nil 414 } 415 416 // RescheduleExpirations moves expiring sectors to the target expiration, 417 // skipping any sectors it can't find. 418 // 419 // The power of the rescheduled sectors is assumed to have not changed since 420 // initial scheduling. 421 // 422 // Note: see the docs on State.RescheduleSectorExpirations for details on why we 423 // skip sectors/partitions we can't find. 424 func (p *Partition) RescheduleExpirations( 425 store adt.Store, sectors Sectors, 426 newExpiration abi.ChainEpoch, sectorNos bitfield.BitField, 427 ssize abi.SectorSize, quant QuantSpec, 428 ) (replaced []*SectorOnChainInfo, err error) { 429 // Ensure these sectors actually belong to this partition. 430 present, err := bitfield.IntersectBitField(sectorNos, p.Sectors) 431 if err != nil { 432 return nil, err 433 } 434 435 // Filter out terminated sectors. 436 live, err := bitfield.SubtractBitField(present, p.Terminated) 437 if err != nil { 438 return nil, err 439 } 440 441 // Filter out faulty sectors. 442 active, err := bitfield.SubtractBitField(live, p.Faults) 443 if err != nil { 444 return nil, err 445 } 446 447 sectorInfos, err := sectors.Load(active) 448 if err != nil { 449 return nil, err 450 } 451 452 expirations, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 453 if err != nil { 454 return nil, xerrors.Errorf("failed to load sector expirations: %w", err) 455 } 456 if err = expirations.RescheduleExpirations(newExpiration, sectorInfos, ssize); err != nil { 457 return nil, err 458 } 459 p.ExpirationsEpochs, err = expirations.Root() 460 if err != nil { 461 return nil, err 462 } 463 464 // check invariants 465 if err := p.ValidateState(); err != nil { 466 return nil, err 467 } 468 469 return sectorInfos, nil 470 } 471 472 // Replaces a number of "old" sectors with new ones. 473 // The old sectors must not be faulty, terminated, or unproven. 474 // If the same sector is both removed and added, this permits rescheduling *with a change in power*, 475 // unlike RescheduleExpirations. 476 // Returns the delta to power and pledge requirement. 477 func (p *Partition) ReplaceSectors(store adt.Store, oldSectors, newSectors []*SectorOnChainInfo, 478 ssize abi.SectorSize, quant QuantSpec) (PowerPair, abi.TokenAmount, error) { 479 expirations, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 480 if err != nil { 481 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("failed to load sector expirations: %w", err) 482 } 483 oldSnos, newSnos, powerDelta, pledgeDelta, err := expirations.ReplaceSectors(oldSectors, newSectors, ssize) 484 if err != nil { 485 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("failed to replace sector expirations: %w", err) 486 } 487 if p.ExpirationsEpochs, err = expirations.Root(); err != nil { 488 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("failed to save sector expirations: %w", err) 489 } 490 491 // Check the sectors being removed are active (alive, not faulty). 492 active, err := p.ActiveSectors() 493 if err != nil { 494 return NewPowerPairZero(), big.Zero(), err 495 } 496 allActive, err := util.BitFieldContainsAll(active, oldSnos) 497 if err != nil { 498 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("failed to check for active sectors: %w", err) 499 } else if !allActive { 500 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("refusing to replace inactive sectors in %v (active: %v)", oldSnos, active) 501 } 502 503 // Update partition metadata. 504 if p.Sectors, err = bitfield.SubtractBitField(p.Sectors, oldSnos); err != nil { 505 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("failed to remove replaced sectors: %w", err) 506 } 507 if p.Sectors, err = bitfield.MergeBitFields(p.Sectors, newSnos); err != nil { 508 return NewPowerPairZero(), big.Zero(), xerrors.Errorf("failed to add replaced sectors: %w", err) 509 } 510 p.LivePower = p.LivePower.Add(powerDelta) 511 512 // check invariants 513 if err := p.ValidateState(); err != nil { 514 return NewPowerPairZero(), big.Zero(), err 515 } 516 517 // No change to faults, recoveries, or terminations. 518 // No change to faulty or recovering power. 519 return powerDelta, pledgeDelta, nil 520 } 521 522 // Record the epoch of any sectors expiring early, for termination fee calculation later. 523 func (p *Partition) recordEarlyTermination(store adt.Store, epoch abi.ChainEpoch, sectors bitfield.BitField) error { 524 etQueue, err := LoadBitfieldQueue(store, p.EarlyTerminated, NoQuantization, PartitionEarlyTerminationArrayAmtBitwidth) 525 if err != nil { 526 return xerrors.Errorf("failed to load early termination queue: %w", err) 527 } 528 if err = etQueue.AddToQueue(epoch, sectors); err != nil { 529 return xerrors.Errorf("failed to add to early termination queue: %w", err) 530 } 531 if p.EarlyTerminated, err = etQueue.Root(); err != nil { 532 return xerrors.Errorf("failed to save early termination queue: %w", err) 533 } 534 return nil 535 } 536 537 // Marks a collection of sectors as terminated. 538 // The sectors are removed from Faults and Recoveries. 539 // The epoch of termination is recorded for future termination fee calculation. 540 func (p *Partition) TerminateSectors( 541 store adt.Store, sectors Sectors, epoch abi.ChainEpoch, sectorNos bitfield.BitField, 542 ssize abi.SectorSize, quant QuantSpec) (*ExpirationSet, error) { 543 liveSectors, err := p.LiveSectors() 544 if err != nil { 545 return nil, err 546 } 547 if contains, err := util.BitFieldContainsAll(liveSectors, sectorNos); err != nil { 548 return nil, xc.ErrIllegalArgument.Wrapf("failed to intersect live sectors with terminating sectors: %w", err) 549 } else if !contains { 550 return nil, xc.ErrIllegalArgument.Wrapf("can only terminate live sectors") 551 } 552 553 sectorInfos, err := sectors.Load(sectorNos) 554 if err != nil { 555 return nil, err 556 } 557 expirations, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 558 if err != nil { 559 return nil, xerrors.Errorf("failed to load sector expirations: %w", err) 560 } 561 removed, removedRecovering, err := expirations.RemoveSectors(sectorInfos, p.Faults, p.Recoveries, ssize) 562 if err != nil { 563 return nil, xerrors.Errorf("failed to remove sector expirations: %w", err) 564 } 565 if p.ExpirationsEpochs, err = expirations.Root(); err != nil { 566 return nil, xerrors.Errorf("failed to save sector expirations: %w", err) 567 } 568 569 removedSectors, err := bitfield.MergeBitFields(removed.OnTimeSectors, removed.EarlySectors) 570 if err != nil { 571 return nil, err 572 } 573 574 // Record early termination. 575 err = p.recordEarlyTermination(store, epoch, removedSectors) 576 if err != nil { 577 return nil, xerrors.Errorf("failed to record early sector termination: %w", err) 578 } 579 580 unprovenNos, err := bitfield.IntersectBitField(removedSectors, p.Unproven) 581 if err != nil { 582 return nil, xerrors.Errorf("failed to determine unproven sectors: %w", err) 583 } 584 585 // Update partition metadata. 586 if p.Faults, err = bitfield.SubtractBitField(p.Faults, removedSectors); err != nil { 587 return nil, xerrors.Errorf("failed to remove terminated sectors from faults: %w", err) 588 } 589 if p.Recoveries, err = bitfield.SubtractBitField(p.Recoveries, removedSectors); err != nil { 590 return nil, xerrors.Errorf("failed to remove terminated sectors from recoveries: %w", err) 591 } 592 if p.Terminated, err = bitfield.MergeBitFields(p.Terminated, removedSectors); err != nil { 593 return nil, xerrors.Errorf("failed to add terminated sectors: %w", err) 594 } 595 if p.Unproven, err = bitfield.SubtractBitField(p.Unproven, unprovenNos); err != nil { 596 return nil, xerrors.Errorf("failed to remove unproven sectors: %w", err) 597 } 598 599 p.LivePower = p.LivePower.Sub(removed.ActivePower).Sub(removed.FaultyPower) 600 p.FaultyPower = p.FaultyPower.Sub(removed.FaultyPower) 601 p.RecoveringPower = p.RecoveringPower.Sub(removedRecovering) 602 if unprovenInfos, err := selectSectors(sectorInfos, unprovenNos); err != nil { 603 return nil, xerrors.Errorf("failed to select unproven sectors: %w", err) 604 } else { 605 removedUnprovenPower := PowerForSectors(ssize, unprovenInfos) 606 p.UnprovenPower = p.UnprovenPower.Sub(removedUnprovenPower) 607 removed.ActivePower = removed.ActivePower.Sub(removedUnprovenPower) 608 } 609 610 // check invariants 611 if err := p.ValidateState(); err != nil { 612 return nil, err 613 } 614 615 return removed, nil 616 } 617 618 // PopExpiredSectors traverses the expiration queue up to and including some epoch, and marks all expiring 619 // sectors as terminated. 620 // 621 // This cannot be called while there are unproven sectors. 622 // 623 // Returns the expired sector aggregates. 624 func (p *Partition) PopExpiredSectors(store adt.Store, until abi.ChainEpoch, quant QuantSpec) (*ExpirationSet, error) { 625 // This is a sanity check to make sure we handle proofs _before_ 626 // handling sector expirations. 627 if noUnproven, err := p.Unproven.IsEmpty(); err != nil { 628 return nil, xerrors.Errorf("failed to determine if partition has unproven sectors: %w", err) 629 } else if !noUnproven { 630 return nil, xerrors.Errorf("cannot pop expired sectors from a partition with unproven sectors: %w", err) 631 } 632 633 expirations, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 634 if err != nil { 635 return nil, xerrors.Errorf("failed to load expiration queue: %w", err) 636 } 637 popped, err := expirations.PopUntil(until) 638 if err != nil { 639 return nil, xerrors.Errorf("failed to pop expiration queue until %d: %w", until, err) 640 } 641 if p.ExpirationsEpochs, err = expirations.Root(); err != nil { 642 return nil, err 643 } 644 645 expiredSectors, err := bitfield.MergeBitFields(popped.OnTimeSectors, popped.EarlySectors) 646 if err != nil { 647 return nil, err 648 } 649 650 // There shouldn't be any recovering sectors or power if this is invoked at deadline end. 651 // Either the partition was PoSted and the recovering became recovered, or the partition was not PoSted 652 // and all recoveries retracted. 653 // No recoveries may be posted until the deadline is closed. 654 noRecoveries, err := p.Recoveries.IsEmpty() 655 if err != nil { 656 return nil, err 657 } else if !noRecoveries { 658 return nil, xerrors.Errorf("unexpected recoveries while processing expirations") 659 } 660 if !p.RecoveringPower.IsZero() { 661 return nil, xerrors.Errorf("unexpected recovering power while processing expirations") 662 } 663 // Nothing expiring now should have already terminated. 664 alreadyTerminated, err := util.BitFieldContainsAny(p.Terminated, expiredSectors) 665 if err != nil { 666 return nil, err 667 } else if alreadyTerminated { 668 return nil, xerrors.Errorf("expiring sectors already terminated") 669 } 670 671 // Mark the sectors as terminated and subtract sector power. 672 if p.Terminated, err = bitfield.MergeBitFields(p.Terminated, expiredSectors); err != nil { 673 return nil, xerrors.Errorf("failed to merge expired sectors: %w", err) 674 } 675 if p.Faults, err = bitfield.SubtractBitField(p.Faults, expiredSectors); err != nil { 676 return nil, err 677 } 678 p.LivePower = p.LivePower.Sub(popped.ActivePower.Add(popped.FaultyPower)) 679 p.FaultyPower = p.FaultyPower.Sub(popped.FaultyPower) 680 681 // Record the epoch of any sectors expiring early, for termination fee calculation later. 682 err = p.recordEarlyTermination(store, until, popped.EarlySectors) 683 if err != nil { 684 return nil, xerrors.Errorf("failed to record early terminations: %w", err) 685 } 686 687 // check invariants 688 if err := p.ValidateState(); err != nil { 689 return nil, err 690 } 691 692 return popped, nil 693 } 694 695 // Marks all non-faulty sectors in the partition as faulty and clears recoveries, updating power memos appropriately. 696 // All sectors' expirations are rescheduled to the fault expiration, as "early" (if not expiring earlier) 697 // Returns the power delta, power that should be penalized (new faults + failed recoveries), and newly faulty power. 698 func (p *Partition) RecordMissedPost( 699 store adt.Store, faultExpiration abi.ChainEpoch, quant QuantSpec, 700 ) (powerDelta, penalizedPower, newFaultyPower PowerPair, err error) { 701 // Collapse tail of queue into the last entry, and mark all power faulty. 702 // Load expiration queue 703 queue, err := LoadExpirationQueue(store, p.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth) 704 if err != nil { 705 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to load partition queue: %w", err) 706 } 707 if err = queue.RescheduleAllAsFaults(faultExpiration); err != nil { 708 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), xerrors.Errorf("failed to reschedule all as faults: %w", err) 709 } 710 // Save expiration queue 711 if p.ExpirationsEpochs, err = queue.Root(); err != nil { 712 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), err 713 } 714 715 // Compute power changes. 716 717 // New faulty power is the total power minus already faulty. 718 newFaultyPower = p.LivePower.Sub(p.FaultyPower) 719 // Penalized power is the newly faulty power, plus the failed recovery power. 720 penalizedPower = p.RecoveringPower.Add(newFaultyPower) 721 // The power delta is -(newFaultyPower-unproven), because unproven power 722 // was never activated in the first place. 723 powerDelta = newFaultyPower.Sub(p.UnprovenPower).Neg() 724 725 // Update partition metadata 726 allFaults, err := p.LiveSectors() 727 if err != nil { 728 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), err 729 } 730 p.Faults = allFaults 731 p.Recoveries = bitfield.New() 732 p.Unproven = bitfield.New() 733 p.FaultyPower = p.LivePower 734 p.RecoveringPower = NewPowerPairZero() 735 p.UnprovenPower = NewPowerPairZero() 736 737 // check invariants 738 if err := p.ValidateState(); err != nil { 739 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), err 740 } 741 742 return powerDelta, penalizedPower, newFaultyPower, nil 743 } 744 745 func (p *Partition) PopEarlyTerminations(store adt.Store, maxSectors uint64) (result TerminationResult, hasMore bool, err error) { 746 stopErr := errors.New("stop iter") 747 748 // Load early terminations. 749 earlyTerminatedQ, err := LoadBitfieldQueue(store, p.EarlyTerminated, NoQuantization, PartitionEarlyTerminationArrayAmtBitwidth) 750 if err != nil { 751 return TerminationResult{}, false, err 752 } 753 754 var ( 755 processed []uint64 756 hasRemaining bool 757 remainingSectors bitfield.BitField 758 remainingEpoch abi.ChainEpoch 759 ) 760 761 result.PartitionsProcessed = 1 762 result.Sectors = make(map[abi.ChainEpoch]bitfield.BitField) 763 764 if err = earlyTerminatedQ.ForEach(func(epoch abi.ChainEpoch, sectors bitfield.BitField) error { 765 toProcess := sectors 766 count, err := sectors.Count() 767 if err != nil { 768 return xerrors.Errorf("failed to count early terminations: %w", err) 769 } 770 771 limit := maxSectors - result.SectorsProcessed 772 773 if limit < count { 774 toProcess, err = sectors.Slice(0, limit) 775 if err != nil { 776 return xerrors.Errorf("failed to slice early terminations: %w", err) 777 } 778 779 rest, err := bitfield.SubtractBitField(sectors, toProcess) 780 if err != nil { 781 return xerrors.Errorf("failed to subtract processed early terminations: %w", err) 782 } 783 hasRemaining = true 784 remainingSectors = rest 785 remainingEpoch = epoch 786 787 result.SectorsProcessed += limit 788 } else { 789 processed = append(processed, uint64(epoch)) 790 result.SectorsProcessed += count 791 } 792 793 result.Sectors[epoch] = toProcess 794 795 if result.SectorsProcessed < maxSectors { 796 return nil 797 } 798 return stopErr 799 }); err != nil && err != stopErr { 800 return TerminationResult{}, false, xerrors.Errorf("failed to walk early terminations queue: %w", err) 801 } 802 803 // Update early terminations 804 err = earlyTerminatedQ.BatchDelete(processed, true) 805 if err != nil { 806 return TerminationResult{}, false, xerrors.Errorf("failed to remove entries from early terminations queue: %w", err) 807 } 808 809 if hasRemaining { 810 err = earlyTerminatedQ.Set(uint64(remainingEpoch), remainingSectors) 811 if err != nil { 812 return TerminationResult{}, false, xerrors.Errorf("failed to update remaining entry early terminations queue: %w", err) 813 } 814 } 815 816 // Save early terminations. 817 p.EarlyTerminated, err = earlyTerminatedQ.Root() 818 if err != nil { 819 return TerminationResult{}, false, xerrors.Errorf("failed to store early terminations queue: %w", err) 820 } 821 822 // check invariants 823 if err := p.ValidateState(); err != nil { 824 return TerminationResult{}, false, err 825 } 826 827 return result, earlyTerminatedQ.Length() > 0, nil 828 } 829 830 // Discovers how skipped faults declared during post intersect with existing faults and recoveries, records the 831 // new faults in state. 832 // Returns the amount of power newly faulty, or declared recovered but faulty again. 833 // 834 // - Skipped faults that are not in the provided partition triggers an error. 835 // - Skipped faults that are already declared (but not delcared recovered) are ignored. 836 func (p *Partition) RecordSkippedFaults( 837 store adt.Store, sectors Sectors, ssize abi.SectorSize, quant QuantSpec, faultExpiration abi.ChainEpoch, skipped bitfield.BitField, 838 ) (powerDelta, newFaultPower, retractedRecoveryPower PowerPair, hasNewFaults bool, err error) { 839 empty, err := skipped.IsEmpty() 840 if err != nil { 841 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xc.ErrIllegalArgument.Wrapf("failed to check if skipped sectors is empty: %w", err) 842 } 843 if empty { 844 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, nil 845 } 846 847 // Check that the declared sectors are actually in the partition. 848 contains, err := util.BitFieldContainsAll(p.Sectors, skipped) 849 if err != nil { 850 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to check if skipped faults are in partition: %w", err) 851 } else if !contains { 852 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xc.ErrIllegalArgument.Wrapf("skipped faults contains sectors outside partition") 853 } 854 855 // Find all skipped faults that have been labeled recovered 856 retractedRecoveries, err := bitfield.IntersectBitField(p.Recoveries, skipped) 857 if err != nil { 858 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to intersect sectors with recoveries: %w", err) 859 } 860 retractedRecoverySectors, err := sectors.Load(retractedRecoveries) 861 if err != nil { 862 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to load sectors: %w", err) 863 } 864 retractedRecoveryPower = PowerForSectors(ssize, retractedRecoverySectors) 865 866 // Ignore skipped faults that are already faults or terminated. 867 newFaults, err := bitfield.SubtractBitField(skipped, p.Terminated) 868 if err != nil { 869 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to subtract terminations from skipped: %w", err) 870 } 871 newFaults, err = bitfield.SubtractBitField(newFaults, p.Faults) 872 if err != nil { 873 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to subtract existing faults from skipped: %w", err) 874 } 875 newFaultSectors, err := sectors.Load(newFaults) 876 if err != nil { 877 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to load sectors: %w", err) 878 } 879 880 // Record new faults 881 powerDelta, newFaultPower, err = p.addFaults(store, newFaults, newFaultSectors, faultExpiration, ssize, quant) 882 if err != nil { 883 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to add skipped faults: %w", err) 884 } 885 886 // Remove faulty recoveries 887 err = p.removeRecoveries(retractedRecoveries, retractedRecoveryPower) 888 if err != nil { 889 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, xerrors.Errorf("failed to remove recoveries: %w", err) 890 } 891 892 // check invariants 893 if err := p.ValidateState(); err != nil { 894 return NewPowerPairZero(), NewPowerPairZero(), NewPowerPairZero(), false, err 895 } 896 897 return powerDelta, newFaultPower, retractedRecoveryPower, len(newFaultSectors) > 0, nil 898 } 899 900 // Test that invariants about partition power hold 901 func (p *Partition) ValidatePowerState() error { 902 if p.LivePower.Raw.LessThan(big.Zero()) || p.LivePower.QA.LessThan(big.Zero()) { 903 return xerrors.Errorf("Partition left with negative live power: %v", p) 904 } 905 906 if p.UnprovenPower.Raw.LessThan(big.Zero()) || p.UnprovenPower.QA.LessThan(big.Zero()) { 907 return xerrors.Errorf("Partition left with negative unproven power: %v", p) 908 } 909 910 if p.FaultyPower.Raw.LessThan(big.Zero()) || p.FaultyPower.QA.LessThan(big.Zero()) { 911 return xerrors.Errorf("Partition left with negative faulty power: %v", p) 912 } 913 914 if p.RecoveringPower.Raw.LessThan(big.Zero()) || p.RecoveringPower.QA.LessThan(big.Zero()) { 915 return xerrors.Errorf("Partition left with negative recovering power: %v", p) 916 } 917 918 if p.UnprovenPower.Raw.GreaterThan(p.LivePower.Raw) { 919 return xerrors.Errorf("Partition left with invalid unproven power: %v", p) 920 } 921 922 if p.FaultyPower.Raw.GreaterThan(p.LivePower.Raw) { 923 return xerrors.Errorf("Partition left with invalid faulty power: %v", p) 924 } 925 926 if p.RecoveringPower.Raw.GreaterThan(p.LivePower.Raw) || p.RecoveringPower.Raw.GreaterThan(p.FaultyPower.Raw) { 927 return xerrors.Errorf("Partition left with invalid recovering power: %v", p) 928 } 929 930 return nil 931 } 932 933 // Test that invariants about sector bitfields hold 934 func (p *Partition) ValidateBFState() error { 935 // Merge unproven and faults for checks 936 merge, err := bitfield.MultiMerge(p.Unproven, p.Faults) 937 if err != nil { 938 return err 939 } 940 941 // Unproven or faulty sectors should not be in terminated 942 if containsAny, err := util.BitFieldContainsAny(p.Terminated, merge); err != nil { 943 return err 944 } else if containsAny { 945 return xerrors.Errorf("Partition left with terminated sectors in multiple states: %v", p) 946 } 947 948 // Merge terminated into set for checks 949 merge, err = bitfield.MergeBitFields(merge, p.Terminated) 950 if err != nil { 951 return err 952 } 953 954 // All merged sectors should exist in p.Sectors 955 if containsAll, err := util.BitFieldContainsAll(p.Sectors, merge); err != nil { 956 return err 957 } else if !containsAll { 958 return xerrors.Errorf("Partition left with invalid sector state: %v", p) 959 } 960 961 // All recoveries should exist in p.Faults 962 if containsAll, err := util.BitFieldContainsAll(p.Faults, p.Recoveries); err != nil { 963 return err 964 } else if !containsAll { 965 return xerrors.Errorf("Partition left with invalid recovery state: %v", p) 966 } 967 968 return nil 969 } 970 971 // Test all invariants hold 972 func (p *Partition) ValidateState() error { 973 var err error 974 if err = p.ValidatePowerState(); err != nil { 975 return err 976 } 977 978 if err = p.ValidateBFState(); err != nil { 979 return err 980 } 981 982 return nil 983 } 984 985 // 986 // PowerPair 987 // 988 989 func NewPowerPairZero() PowerPair { 990 return NewPowerPair(big.Zero(), big.Zero()) 991 } 992 993 func NewPowerPair(raw, qa abi.StoragePower) PowerPair { 994 return PowerPair{Raw: raw, QA: qa} 995 } 996 997 func (pp PowerPair) IsZero() bool { 998 return pp.Raw.IsZero() && pp.QA.IsZero() 999 } 1000 1001 func (pp PowerPair) Add(other PowerPair) PowerPair { 1002 return PowerPair{ 1003 Raw: big.Add(pp.Raw, other.Raw), 1004 QA: big.Add(pp.QA, other.QA), 1005 } 1006 } 1007 1008 func (pp PowerPair) Sub(other PowerPair) PowerPair { 1009 return PowerPair{ 1010 Raw: big.Sub(pp.Raw, other.Raw), 1011 QA: big.Sub(pp.QA, other.QA), 1012 } 1013 } 1014 1015 func (pp PowerPair) Neg() PowerPair { 1016 return PowerPair{ 1017 Raw: pp.Raw.Neg(), 1018 QA: pp.QA.Neg(), 1019 } 1020 } 1021 1022 func (pp *PowerPair) Equals(other PowerPair) bool { 1023 return pp.Raw.Equals(other.Raw) && pp.QA.Equals(other.QA) 1024 }