From b68a944b0febb96c343992aa1d1389cd5cf07334 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Thu, 20 Mar 2025 17:55:05 +1100 Subject: [PATCH] feat: integrate & test FIP-0098 additions Ref: https://github.com/filecoin-project/go-state-types/pull/376 Ref: https://github.com/filecoin-project/builtin-actors/pull/1639 --- chain/actors/builtin/miner/actor.go.template | 117 +++++++++++-- chain/actors/builtin/miner/miner.go | 62 +++++++ chain/actors/builtin/power/actor.go.template | 8 +- chain/actors/builtin/power/power.go | 6 + chain/actors/policy/policy.go | 70 +------- chain/actors/policy/policy.go.template | 26 +-- go.mod | 2 +- go.sum | 4 +- itests/sector_terminate_test.go | 163 ++++++++++++++++++- 9 files changed, 352 insertions(+), 106 deletions(-) diff --git a/chain/actors/builtin/miner/actor.go.template b/chain/actors/builtin/miner/actor.go.template index 058de451514..29f23c17922 100644 --- a/chain/actors/builtin/miner/actor.go.template +++ b/chain/actors/builtin/miner/actor.go.template @@ -2,33 +2,41 @@ package miner import ( "github.com/ipfs/go-cid" - actorstypes "github.com/filecoin-project/go-state-types/actors" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/go-state-types/network" - "github.com/filecoin-project/lotus/chain/actors" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" + actorstypes "github.com/filecoin-project/go-state-types/actors" + "github.com/filecoin-project/go-state-types/big" + gstbuiltin "github.com/filecoin-project/go-state-types/builtin" + minertypes13 "github.com/filecoin-project/go-state-types/builtin/v13/miner" +{{- range .versions}} + {{- if (ge . 16)}} + minertypes{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/miner" + smoothing{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/util/smoothing" + {{- end -}} +{{end}} + minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-state-types/manifest" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/proof" +{{- range .versions}} + {{- if (le . 7)}} + builtin{{.}} "github.com/filecoin-project/specs-actors{{import .}}actors/builtin" + {{- end -}} +{{end}} + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" - minertypes16 "github.com/filecoin-project/go-state-types/builtin/v16/miner" - minertypes13 "github.com/filecoin-project/go-state-types/builtin/v13/miner" - minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" - "github.com/filecoin-project/go-state-types/manifest" - -{{range .versions}} - {{if (le . 7)}} - builtin{{.}} "github.com/filecoin-project/specs-actors{{import .}}actors/builtin" - {{end}} -{{end}} ) +var Methods = gstbuiltin.MethodsMiner + func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { if name != manifest.MinerKey { @@ -81,6 +89,7 @@ type State interface { // Funds locked for various reasons. LockedFunds() (LockedFunds, error) FeeDebt() (abi.TokenAmount, error) + InitialPledge() (abi.TokenAmount, error) // Returns nil, nil if sector is not found GetSector(abi.SectorNumber) (*SectorOnChainInfo, error) @@ -155,7 +164,7 @@ type Partition interface { UnprovenSectors() (bitfield.BitField, error) } -type SectorOnChainInfo = minertypes16.SectorOnChainInfo +type SectorOnChainInfo = minertypes{{.latestVersion}}.SectorOnChainInfo func PreferredSealProofTypeFromWindowPoStType(nver network.Version, proof abi.RegisteredPoStProof, configWantSynthetic bool) (abi.RegisteredSealProof, error) { // We added support for the new proofs in network version 7, and removed support for the old @@ -252,13 +261,16 @@ type SectorClaim = minertypes.SectorClaim type ExpirationExtension2 = minertypes.ExpirationExtension2 type CompactPartitionsParams = minertypes.CompactPartitionsParams type WithdrawBalanceParams = minertypes.WithdrawBalanceParams +type MaxTerminationFeeParams = minertypes{{.latestVersion}}.MaxTerminationFeeParams +type MaxTerminationFeeReturn = minertypes{{.latestVersion}}.MaxTerminationFeeReturn +type InitialPledgeReturn = minertypes{{.latestVersion}}.InitialPledgeReturn type PieceActivationManifest = minertypes13.PieceActivationManifest type ProveCommitSectors3Params = minertypes13.ProveCommitSectors3Params type SectorActivationManifest = minertypes13.SectorActivationManifest type ProveReplicaUpdates3Params = minertypes13.ProveReplicaUpdates3Params type SectorUpdateManifest = minertypes13.SectorUpdateManifest -type SectorOnChainInfoFlags = minertypes16.SectorOnChainInfoFlags +type SectorOnChainInfoFlags = minertypes{{.latestVersion}}.SectorOnChainInfoFlags type VerifiedAllocationKey = minertypes13.VerifiedAllocationKey var QAPowerMax = minertypes.QAPowerMax @@ -274,6 +286,9 @@ const FaultDeclarationCutoff = minertypes.FaultDeclarationCutoff const MinAggregatedSectors = minertypes.MinAggregatedSectors const MinSectorExpiration = minertypes.MinSectorExpiration +var TermFeePledgeMultiple = minertypes{{.latestVersion}}.TermFeePledgeMultiple +var TermFeeMaxFaultFeeMultiple = minertypes{{.latestVersion}}.TermFeeMaxFaultFeeMultiple + type SectorExpiration struct { OnTime abi.ChainEpoch @@ -319,3 +334,73 @@ func AllCodes() []cid.Cid { {{- end}} } } + +func PledgePenaltyForContinuedFault( + nwVer network.Version, + rewardEstimate builtin.FilterEstimate, + networkQaPowerEstimate builtin.FilterEstimate, + qaSectorPower abi.StoragePower, +) (abi.TokenAmount, error) { + v, err := actorstypes.VersionForNetwork(nwVer) + if err != nil { + return big.Zero(), err + } + + if v <= actorstypes.Version16 { + return minertypes16.PledgePenaltyForContinuedFault( + smoothing16.FilterEstimate{ + PositionEstimate: rewardEstimate.PositionEstimate, + VelocityEstimate: rewardEstimate.VelocityEstimate, + }, + smoothing16.FilterEstimate{ + PositionEstimate: networkQaPowerEstimate.PositionEstimate, + VelocityEstimate: networkQaPowerEstimate.VelocityEstimate, + }, + qaSectorPower, + ), nil + } + + switch v { + {{- range .versions}} + {{- if (gt . 16)}} + case actorstypes.Version{{.}}: + return minertypes{{.}}.PledgePenaltyForContinuedFault( + smoothing{{.}}.FilterEstimate{ + PositionEstimate: rewardEstimate.PositionEstimate, + VelocityEstimate: rewardEstimate.VelocityEstimate, + }, + smoothing{{.}}.FilterEstimate{ + PositionEstimate: networkQaPowerEstimate.PositionEstimate, + VelocityEstimate: networkQaPowerEstimate.VelocityEstimate, + }, + qaSectorPower, + ), nil + {{- end}} + {{- end}} + default: + return big.Zero(), xerrors.Errorf("unsupported network version: %d", v) + } +} + +func PledgePenaltyForTermination( + nwVer network.Version, + initialPledge abi.TokenAmount, + sectorAge abi.ChainEpoch, + faultFee abi.TokenAmount, +) (abi.TokenAmount, error) { + v, err := actorstypes.VersionForNetwork(nwVer) + if err != nil { + return big.Zero(), err + } + + switch v { + {{- range .versions}} + {{- if (ge . 16)}} + case actorstypes.Version{{.}}: + return minertypes{{.}}.PledgePenaltyForTermination(initialPledge, sectorAge, faultFee), nil + {{- end}} + {{- end}} + default: + return big.Zero(), xerrors.Errorf("unsupported network version: %d", v) + } +} \ No newline at end of file diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index 0fd65e8d399..1a9678175b8 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -9,8 +9,10 @@ import ( "github.com/filecoin-project/go-state-types/abi" actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" + gstbuiltin "github.com/filecoin-project/go-state-types/builtin" minertypes13 "github.com/filecoin-project/go-state-types/builtin/v13/miner" minertypes16 "github.com/filecoin-project/go-state-types/builtin/v16/miner" + smoothing16 "github.com/filecoin-project/go-state-types/builtin/v16/util/smoothing" minertypes "github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/dline" @@ -27,9 +29,12 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/types" ) +var Methods = gstbuiltin.MethodsMiner + func Load(store adt.Store, act *types.Actor) (State, error) { if name, av, ok := actors.GetActorMetaByCode(act.Code); ok { if name != manifest.MinerKey { @@ -165,6 +170,7 @@ type State interface { // Funds locked for various reasons. LockedFunds() (LockedFunds, error) FeeDebt() (abi.TokenAmount, error) + InitialPledge() (abi.TokenAmount, error) // Returns nil, nil if sector is not found GetSector(abi.SectorNumber) (*SectorOnChainInfo, error) @@ -336,6 +342,9 @@ type SectorClaim = minertypes.SectorClaim type ExpirationExtension2 = minertypes.ExpirationExtension2 type CompactPartitionsParams = minertypes.CompactPartitionsParams type WithdrawBalanceParams = minertypes.WithdrawBalanceParams +type MaxTerminationFeeParams = minertypes16.MaxTerminationFeeParams +type MaxTerminationFeeReturn = minertypes16.MaxTerminationFeeReturn +type InitialPledgeReturn = minertypes16.InitialPledgeReturn type PieceActivationManifest = minertypes13.PieceActivationManifest type ProveCommitSectors3Params = minertypes13.ProveCommitSectors3Params @@ -358,6 +367,9 @@ const FaultDeclarationCutoff = minertypes.FaultDeclarationCutoff const MinAggregatedSectors = minertypes.MinAggregatedSectors const MinSectorExpiration = minertypes.MinSectorExpiration +var TermFeePledgeMultiple = minertypes16.TermFeePledgeMultiple +var TermFeeMaxFaultFeeMultiple = minertypes16.TermFeeMaxFaultFeeMultiple + type SectorExpiration struct { OnTime abi.ChainEpoch @@ -417,3 +429,53 @@ func AllCodes() []cid.Cid { (&state16{}).Code(), } } + +func PledgePenaltyForContinuedFault( + nwVer network.Version, + rewardEstimate builtin.FilterEstimate, + networkQaPowerEstimate builtin.FilterEstimate, + qaSectorPower abi.StoragePower, +) (abi.TokenAmount, error) { + v, err := actorstypes.VersionForNetwork(nwVer) + if err != nil { + return big.Zero(), err + } + + if v <= actorstypes.Version16 { + return minertypes16.PledgePenaltyForContinuedFault( + smoothing16.FilterEstimate{ + PositionEstimate: rewardEstimate.PositionEstimate, + VelocityEstimate: rewardEstimate.VelocityEstimate, + }, + smoothing16.FilterEstimate{ + PositionEstimate: networkQaPowerEstimate.PositionEstimate, + VelocityEstimate: networkQaPowerEstimate.VelocityEstimate, + }, + qaSectorPower, + ), nil + } + + switch v { + default: + return big.Zero(), xerrors.Errorf("unsupported network version: %d", v) + } +} + +func PledgePenaltyForTermination( + nwVer network.Version, + initialPledge abi.TokenAmount, + sectorAge abi.ChainEpoch, + faultFee abi.TokenAmount, +) (abi.TokenAmount, error) { + v, err := actorstypes.VersionForNetwork(nwVer) + if err != nil { + return big.Zero(), err + } + + switch v { + case actorstypes.Version16: + return minertypes16.PledgePenaltyForTermination(initialPledge, sectorAge, faultFee), nil + default: + return big.Zero(), xerrors.Errorf("unsupported network version: %d", v) + } +} diff --git a/chain/actors/builtin/power/actor.go.template b/chain/actors/builtin/power/actor.go.template index 81c2676c065..5beccf5baf1 100644 --- a/chain/actors/builtin/power/actor.go.template +++ b/chain/actors/builtin/power/actor.go.template @@ -22,7 +22,8 @@ import ( builtin{{.}} "github.com/filecoin-project/specs-actors{{import .}}actors/builtin" {{end}} {{end}} - builtin{{.latestVersion}} "github.com/filecoin-project/go-state-types/builtin" + builtin{{.latestVersion}} "github.com/filecoin-project/go-state-types/builtin" + powertypes{{.latestVersion}} "github.com/filecoin-project/go-state-types/builtin/v{{.latestVersion}}/power" ) var ( @@ -137,3 +138,8 @@ func AllCodes() []cid.Cid { {{- end}} } } + +type ( + MinerPowerParams = powertypes{{.latestVersion}}.MinerPowerParams + MinerPowerReturn = powertypes{{.latestVersion}}.MinerPowerReturn +) diff --git a/chain/actors/builtin/power/power.go b/chain/actors/builtin/power/power.go index f5a56d1d4be..d46eb645663 100644 --- a/chain/actors/builtin/power/power.go +++ b/chain/actors/builtin/power/power.go @@ -10,6 +10,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/big" builtin16 "github.com/filecoin-project/go-state-types/builtin" + powertypes16 "github.com/filecoin-project/go-state-types/builtin/v16/power" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/manifest" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" @@ -235,3 +236,8 @@ func AllCodes() []cid.Cid { (&state16{}).Code(), } } + +type ( + MinerPowerParams = powertypes16.MinerPowerParams + MinerPowerReturn = powertypes16.MinerPowerReturn +) diff --git a/chain/actors/policy/policy.go b/chain/actors/policy/policy.go index 6efa7096bb8..49318eafb67 100644 --- a/chain/actors/policy/policy.go +++ b/chain/actors/policy/policy.go @@ -929,71 +929,38 @@ func AggregateProveCommitNetworkFee(nwVer network.Version, aggregateSize int, ba return big.Zero(), err } switch v { - case actorstypes.Version0: - return big.Zero(), nil - case actorstypes.Version2: - return big.Zero(), nil - case actorstypes.Version3: - return big.Zero(), nil - case actorstypes.Version4: - return big.Zero(), nil - case actorstypes.Version5: - return miner5.AggregateNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version6: - return miner6.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version7: - return miner7.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version8: - return miner8.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version9: - return miner9.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version10: - return miner10.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version11: - return miner11.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version12: - return miner12.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version13: - return miner13.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version14: - return miner14.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version15: - return miner15.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version16: - - return miner16.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - + return big.Zero(), nil default: return big.Zero(), xerrors.Errorf("unsupported network version") } @@ -1005,71 +972,38 @@ func AggregatePreCommitNetworkFee(nwVer network.Version, aggregateSize int, base return big.Zero(), err } switch v { - case actorstypes.Version0: - return big.Zero(), nil - case actorstypes.Version2: - return big.Zero(), nil - case actorstypes.Version3: - return big.Zero(), nil - case actorstypes.Version4: - return big.Zero(), nil - case actorstypes.Version5: - return big.Zero(), nil - case actorstypes.Version6: - return miner6.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version7: - return miner7.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version8: - return miner8.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version9: - return miner9.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version10: - return miner10.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version11: - return miner11.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version12: - return miner12.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version13: - return miner13.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version14: - return miner14.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version15: - return miner15.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - case actorstypes.Version16: - - return miner16.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - + return big.Zero(), nil default: return big.Zero(), xerrors.Errorf("unsupported network version") } diff --git a/chain/actors/policy/policy.go.template b/chain/actors/policy/policy.go.template index 76c92103e5e..45fe71e6ade 100644 --- a/chain/actors/policy/policy.go.template +++ b/chain/actors/policy/policy.go.template @@ -315,16 +315,18 @@ func AggregateProveCommitNetworkFee(nwVer network.Version, aggregateSize int, ba return big.Zero(), err } switch v { - {{range .versions}} + {{- range .versions}} case actorstypes.Version{{.}}: - {{if (ge . 6)}} + {{- if (ge . 16)}} + return big.Zero(), nil + {{- else if (ge . 6)}} return miner{{.}}.AggregateProveCommitNetworkFee(aggregateSize, baseFee), nil - {{else if (eq . 5)}} + {{- else if (eq . 5)}} return miner{{.}}.AggregateNetworkFee(aggregateSize, baseFee), nil - {{else}} + {{- else}} return big.Zero(), nil - {{end}} - {{end}} + {{- end -}} + {{- end}} default: return big.Zero(), xerrors.Errorf("unsupported network version") } @@ -336,14 +338,16 @@ func AggregatePreCommitNetworkFee(nwVer network.Version, aggregateSize int, base return big.Zero(), err } switch v { - {{range .versions}} + {{- range .versions}} case actorstypes.Version{{.}}: - {{if (ge . 6)}} + {{- if (ge . 16)}} + return big.Zero(), nil + {{- else if (ge . 6)}} return miner{{.}}.AggregatePreCommitNetworkFee(aggregateSize, baseFee), nil - {{else}} + {{- else}} return big.Zero(), nil - {{end}} - {{end}} + {{- end -}} + {{end}} default: return big.Zero(), xerrors.Errorf("unsupported network version") } diff --git a/go.mod b/go.mod index d99de6c1e21..e30b3b71b3a 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/filecoin-project/go-jsonrpc v0.7.0 github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-paramfetch v0.0.4 - github.com/filecoin-project/go-state-types v0.16.0-rc7 // dependency-check-ignore: unknown + github.com/filecoin-project/go-state-types v0.16.0-rc7.0.20250320064648-8f3281fc0d63 // dependency-check-ignore: unknown github.com/filecoin-project/go-statemachine v1.0.3 github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-storedcounter v0.1.0 diff --git a/go.sum b/go.sum index 53a7077625a..8ff2742c470 100644 --- a/go.sum +++ b/go.sum @@ -305,8 +305,8 @@ github.com/filecoin-project/go-state-types v0.0.0-20200928172055-2df22083d8ab/go github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.16.0-rc7 h1:ODs527FEqmq/kKj4jXqRVGUx8t8+XLPjR9aP1f+YVus= -github.com/filecoin-project/go-state-types v0.16.0-rc7/go.mod h1:YCESyrqnyu17y0MazbV6Uwma5+BrMvEKEQp5QWeIf9g= +github.com/filecoin-project/go-state-types v0.16.0-rc7.0.20250320064648-8f3281fc0d63 h1:mcsUJkoQ1+Kal1wPbIBhjZOqlON8c1sw0K4TiefVwcs= +github.com/filecoin-project/go-state-types v0.16.0-rc7.0.20250320064648-8f3281fc0d63/go.mod h1:YCESyrqnyu17y0MazbV6Uwma5+BrMvEKEQp5QWeIf9g= github.com/filecoin-project/go-statemachine v1.0.3 h1:N07o6alys+V1tNoSTi4WuuoeNC4erS/6jE74+NsgQuk= github.com/filecoin-project/go-statemachine v1.0.3/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= diff --git a/itests/sector_terminate_test.go b/itests/sector_terminate_test.go index fd05a027617..ddaec2b9421 100644 --- a/itests/sector_terminate_test.go +++ b/itests/sector_terminate_test.go @@ -6,15 +6,26 @@ import ( "testing" "time" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime/codec/dagcbor" "github.com/ipld/go-ipld-prime/node/basicnode" "github.com/multiformats/go-multicodec" "github.com/stretchr/testify/require" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" - + "github.com/filecoin-project/go-state-types/big" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin" + minertypes "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/power" + "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/lib/must" @@ -22,9 +33,6 @@ import ( ) func TestTerminate(t *testing.T) { - - kit.Expensive(t) - kit.QuietMiningLogs() var ( @@ -72,13 +80,154 @@ func TestTerminate(t *testing.T) { require.Equal(t, p.MinerPower, p.TotalPower) require.Equal(t, types.NewInt(uint64(ssz)*uint64(nSectors)), p.MinerPower.RawBytePower) - t.Log("Terminate a sector") - toTerminate := abi.SectorNumber(3) - err = miner.SectorTerminate(ctx, toTerminate) + // Testing FIP-0098 additions + + t.Log("Check MaxTerminationFee method") + + sector, err := client.StateSectorGetInfo(ctx, maddr, toTerminate, types.EmptyTSK) require.NoError(t, err) + qaPower := big.NewInt(int64(ssz * 10)) // full verified sector + + maxTermFeeCases := []struct { + power abi.StoragePower + expectedFeeAt func(tsk types.TipSetKey) abi.TokenAmount + }{ + { + // low power resulting in low fault fee => termination fee should be pledge multiple * initial pledge + power: big.Zero(), + expectedFeeAt: func(tsk types.TipSetKey) abi.TokenAmount { + return big.Div(big.Mul(sector.InitialPledge, minertypes.TermFeePledgeMultiple.Numerator), minertypes.TermFeePledgeMultiple.Denominator) + }, + }, + { + // high power resulting in high fault fee => termination fee should be fault fee * max fault fee multiple + power: qaPower, + expectedFeeAt: func(tsk types.TipSetKey) abi.TokenAmount { + var faultFee abi.TokenAmount + rewardActor, err := client.StateGetActor(ctx, reward.Address, tsk) + require.NoError(t, err) + rewardState, err := reward.Load(adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(client))), rewardActor) + require.NoError(t, err) + epochRewardSmooth, err := rewardState.ThisEpochRewardSmoothed() + require.NoError(t, err) + powerActor, err := client.StateGetActor(ctx, power.Address, tsk) + require.NoError(t, err) + powerState, err := power.Load(adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(client))), powerActor) + require.NoError(t, err) + epochQaPowerSmoothed, err := powerState.TotalPowerSmoothed() + require.NoError(t, err) + nv, err := client.StateNetworkVersion(ctx, tsk) + require.NoError(t, err) + faultFee, err = minertypes.PledgePenaltyForContinuedFault( + nv, + builtin.FilterEstimate{ + PositionEstimate: epochRewardSmooth.PositionEstimate, + VelocityEstimate: epochRewardSmooth.VelocityEstimate, + }, + builtin.FilterEstimate{ + PositionEstimate: epochQaPowerSmoothed.PositionEstimate, + VelocityEstimate: epochQaPowerSmoothed.VelocityEstimate, + }, + qaPower, + ) + require.NoError(t, err) + expectedPenalty := big.Div(big.Mul(faultFee, minertypes.TermFeeMaxFaultFeeMultiple.Numerator), minertypes.TermFeeMaxFaultFeeMultiple.Denominator) + + // compare against go-state-types implementation + calculatedPenalty, err := minertypes.PledgePenaltyForTermination(nv, sector.InitialPledge, sector.Expiration-sector.Activation, faultFee) + require.NoError(t, err) + require.Equal(t, calculatedPenalty, expectedPenalty) + return expectedPenalty + }, + }, + } + for _, tc := range maxTermFeeCases { + t.Logf("Testing MaxTerminationFeeExported method with %s", tc.power) + + params, aerr := actors.SerializeParams(&minertypes.MaxTerminationFeeParams{ + Power: tc.power, + InitialPledge: sector.InitialPledge, + }) + require.NoError(t, aerr) + sm, err := client.MpoolPushMessage(ctx, &types.Message{ + To: miner.ActorAddr, + From: client.DefaultKey.Address, + Method: minertypes.Methods.MaxTerminationFeeExported, + Params: params, + Value: big.Zero(), + }, nil) + require.NoError(t, err) + + res, err := client.StateWaitMsg(ctx, sm.Cid(), 1, lapi.LookbackNoLimit, true) + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode) + var retval minertypes.MaxTerminationFeeReturn + require.NoError(t, retval.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))) + ts, err := client.ChainGetTipSet(ctx, res.TipSet) + require.NoError(t, err) + expectedFee := tc.expectedFeeAt(ts.Parents()) + require.Equal(t, expectedFee, retval) + } + + { + t.Log("Testing InitialPledgeExported method") + sm, err := client.MpoolPushMessage(ctx, &types.Message{ + To: miner.ActorAddr, + From: client.DefaultKey.Address, + Method: minertypes.Methods.InitialPledgeExported, + Params: nil, + Value: big.Zero(), + }, nil) + require.NoError(t, err) + res, err := client.StateWaitMsg(ctx, sm.Cid(), 1, lapi.LookbackNoLimit, true) + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode) + var retval minertypes.InitialPledgeReturn + require.NoError(t, retval.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))) + ts, err := client.ChainGetTipSet(ctx, res.TipSet) + require.NoError(t, err) + actor, err := client.StateGetActor(ctx, miner.ActorAddr, ts.Parents()) + require.NoError(t, err) + actorState, err := minertypes.Load(adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(client))), actor) + require.NoError(t, err) + require.Equal(t, must.One(actorState.InitialPledge()), retval) + } + + { + t.Log("Testing MinerPowerExported method") + // This is not strictly related to terminations but it's exposed for contracts to use to + // calculate termination fees so we'll test the export here. + actorId := power.MinerPowerParams(must.One(address.IDFromAddress(miner.ActorAddr))) + params, aerr := actors.SerializeParams(&actorId) + require.NoError(t, aerr) + sm, err := client.MpoolPushMessage(ctx, &types.Message{ + To: power.Address, + From: client.DefaultKey.Address, + Method: power.Methods.MinerPowerExported, + Params: params, + Value: big.Zero(), + }, nil) + require.NoError(t, err) + res, err := client.StateWaitMsg(ctx, sm.Cid(), 1, lapi.LookbackNoLimit, true) + require.NoError(t, err) + require.EqualValues(t, 0, res.Receipt.ExitCode) + var retval power.MinerPowerReturn + require.NoError(t, retval.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return))) + ts, err := client.ChainGetTipSet(ctx, res.TipSet) + require.NoError(t, err) + minerPower, err := client.StateMinerPower(ctx, miner.ActorAddr, ts.Parents()) + require.NoError(t, err) + require.Equal(t, minerPower.MinerPower.RawBytePower, retval.RawBytePower) + require.Equal(t, minerPower.MinerPower.QualityAdjPower, retval.QualityAdjPower) + } + + t.Log("Terminate a sector") + + require.NoError(t, miner.SectorTerminate(ctx, toTerminate)) + msgTriggerred := false loop: for {