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

     1  package miner
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"math"
     8  
     9  	addr "github.com/filecoin-project/go-address"
    10  	"github.com/filecoin-project/go-bitfield"
    11  	"github.com/filecoin-project/go-state-types/abi"
    12  	"github.com/filecoin-project/go-state-types/big"
    13  	"github.com/filecoin-project/go-state-types/cbor"
    14  	"github.com/filecoin-project/go-state-types/crypto"
    15  	"github.com/filecoin-project/go-state-types/dline"
    16  	"github.com/filecoin-project/go-state-types/exitcode"
    17  	rtt "github.com/filecoin-project/go-state-types/rt"
    18  	miner0 "github.com/filecoin-project/specs-actors/actors/builtin/miner"
    19  	miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner"
    20  	miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner"
    21  	cid "github.com/ipfs/go-cid"
    22  	cbg "github.com/whyrusleeping/cbor-gen"
    23  	"golang.org/x/xerrors"
    24  
    25  	"github.com/filecoin-project/specs-actors/v4/actors/builtin"
    26  	"github.com/filecoin-project/specs-actors/v4/actors/builtin/market"
    27  	"github.com/filecoin-project/specs-actors/v4/actors/builtin/power"
    28  	"github.com/filecoin-project/specs-actors/v4/actors/builtin/reward"
    29  	"github.com/filecoin-project/specs-actors/v4/actors/runtime"
    30  	"github.com/filecoin-project/specs-actors/v4/actors/runtime/proof"
    31  	. "github.com/filecoin-project/specs-actors/v4/actors/util"
    32  	"github.com/filecoin-project/specs-actors/v4/actors/util/adt"
    33  	"github.com/filecoin-project/specs-actors/v4/actors/util/smoothing"
    34  )
    35  
    36  type Runtime = runtime.Runtime
    37  
    38  const (
    39  	// The first 1000 actor-specific codes are left open for user error, i.e. things that might
    40  	// actually happen without programming error in the actor code.
    41  	//ErrToBeDetermined = exitcode.FirstActorSpecificExitCode + iota
    42  
    43  	// The following errors are particular cases of illegal state.
    44  	// They're not expected to ever happen, but if they do, distinguished codes can help us
    45  	// diagnose the problem.
    46  	ErrBalanceInvariantBroken = 1000
    47  )
    48  
    49  type Actor struct{}
    50  
    51  func (a Actor) Exports() []interface{} {
    52  	return []interface{}{
    53  		builtin.MethodConstructor: a.Constructor,
    54  		2:                         a.ControlAddresses,
    55  		3:                         a.ChangeWorkerAddress,
    56  		4:                         a.ChangePeerID,
    57  		5:                         a.SubmitWindowedPoSt,
    58  		6:                         a.PreCommitSector,
    59  		7:                         a.ProveCommitSector,
    60  		8:                         a.ExtendSectorExpiration,
    61  		9:                         a.TerminateSectors,
    62  		10:                        a.DeclareFaults,
    63  		11:                        a.DeclareFaultsRecovered,
    64  		12:                        a.OnDeferredCronEvent,
    65  		13:                        a.CheckSectorProven,
    66  		14:                        a.ApplyRewards,
    67  		15:                        a.ReportConsensusFault,
    68  		16:                        a.WithdrawBalance,
    69  		17:                        a.ConfirmSectorProofsValid,
    70  		18:                        a.ChangeMultiaddrs,
    71  		19:                        a.CompactPartitions,
    72  		20:                        a.CompactSectorNumbers,
    73  		21:                        a.ConfirmUpdateWorkerKey,
    74  		22:                        a.RepayDebt,
    75  		23:                        a.ChangeOwnerAddress,
    76  		24:                        a.DisputeWindowedPoSt,
    77  	}
    78  }
    79  
    80  func (a Actor) Code() cid.Cid {
    81  	return builtin.StorageMinerActorCodeID
    82  }
    83  
    84  func (a Actor) State() cbor.Er {
    85  	return new(State)
    86  }
    87  
    88  var _ runtime.VMActor = Actor{}
    89  
    90  /////////////////
    91  // Constructor //
    92  /////////////////
    93  
    94  // Storage miner actors are created exclusively by the storage power actor. In order to break a circular dependency
    95  // between the two, the construction parameters are defined in the power actor.
    96  type ConstructorParams = power.MinerConstructorParams
    97  
    98  func (a Actor) Constructor(rt Runtime, params *ConstructorParams) *abi.EmptyValue {
    99  	rt.ValidateImmediateCallerIs(builtin.InitActorAddr)
   100  
   101  	checkControlAddresses(rt, params.ControlAddrs)
   102  	checkPeerInfo(rt, params.PeerId, params.Multiaddrs)
   103  
   104  	owner := resolveControlAddress(rt, params.OwnerAddr)
   105  	worker := resolveWorkerAddress(rt, params.WorkerAddr)
   106  	controlAddrs := make([]addr.Address, 0, len(params.ControlAddrs))
   107  	for _, ca := range params.ControlAddrs {
   108  		resolved := resolveControlAddress(rt, ca)
   109  		controlAddrs = append(controlAddrs, resolved)
   110  	}
   111  
   112  	currEpoch := rt.CurrEpoch()
   113  	offset, err := assignProvingPeriodOffset(rt.Receiver(), currEpoch, rt.HashBlake2b)
   114  	builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to assign proving period offset")
   115  	periodStart := currentProvingPeriodStart(currEpoch, offset)
   116  	builtin.RequireState(rt, periodStart <= currEpoch, "computed proving period start %d after current epoch %d", periodStart, currEpoch)
   117  	deadlineIndex := currentDeadlineIndex(currEpoch, periodStart)
   118  	builtin.RequireState(rt, deadlineIndex < WPoStPeriodDeadlines, "computed proving deadline index %d invalid", deadlineIndex)
   119  
   120  	info, err := ConstructMinerInfo(owner, worker, controlAddrs, params.PeerId, params.Multiaddrs, params.WindowPoStProofType)
   121  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to construct initial miner info")
   122  	infoCid := rt.StorePut(info)
   123  
   124  	store := adt.AsStore(rt)
   125  	state, err := ConstructState(store, infoCid, periodStart, deadlineIndex)
   126  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to construct state")
   127  	rt.StateCreate(state)
   128  
   129  	return nil
   130  }
   131  
   132  /////////////
   133  // Control //
   134  /////////////
   135  
   136  // type GetControlAddressesReturn struct {
   137  // 	Owner        addr.Address
   138  // 	Worker       addr.Address
   139  // 	ControlAddrs []addr.Address
   140  // }
   141  type GetControlAddressesReturn = miner2.GetControlAddressesReturn
   142  
   143  func (a Actor) ControlAddresses(rt Runtime, _ *abi.EmptyValue) *GetControlAddressesReturn {
   144  	rt.ValidateImmediateCallerAcceptAny()
   145  	var st State
   146  	rt.StateReadonly(&st)
   147  	info := getMinerInfo(rt, &st)
   148  	return &GetControlAddressesReturn{
   149  		Owner:        info.Owner,
   150  		Worker:       info.Worker,
   151  		ControlAddrs: info.ControlAddresses,
   152  	}
   153  }
   154  
   155  //type ChangeWorkerAddressParams struct {
   156  //	NewWorker       addr.Address
   157  //	NewControlAddrs []addr.Address
   158  //}
   159  type ChangeWorkerAddressParams = miner0.ChangeWorkerAddressParams
   160  
   161  // ChangeWorkerAddress will ALWAYS overwrite the existing control addresses with the control addresses passed in the params.
   162  // If a nil addresses slice is passed, the control addresses will be cleared.
   163  // A worker change will be scheduled if the worker passed in the params is different from the existing worker.
   164  func (a Actor) ChangeWorkerAddress(rt Runtime, params *ChangeWorkerAddressParams) *abi.EmptyValue {
   165  	checkControlAddresses(rt, params.NewControlAddrs)
   166  
   167  	newWorker := resolveWorkerAddress(rt, params.NewWorker)
   168  
   169  	var controlAddrs []addr.Address
   170  	for _, ca := range params.NewControlAddrs {
   171  		resolved := resolveControlAddress(rt, ca)
   172  		controlAddrs = append(controlAddrs, resolved)
   173  	}
   174  
   175  	var st State
   176  	rt.StateTransaction(&st, func() {
   177  		info := getMinerInfo(rt, &st)
   178  
   179  		// Only the Owner is allowed to change the newWorker and control addresses.
   180  		rt.ValidateImmediateCallerIs(info.Owner)
   181  
   182  		// save the new control addresses
   183  		info.ControlAddresses = controlAddrs
   184  
   185  		// save newWorker addr key change request
   186  		if newWorker != info.Worker && info.PendingWorkerKey == nil {
   187  			info.PendingWorkerKey = &WorkerKeyChange{
   188  				NewWorker:   newWorker,
   189  				EffectiveAt: rt.CurrEpoch() + WorkerKeyChangeDelay,
   190  			}
   191  		}
   192  
   193  		err := st.SaveInfo(adt.AsStore(rt), info)
   194  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info")
   195  	})
   196  
   197  	return nil
   198  }
   199  
   200  // Triggers a worker address change if a change has been requested and its effective epoch has arrived.
   201  func (a Actor) ConfirmUpdateWorkerKey(rt Runtime, params *abi.EmptyValue) *abi.EmptyValue {
   202  	var st State
   203  	rt.StateTransaction(&st, func() {
   204  		info := getMinerInfo(rt, &st)
   205  
   206  		// Only the Owner is allowed to change the newWorker.
   207  		rt.ValidateImmediateCallerIs(info.Owner)
   208  
   209  		processPendingWorker(info, rt, &st)
   210  	})
   211  
   212  	return nil
   213  }
   214  
   215  // Proposes or confirms a change of owner address.
   216  // If invoked by the current owner, proposes a new owner address for confirmation. If the proposed address is the
   217  // current owner address, revokes any existing proposal.
   218  // If invoked by the previously proposed address, with the same proposal, changes the current owner address to be
   219  // that proposed address.
   220  func (a Actor) ChangeOwnerAddress(rt Runtime, newAddress *addr.Address) *abi.EmptyValue {
   221  	if newAddress.Empty() {
   222  		rt.Abortf(exitcode.ErrIllegalArgument, "empty address")
   223  	}
   224  	if newAddress.Protocol() != addr.ID {
   225  		rt.Abortf(exitcode.ErrIllegalArgument, "owner address must be an ID address")
   226  	}
   227  	var st State
   228  	rt.StateTransaction(&st, func() {
   229  		info := getMinerInfo(rt, &st)
   230  		if rt.Caller() == info.Owner || info.PendingOwnerAddress == nil {
   231  			// Propose new address.
   232  			rt.ValidateImmediateCallerIs(info.Owner)
   233  			info.PendingOwnerAddress = newAddress
   234  		} else { // info.PendingOwnerAddress != nil
   235  			// Confirm the proposal.
   236  			// This validates that the operator can in fact use the proposed new address to sign messages.
   237  			rt.ValidateImmediateCallerIs(*info.PendingOwnerAddress)
   238  			if *newAddress != *info.PendingOwnerAddress {
   239  				rt.Abortf(exitcode.ErrIllegalArgument, "expected confirmation of %v, got %v",
   240  					info.PendingOwnerAddress, newAddress)
   241  			}
   242  			info.Owner = *info.PendingOwnerAddress
   243  		}
   244  
   245  		// Clear any resulting no-op change.
   246  		if info.PendingOwnerAddress != nil && *info.PendingOwnerAddress == info.Owner {
   247  			info.PendingOwnerAddress = nil
   248  		}
   249  
   250  		err := st.SaveInfo(adt.AsStore(rt), info)
   251  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save miner info")
   252  	})
   253  	return nil
   254  }
   255  
   256  //type ChangePeerIDParams struct {
   257  //	NewID abi.PeerID
   258  //}
   259  type ChangePeerIDParams = miner0.ChangePeerIDParams
   260  
   261  func (a Actor) ChangePeerID(rt Runtime, params *ChangePeerIDParams) *abi.EmptyValue {
   262  	checkPeerInfo(rt, params.NewID, nil)
   263  
   264  	var st State
   265  	rt.StateTransaction(&st, func() {
   266  		info := getMinerInfo(rt, &st)
   267  
   268  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
   269  
   270  		info.PeerId = params.NewID
   271  		err := st.SaveInfo(adt.AsStore(rt), info)
   272  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info")
   273  	})
   274  	return nil
   275  }
   276  
   277  //type ChangeMultiaddrsParams struct {
   278  //	NewMultiaddrs []abi.Multiaddrs
   279  //}
   280  type ChangeMultiaddrsParams = miner0.ChangeMultiaddrsParams
   281  
   282  func (a Actor) ChangeMultiaddrs(rt Runtime, params *ChangeMultiaddrsParams) *abi.EmptyValue {
   283  	checkPeerInfo(rt, nil, params.NewMultiaddrs)
   284  
   285  	var st State
   286  	rt.StateTransaction(&st, func() {
   287  		info := getMinerInfo(rt, &st)
   288  
   289  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
   290  
   291  		info.Multiaddrs = params.NewMultiaddrs
   292  		err := st.SaveInfo(adt.AsStore(rt), info)
   293  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info")
   294  	})
   295  	return nil
   296  }
   297  
   298  //////////////////
   299  // WindowedPoSt //
   300  //////////////////
   301  
   302  //type PoStPartition struct {
   303  //	// Partitions are numbered per-deadline, from zero.
   304  //	Index uint64
   305  //	// Sectors skipped while proving that weren't already declared faulty
   306  //	Skipped bitfield.BitField
   307  //}
   308  type PoStPartition = miner0.PoStPartition
   309  
   310  // Information submitted by a miner to provide a Window PoSt.
   311  //type SubmitWindowedPoStParams struct {
   312  //	// The deadline index which the submission targets.
   313  //	Deadline uint64
   314  //	// The partitions being proven.
   315  //	Partitions []PoStPartition
   316  //	// Array of proofs, one per distinct registered proof type present in the sectors being proven.
   317  //	// In the usual case of a single proof type, this array will always have a single element (independent of number of partitions).
   318  //	Proofs []proof.PoStProof
   319  //	// The epoch at which these proofs is being committed to a particular chain.
   320  //	// NOTE: This field should be removed in the future. See
   321  //	// https://github.com/filecoin-project/specs-actors/issues/1094
   322  //	ChainCommitEpoch abi.ChainEpoch
   323  //	// The ticket randomness on the chain at the chain commit epoch.
   324  //	ChainCommitRand abi.Randomness
   325  //}
   326  type SubmitWindowedPoStParams = miner0.SubmitWindowedPoStParams
   327  
   328  // Invoked by miner's worker address to submit their fallback post
   329  func (a Actor) SubmitWindowedPoSt(rt Runtime, params *SubmitWindowedPoStParams) *abi.EmptyValue {
   330  	currEpoch := rt.CurrEpoch()
   331  	store := adt.AsStore(rt)
   332  	var st State
   333  
   334  	if params.Deadline >= WPoStPeriodDeadlines {
   335  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid deadline %d of %d", params.Deadline, WPoStPeriodDeadlines)
   336  	}
   337  	// Technically, ChainCommitRand should be _exactly_ 32 bytes. However:
   338  	// 1. It's convenient to allow smaller slices when testing.
   339  	// 2. Nothing bad will happen if the caller provides too little randomness.
   340  	if len(params.ChainCommitRand) > abi.RandomnessLength {
   341  		rt.Abortf(exitcode.ErrIllegalArgument, "expected at most %d bytes of randomness, got %d", abi.RandomnessLength, len(params.ChainCommitRand))
   342  	}
   343  
   344  	var postResult *PoStResult
   345  	var info *MinerInfo
   346  	rt.StateTransaction(&st, func() {
   347  		info = getMinerInfo(rt, &st)
   348  		maxProofSize, err := info.WindowPoStProofType.ProofSize()
   349  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to determine max window post proof size")
   350  
   351  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
   352  
   353  		// Verify that the miner has passed 0 or 1 proofs. If they've
   354  		// passed 1, verify that it's a good proof.
   355  		//
   356  		// This can be 0 if the miner isn't actually proving anything,
   357  		// just skipping all sectors.
   358  		if len(params.Proofs) != 1 {
   359  			rt.Abortf(exitcode.ErrIllegalArgument, "expected exactly one proof, got %d", len(params.Proofs))
   360  		}
   361  
   362  		// Make sure the miner is using the correct proof type.
   363  		if params.Proofs[0].PoStProof != info.WindowPoStProofType {
   364  			rt.Abortf(exitcode.ErrIllegalArgument, "expected proof of type %s, got proof of type %s", info.WindowPoStProofType, params.Proofs[0])
   365  		}
   366  
   367  		// Make sure the proof size doesn't exceed the max. We could probably check for an exact match, but this is safer.
   368  		if maxSize := maxProofSize * uint64(len(params.Partitions)); uint64(len(params.Proofs[0].ProofBytes)) > maxSize {
   369  			rt.Abortf(exitcode.ErrIllegalArgument, "expected proof to be smaller than %d bytes", maxSize)
   370  		}
   371  
   372  		// Validate that the miner didn't try to prove too many partitions at once.
   373  		submissionPartitionLimit := loadPartitionsSectorsMax(info.WindowPoStPartitionSectors)
   374  		if uint64(len(params.Partitions)) > submissionPartitionLimit {
   375  			rt.Abortf(exitcode.ErrIllegalArgument, "too many partitions %d, limit %d", len(params.Partitions), submissionPartitionLimit)
   376  		}
   377  
   378  		currDeadline := st.DeadlineInfo(currEpoch)
   379  		// Check that the miner state indicates that the current proving deadline has started.
   380  		// This should only fail if the cron actor wasn't invoked, and matters only in case that it hasn't been
   381  		// invoked for a whole proving period, and hence the missed PoSt submissions from the prior occurrence
   382  		// of this deadline haven't been processed yet.
   383  		if !currDeadline.IsOpen() {
   384  			rt.Abortf(exitcode.ErrIllegalState, "proving period %d not yet open at %d", currDeadline.PeriodStart, currEpoch)
   385  		}
   386  
   387  		// The miner may only submit a proof for the current deadline.
   388  		if params.Deadline != currDeadline.Index {
   389  			rt.Abortf(exitcode.ErrIllegalArgument, "invalid deadline %d at epoch %d, expected %d",
   390  				params.Deadline, currEpoch, currDeadline.Index)
   391  		}
   392  
   393  		// Verify that the PoSt was committed to the chain at most WPoStChallengeLookback+WPoStChallengeWindow in the past.
   394  		if params.ChainCommitEpoch < currDeadline.Challenge {
   395  			rt.Abortf(exitcode.ErrIllegalArgument, "expected chain commit epoch %d to be after %d", params.ChainCommitEpoch, currDeadline.Challenge)
   396  		}
   397  		if params.ChainCommitEpoch >= currEpoch {
   398  			rt.Abortf(exitcode.ErrIllegalArgument, "chain commit epoch %d must be less than the current epoch %d", params.ChainCommitEpoch, currEpoch)
   399  		}
   400  		// Verify the chain commit randomness.
   401  		commRand := rt.GetRandomnessFromTickets(crypto.DomainSeparationTag_PoStChainCommit, params.ChainCommitEpoch, nil)
   402  		if !bytes.Equal(commRand, params.ChainCommitRand) {
   403  			rt.Abortf(exitcode.ErrIllegalArgument, "post commit randomness mismatched")
   404  		}
   405  
   406  		sectors, err := LoadSectors(store, st.Sectors)
   407  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors")
   408  
   409  		deadlines, err := st.LoadDeadlines(adt.AsStore(rt))
   410  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
   411  
   412  		deadline, err := deadlines.LoadDeadline(store, params.Deadline)
   413  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %d", params.Deadline)
   414  
   415  		// Record proven sectors/partitions, returning updates to power and the final set of sectors
   416  		// proven/skipped.
   417  		//
   418  		// NOTE: This function does not actually check the proofs but does assume that they're correct. Instead,
   419  		// it snapshots the deadline's state and the submitted proofs at the end of the challenge window and
   420  		// allows third-parties to dispute these proofs.
   421  		//
   422  		// While we could perform _all_ operations at the end of challenge window, we do as we can here to avoid
   423  		// overloading cron.
   424  		faultExpiration := currDeadline.Last() + FaultMaxAge
   425  		postResult, err = deadline.RecordProvenSectors(store, sectors, info.SectorSize, QuantSpecForDeadline(currDeadline), faultExpiration, params.Partitions)
   426  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to process post submission for deadline %d", params.Deadline)
   427  
   428  		// Make sure we actually proved something.
   429  
   430  		provenSectors, err := bitfield.SubtractBitField(postResult.Sectors, postResult.IgnoredSectors)
   431  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to determine proven sectors for deadline %d", params.Deadline)
   432  
   433  		noSectors, err := provenSectors.IsEmpty()
   434  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to determine if any sectors were proven", params.Deadline)
   435  		if noSectors {
   436  			// Abort verification if all sectors are (now) faults. There's nothing to prove.
   437  			// It's not rational for a miner to submit a Window PoSt marking *all* non-faulty sectors as skipped,
   438  			// since that will just cause them to pay a penalty at deadline end that would otherwise be zero
   439  			// if they had *not* declared them.
   440  			rt.Abortf(exitcode.ErrIllegalArgument, "cannot prove partitions with no active sectors")
   441  		}
   442  
   443  		// If we're not recovering power, record the proof for optimistic verification.
   444  		if postResult.RecoveredPower.IsZero() {
   445  			err = deadline.RecordPoStProofs(store, postResult.Partitions, params.Proofs)
   446  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to record proof for optimistic verification", params.Deadline)
   447  		} else {
   448  			// otherwise, check the proof
   449  			sectorInfos, err := sectors.LoadForProof(postResult.Sectors, postResult.IgnoredSectors)
   450  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors for post verification")
   451  
   452  			err = verifyWindowedPost(rt, currDeadline.Challenge, sectorInfos, params.Proofs)
   453  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "window post failed")
   454  		}
   455  
   456  		err = deadlines.UpdateDeadline(store, params.Deadline, deadline)
   457  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update deadline %d", params.Deadline)
   458  
   459  		err = st.SaveDeadlines(store, deadlines)
   460  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
   461  	})
   462  
   463  	// Restore power for recovered sectors. Remove power for new faults.
   464  	// NOTE: It would be permissible to delay the power loss until the deadline closes, but that would require
   465  	// additional accounting state.
   466  	// https://github.com/filecoin-project/specs-actors/issues/414
   467  	requestUpdatePower(rt, postResult.PowerDelta)
   468  
   469  	rt.StateReadonly(&st)
   470  	err := st.CheckBalanceInvariants(rt.CurrentBalance())
   471  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
   472  
   473  	return nil
   474  }
   475  
   476  // type DisputeWindowedPoStParams struct {
   477  // 		Deadline  uint64
   478  // 		PoStIndex uint64 // only one is allowed at a time to avoid loading too many sector infos.
   479  // }
   480  type DisputeWindowedPoStParams = miner3.DisputeWindowedPoStParams
   481  
   482  func (a Actor) DisputeWindowedPoSt(rt Runtime, params *DisputeWindowedPoStParams) *abi.EmptyValue {
   483  	rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...)
   484  	reporter := rt.Caller()
   485  
   486  	if params.Deadline >= WPoStPeriodDeadlines {
   487  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid deadline %d of %d", params.Deadline, WPoStPeriodDeadlines)
   488  	}
   489  
   490  	currEpoch := rt.CurrEpoch()
   491  
   492  	// Note: these are going to be slightly inaccurate as time
   493  	// will have moved on from when the post was actually
   494  	// submitted.
   495  	//
   496  	// However, these are estimates _anyways_.
   497  	epochReward := requestCurrentEpochBlockReward(rt)
   498  	pwrTotal := requestCurrentTotalPower(rt)
   499  
   500  	toBurn := abi.NewTokenAmount(0)
   501  	toReward := abi.NewTokenAmount(0)
   502  	pledgeDelta := abi.NewTokenAmount(0)
   503  	powerDelta := NewPowerPairZero()
   504  	var st State
   505  	rt.StateTransaction(&st, func() {
   506  		dlInfo := st.DeadlineInfo(currEpoch)
   507  		if !deadlineAvailableForOptimisticPoStDispute(dlInfo.PeriodStart, params.Deadline, currEpoch) {
   508  			rt.Abortf(exitcode.ErrForbidden, "can only dispute window posts during the dispute window (%d epochs after the challenge window closes)", WPoStDisputeWindow)
   509  		}
   510  
   511  		info := getMinerInfo(rt, &st)
   512  		penalisedPower := NewPowerPairZero()
   513  		store := adt.AsStore(rt)
   514  
   515  		// Check proof
   516  		{
   517  			// Find the proving period start for the deadline in question.
   518  			ppStart := dlInfo.PeriodStart
   519  			if dlInfo.Index < params.Deadline {
   520  				ppStart -= WPoStProvingPeriod
   521  			}
   522  			targetDeadline := NewDeadlineInfo(ppStart, params.Deadline, currEpoch)
   523  
   524  			// Load the target deadline.
   525  			deadlinesCurrent, err := st.LoadDeadlines(store)
   526  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
   527  
   528  			dlCurrent, err := deadlinesCurrent.LoadDeadline(store, params.Deadline)
   529  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline")
   530  
   531  			// Take the post from the snapshot for dispute.
   532  			// This operation REMOVES the PoSt from the snapshot so
   533  			// it can't be disputed again. If this method fails,
   534  			// this operation must be rolled back.
   535  			partitions, proofs, err := dlCurrent.TakePoStProofs(store, params.PoStIndex)
   536  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load proof for dispute")
   537  
   538  			// Load the partition info we need for the dispute.
   539  			disputeInfo, err := dlCurrent.LoadPartitionsForDispute(store, partitions)
   540  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load partition info for dispute")
   541  			// This includes power that is no longer active (e.g., due to sector terminations).
   542  			// It must only be used for penalty calculations, not power adjustments.
   543  			penalisedPower = disputeInfo.DisputedPower
   544  
   545  			// Load sectors for the dispute.
   546  			sectors, err := LoadSectors(store, st.Sectors)
   547  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors array")
   548  
   549  			sectorInfos, err := sectors.LoadForProof(disputeInfo.AllSectorNos, disputeInfo.IgnoredSectorNos)
   550  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors to dispute window post")
   551  
   552  			// Check proof, we fail if validation succeeds.
   553  			err = verifyWindowedPost(rt, targetDeadline.Challenge, sectorInfos, proofs)
   554  			if err == nil {
   555  				rt.Abortf(exitcode.ErrIllegalArgument, "failed to dispute valid post")
   556  				return
   557  			}
   558  			rt.Log(rtt.INFO, "successfully disputed: %s", err)
   559  
   560  			// Ok, now we record faults. This always works because
   561  			// we don't allow compaction/moving sectors during the
   562  			// challenge window.
   563  			//
   564  			// However, some of these sectors may have been
   565  			// terminated. That's fine, we'll skip them.
   566  			faultExpirationEpoch := targetDeadline.Last() + FaultMaxAge
   567  			powerDelta, err = dlCurrent.RecordFaults(store, sectors, info.SectorSize, QuantSpecForDeadline(targetDeadline), faultExpirationEpoch, disputeInfo.DisputedSectors)
   568  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to declare faults")
   569  
   570  			err = deadlinesCurrent.UpdateDeadline(store, params.Deadline, dlCurrent)
   571  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update deadline %d", params.Deadline)
   572  			err = st.SaveDeadlines(store, deadlinesCurrent)
   573  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
   574  		}
   575  
   576  		// Penalties.
   577  		{
   578  			// Calculate the base penalty.
   579  			penaltyBase := PledgePenaltyForInvalidWindowPoSt(
   580  				epochReward.ThisEpochRewardSmoothed,
   581  				pwrTotal.QualityAdjPowerSmoothed,
   582  				penalisedPower.QA,
   583  			)
   584  
   585  			// Calculate the target reward.
   586  			rewardTarget := RewardForDisputedWindowPoSt(info.WindowPoStProofType, penalisedPower)
   587  
   588  			// Compute the target penalty by adding the
   589  			// base penalty to the target reward. We don't
   590  			// take reward out of the penalty as the miner
   591  			// could end up receiving a substantial
   592  			// portion of their fee back as a reward.
   593  			penaltyTarget := big.Add(penaltyBase, rewardTarget)
   594  
   595  			err := st.ApplyPenalty(penaltyTarget)
   596  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to apply penalty")
   597  			penaltyFromVesting, penaltyFromBalance, err := st.RepayPartialDebtInPriorityOrder(store, currEpoch, rt.CurrentBalance())
   598  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to pay debt")
   599  			toBurn = big.Add(penaltyFromVesting, penaltyFromBalance)
   600  
   601  			// Now, move as much of the target reward as
   602  			// we can from the burn to the reward.
   603  			toReward = big.Min(toBurn, rewardTarget)
   604  			toBurn = big.Sub(toBurn, toReward)
   605  
   606  			pledgeDelta = penaltyFromVesting.Neg()
   607  		}
   608  	})
   609  
   610  	requestUpdatePower(rt, powerDelta)
   611  
   612  	if !toReward.IsZero() {
   613  		// Try to send the reward to the reporter.
   614  		code := rt.Send(reporter, builtin.MethodSend, nil, toReward, &builtin.Discard{})
   615  
   616  		// If we fail, log and burn the reward to make sure the balances remain correct.
   617  		if !code.IsSuccess() {
   618  			rt.Log(rtt.ERROR, "failed to send reward")
   619  			toBurn = big.Add(toBurn, toReward)
   620  		}
   621  	}
   622  	burnFunds(rt, toBurn)
   623  	notifyPledgeChanged(rt, pledgeDelta)
   624  	rt.StateReadonly(&st)
   625  
   626  	err := st.CheckBalanceInvariants(rt.CurrentBalance())
   627  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
   628  	return nil
   629  }
   630  
   631  ///////////////////////
   632  // Sector Commitment //
   633  ///////////////////////
   634  
   635  //type SectorPreCommitInfo struct {
   636  //	SealProof       abi.RegisteredSealProof
   637  //	SectorNumber    abi.SectorNumber
   638  //	SealedCID       cid.Cid `checked:"true"` // CommR
   639  //	SealRandEpoch   abi.ChainEpoch
   640  //	DealIDs         []abi.DealID
   641  //	Expiration      abi.ChainEpoch
   642  //	ReplaceCapacity bool // Whether to replace a "committed capacity" no-deal sector (requires non-empty DealIDs)
   643  //	// The committed capacity sector to replace, and it's deadline/partition location
   644  //	ReplaceSectorDeadline  uint64
   645  //	ReplaceSectorPartition uint64
   646  //	ReplaceSectorNumber    abi.SectorNumber
   647  //}
   648  type PreCommitSectorParams = miner0.SectorPreCommitInfo
   649  
   650  // Proposals must be posted on chain via sma.PublishStorageDeals before PreCommitSector.
   651  // Optimization: PreCommitSector could contain a list of deals that are not published yet.
   652  func (a Actor) PreCommitSector(rt Runtime, params *PreCommitSectorParams) *abi.EmptyValue {
   653  	nv := rt.NetworkVersion()
   654  	if !CanPreCommitSealProof(params.SealProof, nv) {
   655  		rt.Abortf(exitcode.ErrIllegalArgument, "unsupported seal proof type %v at network version %v", params.SealProof, nv)
   656  	}
   657  	if params.SectorNumber > abi.MaxSectorNumber {
   658  		rt.Abortf(exitcode.ErrIllegalArgument, "sector number %d out of range 0..(2^63-1)", params.SectorNumber)
   659  	}
   660  	if !params.SealedCID.Defined() {
   661  		rt.Abortf(exitcode.ErrIllegalArgument, "sealed CID undefined")
   662  	}
   663  	if params.SealedCID.Prefix() != SealedCIDPrefix {
   664  		rt.Abortf(exitcode.ErrIllegalArgument, "sealed CID had wrong prefix")
   665  	}
   666  	if params.SealRandEpoch >= rt.CurrEpoch() {
   667  		rt.Abortf(exitcode.ErrIllegalArgument, "seal challenge epoch %v must be before now %v", params.SealRandEpoch, rt.CurrEpoch())
   668  	}
   669  
   670  	challengeEarliest := rt.CurrEpoch() - MaxPreCommitRandomnessLookback
   671  	if params.SealRandEpoch < challengeEarliest {
   672  		rt.Abortf(exitcode.ErrIllegalArgument, "seal challenge epoch %v too old, must be after %v", params.SealRandEpoch, challengeEarliest)
   673  	}
   674  
   675  	// Require sector lifetime meets minimum by assuming activation happens at last epoch permitted for seal proof.
   676  	// This could make sector maximum lifetime validation more lenient if the maximum sector limit isn't hit first.
   677  	maxActivation := rt.CurrEpoch() + MaxProveCommitDuration[params.SealProof]
   678  	validateExpiration(rt, maxActivation, params.Expiration, params.SealProof)
   679  
   680  	if params.ReplaceCapacity && len(params.DealIDs) == 0 {
   681  		rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector without committing deals")
   682  	}
   683  	if params.ReplaceSectorDeadline >= WPoStPeriodDeadlines {
   684  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid deadline %d", params.ReplaceSectorDeadline)
   685  	}
   686  	if params.ReplaceSectorNumber > abi.MaxSectorNumber {
   687  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid sector number %d", params.ReplaceSectorNumber)
   688  	}
   689  
   690  	// gather information from other actors
   691  
   692  	rewardStats := requestCurrentEpochBlockReward(rt)
   693  	pwrTotal := requestCurrentTotalPower(rt)
   694  	dealWeights := requestDealWeights(rt, []market.SectorDeals{
   695  		{
   696  			SectorExpiry: params.Expiration,
   697  			DealIDs:      params.DealIDs,
   698  		},
   699  	})
   700  	if len(dealWeights.Sectors) == 0 {
   701  		rt.Abortf(exitcode.ErrIllegalState, "deal weight request returned no records")
   702  	}
   703  	dealWeight := dealWeights.Sectors[0]
   704  
   705  	store := adt.AsStore(rt)
   706  	var st State
   707  	var err error
   708  	newlyVested := big.Zero()
   709  	feeToBurn := abi.NewTokenAmount(0)
   710  	var needsCron bool
   711  	rt.StateTransaction(&st, func() {
   712  		// available balance already accounts for fee debt so it is correct to call
   713  		// this before RepayDebts. We would have to
   714  		// subtract fee debt explicitly if we called this after.
   715  		availableBalance, err := st.GetAvailableBalance(rt.CurrentBalance())
   716  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to calculate available balance")
   717  		feeToBurn = RepayDebtsOrAbort(rt, &st)
   718  
   719  		info := getMinerInfo(rt, &st)
   720  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
   721  
   722  		if ConsensusFaultActive(info, rt.CurrEpoch()) {
   723  			rt.Abortf(exitcode.ErrForbidden, "precommit not allowed during active consensus fault")
   724  		}
   725  
   726  		// From network version 7, the pre-commit seal type must have the same Window PoSt proof type as the miner,
   727  		// rather than be exactly the same seal type.
   728  		// This permits a transition window from V1 to V1_1 seal types (which share Window PoSt proof type).
   729  		sectorWPoStProof, err := params.SealProof.RegisteredWindowPoStProof()
   730  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to lookup Window PoSt proof type for sector seal proof %d", params.SealProof)
   731  		if sectorWPoStProof != info.WindowPoStProofType {
   732  			rt.Abortf(exitcode.ErrIllegalArgument, "sector Window PoSt proof type %d must match miner Window PoSt proof type %d (seal proof type %d)",
   733  				sectorWPoStProof, info.WindowPoStProofType, params.SealProof)
   734  		}
   735  
   736  		dealCountMax := SectorDealsMax(info.SectorSize)
   737  		if uint64(len(params.DealIDs)) > dealCountMax {
   738  			rt.Abortf(exitcode.ErrIllegalArgument, "too many deals for sector %d > %d", len(params.DealIDs), dealCountMax)
   739  		}
   740  
   741  		// Ensure total deal space does not exceed sector size.
   742  		if dealWeight.DealSpace > uint64(info.SectorSize) {
   743  			rt.Abortf(exitcode.ErrIllegalArgument, "deals too large to fit in sector %d > %d", dealWeight.DealSpace, info.SectorSize)
   744  		}
   745  
   746  		err = st.AllocateSectorNumber(store, params.SectorNumber)
   747  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to allocate sector id %d", params.SectorNumber)
   748  
   749  		// This sector check is redundant given the allocated sectors bitfield, but remains for safety.
   750  		sectorFound, err := st.HasSectorNo(store, params.SectorNumber)
   751  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to check sector %v", params.SectorNumber)
   752  		if sectorFound {
   753  			rt.Abortf(exitcode.ErrIllegalState, "sector %v already committed", params.SectorNumber)
   754  		}
   755  
   756  		if params.ReplaceCapacity {
   757  			validateReplaceSector(rt, &st, store, params)
   758  		}
   759  
   760  		duration := params.Expiration - rt.CurrEpoch()
   761  		sectorWeight := QAPowerForWeight(info.SectorSize, duration, dealWeight.DealWeight, dealWeight.VerifiedDealWeight)
   762  		depositReq := PreCommitDepositForPower(rewardStats.ThisEpochRewardSmoothed, pwrTotal.QualityAdjPowerSmoothed, sectorWeight)
   763  		if availableBalance.LessThan(depositReq) {
   764  			rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds for pre-commit deposit: %v", depositReq)
   765  		}
   766  
   767  		err = st.AddPreCommitDeposit(depositReq)
   768  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add pre-commit deposit %v", depositReq)
   769  
   770  		if err := st.PutPrecommittedSector(store, &SectorPreCommitOnChainInfo{
   771  			Info:               SectorPreCommitInfo(*params),
   772  			PreCommitDeposit:   depositReq,
   773  			PreCommitEpoch:     rt.CurrEpoch(),
   774  			DealWeight:         dealWeight.DealWeight,
   775  			VerifiedDealWeight: dealWeight.VerifiedDealWeight,
   776  		}); err != nil {
   777  			rt.Abortf(exitcode.ErrIllegalState, "failed to write pre-committed sector %v: %v", params.SectorNumber, err)
   778  		}
   779  		// add precommit expiry to the queue
   780  		msd, ok := MaxProveCommitDuration[params.SealProof]
   781  		if !ok {
   782  			rt.Abortf(exitcode.ErrIllegalArgument, "no max seal duration set for proof type: %d", params.SealProof)
   783  		}
   784  		// The +1 here is critical for the batch verification of proofs. Without it, if a proof arrived exactly on the
   785  		// due epoch, ProveCommitSector would accept it, then the expiry event would remove it, and then
   786  		// ConfirmSectorProofsValid would fail to find it.
   787  		expiryBound := rt.CurrEpoch() + msd + 1
   788  
   789  		err = st.AddPreCommitExpiry(store, expiryBound, params.SectorNumber)
   790  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add pre-commit expiry to queue")
   791  
   792  		// activate miner cron
   793  		needsCron = !st.DeadlineCronActive
   794  		st.DeadlineCronActive = true
   795  	})
   796  	burnFunds(rt, feeToBurn)
   797  	rt.StateReadonly(&st)
   798  	err = st.CheckBalanceInvariants(rt.CurrentBalance())
   799  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
   800  	if needsCron {
   801  		newDlInfo := st.DeadlineInfo(rt.CurrEpoch())
   802  		enrollCronEvent(rt, newDlInfo.Last(), &CronEventPayload{
   803  			EventType: CronEventProvingDeadline,
   804  		})
   805  	}
   806  
   807  	notifyPledgeChanged(rt, newlyVested.Neg())
   808  
   809  	return nil
   810  }
   811  
   812  //type ProveCommitSectorParams struct {
   813  //	SectorNumber abi.SectorNumber
   814  //	Proof        []byte
   815  //}
   816  type ProveCommitSectorParams = miner0.ProveCommitSectorParams
   817  
   818  // Checks state of the corresponding sector pre-commitment, then schedules the proof to be verified in bulk
   819  // by the power actor.
   820  // If valid, the power actor will call ConfirmSectorProofsValid at the end of the same epoch as this message.
   821  func (a Actor) ProveCommitSector(rt Runtime, params *ProveCommitSectorParams) *abi.EmptyValue {
   822  	rt.ValidateImmediateCallerAcceptAny()
   823  
   824  	if params.SectorNumber > abi.MaxSectorNumber {
   825  		rt.Abortf(exitcode.ErrIllegalArgument, "sector number greater than maximum")
   826  	}
   827  
   828  	store := adt.AsStore(rt)
   829  	sectorNo := params.SectorNumber
   830  
   831  	var st State
   832  	rt.StateReadonly(&st)
   833  
   834  	precommit, found, err := st.GetPrecommittedSector(store, sectorNo)
   835  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pre-committed sector %v", sectorNo)
   836  	if !found {
   837  		rt.Abortf(exitcode.ErrNotFound, "no pre-committed sector %v", sectorNo)
   838  	}
   839  
   840  	maxProofSize, err := precommit.Info.SealProof.ProofSize()
   841  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to determine max proof size for sector %v", sectorNo)
   842  	if uint64(len(params.Proof)) > maxProofSize {
   843  		rt.Abortf(exitcode.ErrIllegalArgument, "sector prove-commit proof of size %d exceeds max size of %d",
   844  			len(params.Proof), maxProofSize)
   845  	}
   846  
   847  	msd, ok := MaxProveCommitDuration[precommit.Info.SealProof]
   848  	if !ok {
   849  		rt.Abortf(exitcode.ErrIllegalState, "no max seal duration for proof type: %d", precommit.Info.SealProof)
   850  	}
   851  	proveCommitDue := precommit.PreCommitEpoch + msd
   852  	if rt.CurrEpoch() > proveCommitDue {
   853  		rt.Abortf(exitcode.ErrIllegalArgument, "commitment proof for %d too late at %d, due %d", sectorNo, rt.CurrEpoch(), proveCommitDue)
   854  	}
   855  
   856  	svi := getVerifyInfo(rt, &SealVerifyStuff{
   857  		SealedCID:           precommit.Info.SealedCID,
   858  		InteractiveEpoch:    precommit.PreCommitEpoch + PreCommitChallengeDelay,
   859  		SealRandEpoch:       precommit.Info.SealRandEpoch,
   860  		Proof:               params.Proof,
   861  		DealIDs:             precommit.Info.DealIDs,
   862  		SectorNumber:        precommit.Info.SectorNumber,
   863  		RegisteredSealProof: precommit.Info.SealProof,
   864  	})
   865  
   866  	code := rt.Send(
   867  		builtin.StoragePowerActorAddr,
   868  		builtin.MethodsPower.SubmitPoRepForBulkVerify,
   869  		svi,
   870  		abi.NewTokenAmount(0),
   871  		&builtin.Discard{},
   872  	)
   873  	builtin.RequireSuccess(rt, code, "failed to submit proof for bulk verification")
   874  	return nil
   875  }
   876  
   877  func (a Actor) ConfirmSectorProofsValid(rt Runtime, params *builtin.ConfirmSectorProofsParams) *abi.EmptyValue {
   878  	rt.ValidateImmediateCallerIs(builtin.StoragePowerActorAddr)
   879  
   880  	// This should be enforced by the power actor. We log here just in case
   881  	// something goes wrong.
   882  	if len(params.Sectors) > power.MaxMinerProveCommitsPerEpoch {
   883  		rt.Log(rtt.WARN, "confirmed more prove commits in an epoch than permitted: %d > %d",
   884  			len(params.Sectors), power.MaxMinerProveCommitsPerEpoch,
   885  		)
   886  	}
   887  
   888  	// get network stats from other actors
   889  	rewardStats := requestCurrentEpochBlockReward(rt)
   890  	pwrTotal := requestCurrentTotalPower(rt)
   891  	circulatingSupply := rt.TotalFilCircSupply()
   892  
   893  	// 1. Activate deals, skipping pre-commits with invalid deals.
   894  	//    - calls the market actor.
   895  	// 2. Reschedule replacement sector expiration.
   896  	//    - loads and saves sectors
   897  	//    - loads and saves deadlines/partitions
   898  	// 3. Add new sectors.
   899  	//    - loads and saves sectors.
   900  	//    - loads and saves deadlines/partitions
   901  	//
   902  	// Ideally, we'd combine some of these operations, but at least we have
   903  	// a constant number of them.
   904  
   905  	var st State
   906  	rt.StateReadonly(&st)
   907  	store := adt.AsStore(rt)
   908  	info := getMinerInfo(rt, &st)
   909  
   910  	//
   911  	// Activate storage deals.
   912  	//
   913  
   914  	// This skips missing pre-commits.
   915  	precommittedSectors, err := st.FindPrecommittedSectors(store, params.Sectors...)
   916  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load pre-committed sectors")
   917  
   918  	// Committed-capacity sectors licensed for early removal by new sectors being proven.
   919  	replaceSectors := make(DeadlineSectorMap)
   920  	// Pre-commits for new sectors.
   921  	var preCommits []*SectorPreCommitOnChainInfo
   922  	for _, precommit := range precommittedSectors {
   923  		if len(precommit.Info.DealIDs) > 0 {
   924  			// Check (and activate) storage deals associated to sector. Abort if checks failed.
   925  			// TODO: we should batch these calls...
   926  			// https://github.com/filecoin-project/specs-actors/issues/474
   927  			code := rt.Send(
   928  				builtin.StorageMarketActorAddr,
   929  				builtin.MethodsMarket.ActivateDeals,
   930  				&market.ActivateDealsParams{
   931  					DealIDs:      precommit.Info.DealIDs,
   932  					SectorExpiry: precommit.Info.Expiration,
   933  				},
   934  				abi.NewTokenAmount(0),
   935  				&builtin.Discard{},
   936  			)
   937  
   938  			if code != exitcode.Ok {
   939  				rt.Log(rtt.INFO, "failed to activate deals on sector %d, dropping from prove commit set", precommit.Info.SectorNumber)
   940  				continue
   941  			}
   942  		}
   943  
   944  		preCommits = append(preCommits, precommit)
   945  
   946  		if precommit.Info.ReplaceCapacity {
   947  			err := replaceSectors.AddValues(
   948  				precommit.Info.ReplaceSectorDeadline,
   949  				precommit.Info.ReplaceSectorPartition,
   950  				uint64(precommit.Info.ReplaceSectorNumber),
   951  			)
   952  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to record sectors for replacement")
   953  		}
   954  	}
   955  
   956  	// When all prove commits have failed abort early
   957  	if len(preCommits) == 0 {
   958  		rt.Abortf(exitcode.ErrIllegalArgument, "all prove commits failed to validate")
   959  	}
   960  
   961  	totalPledge := big.Zero()
   962  	depositToUnlock := big.Zero()
   963  	newSectors := make([]*SectorOnChainInfo, 0)
   964  	newlyVested := big.Zero()
   965  	rt.StateTransaction(&st, func() {
   966  		// Schedule expiration for replaced sectors to the end of their next deadline window.
   967  		// They can't be removed right now because we want to challenge them immediately before termination.
   968  		replaced, err := st.RescheduleSectorExpirations(store, rt.CurrEpoch(), info.SectorSize, replaceSectors)
   969  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to replace sector expirations")
   970  		replacedBySectorNumber := asMapBySectorNumber(replaced)
   971  
   972  		newSectorNos := make([]abi.SectorNumber, 0, len(preCommits))
   973  		for _, precommit := range preCommits {
   974  			// compute initial pledge
   975  			activation := rt.CurrEpoch()
   976  			duration := precommit.Info.Expiration - activation
   977  
   978  			// This should have been caught in precommit, but don't let other sectors fail because of it.
   979  			if duration < MinSectorExpiration {
   980  				rt.Log(rtt.WARN, "precommit %d has lifetime %d less than minimum. ignoring", precommit.Info.SectorNumber, duration, MinSectorExpiration)
   981  				continue
   982  			}
   983  
   984  			pwr := QAPowerForWeight(info.SectorSize, duration, precommit.DealWeight, precommit.VerifiedDealWeight)
   985  			dayReward := ExpectedRewardForPower(rewardStats.ThisEpochRewardSmoothed, pwrTotal.QualityAdjPowerSmoothed, pwr, builtin.EpochsInDay)
   986  			// The storage pledge is recorded for use in computing the penalty if this sector is terminated
   987  			// before its declared expiration.
   988  			// It's not capped to 1 FIL, so can exceed the actual initial pledge requirement.
   989  			storagePledge := ExpectedRewardForPower(rewardStats.ThisEpochRewardSmoothed, pwrTotal.QualityAdjPowerSmoothed, pwr, InitialPledgeProjectionPeriod)
   990  			initialPledge := InitialPledgeForPower(pwr, rewardStats.ThisEpochBaselinePower, rewardStats.ThisEpochRewardSmoothed,
   991  				pwrTotal.QualityAdjPowerSmoothed, circulatingSupply)
   992  
   993  			// Lower-bound the pledge by that of the sector being replaced.
   994  			// Record the replaced age and reward rate for termination fee calculations.
   995  			replacedPledge, replacedAge, replacedDayReward := replacedSectorParameters(rt, precommit, replacedBySectorNumber)
   996  			initialPledge = big.Max(initialPledge, replacedPledge)
   997  
   998  			newSectorInfo := SectorOnChainInfo{
   999  				SectorNumber:          precommit.Info.SectorNumber,
  1000  				SealProof:             precommit.Info.SealProof,
  1001  				SealedCID:             precommit.Info.SealedCID,
  1002  				DealIDs:               precommit.Info.DealIDs,
  1003  				Expiration:            precommit.Info.Expiration,
  1004  				Activation:            activation,
  1005  				DealWeight:            precommit.DealWeight,
  1006  				VerifiedDealWeight:    precommit.VerifiedDealWeight,
  1007  				InitialPledge:         initialPledge,
  1008  				ExpectedDayReward:     dayReward,
  1009  				ExpectedStoragePledge: storagePledge,
  1010  				ReplacedSectorAge:     replacedAge,
  1011  				ReplacedDayReward:     replacedDayReward,
  1012  			}
  1013  
  1014  			depositToUnlock = big.Add(depositToUnlock, precommit.PreCommitDeposit)
  1015  			newSectors = append(newSectors, &newSectorInfo)
  1016  			newSectorNos = append(newSectorNos, newSectorInfo.SectorNumber)
  1017  			totalPledge = big.Add(totalPledge, initialPledge)
  1018  		}
  1019  
  1020  		err = st.PutSectors(store, newSectors...)
  1021  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to put new sectors")
  1022  
  1023  		err = st.DeletePrecommittedSectors(store, newSectorNos...)
  1024  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to delete precommited sectors")
  1025  
  1026  		err = st.AssignSectorsToDeadlines(store, rt.CurrEpoch(), newSectors, info.WindowPoStPartitionSectors, info.SectorSize)
  1027  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to assign new sectors to deadlines")
  1028  
  1029  		// Unlock deposit for successful proofs, make it available for lock-up as initial pledge.
  1030  		err = st.AddPreCommitDeposit(depositToUnlock.Neg())
  1031  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add pre-commit deposit %v", depositToUnlock.Neg())
  1032  
  1033  		unlockedBalance, err := st.GetUnlockedBalance(rt.CurrentBalance())
  1034  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to calculate unlocked balance")
  1035  		if unlockedBalance.LessThan(totalPledge) {
  1036  			rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds for aggregate initial pledge requirement %s, available: %s", totalPledge, unlockedBalance)
  1037  		}
  1038  
  1039  		err = st.AddInitialPledge(totalPledge)
  1040  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add initial pledge %v", totalPledge)
  1041  		err = st.CheckBalanceInvariants(rt.CurrentBalance())
  1042  		builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1043  	})
  1044  
  1045  	// Request pledge update for activated sector.
  1046  	notifyPledgeChanged(rt, big.Sub(totalPledge, newlyVested))
  1047  	return nil
  1048  }
  1049  
  1050  //type CheckSectorProvenParams struct {
  1051  //	SectorNumber abi.SectorNumber
  1052  //}
  1053  type CheckSectorProvenParams = miner0.CheckSectorProvenParams
  1054  
  1055  func (a Actor) CheckSectorProven(rt Runtime, params *CheckSectorProvenParams) *abi.EmptyValue {
  1056  	rt.ValidateImmediateCallerAcceptAny()
  1057  
  1058  	if params.SectorNumber > abi.MaxSectorNumber {
  1059  		rt.Abortf(exitcode.ErrIllegalArgument, "sector number out of range")
  1060  	}
  1061  
  1062  	var st State
  1063  	rt.StateReadonly(&st)
  1064  	store := adt.AsStore(rt)
  1065  	sectorNo := params.SectorNumber
  1066  
  1067  	if _, found, err := st.GetSector(store, sectorNo); err != nil {
  1068  		rt.Abortf(exitcode.ErrIllegalState, "failed to load proven sector %v", sectorNo)
  1069  	} else if !found {
  1070  		rt.Abortf(exitcode.ErrNotFound, "sector %v not proven", sectorNo)
  1071  	}
  1072  	return nil
  1073  }
  1074  
  1075  /////////////////////////
  1076  // Sector Modification //
  1077  /////////////////////////
  1078  
  1079  //type ExtendSectorExpirationParams struct {
  1080  //	Extensions []ExpirationExtension
  1081  //}
  1082  type ExtendSectorExpirationParams = miner0.ExtendSectorExpirationParams
  1083  
  1084  //type ExpirationExtension struct {
  1085  //	Deadline      uint64
  1086  //	Partition     uint64
  1087  //	Sectors       bitfield.BitField
  1088  //	NewExpiration abi.ChainEpoch
  1089  //}
  1090  type ExpirationExtension = miner0.ExpirationExtension
  1091  
  1092  // Changes the expiration epoch for a sector to a new, later one.
  1093  // The sector must not be terminated or faulty.
  1094  // The sector's power is recomputed for the new expiration.
  1095  func (a Actor) ExtendSectorExpiration(rt Runtime, params *ExtendSectorExpirationParams) *abi.EmptyValue {
  1096  	if uint64(len(params.Extensions)) > DeclarationsMax {
  1097  		rt.Abortf(exitcode.ErrIllegalArgument, "too many declarations %d, max %d", len(params.Extensions), DeclarationsMax)
  1098  	}
  1099  
  1100  	// limit the number of sectors declared at once
  1101  	// https://github.com/filecoin-project/specs-actors/issues/416
  1102  	var sectorCount uint64
  1103  	for _, decl := range params.Extensions {
  1104  		if decl.Deadline >= WPoStPeriodDeadlines {
  1105  			rt.Abortf(exitcode.ErrIllegalArgument, "deadline %d not in range 0..%d", decl.Deadline, WPoStPeriodDeadlines)
  1106  		}
  1107  		count, err := decl.Sectors.Count()
  1108  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument,
  1109  			"failed to count sectors for deadline %d, partition %d",
  1110  			decl.Deadline, decl.Partition,
  1111  		)
  1112  		if sectorCount > math.MaxUint64-count {
  1113  			rt.Abortf(exitcode.ErrIllegalArgument, "sector bitfield integer overflow")
  1114  		}
  1115  		sectorCount += count
  1116  	}
  1117  	if sectorCount > AddressedSectorsMax {
  1118  		rt.Abortf(exitcode.ErrIllegalArgument,
  1119  			"too many sectors for declaration %d, max %d",
  1120  			sectorCount, AddressedSectorsMax,
  1121  		)
  1122  	}
  1123  
  1124  	currEpoch := rt.CurrEpoch()
  1125  
  1126  	powerDelta := NewPowerPairZero()
  1127  	pledgeDelta := big.Zero()
  1128  	store := adt.AsStore(rt)
  1129  	var st State
  1130  	rt.StateTransaction(&st, func() {
  1131  		info := getMinerInfo(rt, &st)
  1132  
  1133  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1134  
  1135  		deadlines, err := st.LoadDeadlines(adt.AsStore(rt))
  1136  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
  1137  
  1138  		// Group declarations by deadline, and remember iteration order.
  1139  		// This should be merged with the iteration outside the state transaction.
  1140  		declsByDeadline := map[uint64][]*ExpirationExtension{}
  1141  		var deadlinesToLoad []uint64
  1142  		for i := range params.Extensions {
  1143  			// Take a pointer to the value inside the slice, don't
  1144  			// take a reference to the temporary loop variable as it
  1145  			// will be overwritten every iteration.
  1146  			decl := &params.Extensions[i]
  1147  			if _, ok := declsByDeadline[decl.Deadline]; !ok {
  1148  				deadlinesToLoad = append(deadlinesToLoad, decl.Deadline)
  1149  			}
  1150  			declsByDeadline[decl.Deadline] = append(declsByDeadline[decl.Deadline], decl)
  1151  		}
  1152  
  1153  		sectors, err := LoadSectors(store, st.Sectors)
  1154  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors array")
  1155  
  1156  		for _, dlIdx := range deadlinesToLoad {
  1157  			deadline, err := deadlines.LoadDeadline(store, dlIdx)
  1158  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %d", dlIdx)
  1159  
  1160  			partitions, err := deadline.PartitionsArray(store)
  1161  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load partitions for deadline %d", dlIdx)
  1162  
  1163  			quant := st.QuantSpecForDeadline(dlIdx)
  1164  
  1165  			// Group modified partitions by epoch to which they are extended. Duplicates are ok.
  1166  			partitionsByNewEpoch := map[abi.ChainEpoch][]uint64{}
  1167  			// Remember iteration order of epochs.
  1168  			var epochsToReschedule []abi.ChainEpoch
  1169  
  1170  			for _, decl := range declsByDeadline[dlIdx] {
  1171  				var partition Partition
  1172  				found, err := partitions.Get(decl.Partition, &partition)
  1173  				builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %v partition %v", dlIdx, decl.Partition)
  1174  				if !found {
  1175  					rt.Abortf(exitcode.ErrNotFound, "no such deadline %v partition %v", dlIdx, decl.Partition)
  1176  				}
  1177  
  1178  				oldSectors, err := sectors.Load(decl.Sectors)
  1179  				builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors in deadline %v partition %v", dlIdx, decl.Partition)
  1180  				newSectors := make([]*SectorOnChainInfo, len(oldSectors))
  1181  				for i, sector := range oldSectors {
  1182  					if !CanExtendSealProofType(sector.SealProof, rt.NetworkVersion()) {
  1183  						rt.Abortf(exitcode.ErrForbidden, "cannot extend expiration for sector %v with unsupported seal type %v",
  1184  							sector.SectorNumber, sector.SealProof)
  1185  					}
  1186  					// This can happen if the sector should have already expired, but hasn't
  1187  					// because the end of its deadline hasn't passed yet.
  1188  					if sector.Expiration < currEpoch {
  1189  						rt.Abortf(exitcode.ErrForbidden, "cannot extend expiration for expired sector %v, expired at %d, now %d",
  1190  							sector.SectorNumber,
  1191  							sector.Expiration,
  1192  							currEpoch,
  1193  						)
  1194  					}
  1195  					if decl.NewExpiration < sector.Expiration {
  1196  						rt.Abortf(exitcode.ErrIllegalArgument, "cannot reduce sector %v's expiration to %d from %d",
  1197  							sector.SectorNumber, decl.NewExpiration, sector.Expiration)
  1198  					}
  1199  					validateExpiration(rt, sector.Activation, decl.NewExpiration, sector.SealProof)
  1200  
  1201  					newSector := *sector
  1202  					newSector.Expiration = decl.NewExpiration
  1203  
  1204  					newSectors[i] = &newSector
  1205  				}
  1206  
  1207  				// Overwrite sector infos.
  1208  				err = sectors.Store(newSectors...)
  1209  				builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update sectors %v", decl.Sectors)
  1210  
  1211  				// Remove old sectors from partition and assign new sectors.
  1212  				partitionPowerDelta, partitionPledgeDelta, err := partition.ReplaceSectors(store, oldSectors, newSectors, info.SectorSize, quant)
  1213  				builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to replace sector expirations at deadline %v partition %v", dlIdx, decl.Partition)
  1214  
  1215  				powerDelta = powerDelta.Add(partitionPowerDelta)
  1216  				pledgeDelta = big.Add(pledgeDelta, partitionPledgeDelta) // expected to be zero, see note below.
  1217  
  1218  				err = partitions.Set(decl.Partition, &partition)
  1219  				builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadline %v partition %v", dlIdx, decl.Partition)
  1220  
  1221  				// Record the new partition expiration epoch for setting outside this loop over declarations.
  1222  				prevEpochPartitions, ok := partitionsByNewEpoch[decl.NewExpiration]
  1223  				partitionsByNewEpoch[decl.NewExpiration] = append(prevEpochPartitions, decl.Partition)
  1224  				if !ok {
  1225  					epochsToReschedule = append(epochsToReschedule, decl.NewExpiration)
  1226  				}
  1227  			}
  1228  
  1229  			deadline.Partitions, err = partitions.Root()
  1230  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save partitions for deadline %d", dlIdx)
  1231  
  1232  			// Record partitions in deadline expiration queue
  1233  			for _, epoch := range epochsToReschedule {
  1234  				pIdxs := partitionsByNewEpoch[epoch]
  1235  				err := deadline.AddExpirationPartitions(store, epoch, pIdxs, quant)
  1236  				builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add expiration partitions to deadline %v epoch %v: %v",
  1237  					dlIdx, epoch, pIdxs)
  1238  			}
  1239  
  1240  			err = deadlines.UpdateDeadline(store, dlIdx, deadline)
  1241  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadline %d", dlIdx)
  1242  		}
  1243  
  1244  		st.Sectors, err = sectors.Root()
  1245  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save sectors")
  1246  
  1247  		err = st.SaveDeadlines(store, deadlines)
  1248  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
  1249  	})
  1250  
  1251  	requestUpdatePower(rt, powerDelta)
  1252  	// Note: the pledge delta is expected to be zero, since pledge is not re-calculated for the extension.
  1253  	// But in case that ever changes, we can do the right thing here.
  1254  	notifyPledgeChanged(rt, pledgeDelta)
  1255  	return nil
  1256  }
  1257  
  1258  //type TerminateSectorsParams struct {
  1259  //	Terminations []TerminationDeclaration
  1260  //}
  1261  type TerminateSectorsParams = miner0.TerminateSectorsParams
  1262  
  1263  //type TerminationDeclaration struct {
  1264  //	Deadline  uint64
  1265  //	Partition uint64
  1266  //	Sectors   bitfield.BitField
  1267  //}
  1268  type TerminationDeclaration = miner0.TerminationDeclaration
  1269  
  1270  //type TerminateSectorsReturn struct {
  1271  //	// Set to true if all early termination work has been completed. When
  1272  //	// false, the miner may choose to repeatedly invoke TerminateSectors
  1273  //	// with no new sectors to process the remainder of the pending
  1274  //	// terminations. While pending terminations are outstanding, the miner
  1275  //	// will not be able to withdraw funds.
  1276  //	Done bool
  1277  //}
  1278  type TerminateSectorsReturn = miner0.TerminateSectorsReturn
  1279  
  1280  // Marks some sectors as terminated at the present epoch, earlier than their
  1281  // scheduled termination, and adds these sectors to the early termination queue.
  1282  // This method then processes up to AddressedSectorsMax sectors and
  1283  // AddressedPartitionsMax partitions from the early termination queue,
  1284  // terminating deals, paying fines, and returning pledge collateral. While
  1285  // sectors remain in this queue:
  1286  //
  1287  //  1. The miner will be unable to withdraw funds.
  1288  //  2. The chain will process up to AddressedSectorsMax sectors and
  1289  //     AddressedPartitionsMax per epoch until the queue is empty.
  1290  //
  1291  // The sectors are immediately ignored for Window PoSt proofs, and should be
  1292  // masked in the same way as faulty sectors. A miner may not terminate sectors in the
  1293  // current deadline or the next deadline to be proven.
  1294  //
  1295  // This function may be invoked with no new sectors to explicitly process the
  1296  // next batch of sectors.
  1297  func (a Actor) TerminateSectors(rt Runtime, params *TerminateSectorsParams) *TerminateSectorsReturn {
  1298  	// Note: this cannot terminate pre-committed but un-proven sectors.
  1299  	// They must be allowed to expire (and deposit burnt).
  1300  
  1301  	if len(params.Terminations) > DeclarationsMax {
  1302  		rt.Abortf(exitcode.ErrIllegalArgument,
  1303  			"too many declarations when terminating sectors: %d > %d",
  1304  			len(params.Terminations), DeclarationsMax,
  1305  		)
  1306  	}
  1307  
  1308  	toProcess := make(DeadlineSectorMap)
  1309  	for _, term := range params.Terminations {
  1310  		err := toProcess.Add(term.Deadline, term.Partition, term.Sectors)
  1311  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument,
  1312  			"failed to process deadline %d, partition %d", term.Deadline, term.Partition,
  1313  		)
  1314  	}
  1315  	err := toProcess.Check(AddressedPartitionsMax, AddressedSectorsMax)
  1316  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "cannot process requested parameters")
  1317  
  1318  	var hadEarlyTerminations bool
  1319  	var st State
  1320  	store := adt.AsStore(rt)
  1321  	currEpoch := rt.CurrEpoch()
  1322  	powerDelta := NewPowerPairZero()
  1323  	rt.StateTransaction(&st, func() {
  1324  		hadEarlyTerminations = havePendingEarlyTerminations(rt, &st)
  1325  
  1326  		info := getMinerInfo(rt, &st)
  1327  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1328  
  1329  		deadlines, err := st.LoadDeadlines(adt.AsStore(rt))
  1330  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
  1331  
  1332  		// We're only reading the sectors, so there's no need to save this back.
  1333  		// However, we still want to avoid re-loading this array per-partition.
  1334  		sectors, err := LoadSectors(store, st.Sectors)
  1335  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors")
  1336  
  1337  		err = toProcess.ForEach(func(dlIdx uint64, partitionSectors PartitionSectorMap) error {
  1338  			// If the deadline the current or next deadline to prove, don't allow terminating sectors.
  1339  			// We assume that deadlines are immutable when being proven.
  1340  			if !deadlineIsMutable(st.CurrentProvingPeriodStart(currEpoch), dlIdx, currEpoch) {
  1341  				rt.Abortf(exitcode.ErrIllegalArgument, "cannot terminate sectors in immutable deadline %d", dlIdx)
  1342  			}
  1343  
  1344  			quant := st.QuantSpecForDeadline(dlIdx)
  1345  
  1346  			deadline, err := deadlines.LoadDeadline(store, dlIdx)
  1347  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %d", dlIdx)
  1348  
  1349  			removedPower, err := deadline.TerminateSectors(store, sectors, currEpoch, partitionSectors, info.SectorSize, quant)
  1350  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to terminate sectors in deadline %d", dlIdx)
  1351  
  1352  			st.EarlyTerminations.Set(dlIdx)
  1353  
  1354  			powerDelta = powerDelta.Sub(removedPower)
  1355  
  1356  			err = deadlines.UpdateDeadline(store, dlIdx, deadline)
  1357  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update deadline %d", dlIdx)
  1358  
  1359  			return nil
  1360  		})
  1361  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to walk sectors")
  1362  
  1363  		err = st.SaveDeadlines(store, deadlines)
  1364  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
  1365  	})
  1366  
  1367  	// Now, try to process these sectors.
  1368  	more := processEarlyTerminations(rt)
  1369  	if more && !hadEarlyTerminations {
  1370  		// We have remaining terminations, and we didn't _previously_
  1371  		// have early terminations to process, schedule a cron job.
  1372  		// NOTE: This isn't quite correct. If we repeatedly fill, empty,
  1373  		// fill, and empty, the queue, we'll keep scheduling new cron
  1374  		// jobs. However, in practice, that shouldn't be all that bad.
  1375  		scheduleEarlyTerminationWork(rt)
  1376  	}
  1377  
  1378  	rt.StateReadonly(&st)
  1379  	err = st.CheckBalanceInvariants(rt.CurrentBalance())
  1380  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1381  
  1382  	requestUpdatePower(rt, powerDelta)
  1383  	return &TerminateSectorsReturn{Done: !more}
  1384  }
  1385  
  1386  ////////////
  1387  // Faults //
  1388  ////////////
  1389  
  1390  //type DeclareFaultsParams struct {
  1391  //	Faults []FaultDeclaration
  1392  //}
  1393  type DeclareFaultsParams = miner0.DeclareFaultsParams
  1394  
  1395  //type FaultDeclaration struct {
  1396  //	// The deadline to which the faulty sectors are assigned, in range [0..WPoStPeriodDeadlines)
  1397  //	Deadline uint64
  1398  //	// Partition index within the deadline containing the faulty sectors.
  1399  //	Partition uint64
  1400  //	// Sectors in the partition being declared faulty.
  1401  //	Sectors bitfield.BitField
  1402  //}
  1403  type FaultDeclaration = miner0.FaultDeclaration
  1404  
  1405  func (a Actor) DeclareFaults(rt Runtime, params *DeclareFaultsParams) *abi.EmptyValue {
  1406  	if len(params.Faults) > DeclarationsMax {
  1407  		rt.Abortf(exitcode.ErrIllegalArgument,
  1408  			"too many fault declarations for a single message: %d > %d",
  1409  			len(params.Faults), DeclarationsMax,
  1410  		)
  1411  	}
  1412  
  1413  	toProcess := make(DeadlineSectorMap)
  1414  	for _, term := range params.Faults {
  1415  		err := toProcess.Add(term.Deadline, term.Partition, term.Sectors)
  1416  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument,
  1417  			"failed to process deadline %d, partition %d", term.Deadline, term.Partition,
  1418  		)
  1419  	}
  1420  	err := toProcess.Check(AddressedPartitionsMax, AddressedSectorsMax)
  1421  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "cannot process requested parameters")
  1422  
  1423  	store := adt.AsStore(rt)
  1424  	var st State
  1425  	powerDelta := NewPowerPairZero()
  1426  	rt.StateTransaction(&st, func() {
  1427  		info := getMinerInfo(rt, &st)
  1428  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1429  
  1430  		deadlines, err := st.LoadDeadlines(store)
  1431  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
  1432  
  1433  		sectors, err := LoadSectors(store, st.Sectors)
  1434  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors array")
  1435  
  1436  		currEpoch := rt.CurrEpoch()
  1437  		err = toProcess.ForEach(func(dlIdx uint64, pm PartitionSectorMap) error {
  1438  			targetDeadline, err := declarationDeadlineInfo(st.CurrentProvingPeriodStart(currEpoch), dlIdx, currEpoch)
  1439  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid fault declaration deadline %d", dlIdx)
  1440  
  1441  			err = validateFRDeclarationDeadline(targetDeadline)
  1442  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed fault declaration at deadline %d", dlIdx)
  1443  
  1444  			deadline, err := deadlines.LoadDeadline(store, dlIdx)
  1445  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %d", dlIdx)
  1446  
  1447  			faultExpirationEpoch := targetDeadline.Last() + FaultMaxAge
  1448  			deadlinePowerDelta, err := deadline.RecordFaults(store, sectors, info.SectorSize, QuantSpecForDeadline(targetDeadline), faultExpirationEpoch, pm)
  1449  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to declare faults for deadline %d", dlIdx)
  1450  
  1451  			err = deadlines.UpdateDeadline(store, dlIdx, deadline)
  1452  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to store deadline %d partitions", dlIdx)
  1453  
  1454  			powerDelta = powerDelta.Add(deadlinePowerDelta)
  1455  			return nil
  1456  		})
  1457  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to iterate deadlines")
  1458  
  1459  		err = st.SaveDeadlines(store, deadlines)
  1460  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
  1461  	})
  1462  
  1463  	// Remove power for new faulty sectors.
  1464  	// NOTE: It would be permissible to delay the power loss until the deadline closes, but that would require
  1465  	// additional accounting state.
  1466  	// https://github.com/filecoin-project/specs-actors/issues/414
  1467  	requestUpdatePower(rt, powerDelta)
  1468  
  1469  	// Payment of penalty for declared faults is deferred to the deadline cron.
  1470  	return nil
  1471  }
  1472  
  1473  //type DeclareFaultsRecoveredParams struct {
  1474  //	Recoveries []RecoveryDeclaration
  1475  //}
  1476  type DeclareFaultsRecoveredParams = miner0.DeclareFaultsRecoveredParams
  1477  
  1478  //type RecoveryDeclaration struct {
  1479  //	// The deadline to which the recovered sectors are assigned, in range [0..WPoStPeriodDeadlines)
  1480  //	Deadline uint64
  1481  //	// Partition index within the deadline containing the recovered sectors.
  1482  //	Partition uint64
  1483  //	// Sectors in the partition being declared recovered.
  1484  //	Sectors bitfield.BitField
  1485  //}
  1486  type RecoveryDeclaration = miner0.RecoveryDeclaration
  1487  
  1488  func (a Actor) DeclareFaultsRecovered(rt Runtime, params *DeclareFaultsRecoveredParams) *abi.EmptyValue {
  1489  	if len(params.Recoveries) > DeclarationsMax {
  1490  		rt.Abortf(exitcode.ErrIllegalArgument,
  1491  			"too many recovery declarations for a single message: %d > %d",
  1492  			len(params.Recoveries), DeclarationsMax,
  1493  		)
  1494  	}
  1495  
  1496  	toProcess := make(DeadlineSectorMap)
  1497  	for _, term := range params.Recoveries {
  1498  		err := toProcess.Add(term.Deadline, term.Partition, term.Sectors)
  1499  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument,
  1500  			"failed to process deadline %d, partition %d", term.Deadline, term.Partition,
  1501  		)
  1502  	}
  1503  	err := toProcess.Check(AddressedPartitionsMax, AddressedSectorsMax)
  1504  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "cannot process requested parameters")
  1505  
  1506  	store := adt.AsStore(rt)
  1507  	var st State
  1508  	feeToBurn := abi.NewTokenAmount(0)
  1509  	rt.StateTransaction(&st, func() {
  1510  		// Verify unlocked funds cover both InitialPledgeRequirement and FeeDebt
  1511  		// and repay fee debt now.
  1512  		feeToBurn = RepayDebtsOrAbort(rt, &st)
  1513  
  1514  		info := getMinerInfo(rt, &st)
  1515  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1516  		if ConsensusFaultActive(info, rt.CurrEpoch()) {
  1517  			rt.Abortf(exitcode.ErrForbidden, "recovery not allowed during active consensus fault")
  1518  		}
  1519  
  1520  		deadlines, err := st.LoadDeadlines(adt.AsStore(rt))
  1521  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
  1522  
  1523  		sectors, err := LoadSectors(store, st.Sectors)
  1524  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors array")
  1525  
  1526  		currEpoch := rt.CurrEpoch()
  1527  		err = toProcess.ForEach(func(dlIdx uint64, pm PartitionSectorMap) error {
  1528  			targetDeadline, err := declarationDeadlineInfo(st.CurrentProvingPeriodStart(currEpoch), dlIdx, currEpoch)
  1529  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid recovery declaration deadline %d", dlIdx)
  1530  			err = validateFRDeclarationDeadline(targetDeadline)
  1531  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed recovery declaration at deadline %d", dlIdx)
  1532  
  1533  			deadline, err := deadlines.LoadDeadline(store, dlIdx)
  1534  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %d", dlIdx)
  1535  
  1536  			err = deadline.DeclareFaultsRecovered(store, sectors, info.SectorSize, pm)
  1537  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to declare recoveries for deadline %d", dlIdx)
  1538  
  1539  			err = deadlines.UpdateDeadline(store, dlIdx, deadline)
  1540  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to store deadline %d", dlIdx)
  1541  			return nil
  1542  		})
  1543  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to walk sectors")
  1544  
  1545  		err = st.SaveDeadlines(store, deadlines)
  1546  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
  1547  	})
  1548  
  1549  	burnFunds(rt, feeToBurn)
  1550  	rt.StateReadonly(&st)
  1551  	err = st.CheckBalanceInvariants(rt.CurrentBalance())
  1552  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1553  
  1554  	// Power is not restored yet, but when the recovered sectors are successfully PoSted.
  1555  	return nil
  1556  }
  1557  
  1558  /////////////////
  1559  // Maintenance //
  1560  /////////////////
  1561  
  1562  //type CompactPartitionsParams struct {
  1563  //	Deadline   uint64
  1564  //	Partitions bitfield.BitField
  1565  //}
  1566  type CompactPartitionsParams = miner0.CompactPartitionsParams
  1567  
  1568  // Compacts a number of partitions at one deadline by removing terminated sectors, re-ordering the remaining sectors,
  1569  // and assigning them to new partitions so as to completely fill all but one partition with live sectors.
  1570  // The addressed partitions are removed from the deadline, and new ones appended.
  1571  // The final partition in the deadline is always included in the compaction, whether or not explicitly requested.
  1572  // Removed sectors are removed from state entirely.
  1573  // May not be invoked if the deadline has any un-processed early terminations.
  1574  func (a Actor) CompactPartitions(rt Runtime, params *CompactPartitionsParams) *abi.EmptyValue {
  1575  	if params.Deadline >= WPoStPeriodDeadlines {
  1576  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid deadline %v", params.Deadline)
  1577  	}
  1578  
  1579  	partitionCount, err := params.Partitions.Count()
  1580  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to parse partitions bitfield")
  1581  
  1582  	store := adt.AsStore(rt)
  1583  	var st State
  1584  	rt.StateTransaction(&st, func() {
  1585  		info := getMinerInfo(rt, &st)
  1586  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1587  
  1588  		if !deadlineAvailableForCompaction(st.CurrentProvingPeriodStart(rt.CurrEpoch()), params.Deadline, rt.CurrEpoch()) {
  1589  			rt.Abortf(exitcode.ErrForbidden,
  1590  				"cannot compact deadline %d during its challenge window, or the prior challenge window, or before %d epochs have passed since its last challenge window ended", params.Deadline, WPoStDisputeWindow)
  1591  		}
  1592  
  1593  		submissionPartitionLimit := loadPartitionsSectorsMax(info.WindowPoStPartitionSectors)
  1594  		if partitionCount > submissionPartitionLimit {
  1595  			rt.Abortf(exitcode.ErrIllegalArgument, "too many partitions %d, limit %d", partitionCount, submissionPartitionLimit)
  1596  		}
  1597  
  1598  		quant := st.QuantSpecForDeadline(params.Deadline)
  1599  
  1600  		deadlines, err := st.LoadDeadlines(store)
  1601  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadlines")
  1602  
  1603  		deadline, err := deadlines.LoadDeadline(store, params.Deadline)
  1604  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load deadline %d", params.Deadline)
  1605  
  1606  		live, dead, removedPower, err := deadline.RemovePartitions(store, params.Partitions, quant)
  1607  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to remove partitions from deadline %d", params.Deadline)
  1608  
  1609  		err = st.DeleteSectors(store, dead)
  1610  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to delete dead sectors")
  1611  
  1612  		sectors, err := st.LoadSectorInfos(store, live)
  1613  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load moved sectors")
  1614  
  1615  		proven := true
  1616  		addedPower, err := deadline.AddSectors(store, info.WindowPoStPartitionSectors, proven, sectors, info.SectorSize, quant)
  1617  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add back moved sectors")
  1618  
  1619  		if !removedPower.Equals(addedPower) {
  1620  			rt.Abortf(exitcode.ErrIllegalState, "power changed when compacting partitions: was %v, is now %v", removedPower, addedPower)
  1621  		}
  1622  		err = deadlines.UpdateDeadline(store, params.Deadline, deadline)
  1623  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to update deadline %d", params.Deadline)
  1624  
  1625  		err = st.SaveDeadlines(store, deadlines)
  1626  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to save deadlines")
  1627  	})
  1628  	return nil
  1629  }
  1630  
  1631  //type CompactSectorNumbersParams struct {
  1632  //	MaskSectorNumbers bitfield.BitField
  1633  //}
  1634  type CompactSectorNumbersParams = miner0.CompactSectorNumbersParams
  1635  
  1636  // Compacts sector number allocations to reduce the size of the allocated sector
  1637  // number bitfield.
  1638  //
  1639  // When allocating sector numbers sequentially, or in sequential groups, this
  1640  // bitfield should remain fairly small. However, if the bitfield grows large
  1641  // enough such that PreCommitSector fails (or becomes expensive), this method
  1642  // can be called to mask out (throw away) entire ranges of unused sector IDs.
  1643  // For example, if sectors 1-99 and 101-200 have been allocated, sector number
  1644  // 99 can be masked out to collapse these two ranges into one.
  1645  func (a Actor) CompactSectorNumbers(rt Runtime, params *CompactSectorNumbersParams) *abi.EmptyValue {
  1646  	lastSectorNo, err := params.MaskSectorNumbers.Last()
  1647  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "invalid mask bitfield")
  1648  	if lastSectorNo > abi.MaxSectorNumber {
  1649  		rt.Abortf(exitcode.ErrIllegalArgument, "masked sector number %d exceeded max sector number", lastSectorNo)
  1650  	}
  1651  
  1652  	store := adt.AsStore(rt)
  1653  	var st State
  1654  	rt.StateTransaction(&st, func() {
  1655  		info := getMinerInfo(rt, &st)
  1656  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1657  
  1658  		err := st.MaskSectorNumbers(store, params.MaskSectorNumbers)
  1659  
  1660  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to mask sector numbers")
  1661  	})
  1662  	return nil
  1663  }
  1664  
  1665  ///////////////////////
  1666  // Pledge Collateral //
  1667  ///////////////////////
  1668  
  1669  // Locks up some amount of the miner's unlocked balance (including funds received alongside the invoking message).
  1670  func (a Actor) ApplyRewards(rt Runtime, params *builtin.ApplyRewardParams) *abi.EmptyValue {
  1671  	if params.Reward.Sign() < 0 {
  1672  		rt.Abortf(exitcode.ErrIllegalArgument, "cannot lock up a negative amount of funds")
  1673  	}
  1674  	if params.Penalty.Sign() < 0 {
  1675  		rt.Abortf(exitcode.ErrIllegalArgument, "cannot penalize a negative amount of funds")
  1676  	}
  1677  
  1678  	var st State
  1679  	pledgeDeltaTotal := big.Zero()
  1680  	toBurn := big.Zero()
  1681  	rt.StateTransaction(&st, func() {
  1682  		var err error
  1683  		store := adt.AsStore(rt)
  1684  		rt.ValidateImmediateCallerIs(builtin.RewardActorAddr)
  1685  
  1686  		rewardToLock, lockedRewardVestingSpec := LockedRewardFromReward(params.Reward)
  1687  
  1688  		// This ensures the miner has sufficient funds to lock up amountToLock.
  1689  		// This should always be true if reward actor sends reward funds with the message.
  1690  		unlockedBalance, err := st.GetUnlockedBalance(rt.CurrentBalance())
  1691  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to calculate unlocked balance")
  1692  		if unlockedBalance.LessThan(rewardToLock) {
  1693  			rt.Abortf(exitcode.ErrInsufficientFunds, "insufficient funds to lock, available: %v, requested: %v", unlockedBalance, rewardToLock)
  1694  		}
  1695  
  1696  		newlyVested, err := st.AddLockedFunds(store, rt.CurrEpoch(), rewardToLock, lockedRewardVestingSpec)
  1697  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to lock funds in vesting table")
  1698  		pledgeDeltaTotal = big.Sub(pledgeDeltaTotal, newlyVested)
  1699  		pledgeDeltaTotal = big.Add(pledgeDeltaTotal, rewardToLock)
  1700  
  1701  		// If the miner incurred block mining penalties charge these to miner's fee debt
  1702  		err = st.ApplyPenalty(params.Penalty)
  1703  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to apply penalty")
  1704  		// Attempt to repay all fee debt in this call. In most cases the miner will have enough
  1705  		// funds in the *reward alone* to cover the penalty. In the rare case a miner incurs more
  1706  		// penalty than it can pay for with reward and existing funds, it will go into fee debt.
  1707  		penaltyFromVesting, penaltyFromBalance, err := st.RepayPartialDebtInPriorityOrder(store, rt.CurrEpoch(), rt.CurrentBalance())
  1708  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to repay penalty")
  1709  		pledgeDeltaTotal = big.Sub(pledgeDeltaTotal, penaltyFromVesting)
  1710  		toBurn = big.Add(penaltyFromVesting, penaltyFromBalance)
  1711  	})
  1712  
  1713  	notifyPledgeChanged(rt, pledgeDeltaTotal)
  1714  	burnFunds(rt, toBurn)
  1715  	rt.StateReadonly(&st)
  1716  	err := st.CheckBalanceInvariants(rt.CurrentBalance())
  1717  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1718  
  1719  	return nil
  1720  }
  1721  
  1722  //type ReportConsensusFaultParams struct {
  1723  //	BlockHeader1     []byte
  1724  //	BlockHeader2     []byte
  1725  //	BlockHeaderExtra []byte
  1726  //}
  1727  type ReportConsensusFaultParams = miner0.ReportConsensusFaultParams
  1728  
  1729  func (a Actor) ReportConsensusFault(rt Runtime, params *ReportConsensusFaultParams) *abi.EmptyValue {
  1730  	// Note: only the first report of any fault is processed because it sets the
  1731  	// ConsensusFaultElapsed state variable to an epoch after the fault, and reports prior to
  1732  	// that epoch are no longer valid.
  1733  	rt.ValidateImmediateCallerType(builtin.CallerTypesSignable...)
  1734  	reporter := rt.Caller()
  1735  
  1736  	fault, err := rt.VerifyConsensusFault(params.BlockHeader1, params.BlockHeader2, params.BlockHeaderExtra)
  1737  	if err != nil {
  1738  		rt.Abortf(exitcode.ErrIllegalArgument, "fault not verified: %s", err)
  1739  	}
  1740  	if fault.Target != rt.Receiver() {
  1741  		rt.Abortf(exitcode.ErrIllegalArgument, "fault by %v reported to miner %v", fault.Target, rt.Receiver())
  1742  	}
  1743  
  1744  	// Elapsed since the fault (i.e. since the higher of the two blocks)
  1745  	currEpoch := rt.CurrEpoch()
  1746  	faultAge := currEpoch - fault.Epoch
  1747  	if faultAge <= 0 {
  1748  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid fault epoch %v ahead of current %v", fault.Epoch, currEpoch)
  1749  	}
  1750  
  1751  	// Penalize miner consensus fault fee
  1752  	// Give a portion of this to the reporter as reward
  1753  	var st State
  1754  	rewardStats := requestCurrentEpochBlockReward(rt)
  1755  	// The policy amounts we should burn and send to reporter
  1756  	// These may differ from actual funds send when miner goes into fee debt
  1757  	faultPenalty := ConsensusFaultPenalty(rewardStats.ThisEpochRewardSmoothed.Estimate())
  1758  	slasherReward := RewardForConsensusSlashReport(faultAge, faultPenalty)
  1759  	pledgeDelta := big.Zero()
  1760  
  1761  	// The amounts actually sent to burnt funds and reporter
  1762  	burnAmount := big.Zero()
  1763  	rewardAmount := big.Zero()
  1764  	rt.StateTransaction(&st, func() {
  1765  		info := getMinerInfo(rt, &st)
  1766  
  1767  		// verify miner hasn't already been faulted
  1768  		if fault.Epoch < info.ConsensusFaultElapsed {
  1769  			rt.Abortf(exitcode.ErrForbidden, "fault epoch %d is too old, last exclusion period ended at %d", fault.Epoch, info.ConsensusFaultElapsed)
  1770  		}
  1771  
  1772  		err := st.ApplyPenalty(faultPenalty)
  1773  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to apply penalty")
  1774  
  1775  		// Pay penalty
  1776  		penaltyFromVesting, penaltyFromBalance, err := st.RepayPartialDebtInPriorityOrder(adt.AsStore(rt), currEpoch, rt.CurrentBalance())
  1777  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to pay fees")
  1778  		// Burn the amount actually payable. Any difference in this and faultPenalty already recorded as FeeDebt
  1779  		burnAmount = big.Add(penaltyFromVesting, penaltyFromBalance)
  1780  		pledgeDelta = big.Add(pledgeDelta, penaltyFromVesting.Neg())
  1781  
  1782  		// clamp reward at funds burnt
  1783  		rewardAmount = big.Min(burnAmount, slasherReward)
  1784  		// reduce burnAmount by rewardAmount
  1785  		burnAmount = big.Sub(burnAmount, rewardAmount)
  1786  		info.ConsensusFaultElapsed = currEpoch + ConsensusFaultIneligibilityDuration
  1787  		err = st.SaveInfo(adt.AsStore(rt), info)
  1788  		builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to save miner info")
  1789  	})
  1790  	code := rt.Send(reporter, builtin.MethodSend, nil, rewardAmount, &builtin.Discard{})
  1791  	if !code.IsSuccess() {
  1792  		rt.Log(rtt.ERROR, "failed to send reward")
  1793  	}
  1794  	burnFunds(rt, burnAmount)
  1795  	notifyPledgeChanged(rt, pledgeDelta)
  1796  
  1797  	rt.StateReadonly(&st)
  1798  	err = st.CheckBalanceInvariants(rt.CurrentBalance())
  1799  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1800  
  1801  	return nil
  1802  }
  1803  
  1804  //type WithdrawBalanceParams struct {
  1805  //	AmountRequested abi.TokenAmount
  1806  //}
  1807  type WithdrawBalanceParams = miner0.WithdrawBalanceParams
  1808  
  1809  func (a Actor) WithdrawBalance(rt Runtime, params *WithdrawBalanceParams) *abi.EmptyValue {
  1810  	var st State
  1811  	if params.AmountRequested.LessThan(big.Zero()) {
  1812  		rt.Abortf(exitcode.ErrIllegalArgument, "negative fund requested for withdrawal: %s", params.AmountRequested)
  1813  	}
  1814  	var info *MinerInfo
  1815  	newlyVested := big.Zero()
  1816  	feeToBurn := big.Zero()
  1817  	availableBalance := big.Zero()
  1818  	rt.StateTransaction(&st, func() {
  1819  		var err error
  1820  		info = getMinerInfo(rt, &st)
  1821  		// Only the owner is allowed to withdraw the balance as it belongs to/is controlled by the owner
  1822  		// and not the worker.
  1823  		rt.ValidateImmediateCallerIs(info.Owner)
  1824  
  1825  		// Ensure we don't have any pending terminations.
  1826  		if count, err := st.EarlyTerminations.Count(); err != nil {
  1827  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to count early terminations")
  1828  		} else if count > 0 {
  1829  			rt.Abortf(exitcode.ErrForbidden,
  1830  				"cannot withdraw funds while %d deadlines have terminated sectors with outstanding fees",
  1831  				count,
  1832  			)
  1833  		}
  1834  
  1835  		// Unlock vested funds so we can spend them.
  1836  		newlyVested, err = st.UnlockVestedFunds(adt.AsStore(rt), rt.CurrEpoch())
  1837  		if err != nil {
  1838  			rt.Abortf(exitcode.ErrIllegalState, "failed to vest fund: %v", err)
  1839  		}
  1840  		// available balance already accounts for fee debt so it is correct to call
  1841  		// this before RepayDebts. We would have to
  1842  		// subtract fee debt explicitly if we called this after.
  1843  		availableBalance, err = st.GetAvailableBalance(rt.CurrentBalance())
  1844  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to calculate available balance")
  1845  
  1846  		// Verify unlocked funds cover both InitialPledgeRequirement and FeeDebt
  1847  		// and repay fee debt now.
  1848  		feeToBurn = RepayDebtsOrAbort(rt, &st)
  1849  	})
  1850  
  1851  	amountWithdrawn := big.Min(availableBalance, params.AmountRequested)
  1852  	builtin.RequireState(rt, amountWithdrawn.GreaterThanEqual(big.Zero()), "negative amount to withdraw: %v", amountWithdrawn)
  1853  	builtin.RequireState(rt, amountWithdrawn.LessThanEqual(availableBalance), "amount to withdraw %v < available %v", amountWithdrawn, availableBalance)
  1854  
  1855  	if amountWithdrawn.GreaterThan(abi.NewTokenAmount(0)) {
  1856  		code := rt.Send(info.Owner, builtin.MethodSend, nil, amountWithdrawn, &builtin.Discard{})
  1857  		builtin.RequireSuccess(rt, code, "failed to withdraw balance")
  1858  	}
  1859  
  1860  	burnFunds(rt, feeToBurn)
  1861  
  1862  	pledgeDelta := newlyVested.Neg()
  1863  	notifyPledgeChanged(rt, pledgeDelta)
  1864  
  1865  	err := st.CheckBalanceInvariants(rt.CurrentBalance())
  1866  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1867  
  1868  	return nil
  1869  }
  1870  
  1871  func (a Actor) RepayDebt(rt Runtime, _ *abi.EmptyValue) *abi.EmptyValue {
  1872  	var st State
  1873  	var fromVesting, fromBalance abi.TokenAmount
  1874  	rt.StateTransaction(&st, func() {
  1875  		var err error
  1876  		info := getMinerInfo(rt, &st)
  1877  		rt.ValidateImmediateCallerIs(append(info.ControlAddresses, info.Owner, info.Worker)...)
  1878  
  1879  		// Repay as much fee debt as possible.
  1880  		fromVesting, fromBalance, err = st.RepayPartialDebtInPriorityOrder(adt.AsStore(rt), rt.CurrEpoch(), rt.CurrentBalance())
  1881  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to unlock fee debt")
  1882  	})
  1883  
  1884  	notifyPledgeChanged(rt, fromVesting.Neg())
  1885  	burnFunds(rt, big.Sum(fromVesting, fromBalance))
  1886  	err := st.CheckBalanceInvariants(rt.CurrentBalance())
  1887  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1888  
  1889  	return nil
  1890  }
  1891  
  1892  //////////
  1893  // Cron //
  1894  //////////
  1895  
  1896  //type CronEventPayload struct {
  1897  //	EventType CronEventType
  1898  //}
  1899  type CronEventPayload = miner0.CronEventPayload
  1900  
  1901  type CronEventType = miner0.CronEventType
  1902  
  1903  const (
  1904  	CronEventProvingDeadline          = miner0.CronEventProvingDeadline
  1905  	CronEventProcessEarlyTerminations = miner0.CronEventProcessEarlyTerminations
  1906  )
  1907  
  1908  func (a Actor) OnDeferredCronEvent(rt Runtime, payload *CronEventPayload) *abi.EmptyValue {
  1909  	rt.ValidateImmediateCallerIs(builtin.StoragePowerActorAddr)
  1910  
  1911  	switch payload.EventType {
  1912  	case CronEventProvingDeadline:
  1913  		handleProvingDeadline(rt)
  1914  	case CronEventProcessEarlyTerminations:
  1915  		if processEarlyTerminations(rt) {
  1916  			scheduleEarlyTerminationWork(rt)
  1917  		}
  1918  	}
  1919  
  1920  	var st State
  1921  	rt.StateReadonly(&st)
  1922  	err := st.CheckBalanceInvariants(rt.CurrentBalance())
  1923  	builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")
  1924  	return nil
  1925  }
  1926  
  1927  ////////////////////////////////////////////////////////////////////////////////
  1928  // Utility functions & helpers
  1929  ////////////////////////////////////////////////////////////////////////////////
  1930  
  1931  func processEarlyTerminations(rt Runtime) (more bool) {
  1932  	store := adt.AsStore(rt)
  1933  
  1934  	// TODO: We're using the current power+epoch reward. Technically, we
  1935  	// should use the power/reward at the time of termination.
  1936  	// https://github.com/filecoin-project/specs-actors/v4/pull/648
  1937  	rewardStats := requestCurrentEpochBlockReward(rt)
  1938  	pwrTotal := requestCurrentTotalPower(rt)
  1939  
  1940  	var (
  1941  		result           TerminationResult
  1942  		dealsToTerminate []market.OnMinerSectorsTerminateParams
  1943  		penalty          = big.Zero()
  1944  		pledgeDelta      = big.Zero()
  1945  	)
  1946  
  1947  	var st State
  1948  	rt.StateTransaction(&st, func() {
  1949  		var err error
  1950  		result, more, err = st.PopEarlyTerminations(store, AddressedPartitionsMax, AddressedSectorsMax)
  1951  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to pop early terminations")
  1952  
  1953  		// Nothing to do, don't waste any time.
  1954  		// This can happen if we end up processing early terminations
  1955  		// before the cron callback fires.
  1956  		if result.IsEmpty() {
  1957  			return
  1958  		}
  1959  
  1960  		info := getMinerInfo(rt, &st)
  1961  
  1962  		sectors, err := LoadSectors(store, st.Sectors)
  1963  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sectors array")
  1964  
  1965  		totalInitialPledge := big.Zero()
  1966  		dealsToTerminate = make([]market.OnMinerSectorsTerminateParams, 0, len(result.Sectors))
  1967  		err = result.ForEach(func(epoch abi.ChainEpoch, sectorNos bitfield.BitField) error {
  1968  			sectors, err := sectors.Load(sectorNos)
  1969  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sector infos")
  1970  			params := market.OnMinerSectorsTerminateParams{
  1971  				Epoch:   epoch,
  1972  				DealIDs: make([]abi.DealID, 0, len(sectors)), // estimate ~one deal per sector.
  1973  			}
  1974  			for _, sector := range sectors {
  1975  				params.DealIDs = append(params.DealIDs, sector.DealIDs...)
  1976  				totalInitialPledge = big.Add(totalInitialPledge, sector.InitialPledge)
  1977  			}
  1978  			penalty = big.Add(penalty, terminationPenalty(info.SectorSize, epoch,
  1979  				rewardStats.ThisEpochRewardSmoothed, pwrTotal.QualityAdjPowerSmoothed, sectors))
  1980  			dealsToTerminate = append(dealsToTerminate, params)
  1981  
  1982  			return nil
  1983  		})
  1984  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to process terminations")
  1985  
  1986  		// Pay penalty
  1987  		err = st.ApplyPenalty(penalty)
  1988  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to apply penalty")
  1989  
  1990  		// Remove pledge requirement.
  1991  		err = st.AddInitialPledge(totalInitialPledge.Neg())
  1992  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to add initial pledge %v", totalInitialPledge.Neg())
  1993  		pledgeDelta = big.Sub(pledgeDelta, totalInitialPledge)
  1994  
  1995  		// Use unlocked pledge to pay down outstanding fee debt
  1996  		penaltyFromVesting, penaltyFromBalance, err := st.RepayPartialDebtInPriorityOrder(store, rt.CurrEpoch(), rt.CurrentBalance())
  1997  		builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to pay penalty")
  1998  		penalty = big.Add(penaltyFromVesting, penaltyFromBalance)
  1999  		pledgeDelta = big.Sub(pledgeDelta, penaltyFromVesting)
  2000  	})
  2001  
  2002  	// We didn't do anything, abort.
  2003  	if result.IsEmpty() {
  2004  		return more
  2005  	}
  2006  
  2007  	// Burn penalty.
  2008  	burnFunds(rt, penalty)
  2009  
  2010  	// Return pledge.
  2011  	notifyPledgeChanged(rt, pledgeDelta)
  2012  
  2013  	// Terminate deals.
  2014  	for _, params := range dealsToTerminate {
  2015  		requestTerminateDeals(rt, params.Epoch, params.DealIDs)
  2016  	}
  2017  
  2018  	// reschedule cron worker, if necessary.
  2019  	return more
  2020  }
  2021  
  2022  // Invoked at the end of the last epoch for each proving deadline.
  2023  func handleProvingDeadline(rt Runtime) {
  2024  	currEpoch := rt.CurrEpoch()
  2025  	store := adt.AsStore(rt)
  2026  
  2027  	epochReward := requestCurrentEpochBlockReward(rt)
  2028  	pwrTotal := requestCurrentTotalPower(rt)
  2029  
  2030  	hadEarlyTerminations := false
  2031  
  2032  	powerDeltaTotal := NewPowerPairZero()
  2033  	penaltyTotal := abi.NewTokenAmount(0)
  2034  	pledgeDeltaTotal := abi.NewTokenAmount(0)
  2035  
  2036  	var continueCron bool
  2037  	var st State
  2038  	rt.StateTransaction(&st, func() {
  2039  		{
  2040  			// Vest locked funds.
  2041  			// This happens first so that any subsequent penalties are taken
  2042  			// from locked vesting funds before funds free this epoch.
  2043  			newlyVested, err := st.UnlockVestedFunds(store, rt.CurrEpoch())
  2044  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to vest funds")
  2045  			pledgeDeltaTotal = big.Add(pledgeDeltaTotal, newlyVested.Neg())
  2046  		}
  2047  
  2048  		{
  2049  			// Process pending worker change if any
  2050  			info := getMinerInfo(rt, &st)
  2051  			processPendingWorker(info, rt, &st)
  2052  		}
  2053  
  2054  		{
  2055  			depositToBurn, err := st.ExpirePreCommits(store, currEpoch)
  2056  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to expire pre-committed sectors")
  2057  
  2058  			err = st.ApplyPenalty(depositToBurn)
  2059  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to apply penalty")
  2060  		}
  2061  
  2062  		// Record whether or not we _had_ early terminations in the queue before this method.
  2063  		// That way, don't re-schedule a cron callback if one is already scheduled.
  2064  		hadEarlyTerminations = havePendingEarlyTerminations(rt, &st)
  2065  
  2066  		{
  2067  			result, err := st.AdvanceDeadline(store, currEpoch)
  2068  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to advance deadline")
  2069  
  2070  			// Faults detected by this missed PoSt pay no penalty, but sectors that were already faulty
  2071  			// and remain faulty through this deadline pay the fault fee.
  2072  			penaltyTarget := PledgePenaltyForContinuedFault(
  2073  				epochReward.ThisEpochRewardSmoothed,
  2074  				pwrTotal.QualityAdjPowerSmoothed,
  2075  				result.PreviouslyFaultyPower.QA,
  2076  			)
  2077  
  2078  			powerDeltaTotal = powerDeltaTotal.Add(result.PowerDelta)
  2079  			pledgeDeltaTotal = big.Add(pledgeDeltaTotal, result.PledgeDelta)
  2080  
  2081  			err = st.ApplyPenalty(penaltyTarget)
  2082  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to apply penalty")
  2083  
  2084  			penaltyFromVesting, penaltyFromBalance, err := st.RepayPartialDebtInPriorityOrder(store, currEpoch, rt.CurrentBalance())
  2085  			builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to unlock penalty")
  2086  			penaltyTotal = big.Add(penaltyFromVesting, penaltyFromBalance)
  2087  			pledgeDeltaTotal = big.Sub(pledgeDeltaTotal, penaltyFromVesting)
  2088  		}
  2089  
  2090  		continueCron = st.ContinueDeadlineCron()
  2091  		if !continueCron {
  2092  			st.DeadlineCronActive = false
  2093  		}
  2094  	})
  2095  
  2096  	// Remove power for new faults, and burn penalties.
  2097  	requestUpdatePower(rt, powerDeltaTotal)
  2098  	burnFunds(rt, penaltyTotal)
  2099  	notifyPledgeChanged(rt, pledgeDeltaTotal)
  2100  
  2101  	// Schedule cron callback for next deadline's last epoch.
  2102  	if continueCron {
  2103  		newDlInfo := st.DeadlineInfo(currEpoch + 1)
  2104  		enrollCronEvent(rt, newDlInfo.Last(), &CronEventPayload{
  2105  			EventType: CronEventProvingDeadline,
  2106  		})
  2107  	} else {
  2108  		rt.Log(rtt.INFO, "miner %s going inactive, deadline cron discontinued", rt.Receiver())
  2109  	}
  2110  
  2111  	// Record whether or not we _have_ early terminations now.
  2112  	hasEarlyTerminations := havePendingEarlyTerminations(rt, &st)
  2113  
  2114  	// If we didn't have pending early terminations before, but we do now,
  2115  	// handle them at the next epoch.
  2116  	if !hadEarlyTerminations && hasEarlyTerminations {
  2117  		// First, try to process some of these terminations.
  2118  		if processEarlyTerminations(rt) {
  2119  			// If that doesn't work, just defer till the next epoch.
  2120  			scheduleEarlyTerminationWork(rt)
  2121  		}
  2122  		// Note: _don't_ process early terminations if we had a cron
  2123  		// callback already scheduled. In that case, we'll already have
  2124  		// processed AddressedSectorsMax terminations this epoch.
  2125  	}
  2126  }
  2127  
  2128  // Check expiry is exactly *the epoch before* the start of a proving period.
  2129  func validateExpiration(rt Runtime, activation, expiration abi.ChainEpoch, sealProof abi.RegisteredSealProof) {
  2130  	// Expiration must be after activation. Check this explicitly to avoid an underflow below.
  2131  	if expiration <= activation {
  2132  		rt.Abortf(exitcode.ErrIllegalArgument, "sector expiration %v must be after activation (%v)", expiration, activation)
  2133  	}
  2134  	// expiration cannot be less than minimum after activation
  2135  	if expiration-activation < MinSectorExpiration {
  2136  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid expiration %d, total sector lifetime (%d) must exceed %d after activation %d",
  2137  			expiration, expiration-activation, MinSectorExpiration, activation)
  2138  	}
  2139  
  2140  	// expiration cannot exceed MaxSectorExpirationExtension from now
  2141  	if expiration > rt.CurrEpoch()+MaxSectorExpirationExtension {
  2142  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid expiration %d, cannot be more than %d past current epoch %d",
  2143  			expiration, MaxSectorExpirationExtension, rt.CurrEpoch())
  2144  	}
  2145  
  2146  	// total sector lifetime cannot exceed SectorMaximumLifetime for the sector's seal proof
  2147  	maxLifetime, err := builtin.SealProofSectorMaximumLifetime(sealProof, rt.NetworkVersion())
  2148  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "unrecognized seal proof type %d", sealProof)
  2149  	if expiration-activation > maxLifetime {
  2150  		rt.Abortf(exitcode.ErrIllegalArgument, "invalid expiration %d, total sector lifetime (%d) cannot exceed %d after activation %d",
  2151  			expiration, expiration-activation, maxLifetime, activation)
  2152  	}
  2153  }
  2154  
  2155  func validateReplaceSector(rt Runtime, st *State, store adt.Store, params *PreCommitSectorParams) {
  2156  	replaceSector, found, err := st.GetSector(store, params.ReplaceSectorNumber)
  2157  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to load sector %v", params.SectorNumber)
  2158  	if !found {
  2159  		rt.Abortf(exitcode.ErrNotFound, "no such sector %v to replace", params.ReplaceSectorNumber)
  2160  	}
  2161  
  2162  	if len(replaceSector.DealIDs) > 0 {
  2163  		rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector %v which has deals", params.ReplaceSectorNumber)
  2164  	}
  2165  	// From network version 7, the new sector's seal type must have the same Window PoSt proof type as the one
  2166  	// being replaced, rather than be exactly the same seal type.
  2167  	// This permits replacing sectors with V1 seal types with V1_1 seal types.
  2168  	replaceWPoStProof, err := replaceSector.SealProof.RegisteredWindowPoStProof()
  2169  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to lookup Window PoSt proof type for sector seal proof %d", replaceSector.SealProof)
  2170  	newWPoStProof, err := params.SealProof.RegisteredWindowPoStProof()
  2171  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "failed to lookup Window PoSt proof type for new seal proof %d", params.SealProof)
  2172  	if newWPoStProof != replaceWPoStProof {
  2173  		rt.Abortf(exitcode.ErrIllegalArgument, "new sector window PoSt proof type %d must match replaced proof type %d (seal proof type %d)",
  2174  			newWPoStProof, replaceWPoStProof, params.SealProof)
  2175  	}
  2176  	if params.Expiration < replaceSector.Expiration {
  2177  		rt.Abortf(exitcode.ErrIllegalArgument, "cannot replace sector %v expiration %v with sooner expiration %v",
  2178  			params.ReplaceSectorNumber, replaceSector.Expiration, params.Expiration)
  2179  	}
  2180  
  2181  	err = st.CheckSectorHealth(store, params.ReplaceSectorDeadline, params.ReplaceSectorPartition, params.ReplaceSectorNumber)
  2182  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to replace sector %v", params.ReplaceSectorNumber)
  2183  }
  2184  
  2185  func enrollCronEvent(rt Runtime, eventEpoch abi.ChainEpoch, callbackPayload *CronEventPayload) {
  2186  	payload := new(bytes.Buffer)
  2187  	err := callbackPayload.MarshalCBOR(payload)
  2188  	if err != nil {
  2189  		rt.Abortf(exitcode.ErrIllegalArgument, "failed to serialize payload: %v", err)
  2190  	}
  2191  	code := rt.Send(
  2192  		builtin.StoragePowerActorAddr,
  2193  		builtin.MethodsPower.EnrollCronEvent,
  2194  		&power.EnrollCronEventParams{
  2195  			EventEpoch: eventEpoch,
  2196  			Payload:    payload.Bytes(),
  2197  		},
  2198  		abi.NewTokenAmount(0),
  2199  		&builtin.Discard{},
  2200  	)
  2201  	builtin.RequireSuccess(rt, code, "failed to enroll cron event")
  2202  }
  2203  
  2204  func requestUpdatePower(rt Runtime, delta PowerPair) {
  2205  	if delta.IsZero() {
  2206  		return
  2207  	}
  2208  	code := rt.Send(
  2209  		builtin.StoragePowerActorAddr,
  2210  		builtin.MethodsPower.UpdateClaimedPower,
  2211  		&power.UpdateClaimedPowerParams{
  2212  			RawByteDelta:         delta.Raw,
  2213  			QualityAdjustedDelta: delta.QA,
  2214  		},
  2215  		abi.NewTokenAmount(0),
  2216  		&builtin.Discard{},
  2217  	)
  2218  	builtin.RequireSuccess(rt, code, "failed to update power with %v", delta)
  2219  }
  2220  
  2221  func requestTerminateDeals(rt Runtime, epoch abi.ChainEpoch, dealIDs []abi.DealID) {
  2222  	for len(dealIDs) > 0 {
  2223  		size := min64(cbg.MaxLength, uint64(len(dealIDs)))
  2224  		code := rt.Send(
  2225  			builtin.StorageMarketActorAddr,
  2226  			builtin.MethodsMarket.OnMinerSectorsTerminate,
  2227  			&market.OnMinerSectorsTerminateParams{
  2228  				Epoch:   epoch,
  2229  				DealIDs: dealIDs[:size],
  2230  			},
  2231  			abi.NewTokenAmount(0),
  2232  			&builtin.Discard{},
  2233  		)
  2234  		builtin.RequireSuccess(rt, code, "failed to terminate deals, exit code %v", code)
  2235  		dealIDs = dealIDs[size:]
  2236  	}
  2237  }
  2238  
  2239  func scheduleEarlyTerminationWork(rt Runtime) {
  2240  	enrollCronEvent(rt, rt.CurrEpoch()+1, &CronEventPayload{
  2241  		EventType: CronEventProcessEarlyTerminations,
  2242  	})
  2243  }
  2244  
  2245  func havePendingEarlyTerminations(rt Runtime, st *State) bool {
  2246  	// Record this up-front
  2247  	noEarlyTerminations, err := st.EarlyTerminations.IsEmpty()
  2248  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "failed to count early terminations")
  2249  	return !noEarlyTerminations
  2250  }
  2251  
  2252  func verifyWindowedPost(rt Runtime, challengeEpoch abi.ChainEpoch, sectors []*SectorOnChainInfo, proofs []proof.PoStProof) error {
  2253  	minerActorID, err := addr.IDFromAddress(rt.Receiver())
  2254  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "runtime provided bad receiver address %v", rt.Receiver())
  2255  
  2256  	// Regenerate challenge randomness, which must match that generated for the proof.
  2257  	var addrBuf bytes.Buffer
  2258  	receiver := rt.Receiver()
  2259  	err = receiver.MarshalCBOR(&addrBuf)
  2260  	builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to marshal address for window post challenge")
  2261  	postRandomness := rt.GetRandomnessFromBeacon(crypto.DomainSeparationTag_WindowedPoStChallengeSeed, challengeEpoch, addrBuf.Bytes())
  2262  
  2263  	sectorProofInfo := make([]proof.SectorInfo, len(sectors))
  2264  	for i, s := range sectors {
  2265  		sectorProofInfo[i] = proof.SectorInfo{
  2266  			SealProof:    s.SealProof,
  2267  			SectorNumber: s.SectorNumber,
  2268  			SealedCID:    s.SealedCID,
  2269  		}
  2270  	}
  2271  
  2272  	// Get public inputs
  2273  	pvInfo := proof.WindowPoStVerifyInfo{
  2274  		Randomness:        abi.PoStRandomness(postRandomness),
  2275  		Proofs:            proofs,
  2276  		ChallengedSectors: sectorProofInfo,
  2277  		Prover:            abi.ActorID(minerActorID),
  2278  	}
  2279  
  2280  	// Verify the PoSt Proof
  2281  	err = rt.VerifyPoSt(pvInfo)
  2282  	if err != nil {
  2283  		return fmt.Errorf("invalid PoSt %+v: %w", pvInfo, err)
  2284  	}
  2285  	return nil
  2286  }
  2287  
  2288  // SealVerifyParams is the structure of information that must be sent with a
  2289  // message to commit a sector. Most of this information is not needed in the
  2290  // state tree but will be verified in sm.CommitSector. See SealCommitment for
  2291  // data stored on the state tree for each sector.
  2292  type SealVerifyStuff struct {
  2293  	SealedCID        cid.Cid        // CommR
  2294  	InteractiveEpoch abi.ChainEpoch // Used to derive the interactive PoRep challenge.
  2295  	abi.RegisteredSealProof
  2296  	Proof   []byte
  2297  	DealIDs []abi.DealID
  2298  	abi.SectorNumber
  2299  	SealRandEpoch abi.ChainEpoch // Used to tie the seal to a chain.
  2300  }
  2301  
  2302  func getVerifyInfo(rt Runtime, params *SealVerifyStuff) *proof.SealVerifyInfo {
  2303  	if rt.CurrEpoch() <= params.InteractiveEpoch {
  2304  		rt.Abortf(exitcode.ErrForbidden, "too early to prove sector")
  2305  	}
  2306  
  2307  	commD := requestUnsealedSectorCID(rt, params.RegisteredSealProof, params.DealIDs)
  2308  
  2309  	minerActorID, err := addr.IDFromAddress(rt.Receiver())
  2310  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "runtime provided non-ID receiver address %v", rt.Receiver())
  2311  
  2312  	buf := new(bytes.Buffer)
  2313  	receiver := rt.Receiver()
  2314  	err = receiver.MarshalCBOR(buf)
  2315  	builtin.RequireNoErr(rt, err, exitcode.ErrSerialization, "failed to marshal address for seal verification challenge")
  2316  
  2317  	svInfoRandomness := rt.GetRandomnessFromTickets(crypto.DomainSeparationTag_SealRandomness, params.SealRandEpoch, buf.Bytes())
  2318  	svInfoInteractiveRandomness := rt.GetRandomnessFromBeacon(crypto.DomainSeparationTag_InteractiveSealChallengeSeed, params.InteractiveEpoch, buf.Bytes())
  2319  
  2320  	return &proof.SealVerifyInfo{
  2321  		SealProof: params.RegisteredSealProof,
  2322  		SectorID: abi.SectorID{
  2323  			Miner:  abi.ActorID(minerActorID),
  2324  			Number: params.SectorNumber,
  2325  		},
  2326  		DealIDs:               params.DealIDs,
  2327  		InteractiveRandomness: abi.InteractiveSealRandomness(svInfoInteractiveRandomness),
  2328  		Proof:                 params.Proof,
  2329  		Randomness:            abi.SealRandomness(svInfoRandomness),
  2330  		SealedCID:             params.SealedCID,
  2331  		UnsealedCID:           commD,
  2332  	}
  2333  }
  2334  
  2335  // Requests the storage market actor compute the unsealed sector CID from a sector's deals.
  2336  func requestUnsealedSectorCID(rt Runtime, proofType abi.RegisteredSealProof, dealIDs []abi.DealID) cid.Cid {
  2337  	var unsealedCID cbg.CborCid
  2338  	code := rt.Send(
  2339  		builtin.StorageMarketActorAddr,
  2340  		builtin.MethodsMarket.ComputeDataCommitment,
  2341  		&market.ComputeDataCommitmentParams{
  2342  			SectorType: proofType,
  2343  			DealIDs:    dealIDs,
  2344  		},
  2345  		abi.NewTokenAmount(0),
  2346  		&unsealedCID,
  2347  	)
  2348  	builtin.RequireSuccess(rt, code, "failed request for unsealed sector CID for deals %v", dealIDs)
  2349  	return cid.Cid(unsealedCID)
  2350  }
  2351  
  2352  func requestDealWeights(rt Runtime, sectors []market.SectorDeals) *market.VerifyDealsForActivationReturn {
  2353  	// Short-circuit if there are no deals in any of the sectors.
  2354  	dealCount := 0
  2355  	for _, sector := range sectors {
  2356  		dealCount += len(sector.DealIDs)
  2357  	}
  2358  	if dealCount == 0 {
  2359  		emptyResult := &market.VerifyDealsForActivationReturn{
  2360  			Sectors: make([]market.SectorWeights, len(sectors)),
  2361  		}
  2362  		for i := 0; i < len(sectors); i++ {
  2363  			emptyResult.Sectors[i] = market.SectorWeights{
  2364  				DealSpace:          0,
  2365  				DealWeight:         big.Zero(),
  2366  				VerifiedDealWeight: big.Zero(),
  2367  			}
  2368  		}
  2369  		return emptyResult
  2370  	}
  2371  
  2372  	var dealWeights market.VerifyDealsForActivationReturn
  2373  	code := rt.Send(
  2374  		builtin.StorageMarketActorAddr,
  2375  		builtin.MethodsMarket.VerifyDealsForActivation,
  2376  		&market.VerifyDealsForActivationParams{
  2377  			Sectors: sectors,
  2378  		},
  2379  		abi.NewTokenAmount(0),
  2380  		&dealWeights,
  2381  	)
  2382  	builtin.RequireSuccess(rt, code, "failed to verify deals and get deal weight")
  2383  	return &dealWeights
  2384  }
  2385  
  2386  // Requests the current epoch target block reward from the reward actor.
  2387  // return value includes reward, smoothed estimate of reward, and baseline power
  2388  func requestCurrentEpochBlockReward(rt Runtime) reward.ThisEpochRewardReturn {
  2389  	var ret reward.ThisEpochRewardReturn
  2390  	code := rt.Send(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), &ret)
  2391  	builtin.RequireSuccess(rt, code, "failed to check epoch baseline power")
  2392  	return ret
  2393  }
  2394  
  2395  // Requests the current network total power and pledge from the power actor.
  2396  func requestCurrentTotalPower(rt Runtime) *power.CurrentTotalPowerReturn {
  2397  	var pwr power.CurrentTotalPowerReturn
  2398  	code := rt.Send(builtin.StoragePowerActorAddr, builtin.MethodsPower.CurrentTotalPower, nil, big.Zero(), &pwr)
  2399  	builtin.RequireSuccess(rt, code, "failed to check current power")
  2400  	return &pwr
  2401  }
  2402  
  2403  // Resolves an address to an ID address and verifies that it is address of an account or multisig actor.
  2404  func resolveControlAddress(rt Runtime, raw addr.Address) addr.Address {
  2405  	resolved, ok := rt.ResolveAddress(raw)
  2406  	if !ok {
  2407  		rt.Abortf(exitcode.ErrIllegalArgument, "unable to resolve address %v", raw)
  2408  	}
  2409  	ownerCode, ok := rt.GetActorCodeCID(resolved)
  2410  	if !ok {
  2411  		rt.Abortf(exitcode.ErrIllegalArgument, "no code for address %v", resolved)
  2412  	}
  2413  	if !builtin.IsPrincipal(ownerCode) {
  2414  		rt.Abortf(exitcode.ErrIllegalArgument, "owner actor type must be a principal, was %v", ownerCode)
  2415  	}
  2416  	return resolved
  2417  }
  2418  
  2419  // Resolves an address to an ID address and verifies that it is address of an account actor with an associated BLS key.
  2420  // The worker must be BLS since the worker key will be used alongside a BLS-VRF.
  2421  func resolveWorkerAddress(rt Runtime, raw addr.Address) addr.Address {
  2422  	resolved, ok := rt.ResolveAddress(raw)
  2423  	if !ok {
  2424  		rt.Abortf(exitcode.ErrIllegalArgument, "unable to resolve address %v", raw)
  2425  	}
  2426  	workerCode, ok := rt.GetActorCodeCID(resolved)
  2427  	if !ok {
  2428  		rt.Abortf(exitcode.ErrIllegalArgument, "no code for address %v", resolved)
  2429  	}
  2430  	if workerCode != builtin.AccountActorCodeID {
  2431  		rt.Abortf(exitcode.ErrIllegalArgument, "worker actor type must be an account, was %v", workerCode)
  2432  	}
  2433  
  2434  	if raw.Protocol() != addr.BLS {
  2435  		var pubkey addr.Address
  2436  		code := rt.Send(resolved, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &pubkey)
  2437  		builtin.RequireSuccess(rt, code, "failed to fetch account pubkey from %v", resolved)
  2438  		if pubkey.Protocol() != addr.BLS {
  2439  			rt.Abortf(exitcode.ErrIllegalArgument, "worker account %v must have BLS pubkey, was %v", resolved, pubkey.Protocol())
  2440  		}
  2441  	}
  2442  	return resolved
  2443  }
  2444  
  2445  func burnFunds(rt Runtime, amt abi.TokenAmount) {
  2446  	if amt.GreaterThan(big.Zero()) {
  2447  		code := rt.Send(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, amt, &builtin.Discard{})
  2448  		builtin.RequireSuccess(rt, code, "failed to burn funds")
  2449  	}
  2450  }
  2451  
  2452  func notifyPledgeChanged(rt Runtime, pledgeDelta abi.TokenAmount) {
  2453  	if !pledgeDelta.IsZero() {
  2454  		code := rt.Send(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), &builtin.Discard{})
  2455  		builtin.RequireSuccess(rt, code, "failed to update total pledge")
  2456  	}
  2457  }
  2458  
  2459  // Assigns proving period offset randomly in the range [0, WPoStProvingPeriod) by hashing
  2460  // the actor's address and current epoch.
  2461  func assignProvingPeriodOffset(myAddr addr.Address, currEpoch abi.ChainEpoch, hash func(data []byte) [32]byte) (abi.ChainEpoch, error) {
  2462  	offsetSeed := bytes.Buffer{}
  2463  	err := myAddr.MarshalCBOR(&offsetSeed)
  2464  	if err != nil {
  2465  		return 0, fmt.Errorf("failed to serialize address: %w", err)
  2466  	}
  2467  
  2468  	err = binary.Write(&offsetSeed, binary.BigEndian, currEpoch)
  2469  	if err != nil {
  2470  		return 0, fmt.Errorf("failed to serialize epoch: %w", err)
  2471  	}
  2472  
  2473  	digest := hash(offsetSeed.Bytes())
  2474  	var offset uint64
  2475  	err = binary.Read(bytes.NewBuffer(digest[:]), binary.BigEndian, &offset)
  2476  	if err != nil {
  2477  		return 0, fmt.Errorf("failed to interpret digest: %w", err)
  2478  	}
  2479  
  2480  	offset = offset % uint64(WPoStProvingPeriod)
  2481  	return abi.ChainEpoch(offset), nil
  2482  }
  2483  
  2484  // Computes the epoch at which a proving period should start such that it is greater than the current epoch, and
  2485  // has a defined offset from being an exact multiple of WPoStProvingPeriod.
  2486  // A miner is exempt from Winow PoSt until the first full proving period starts.
  2487  func currentProvingPeriodStart(currEpoch abi.ChainEpoch, offset abi.ChainEpoch) abi.ChainEpoch {
  2488  	currModulus := currEpoch % WPoStProvingPeriod
  2489  	var periodProgress abi.ChainEpoch // How far ahead is currEpoch from previous offset boundary.
  2490  	if currModulus >= offset {
  2491  		periodProgress = currModulus - offset
  2492  	} else {
  2493  		periodProgress = WPoStProvingPeriod - (offset - currModulus)
  2494  	}
  2495  
  2496  	periodStart := currEpoch - periodProgress
  2497  	return periodStart
  2498  }
  2499  
  2500  // Computes the deadline index for the current epoch for a given period start.
  2501  // currEpoch must be within the proving period that starts at provingPeriodStart to produce a valid index.
  2502  func currentDeadlineIndex(currEpoch abi.ChainEpoch, periodStart abi.ChainEpoch) uint64 {
  2503  	return uint64((currEpoch - periodStart) / WPoStChallengeWindow)
  2504  }
  2505  
  2506  func asMapBySectorNumber(sectors []*SectorOnChainInfo) map[abi.SectorNumber]*SectorOnChainInfo {
  2507  	m := make(map[abi.SectorNumber]*SectorOnChainInfo, len(sectors))
  2508  	for _, s := range sectors {
  2509  		m[s.SectorNumber] = s
  2510  	}
  2511  	return m
  2512  }
  2513  
  2514  func replacedSectorParameters(rt Runtime, precommit *SectorPreCommitOnChainInfo,
  2515  	replacedByNum map[abi.SectorNumber]*SectorOnChainInfo) (pledge abi.TokenAmount, age abi.ChainEpoch, dayReward big.Int) {
  2516  	if !precommit.Info.ReplaceCapacity {
  2517  		return big.Zero(), abi.ChainEpoch(0), big.Zero()
  2518  	}
  2519  	replaced, ok := replacedByNum[precommit.Info.ReplaceSectorNumber]
  2520  	if !ok {
  2521  		rt.Abortf(exitcode.ErrNotFound, "no such sector %v to replace", precommit.Info.ReplaceSectorNumber)
  2522  	}
  2523  	// The sector will actually be active for the period between activation and its next proving deadline,
  2524  	// but this covers the period for which we will be looking to the old sector for termination fees.
  2525  	return replaced.InitialPledge,
  2526  		maxEpoch(0, rt.CurrEpoch()-replaced.Activation),
  2527  		replaced.ExpectedDayReward
  2528  }
  2529  
  2530  // Update worker address with pending worker key if exists and delay has passed
  2531  func processPendingWorker(info *MinerInfo, rt Runtime, st *State) {
  2532  	if info.PendingWorkerKey == nil || rt.CurrEpoch() < info.PendingWorkerKey.EffectiveAt {
  2533  		return
  2534  	}
  2535  
  2536  	info.Worker = info.PendingWorkerKey.NewWorker
  2537  	info.PendingWorkerKey = nil
  2538  
  2539  	err := st.SaveInfo(adt.AsStore(rt), info)
  2540  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not save miner info")
  2541  }
  2542  
  2543  // Computes deadline information for a fault or recovery declaration.
  2544  // If the deadline has not yet elapsed, the declaration is taken as being for the current proving period.
  2545  // If the deadline has elapsed, it's instead taken as being for the next proving period after the current epoch.
  2546  func declarationDeadlineInfo(periodStart abi.ChainEpoch, deadlineIdx uint64, currEpoch abi.ChainEpoch) (*dline.Info, error) {
  2547  	if deadlineIdx >= WPoStPeriodDeadlines {
  2548  		return nil, fmt.Errorf("invalid deadline %d, must be < %d", deadlineIdx, WPoStPeriodDeadlines)
  2549  	}
  2550  
  2551  	deadline := NewDeadlineInfo(periodStart, deadlineIdx, currEpoch).NextNotElapsed()
  2552  	return deadline, nil
  2553  }
  2554  
  2555  // Checks that a fault or recovery declaration at a specific deadline is outside the exclusion window for the deadline.
  2556  func validateFRDeclarationDeadline(deadline *dline.Info) error {
  2557  	if deadline.FaultCutoffPassed() {
  2558  		return fmt.Errorf("late fault or recovery declaration at %v", deadline)
  2559  	}
  2560  	return nil
  2561  }
  2562  
  2563  // Validates that a partition contains the given sectors.
  2564  func validatePartitionContainsSectors(partition *Partition, sectors bitfield.BitField) error {
  2565  	// Check that the declared sectors are actually assigned to the partition.
  2566  	contains, err := BitFieldContainsAll(partition.Sectors, sectors)
  2567  	if err != nil {
  2568  		return xerrors.Errorf("failed to check sectors: %w", err)
  2569  	}
  2570  	if !contains {
  2571  		return xerrors.Errorf("not all sectors are assigned to the partition")
  2572  	}
  2573  	return nil
  2574  }
  2575  
  2576  func terminationPenalty(sectorSize abi.SectorSize, currEpoch abi.ChainEpoch,
  2577  	rewardEstimate, networkQAPowerEstimate smoothing.FilterEstimate, sectors []*SectorOnChainInfo) abi.TokenAmount {
  2578  	totalFee := big.Zero()
  2579  	for _, s := range sectors {
  2580  		sectorPower := QAPowerForSector(sectorSize, s)
  2581  		fee := PledgePenaltyForTermination(s.ExpectedDayReward, currEpoch-s.Activation, s.ExpectedStoragePledge,
  2582  			networkQAPowerEstimate, sectorPower, rewardEstimate, s.ReplacedDayReward, s.ReplacedSectorAge)
  2583  		totalFee = big.Add(fee, totalFee)
  2584  	}
  2585  	return totalFee
  2586  }
  2587  
  2588  func PowerForSector(sectorSize abi.SectorSize, sector *SectorOnChainInfo) PowerPair {
  2589  	return PowerPair{
  2590  		Raw: big.NewIntUnsigned(uint64(sectorSize)),
  2591  		QA:  QAPowerForSector(sectorSize, sector),
  2592  	}
  2593  }
  2594  
  2595  // Returns the sum of the raw byte and quality-adjusted power for sectors.
  2596  func PowerForSectors(ssize abi.SectorSize, sectors []*SectorOnChainInfo) PowerPair {
  2597  	qa := big.Zero()
  2598  	for _, s := range sectors {
  2599  		qa = big.Add(qa, QAPowerForSector(ssize, s))
  2600  	}
  2601  
  2602  	return PowerPair{
  2603  		Raw: big.Mul(big.NewIntUnsigned(uint64(ssize)), big.NewIntUnsigned(uint64(len(sectors)))),
  2604  		QA:  qa,
  2605  	}
  2606  }
  2607  
  2608  func ConsensusFaultActive(info *MinerInfo, currEpoch abi.ChainEpoch) bool {
  2609  	// For penalization period to last for exactly finality epochs
  2610  	// consensus faults are active until currEpoch exceeds ConsensusFaultElapsed
  2611  	return currEpoch <= info.ConsensusFaultElapsed
  2612  }
  2613  
  2614  func getMinerInfo(rt Runtime, st *State) *MinerInfo {
  2615  	info, err := st.GetInfo(adt.AsStore(rt))
  2616  	builtin.RequireNoErr(rt, err, exitcode.ErrIllegalState, "could not read miner info")
  2617  	return info
  2618  }
  2619  
  2620  func min64(a, b uint64) uint64 {
  2621  	if a < b {
  2622  		return a
  2623  	}
  2624  	return b
  2625  }
  2626  
  2627  func max64(a, b uint64) uint64 {
  2628  	if a > b {
  2629  		return a
  2630  	}
  2631  	return b
  2632  }
  2633  
  2634  func minEpoch(a, b abi.ChainEpoch) abi.ChainEpoch {
  2635  	if a < b {
  2636  		return a
  2637  	}
  2638  	return b
  2639  }
  2640  
  2641  func maxEpoch(a, b abi.ChainEpoch) abi.ChainEpoch {
  2642  	if a > b {
  2643  		return a
  2644  	}
  2645  	return b
  2646  }
  2647  
  2648  func checkControlAddresses(rt Runtime, controlAddrs []addr.Address) {
  2649  	if len(controlAddrs) > MaxControlAddresses {
  2650  		rt.Abortf(exitcode.ErrIllegalArgument, "control addresses length %d exceeds max control addresses length %d", len(controlAddrs), MaxControlAddresses)
  2651  	}
  2652  }
  2653  
  2654  func checkPeerInfo(rt Runtime, peerID abi.PeerID, multiaddrs []abi.Multiaddrs) {
  2655  	if len(peerID) > MaxPeerIDLength {
  2656  		rt.Abortf(exitcode.ErrIllegalArgument, "peer ID size of %d exceeds maximum size of %d", peerID, MaxPeerIDLength)
  2657  	}
  2658  
  2659  	totalSize := 0
  2660  	for _, ma := range multiaddrs {
  2661  		if len(ma) == 0 {
  2662  			rt.Abortf(exitcode.ErrIllegalArgument, "invalid empty multiaddr")
  2663  		}
  2664  		totalSize += len(ma)
  2665  	}
  2666  	if totalSize > MaxMultiaddrData {
  2667  		rt.Abortf(exitcode.ErrIllegalArgument, "multiaddr size of %d exceeds maximum of %d", totalSize, MaxMultiaddrData)
  2668  	}
  2669  }