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  }