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

     1  package miner
     2  
     3  import (
     4  	addr "github.com/filecoin-project/go-address"
     5  	"github.com/filecoin-project/go-bitfield"
     6  	"github.com/filecoin-project/go-state-types/abi"
     7  	"github.com/filecoin-project/go-state-types/big"
     8  
     9  	"github.com/filecoin-project/specs-actors/v4/actors/builtin"
    10  	"github.com/filecoin-project/specs-actors/v4/actors/util"
    11  	"github.com/filecoin-project/specs-actors/v4/actors/util/adt"
    12  )
    13  
    14  type DealSummary struct {
    15  	SectorStart      abi.ChainEpoch
    16  	SectorExpiration abi.ChainEpoch
    17  }
    18  
    19  type StateSummary struct {
    20  	LivePower           PowerPair
    21  	ActivePower         PowerPair
    22  	FaultyPower         PowerPair
    23  	Deals               map[abi.DealID]DealSummary
    24  	WindowPoStProofType abi.RegisteredPoStProof
    25  	DeadlineCronActive  bool
    26  }
    27  
    28  // Checks internal invariants of init state.
    29  func CheckStateInvariants(st *State, store adt.Store, balance abi.TokenAmount) (*StateSummary, *builtin.MessageAccumulator) {
    30  	acc := &builtin.MessageAccumulator{}
    31  	sectorSize := abi.SectorSize(0)
    32  	minerSummary := &StateSummary{
    33  		LivePower:           NewPowerPairZero(),
    34  		ActivePower:         NewPowerPairZero(),
    35  		FaultyPower:         NewPowerPairZero(),
    36  		WindowPoStProofType: 0,
    37  		DeadlineCronActive:  st.DeadlineCronActive,
    38  	}
    39  
    40  	// Load data from linked structures.
    41  	if info, err := st.GetInfo(store); err != nil {
    42  		acc.Addf("error loading miner info: %v", err)
    43  		// Stop here, it's too hard to make other useful checks.
    44  		return minerSummary, acc
    45  	} else {
    46  		minerSummary.WindowPoStProofType = info.WindowPoStProofType
    47  		sectorSize = info.SectorSize
    48  		CheckMinerInfo(info, acc)
    49  	}
    50  
    51  	CheckMinerBalances(st, store, balance, acc)
    52  
    53  	var allocatedSectors bitfield.BitField
    54  	var allocatedSectorsMap map[uint64]bool
    55  	if err := store.Get(store.Context(), st.AllocatedSectors, &allocatedSectors); err != nil {
    56  		acc.Addf("error loading allocated sector bitfield: %v", err)
    57  	} else {
    58  		allocatedSectorsMap, err = allocatedSectors.AllMap(1 << 30)
    59  		if err != nil {
    60  			acc.Addf("error expanding allocated sector bitfield: %v", err)
    61  			allocatedSectorsMap = nil
    62  		}
    63  	}
    64  
    65  	CheckPreCommits(st, store, allocatedSectorsMap, acc)
    66  
    67  	minerSummary.Deals = map[abi.DealID]DealSummary{}
    68  	var allSectors map[abi.SectorNumber]*SectorOnChainInfo
    69  	if sectorsArr, err := adt.AsArray(store, st.Sectors, SectorsAmtBitwidth); err != nil {
    70  		acc.Addf("error loading sectors")
    71  	} else {
    72  		allSectors = map[abi.SectorNumber]*SectorOnChainInfo{}
    73  		var sector SectorOnChainInfo
    74  		err = sectorsArr.ForEach(&sector, func(sno int64) error {
    75  			cpy := sector
    76  			allSectors[abi.SectorNumber(sno)] = &cpy
    77  			acc.Require(allocatedSectorsMap == nil || allocatedSectorsMap[uint64(sno)],
    78  				"on chain sector's sector number has not been allocated %d", sno)
    79  
    80  			for _, dealID := range sector.DealIDs {
    81  				minerSummary.Deals[dealID] = DealSummary{
    82  					SectorStart:      sector.Activation,
    83  					SectorExpiration: sector.Expiration,
    84  				}
    85  			}
    86  
    87  			return nil
    88  		})
    89  		acc.RequireNoError(err, "error iterating sectors")
    90  	}
    91  
    92  	// Check deadlines
    93  	acc.Require(st.CurrentDeadline < WPoStPeriodDeadlines,
    94  		"current deadline index is greater than deadlines per period(%d): %d", WPoStPeriodDeadlines, st.CurrentDeadline)
    95  
    96  	deadlines, err := st.LoadDeadlines(store)
    97  	if err != nil {
    98  		acc.Addf("error loading deadlines: %v", err)
    99  		deadlines = nil
   100  	}
   101  
   102  	if allSectors != nil && deadlines != nil {
   103  		err = deadlines.ForEach(store, func(dlIdx uint64, dl *Deadline) error {
   104  			acc := acc.WithPrefix("deadline %d: ", dlIdx) // Shadow
   105  			quant := st.QuantSpecForDeadline(dlIdx)
   106  			dlSummary := CheckDeadlineStateInvariants(dl, store, quant, sectorSize, allSectors, acc)
   107  
   108  			minerSummary.LivePower = minerSummary.LivePower.Add(dlSummary.LivePower)
   109  			minerSummary.ActivePower = minerSummary.ActivePower.Add(dlSummary.ActivePower)
   110  			minerSummary.FaultyPower = minerSummary.FaultyPower.Add(dlSummary.FaultyPower)
   111  			return nil
   112  		})
   113  		acc.RequireNoError(err, "error iterating deadlines")
   114  	}
   115  
   116  	return minerSummary, acc
   117  }
   118  
   119  type DeadlineStateSummary struct {
   120  	AllSectors        bitfield.BitField
   121  	LiveSectors       bitfield.BitField
   122  	FaultySectors     bitfield.BitField
   123  	RecoveringSectors bitfield.BitField
   124  	UnprovenSectors   bitfield.BitField
   125  	TerminatedSectors bitfield.BitField
   126  	LivePower         PowerPair
   127  	ActivePower       PowerPair
   128  	FaultyPower       PowerPair
   129  }
   130  
   131  func CheckDeadlineStateInvariants(deadline *Deadline, store adt.Store, quant QuantSpec, ssize abi.SectorSize,
   132  	sectors map[abi.SectorNumber]*SectorOnChainInfo, acc *builtin.MessageAccumulator) *DeadlineStateSummary {
   133  
   134  	// Load linked structures.
   135  	partitions, err := deadline.PartitionsArray(store)
   136  	if err != nil {
   137  		acc.Addf("error loading partitions: %v", err)
   138  		// Hard to do any useful checks.
   139  		return &DeadlineStateSummary{
   140  			AllSectors:        bitfield.New(),
   141  			LiveSectors:       bitfield.New(),
   142  			FaultySectors:     bitfield.New(),
   143  			RecoveringSectors: bitfield.New(),
   144  			UnprovenSectors:   bitfield.New(),
   145  			TerminatedSectors: bitfield.New(),
   146  			LivePower:         NewPowerPairZero(),
   147  			ActivePower:       NewPowerPairZero(),
   148  			FaultyPower:       NewPowerPairZero(),
   149  		}
   150  	}
   151  
   152  	allSectors := bitfield.New()
   153  	var allLiveSectors []bitfield.BitField
   154  	var allFaultySectors []bitfield.BitField
   155  	var allRecoveringSectors []bitfield.BitField
   156  	var allUnprovenSectors []bitfield.BitField
   157  	var allTerminatedSectors []bitfield.BitField
   158  	allLivePower := NewPowerPairZero()
   159  	allActivePower := NewPowerPairZero()
   160  	allFaultyPower := NewPowerPairZero()
   161  
   162  	// Check partitions.
   163  	partitionsWithExpirations := map[abi.ChainEpoch][]uint64{}
   164  	var partitionsWithEarlyTerminations []uint64
   165  	partitionCount := uint64(0)
   166  	var partition Partition
   167  	err = partitions.ForEach(&partition, func(i int64) error {
   168  		pIdx := uint64(i)
   169  		// Check sequential partitions.
   170  		acc.Require(pIdx == partitionCount, "Non-sequential partitions, expected index %d, found %d", partitionCount, pIdx)
   171  		partitionCount++
   172  
   173  		acc := acc.WithPrefix("partition %d: ", pIdx) // Shadow
   174  		summary := CheckPartitionStateInvariants(&partition, store, quant, ssize, sectors, acc)
   175  
   176  		if contains, err := util.BitFieldContainsAny(allSectors, summary.AllSectors); err != nil {
   177  			acc.Addf("error checking bitfield contains: %v", err)
   178  		} else {
   179  			acc.Require(!contains, "duplicate sector in partition %d", pIdx)
   180  		}
   181  
   182  		for _, e := range summary.ExpirationEpochs {
   183  			partitionsWithExpirations[e] = append(partitionsWithExpirations[e], pIdx)
   184  		}
   185  		if summary.EarlyTerminationCount > 0 {
   186  			partitionsWithEarlyTerminations = append(partitionsWithEarlyTerminations, pIdx)
   187  		}
   188  
   189  		allSectors, err = bitfield.MergeBitFields(allSectors, summary.AllSectors)
   190  		if err != nil {
   191  			acc.Addf("error merging partition sector numbers with all: %v", err)
   192  			allSectors = bitfield.New()
   193  		}
   194  		allLiveSectors = append(allLiveSectors, summary.LiveSectors)
   195  		allFaultySectors = append(allFaultySectors, summary.FaultySectors)
   196  		allRecoveringSectors = append(allRecoveringSectors, summary.RecoveringSectors)
   197  		allUnprovenSectors = append(allUnprovenSectors, summary.UnprovenSectors)
   198  		allTerminatedSectors = append(allTerminatedSectors, summary.TerminatedSectors)
   199  		allLivePower = allLivePower.Add(summary.LivePower)
   200  		allActivePower = allActivePower.Add(summary.ActivePower)
   201  		allFaultyPower = allFaultyPower.Add(summary.FaultyPower)
   202  		return nil
   203  	})
   204  	acc.RequireNoError(err, "error iterating partitions")
   205  
   206  	// Check invariants on partitions proven.
   207  	{
   208  		if lastProof, err := deadline.PartitionsPoSted.Last(); err != nil {
   209  			if err != bitfield.ErrNoBitsSet {
   210  				acc.Addf("error determining the last partition proven: %v", err)
   211  			}
   212  		} else {
   213  			acc.Require(partitionCount >= (lastProof+1), "expected at least %d partitions, found %d", lastProof+1, partitionCount)
   214  			acc.Require(deadline.LiveSectors > 0, "expected at least one live sector when partitions have been proven")
   215  		}
   216  	}
   217  
   218  	// Check partitions snapshot to make sure we take the snapshot after
   219  	// dealing with recovering power and unproven power.
   220  	partitionsSnapshot, err := deadline.PartitionsSnapshotArray(store)
   221  	acc.RequireNoError(err, "error loading partitions snapshot")
   222  	err = partitionsSnapshot.ForEach(&partition, func(i int64) error {
   223  		acc := acc.WithPrefix("partition snapshot %d: ", i) // Shadow
   224  
   225  		acc.Require(partition.RecoveringPower.IsZero(), "snapshot partition has recovering power")
   226  		if noRecoveries, err := partition.Recoveries.IsEmpty(); err != nil {
   227  			acc.Addf("error counting recoveries: %v", err)
   228  		} else {
   229  			acc.Require(noRecoveries, "snapshot partition has pending recoveries")
   230  		}
   231  
   232  		acc.Require(partition.UnprovenPower.IsZero(), "snapshot partition has unproven power")
   233  		if noUnproven, err := partition.Unproven.IsEmpty(); err != nil {
   234  			acc.Addf("error counting unproven: %v", err)
   235  		} else {
   236  			acc.Require(noUnproven, "snapshot partition has unproven sectors")
   237  		}
   238  
   239  		return nil
   240  	})
   241  	acc.RequireNoError(err, "error iterating partitions snapshot")
   242  
   243  	// Check that we don't have any proofs proving partitions that are not in the snapshot.
   244  	proofsSnapshot, err := deadline.OptimisticProofsSnapshotArray(store)
   245  	acc.RequireNoError(err, "error loading proofs snapshot")
   246  	var proof WindowedPoSt
   247  	err = proofsSnapshot.ForEach(&proof, func(_ int64) error {
   248  		err = proof.Partitions.ForEach(func(i uint64) error {
   249  			found, err := partitionsSnapshot.Get(i, &partition)
   250  			acc.RequireNoError(err, "error loading partition snapshot")
   251  			acc.Require(found, "failed to find partition for recorded proof in the snapshot")
   252  			return nil
   253  		})
   254  		acc.RequireNoError(err, "error iterating proof partitions bitfield")
   255  		return nil
   256  	})
   257  	acc.RequireNoError(err, "error iterating proofs snapshot")
   258  
   259  	// Check memoized sector and power values.
   260  	live, err := bitfield.MultiMerge(allLiveSectors...)
   261  	if err != nil {
   262  		acc.Addf("error merging live sector numbers: %v", err)
   263  		live = bitfield.New()
   264  	} else {
   265  		if liveCount, err := live.Count(); err != nil {
   266  			acc.Addf("error counting live sectors: %v", err)
   267  		} else {
   268  			acc.Require(deadline.LiveSectors == liveCount, "deadline live sectors %d != partitions count %d", deadline.LiveSectors, liveCount)
   269  		}
   270  	}
   271  
   272  	if allCount, err := allSectors.Count(); err != nil {
   273  		acc.Addf("error counting all sectors: %v", err)
   274  	} else {
   275  		acc.Require(deadline.TotalSectors == allCount, "deadline total sectors %d != partitions count %d", deadline.TotalSectors, allCount)
   276  	}
   277  
   278  	faulty, err := bitfield.MultiMerge(allFaultySectors...)
   279  	if err != nil {
   280  		acc.Addf("error merging faulty sector numbers: %v", err)
   281  		faulty = bitfield.New()
   282  	}
   283  	recovering, err := bitfield.MultiMerge(allRecoveringSectors...)
   284  	if err != nil {
   285  		acc.Addf("error merging recovering sector numbers: %v", err)
   286  		recovering = bitfield.New()
   287  	}
   288  	unproven, err := bitfield.MultiMerge(allUnprovenSectors...)
   289  	if err != nil {
   290  		acc.Addf("error merging unproven sector numbers: %v", err)
   291  		unproven = bitfield.New()
   292  	}
   293  	terminated, err := bitfield.MultiMerge(allTerminatedSectors...)
   294  	if err != nil {
   295  		acc.Addf("error merging terminated sector numbers: %v", err)
   296  		terminated = bitfield.New()
   297  	}
   298  
   299  	acc.Require(deadline.FaultyPower.Equals(allFaultyPower), "deadline faulty power %v != partitions total %v", deadline.FaultyPower, allFaultyPower)
   300  
   301  	{
   302  		// Validate partition expiration queue contains an entry for each partition and epoch with an expiration.
   303  		// The queue may be a superset of the partitions that have expirations because we never remove from it.
   304  		if expirationEpochs, err := adt.AsArray(store, deadline.ExpirationsEpochs, DeadlineExpirationAmtBitwidth); err != nil {
   305  			acc.Addf("error loading expiration queue: %v", err)
   306  		} else {
   307  			for epoch, expiringPIdxs := range partitionsWithExpirations { // nolint:nomaprange
   308  				var bf bitfield.BitField
   309  				if found, err := expirationEpochs.Get(uint64(epoch), &bf); err != nil {
   310  					acc.Addf("error fetching expiration bitfield: %v", err)
   311  				} else {
   312  					acc.Require(found, "expected to find partition expiration entry at epoch %d", epoch)
   313  				}
   314  
   315  				if queuedPIdxs, err := bf.AllMap(1 << 20); err != nil {
   316  					acc.Addf("error expanding expirating partitions: %v", err)
   317  				} else {
   318  					for _, p := range expiringPIdxs {
   319  						acc.Require(queuedPIdxs[p], "expected partition %d to be present in deadline expiration queue at epoch %d", p, epoch)
   320  					}
   321  				}
   322  			}
   323  		}
   324  	}
   325  	{
   326  		// Validate the early termination queue contains exactly the partitions with early terminations.
   327  		expected := bitfield.NewFromSet(partitionsWithEarlyTerminations)
   328  		requireEqual(expected, deadline.EarlyTerminations, acc, "deadline early terminations doesn't match expected partitions")
   329  	}
   330  
   331  	return &DeadlineStateSummary{
   332  		AllSectors:        allSectors,
   333  		LiveSectors:       live,
   334  		FaultySectors:     faulty,
   335  		RecoveringSectors: recovering,
   336  		UnprovenSectors:   unproven,
   337  		TerminatedSectors: terminated,
   338  		LivePower:         allLivePower,
   339  		ActivePower:       allActivePower,
   340  		FaultyPower:       allFaultyPower,
   341  	}
   342  }
   343  
   344  type PartitionStateSummary struct {
   345  	AllSectors            bitfield.BitField
   346  	LiveSectors           bitfield.BitField
   347  	FaultySectors         bitfield.BitField
   348  	RecoveringSectors     bitfield.BitField
   349  	UnprovenSectors       bitfield.BitField
   350  	TerminatedSectors     bitfield.BitField
   351  	LivePower             PowerPair
   352  	ActivePower           PowerPair
   353  	FaultyPower           PowerPair
   354  	RecoveringPower       PowerPair
   355  	ExpirationEpochs      []abi.ChainEpoch // Epochs at which some sector is scheduled to expire.
   356  	EarlyTerminationCount int
   357  }
   358  
   359  func CheckPartitionStateInvariants(
   360  	partition *Partition,
   361  	store adt.Store,
   362  	quant QuantSpec,
   363  	sectorSize abi.SectorSize,
   364  	sectors map[abi.SectorNumber]*SectorOnChainInfo,
   365  	acc *builtin.MessageAccumulator,
   366  ) *PartitionStateSummary {
   367  	irrecoverable := false // State is so broken we can't make useful checks.
   368  	live, err := partition.LiveSectors()
   369  	if err != nil {
   370  		acc.Addf("error computing live sectors: %v", err)
   371  		irrecoverable = true
   372  	}
   373  	active, err := partition.ActiveSectors()
   374  	if err != nil {
   375  		acc.Addf("error computing active sectors: %v", err)
   376  		irrecoverable = true
   377  	}
   378  
   379  	if irrecoverable {
   380  		return &PartitionStateSummary{
   381  			AllSectors:            partition.Sectors,
   382  			LiveSectors:           bitfield.New(),
   383  			FaultySectors:         partition.Faults,
   384  			RecoveringSectors:     partition.Recoveries,
   385  			UnprovenSectors:       partition.Unproven,
   386  			TerminatedSectors:     partition.Terminated,
   387  			LivePower:             partition.LivePower,
   388  			ActivePower:           partition.ActivePower(),
   389  			FaultyPower:           partition.FaultyPower,
   390  			RecoveringPower:       partition.RecoveringPower,
   391  			ExpirationEpochs:      nil,
   392  			EarlyTerminationCount: 0,
   393  		}
   394  	}
   395  
   396  	// Live contains all active sectors.
   397  	requireContainsAll(live, active, acc, "live does not contain active")
   398  
   399  	// Live contains all faults.
   400  	requireContainsAll(live, partition.Faults, acc, "live does not contain faults")
   401  
   402  	// Live contains all unproven.
   403  	requireContainsAll(live, partition.Unproven, acc, "live does not contain unproven")
   404  
   405  	// Active contains no faults
   406  	requireContainsNone(active, partition.Faults, acc, "active includes faults")
   407  
   408  	// Active contains no unproven
   409  	requireContainsNone(active, partition.Unproven, acc, "active includes unproven")
   410  
   411  	// Faults contains all recoveries.
   412  	requireContainsAll(partition.Faults, partition.Recoveries, acc, "faults do not contain recoveries")
   413  
   414  	// Live contains no terminated sectors
   415  	requireContainsNone(live, partition.Terminated, acc, "live includes terminations")
   416  
   417  	// Unproven contains no faults
   418  	requireContainsNone(partition.Faults, partition.Unproven, acc, "unproven includes faults")
   419  
   420  	// All terminated sectors are part of the partition.
   421  	requireContainsAll(partition.Sectors, partition.Terminated, acc, "sectors do not contain terminations")
   422  
   423  	// Validate power
   424  	var liveSectors map[abi.SectorNumber]*SectorOnChainInfo
   425  	var missing []abi.SectorNumber
   426  	livePower := NewPowerPairZero()
   427  	faultyPower := NewPowerPairZero()
   428  	unprovenPower := NewPowerPairZero()
   429  
   430  	if liveSectors, missing, err = selectSectorsMap(sectors, live); err != nil {
   431  		acc.Addf("error selecting live sectors: %v", err)
   432  	} else if len(missing) > 0 {
   433  		acc.Addf("live sectors missing from all sectors: %v", missing)
   434  	} else {
   435  		livePower = powerForSectors(liveSectors, sectorSize)
   436  		acc.Require(partition.LivePower.Equals(livePower), "live power was %v, expected %v", partition.LivePower, livePower)
   437  	}
   438  
   439  	if unprovenSectors, missing, err := selectSectorsMap(sectors, partition.Unproven); err != nil {
   440  		acc.Addf("error selecting unproven sectors: %v", err)
   441  	} else if len(missing) > 0 {
   442  		acc.Addf("unproven sectors missing from all sectors: %v", missing)
   443  	} else {
   444  		unprovenPower = powerForSectors(unprovenSectors, sectorSize)
   445  		acc.Require(partition.UnprovenPower.Equals(unprovenPower), "unproven power was %v, expected %v", partition.UnprovenPower, unprovenPower)
   446  	}
   447  
   448  	if faultySectors, missing, err := selectSectorsMap(sectors, partition.Faults); err != nil {
   449  		acc.Addf("error selecting faulty sectors: %v", err)
   450  	} else if len(missing) > 0 {
   451  		acc.Addf("faulty sectors missing from all sectors: %v", missing)
   452  	} else {
   453  		faultyPower = powerForSectors(faultySectors, sectorSize)
   454  		acc.Require(partition.FaultyPower.Equals(faultyPower), "faulty power was %v, expected %v", partition.FaultyPower, faultyPower)
   455  	}
   456  
   457  	if recoveringSectors, missing, err := selectSectorsMap(sectors, partition.Recoveries); err != nil {
   458  		acc.Addf("error selecting recovering sectors: %v", err)
   459  	} else if len(missing) > 0 {
   460  		acc.Addf("recovering sectors missing from all sectors: %v", missing)
   461  	} else {
   462  		recoveringPower := powerForSectors(recoveringSectors, sectorSize)
   463  		acc.Require(partition.RecoveringPower.Equals(recoveringPower), "recovering power was %v, expected %v", partition.RecoveringPower, recoveringPower)
   464  	}
   465  
   466  	activePower := livePower.Sub(faultyPower).Sub(unprovenPower)
   467  	partitionActivePower := partition.ActivePower()
   468  	acc.Require(partitionActivePower.Equals(activePower), "active power was %v, expected %v", partitionActivePower, activePower)
   469  
   470  	// Validate the expiration queue.
   471  	var expirationEpochs []abi.ChainEpoch
   472  	if expQ, err := LoadExpirationQueue(store, partition.ExpirationsEpochs, quant, PartitionExpirationAmtBitwidth); err != nil {
   473  		acc.Addf("error loading expiration queue: %v", err)
   474  	} else if liveSectors != nil {
   475  		qsummary := CheckExpirationQueue(expQ, liveSectors, partition.Faults, quant, sectorSize, acc)
   476  		expirationEpochs = qsummary.ExpirationEpochs
   477  
   478  		// Check the queue is compatible with partition fields
   479  		if qSectors, err := bitfield.MergeBitFields(qsummary.OnTimeSectors, qsummary.EarlySectors); err != nil {
   480  			acc.Addf("error merging summary on-time and early sectors: %v", err)
   481  		} else {
   482  			requireEqual(live, qSectors, acc, "live does not equal all expirations")
   483  		}
   484  	}
   485  
   486  	// Validate the early termination queue.
   487  	earlyTerminationCount := 0
   488  	if earlyQ, err := LoadBitfieldQueue(store, partition.EarlyTerminated, NoQuantization, PartitionEarlyTerminationArrayAmtBitwidth); err != nil {
   489  		acc.Addf("error loading early termination queue: %v", err)
   490  	} else {
   491  		earlyTerminationCount = CheckEarlyTerminationQueue(earlyQ, partition.Terminated, acc)
   492  	}
   493  
   494  	return &PartitionStateSummary{
   495  		AllSectors:            partition.Sectors,
   496  		LiveSectors:           live,
   497  		FaultySectors:         partition.Faults,
   498  		RecoveringSectors:     partition.Recoveries,
   499  		UnprovenSectors:       partition.Unproven,
   500  		TerminatedSectors:     partition.Terminated,
   501  		LivePower:             livePower,
   502  		ActivePower:           activePower,
   503  		FaultyPower:           partition.FaultyPower,
   504  		RecoveringPower:       partition.RecoveringPower,
   505  		ExpirationEpochs:      expirationEpochs,
   506  		EarlyTerminationCount: earlyTerminationCount,
   507  	}
   508  }
   509  
   510  type ExpirationQueueStateSummary struct {
   511  	OnTimeSectors    bitfield.BitField
   512  	EarlySectors     bitfield.BitField
   513  	ActivePower      PowerPair
   514  	FaultyPower      PowerPair
   515  	OnTimePledge     abi.TokenAmount
   516  	ExpirationEpochs []abi.ChainEpoch
   517  }
   518  
   519  // Checks the expiration queue for consistency.
   520  func CheckExpirationQueue(expQ ExpirationQueue, liveSectors map[abi.SectorNumber]*SectorOnChainInfo,
   521  	partitionFaults bitfield.BitField, quant QuantSpec, sectorSize abi.SectorSize, acc *builtin.MessageAccumulator) *ExpirationQueueStateSummary {
   522  	partitionFaultsMap, err := partitionFaults.AllMap(1 << 30)
   523  	if err != nil {
   524  		acc.Addf("error loading partition faults map: %v", err)
   525  		partitionFaultsMap = nil
   526  	}
   527  
   528  	seenSectors := make(map[abi.SectorNumber]bool)
   529  	var allOnTime []bitfield.BitField
   530  	var allEarly []bitfield.BitField
   531  	var expirationEpochs []abi.ChainEpoch
   532  	allActivePower := NewPowerPairZero()
   533  	allFaultyPower := NewPowerPairZero()
   534  	allOnTimePledge := big.Zero()
   535  	firstQueueEpoch := abi.ChainEpoch(-1)
   536  	var exp ExpirationSet
   537  	err = expQ.ForEach(&exp, func(e int64) error {
   538  		epoch := abi.ChainEpoch(e)
   539  		acc := acc.WithPrefix("expiration epoch %d: ", epoch)
   540  		acc.Require(quant.QuantizeUp(epoch) == epoch,
   541  			"expiration queue key %d is not quantized, expected %d", epoch, quant.QuantizeUp(epoch))
   542  		if firstQueueEpoch == abi.ChainEpoch(-1) {
   543  			firstQueueEpoch = epoch
   544  		}
   545  		expirationEpochs = append(expirationEpochs, epoch)
   546  
   547  		onTimeSectorsPledge := big.Zero()
   548  		err := exp.OnTimeSectors.ForEach(func(n uint64) error {
   549  			sno := abi.SectorNumber(n)
   550  			// Check sectors are present only once.
   551  			acc.Require(!seenSectors[sno], "sector %d in expiration queue twice", sno)
   552  			seenSectors[sno] = true
   553  
   554  			// Check expiring sectors are still alive.
   555  			if sector, ok := liveSectors[sno]; ok {
   556  				// The sector can be "on time" either at its target expiration epoch, or in the first queue entry
   557  				// (a CC-replaced sector moved forward).
   558  				target := quant.QuantizeUp(sector.Expiration)
   559  				acc.Require(epoch == target || epoch == firstQueueEpoch, "invalid expiration %d for sector %d, expected %d or %d",
   560  					epoch, sector.SectorNumber, firstQueueEpoch, target)
   561  
   562  				onTimeSectorsPledge = big.Add(onTimeSectorsPledge, sector.InitialPledge)
   563  			} else {
   564  				acc.Addf("on-time expiration sector %d isn't live", n)
   565  			}
   566  			return nil
   567  		})
   568  		acc.RequireNoError(err, "error iterating on-time sectors")
   569  
   570  		err = exp.EarlySectors.ForEach(func(n uint64) error {
   571  			sno := abi.SectorNumber(n)
   572  			// Check sectors are present only once.
   573  			acc.Require(!seenSectors[sno], "sector %d in expiration queue twice", sno)
   574  			seenSectors[sno] = true
   575  
   576  			// Check early sectors are faulty
   577  			acc.Require(partitionFaultsMap == nil || partitionFaultsMap[n], "sector %d expiring early but not faulty", sno)
   578  
   579  			// Check expiring sectors are still alive.
   580  			if sector, ok := liveSectors[sno]; ok {
   581  				target := quant.QuantizeUp(sector.Expiration)
   582  				acc.Require(epoch < target, "invalid early expiration %d for sector %d, expected < %d",
   583  					epoch, sector.SectorNumber, target)
   584  			} else {
   585  				acc.Addf("on-time expiration sector %d isn't live", n)
   586  			}
   587  			return nil
   588  		})
   589  		acc.RequireNoError(err, "error iterating early sectors")
   590  
   591  		// Validate power and pledge.
   592  		var activeSectors, faultySectors map[abi.SectorNumber]*SectorOnChainInfo
   593  		var missing []abi.SectorNumber
   594  
   595  		all, err := bitfield.MergeBitFields(exp.OnTimeSectors, exp.EarlySectors)
   596  		if err != nil {
   597  			acc.Addf("error merging all on-time and early bitfields: %v", err)
   598  		} else {
   599  			if allActive, err := bitfield.SubtractBitField(all, partitionFaults); err != nil {
   600  				acc.Addf("error computing active sectors: %v", err)
   601  			} else {
   602  				activeSectors, missing, err = selectSectorsMap(liveSectors, allActive)
   603  				if err != nil {
   604  					acc.Addf("error selecting active sectors: %v", err)
   605  					activeSectors = nil
   606  				} else if len(missing) > 0 {
   607  					acc.Addf("active sectors missing from live: %v", missing)
   608  				}
   609  			}
   610  
   611  			if allFaulty, err := bitfield.IntersectBitField(all, partitionFaults); err != nil {
   612  				acc.Addf("error computing faulty sectors: %v", err)
   613  			} else {
   614  				faultySectors, missing, err = selectSectorsMap(liveSectors, allFaulty)
   615  				if err != nil {
   616  					acc.Addf("error selecting faulty sectors: %v", err)
   617  					faultySectors = nil
   618  				} else if len(missing) > 0 {
   619  					acc.Addf("faulty sectors missing from live: %v", missing)
   620  				}
   621  			}
   622  		}
   623  
   624  		if activeSectors != nil && faultySectors != nil {
   625  			activeSectorsPower := powerForSectors(activeSectors, sectorSize)
   626  			acc.Require(exp.ActivePower.Equals(activeSectorsPower), "active power recorded %v doesn't match computed %v", exp.ActivePower, activeSectorsPower)
   627  
   628  			faultySectorsPower := powerForSectors(faultySectors, sectorSize)
   629  			acc.Require(exp.FaultyPower.Equals(faultySectorsPower), "faulty power recorded %v doesn't match computed %v", exp.FaultyPower, faultySectorsPower)
   630  		}
   631  
   632  		acc.Require(exp.OnTimePledge.Equals(onTimeSectorsPledge), "on time pledge recorded %v doesn't match computed %v", exp.OnTimePledge, onTimeSectorsPledge)
   633  
   634  		allOnTime = append(allOnTime, exp.OnTimeSectors)
   635  		allEarly = append(allEarly, exp.EarlySectors)
   636  		allActivePower = allActivePower.Add(exp.ActivePower)
   637  		allFaultyPower = allFaultyPower.Add(exp.FaultyPower)
   638  		allOnTimePledge = big.Add(allOnTimePledge, exp.OnTimePledge)
   639  		return nil
   640  	})
   641  	acc.RequireNoError(err, "error iterating expiration queue")
   642  
   643  	unionOnTime, err := bitfield.MultiMerge(allOnTime...)
   644  	if err != nil {
   645  		acc.Addf("error merging on-time sector numbers: %v", err)
   646  		unionOnTime = bitfield.New()
   647  	}
   648  	unionEarly, err := bitfield.MultiMerge(allEarly...)
   649  	if err != nil {
   650  		acc.Addf("error merging early sector numbers: %v", err)
   651  		unionEarly = bitfield.New()
   652  	}
   653  	return &ExpirationQueueStateSummary{
   654  		OnTimeSectors:    unionOnTime,
   655  		EarlySectors:     unionEarly,
   656  		ActivePower:      allActivePower,
   657  		FaultyPower:      allFaultyPower,
   658  		OnTimePledge:     allOnTimePledge,
   659  		ExpirationEpochs: expirationEpochs,
   660  	}
   661  }
   662  
   663  // Checks the early termination queue for consistency.
   664  // Returns the number of sectors in the queue.
   665  func CheckEarlyTerminationQueue(earlyQ BitfieldQueue, terminated bitfield.BitField, acc *builtin.MessageAccumulator) int {
   666  	seenMap := make(map[uint64]bool)
   667  	seenBf := bitfield.New()
   668  	err := earlyQ.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error {
   669  		acc := acc.WithPrefix("early termination epoch %d: ", epoch)
   670  		err := bf.ForEach(func(i uint64) error {
   671  			acc.Require(!seenMap[i], "sector %v in early termination queue twice", i)
   672  			seenMap[i] = true
   673  			seenBf.Set(i)
   674  			return nil
   675  		})
   676  		acc.RequireNoError(err, "error iterating early termination bitfield")
   677  		return nil
   678  	})
   679  	acc.RequireNoError(err, "error iterating early termination queue")
   680  
   681  	requireContainsAll(terminated, seenBf, acc, "terminated sectors missing early termination entry")
   682  	return len(seenMap)
   683  }
   684  
   685  func CheckMinerInfo(info *MinerInfo, acc *builtin.MessageAccumulator) {
   686  	acc.Require(info.Owner.Protocol() == addr.ID, "owner address %v is not an ID address", info.Owner)
   687  	acc.Require(info.Worker.Protocol() == addr.ID, "worker address %v is not an ID address", info.Worker)
   688  	for _, a := range info.ControlAddresses {
   689  		acc.Require(a.Protocol() == addr.ID, "control address %v is not an ID address", a)
   690  	}
   691  
   692  	if info.PendingWorkerKey != nil {
   693  		acc.Require(info.PendingWorkerKey.NewWorker.Protocol() == addr.ID,
   694  			"pending worker address %v is not an ID address", info.PendingWorkerKey.NewWorker)
   695  		acc.Require(info.PendingWorkerKey.NewWorker != info.Worker,
   696  			"pending worker key %v is same as existing worker %v", info.PendingWorkerKey.NewWorker, info.Worker)
   697  	}
   698  
   699  	if info.PendingOwnerAddress != nil {
   700  		acc.Require(info.PendingOwnerAddress.Protocol() == addr.ID,
   701  			"pending owner address %v is not an ID address", info.PendingOwnerAddress)
   702  		acc.Require(*info.PendingOwnerAddress != info.Owner,
   703  			"pending owner address %v is same as existing owner %v", info.PendingOwnerAddress, info.Owner)
   704  	}
   705  
   706  	windowPoStProofInfo, found := abi.PoStProofInfos[info.WindowPoStProofType]
   707  	acc.Require(found, "miner has unrecognized Window PoSt proof type %d", info.WindowPoStProofType)
   708  	if found {
   709  		acc.Require(windowPoStProofInfo.SectorSize == info.SectorSize,
   710  			"sector size %d is wrong for Window PoSt proof type %d: %d", info.SectorSize, info.WindowPoStProofType, windowPoStProofInfo.SectorSize)
   711  	}
   712  
   713  	poStProofPolicy, found := builtin.PoStProofPolicies[info.WindowPoStProofType]
   714  	acc.Require(found, "no PoSt proof policy exists for proof type %d", info.WindowPoStProofType)
   715  	if found {
   716  		acc.Require(poStProofPolicy.WindowPoStPartitionSectors == info.WindowPoStPartitionSectors,
   717  			"miner partition sectors %d does not match partition sectors %d for PoSt proof type %d",
   718  			info.WindowPoStPartitionSectors, poStProofPolicy.WindowPoStPartitionSectors, info.WindowPoStProofType)
   719  	}
   720  }
   721  
   722  func CheckMinerBalances(st *State, store adt.Store, balance abi.TokenAmount, acc *builtin.MessageAccumulator) {
   723  	acc.Require(balance.GreaterThanEqual(big.Zero()), "miner actor balance is less than zero: %v", balance)
   724  	acc.Require(st.LockedFunds.GreaterThanEqual(big.Zero()), "miner locked funds is less than zero: %v", st.LockedFunds)
   725  	acc.Require(st.PreCommitDeposits.GreaterThanEqual(big.Zero()), "miner precommit deposit is less than zero: %v", st.PreCommitDeposits)
   726  	acc.Require(st.InitialPledge.GreaterThanEqual(big.Zero()), "miner initial pledge is less than zero: %v", st.InitialPledge)
   727  	acc.Require(st.FeeDebt.GreaterThanEqual(big.Zero()), "miner fee debt is less than zero: %v", st.FeeDebt)
   728  
   729  	acc.Require(big.Subtract(balance, st.LockedFunds, st.PreCommitDeposits, st.InitialPledge).GreaterThanEqual(big.Zero()),
   730  		"miner balance (%v) is less than sum of locked funds (%v), precommit deposit (%v), and initial pledge (%v)",
   731  		balance, st.LockedFunds, st.PreCommitDeposits, st.InitialPledge)
   732  
   733  	// locked funds must be sum of vesting table and vesting table payments must be quantized
   734  	vestingSum := big.Zero()
   735  	if funds, err := st.LoadVestingFunds(store); err != nil {
   736  		acc.Addf("error loading vesting funds: %v", err)
   737  	} else {
   738  		quant := st.QuantSpecEveryDeadline()
   739  		for _, entry := range funds.Funds {
   740  			acc.Require(entry.Amount.GreaterThan(big.Zero()), "non-positive amount in miner vesting table entry %v", entry)
   741  			vestingSum = big.Add(vestingSum, entry.Amount)
   742  
   743  			quantized := quant.QuantizeUp(entry.Epoch)
   744  			acc.Require(entry.Epoch == quantized, "vesting table entry has non-quantized epoch %d (should be %d)", entry.Epoch, quantized)
   745  		}
   746  	}
   747  
   748  	acc.Require(st.LockedFunds.Equals(vestingSum),
   749  		"locked funds %d is not sum of vesting table entries %d", st.LockedFunds, vestingSum)
   750  
   751  	// Non zero funds implies that DeadlineCronActive is true.
   752  	if st.ContinueDeadlineCron() {
   753  		acc.Require(st.DeadlineCronActive, "DeadlineCronActive == false when IP+PCD+LF > 0")
   754  	}
   755  }
   756  
   757  func CheckPreCommits(st *State, store adt.Store, allocatedSectors map[uint64]bool, acc *builtin.MessageAccumulator) {
   758  	quant := st.QuantSpecEveryDeadline()
   759  
   760  	// invert pre-commit expiry queue into a lookup by sector number
   761  	expireEpochs := make(map[uint64]abi.ChainEpoch)
   762  	if expiryQ, err := LoadBitfieldQueue(store, st.PreCommittedSectorsExpiry, st.QuantSpecEveryDeadline(), PrecommitExpiryAmtBitwidth); err != nil {
   763  		acc.Addf("error loading pre-commit expiry queue: %v", err)
   764  	} else {
   765  		err = expiryQ.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error {
   766  			quantized := quant.QuantizeUp(epoch)
   767  			acc.Require(quantized == epoch, "precommit expiration %d is not quantized", epoch)
   768  			if err = bf.ForEach(func(secNum uint64) error {
   769  				expireEpochs[secNum] = epoch
   770  				return nil
   771  			}); err != nil {
   772  				acc.Addf("error iteration pre-commit expiration bitfield: %v", err)
   773  			}
   774  			return nil
   775  		})
   776  		acc.RequireNoError(err, "error iterating pre-commit expiry queue")
   777  	}
   778  
   779  	precommitTotal := big.Zero()
   780  	if precommitted, err := adt.AsMap(store, st.PreCommittedSectors, builtin.DefaultHamtBitwidth); err != nil {
   781  		acc.Addf("error loading precommitted sectors: %v", err)
   782  	} else {
   783  		var precommit SectorPreCommitOnChainInfo
   784  		err = precommitted.ForEach(&precommit, func(key string) error {
   785  			secNum, err := abi.ParseUIntKey(key)
   786  			if err != nil {
   787  				acc.Addf("error parsing pre-commit key as uint: %v", err)
   788  				return nil
   789  			}
   790  
   791  			acc.Require(allocatedSectors[secNum], "pre-committed sector number has not been allocated %d", secNum)
   792  
   793  			_, found := expireEpochs[secNum]
   794  			acc.Require(found, "no expiry epoch for pre-commit at %d", precommit.PreCommitEpoch)
   795  
   796  			precommitTotal = big.Add(precommitTotal, precommit.PreCommitDeposit)
   797  			return nil
   798  		})
   799  		acc.RequireNoError(err, "error iterating pre-committed sectors")
   800  	}
   801  
   802  	acc.Require(st.PreCommitDeposits.Equals(precommitTotal),
   803  		"sum of precommit deposits %v does not equal recorded precommit deposit %v", precommitTotal, st.PreCommitDeposits)
   804  }
   805  
   806  // Selects a subset of sectors from a map by sector number.
   807  // Returns the selected sectors, and a slice of any sector numbers not found.
   808  func selectSectorsMap(sectors map[abi.SectorNumber]*SectorOnChainInfo, include bitfield.BitField) (map[abi.SectorNumber]*SectorOnChainInfo, []abi.SectorNumber, error) {
   809  	included := map[abi.SectorNumber]*SectorOnChainInfo{}
   810  	missing := []abi.SectorNumber{}
   811  	if err := include.ForEach(func(n uint64) error {
   812  		if s, ok := sectors[abi.SectorNumber(n)]; ok {
   813  			included[abi.SectorNumber(n)] = s
   814  		} else {
   815  			missing = append(missing, abi.SectorNumber(n))
   816  		}
   817  		return nil
   818  	}); err != nil {
   819  		return nil, nil, err
   820  	}
   821  	return included, missing, nil
   822  }
   823  
   824  func powerForSectors(sectors map[abi.SectorNumber]*SectorOnChainInfo, ssize abi.SectorSize) PowerPair {
   825  	qa := big.Zero()
   826  	for _, s := range sectors { // nolint:nomaprange
   827  		qa = big.Add(qa, QAPowerForSector(ssize, s))
   828  	}
   829  
   830  	return PowerPair{
   831  		Raw: big.Mul(big.NewIntUnsigned(uint64(ssize)), big.NewIntUnsigned(uint64(len(sectors)))),
   832  		QA:  qa,
   833  	}
   834  }
   835  
   836  func requireContainsAll(superset, subset bitfield.BitField, acc *builtin.MessageAccumulator, msg string) {
   837  	if contains, err := util.BitFieldContainsAll(superset, subset); err != nil {
   838  		acc.Addf("error in BitfieldContainsAll(): %v", err)
   839  	} else if !contains {
   840  		acc.Addf(msg+": %v, %v", superset, subset)
   841  		// Verbose output for debugging
   842  		//sup, err := superset.All(1 << 20)
   843  		//if err != nil {
   844  		//	acc.Addf("error in Bitfield.All(): %v", err)
   845  		//	return
   846  		//}
   847  		//sub, err := subset.All(1 << 20)
   848  		//if err != nil {
   849  		//	acc.Addf("error in Bitfield.All(): %v", err)
   850  		//	return
   851  		//}
   852  		//acc.Addf(msg+": %v, %v", sup, sub)
   853  	}
   854  }
   855  
   856  func requireContainsNone(superset, subset bitfield.BitField, acc *builtin.MessageAccumulator, msg string) {
   857  	if contains, err := util.BitFieldContainsAny(superset, subset); err != nil {
   858  		acc.Addf("error in BitfieldContainsAny(): %v", err)
   859  	} else if contains {
   860  		acc.Addf(msg+": %v, %v", superset, subset)
   861  		// Verbose output for debugging
   862  		//sup, err := superset.All(1 << 20)
   863  		//if err != nil {
   864  		//	acc.Addf("error in Bitfield.All(): %v", err)
   865  		//	return
   866  		//}
   867  		//sub, err := subset.All(1 << 20)
   868  		//if err != nil {
   869  		//	acc.Addf("error in Bitfield.All(): %v", err)
   870  		//	return
   871  		//}
   872  		//acc.Addf(msg+": %v, %v", sup, sub)
   873  	}
   874  }
   875  
   876  func requireEqual(a, b bitfield.BitField, acc *builtin.MessageAccumulator, msg string) {
   877  	requireContainsAll(a, b, acc, msg)
   878  	requireContainsAll(b, a, acc, msg)
   879  }