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(§or, 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 }