Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Commit

Permalink
Feat/param finalization (#1438)
Browse files Browse the repository at this point in the history
* Add aggregate network fee

* Fix test

* Size limit failure scenario tests

* Test network fee for aggregate

* Fix after rebase

* Review response

Co-authored-by: ZenGround0 <[email protected]>
  • Loading branch information
ZenGround0 and ZenGround0 authored May 28, 2021
1 parent 566ad95 commit a9f9f95
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 14 deletions.
5 changes: 5 additions & 0 deletions actors/builtin/miner/miner_actor.go
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,11 @@ func (a Actor) ProveCommitAggregate(rt Runtime, params *ProveCommitAggregatePara
builtin.RequireNoErr(rt, err, exitcode.ErrIllegalArgument, "aggregate seal verify failed")
confirmSectorProofsValid(rt, precommitsToConfirm)

burnFunds(rt, AggregateNetworkFee(len(precommitsToConfirm), rt.BaseFee()))
rt.StateReadonly(&st)
err = st.CheckBalanceInvariants(rt.CurrentBalance())
builtin.RequireNoErr(rt, err, ErrBalanceInvariantBroken, "balance invariants broken")

return nil
}

Expand Down
7 changes: 4 additions & 3 deletions actors/builtin/miner/miner_commitment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ func TestCommitments(t *testing.T) {

// Expires too early
rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "must exceed", func() {
actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, expiration-20*builtin.EpochsInDay, nil), preCommitConf{}, false)
earlyExpiration := abi.ChainEpoch(miner.MinSectorExpiration - builtin.EpochsInDay)
actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, earlyExpiration, nil), preCommitConf{}, false)
})
rt.Reset()

Expand Down Expand Up @@ -484,10 +485,10 @@ func TestPreCommitBatch(t *testing.T) {
error: "batch empty",
}, {
name: "too many sectors",
batchSize: 33,
batchSize: 257,
balanceSurplus: big.Zero(),
exit: exitcode.ErrIllegalArgument,
error: "batch of 33 too large",
error: "batch of 257 too large",
}, {
name: "insufficient balance",
batchSize: 10,
Expand Down
10 changes: 8 additions & 2 deletions actors/builtin/miner/miner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ var bigBalance = big.Mul(big.NewInt(1_000_000), big.NewInt(1e18))
// A reward amount for use in tests where the vesting amount wants to be large enough to cover penalties.
var bigRewards = big.Mul(big.NewInt(1_000), big.NewInt(1e18))

// an expriration 1 greater than min expiration
const defaultSectorExpiration = 190
// an expriration ~10 days greater than effective min expiration taking into account 30 days max between pre and prove commit
const defaultSectorExpiration = 220

func init() {
testPid = abi.PeerID("peerID")
Expand Down Expand Up @@ -5076,6 +5076,12 @@ func (h *actorHarness) proveCommitAggregateSector(rt *mock.Runtime, conf proveCo
h.confirmSectorProofsValidInternal(rt, conf, precommits...)
}

// burn networkFee
{
expectedFee := miner.AggregateNetworkFee(len(precommits), big.Zero())
rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectedFee, nil, exitcode.Ok)
}

rt.SetCaller(h.worker, builtin.AccountActorCodeID)
rt.ExpectValidateCallerAny()
rt.Call(h.a.ProveCommitAggregate, params)
Expand Down
14 changes: 14 additions & 0 deletions actors/builtin/miner/monies.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,17 @@ func LockedRewardFromReward(reward abi.TokenAmount) (abi.TokenAmount, *VestSpec)
lockAmount := big.Div(big.Mul(reward, LockedRewardFactorNum), LockedRewardFactorDenom)
return lockAmount, &RewardVestingSpec
}

var EstimatedSingleProofGasUsage = big.NewInt(65733297) // PARAM_SPEC
var BatchDiscount = builtin.BigFrac{ // PARAM_SPEC
Numerator: big.NewInt(1),
Denominator: big.NewInt(20),
}
var BatchBalancer = big.Mul(big.NewInt(2), builtin.OneNanoFIL) // PARAM_SPEC

func AggregateNetworkFee(aggregateSize int, baseFee abi.TokenAmount) abi.TokenAmount {
effectiveGasFee := big.Max(baseFee, BatchBalancer)
networkFeeNum := big.Product(effectiveGasFee, EstimatedSingleProofGasUsage, big.NewInt(int64(aggregateSize)), BatchDiscount.Numerator)
networkFee := big.Div(networkFeeNum, BatchDiscount.Denominator)
return networkFee
}
35 changes: 35 additions & 0 deletions actors/builtin/miner/monies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,38 @@ func TestPrecommitDepositAndInitialPledgePostiive(t *testing.T) {
assert.Equal(t, abi.NewTokenAmount(1), pcd)
})
}

func TestAggregateNetworkFee(t *testing.T) {

t.Run("Constant fee per sector when base fee is below 2 nFIL", func(t *testing.T) {
oneSectorFee := miner.AggregateNetworkFee(1, big.Zero())
tenSectorFee := miner.AggregateNetworkFee(10, big.Zero())
assert.Equal(t, big.Mul(oneSectorFee, big.NewInt(10)), tenSectorFee)
fortySectorFee := miner.AggregateNetworkFee(40, builtin.OneNanoFIL)
assert.Equal(t, big.Mul(oneSectorFee, big.NewInt(40)), fortySectorFee)
})

t.Run("Fee increases iff basefee crosses threshold", func(t *testing.T) {
atNoBaseFee := miner.AggregateNetworkFee(10, big.Zero())
atBalanceMinusOneBaseFee := miner.AggregateNetworkFee(10, big.Sub(miner.BatchBalancer, builtin.OneNanoFIL))
atBalanceBaseFee := miner.AggregateNetworkFee(10, miner.BatchBalancer)
atBalancePlusOneBaseFee := miner.AggregateNetworkFee(10, big.Sum(miner.BatchBalancer, builtin.OneNanoFIL))
atBalancePlusTwoBaseFee := miner.AggregateNetworkFee(10, big.Sum(miner.BatchBalancer, builtin.OneNanoFIL, builtin.OneNanoFIL))
atBalanceTimesTwoBaseFee := miner.AggregateNetworkFee(10, big.Mul(miner.BatchBalancer, big.NewInt(2)))

assert.True(t, atNoBaseFee.Equals(atBalanceMinusOneBaseFee))
assert.True(t, atNoBaseFee.Equals(atBalanceBaseFee))
assert.True(t, atBalanceBaseFee.LessThan(atBalancePlusOneBaseFee))
assert.True(t, atBalancePlusOneBaseFee.LessThan(atBalancePlusTwoBaseFee))
assert.True(t, atBalanceTimesTwoBaseFee.Equals(big.Mul(big.NewInt(2), atBalanceBaseFee)))
})

t.Run("Regression tests", func(t *testing.T) {
tenAtNoBaseFee := miner.AggregateNetworkFee(10, big.Zero())
assert.Equal(t, big.Mul(builtin.OneNanoFIL, big.NewInt(65733297)), tenAtNoBaseFee)
tenAtOneNanoBaseFee := miner.AggregateNetworkFee(10, builtin.OneNanoFIL)
assert.Equal(t, big.Mul(builtin.OneNanoFIL, big.NewInt(65733297)), tenAtOneNanoBaseFee)
hundredAtThreeNanoBaseFee := miner.AggregateNetworkFee(100, big.Mul(big.NewInt(3), builtin.OneNanoFIL))
assert.Equal(t, big.Mul(builtin.OneNanoFIL, big.NewInt(985999455)), hundredAtThreeNanoBaseFee)
})
}
16 changes: 8 additions & 8 deletions actors/builtin/miner/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,16 @@ var MaxProveCommitDuration = map[abi.RegisteredSealProof]abi.ChainEpoch{
abi.RegisteredSealProof_StackedDrg512MiBV1: builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg64GiBV1: builtin.EpochsInDay + PreCommitChallengeDelay,

abi.RegisteredSealProof_StackedDrg32GiBV1_1: 6*builtin.EpochsInDay + PreCommitChallengeDelay, // PARAM_SPEC
abi.RegisteredSealProof_StackedDrg2KiBV1_1: 6*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg8MiBV1_1: 6*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg512MiBV1_1: 6*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg64GiBV1_1: 6*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg32GiBV1_1: 9*builtin.EpochsInDay + PreCommitChallengeDelay, // PARAM_SPEC
abi.RegisteredSealProof_StackedDrg2KiBV1_1: 9*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg8MiBV1_1: 9*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg512MiBV1_1: 9*builtin.EpochsInDay + PreCommitChallengeDelay,
abi.RegisteredSealProof_StackedDrg64GiBV1_1: 9*builtin.EpochsInDay + PreCommitChallengeDelay,
}

// The maximum number of sector pre-commitments in a single batch.
// 32 sectors per epoch would support a single miner onboarding 1EiB of 32GiB sectors in 1 year.
const PreCommitSectorBatchMaxSize = 32
const PreCommitSectorBatchMaxSize = 256

// Maximum delay between challenge and pre-commitment.
// This prevents a miner sealing sectors far in advance of committing them to the chain, thus committing to a
Expand Down Expand Up @@ -297,8 +297,8 @@ func RewardForDisputedWindowPoSt(proofType abi.RegisteredPoStProof, disputedPowe
}

const MaxAggregatedSectors = 819
const MinAggregatedSectors = 1
const MaxAggregateProofSize = 192000
const MinAggregatedSectors = 4
const MaxAggregateProofSize = 81960

// The delay between pre commit expiration and clean up from state. This enforces that expired pre-commits
// stay in state for a period of time creating a grace period during which a late-running aggregated prove-commit
Expand Down
3 changes: 3 additions & 0 deletions actors/builtin/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ var VerifiedDealWeightMultiplier = big.NewInt(100)

// Precision used for making QA power calculations
const SectorQualityPrecision = 20

// 1 NanoFIL
var OneNanoFIL = big.NewInt(1_000_000_000)
3 changes: 3 additions & 0 deletions actors/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ type Runtime interface {

// Note events that may make debugging easier
Log(level rt.LogLevel, msg string, args ...interface{})

// BaseFee returns the basefee value in attoFIL per unit gas for the currently exectuting tipset.
BaseFee() abi.TokenAmount
}

// Store defines the storage module exposed to actors.
Expand Down
72 changes: 71 additions & 1 deletion actors/test/commit_post_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ func TestAggregateOnePreCommitExpires(t *testing.T) {
v, _ = vm.AdvanceByDeadlineTillEpoch(t, v, minerAddrs.IDAddress, earlyPreCommitInvalid)

// later precommits
laterPrecommits := preCommitSectors(t, v, 2, miner.PreCommitSectorBatchMaxSize, addrs[0], minerAddrs.IDAddress, sealProof, firstSectorNo+1, false)
laterPrecommits := preCommitSectors(t, v, 3, miner.PreCommitSectorBatchMaxSize, addrs[0], minerAddrs.IDAddress, sealProof, firstSectorNo+1, false)
allPrecommits := append(earlyPrecommits, laterPrecommits...)
sectorNosBf := precommitSectorNumbers(allPrecommits)

Expand All @@ -596,6 +596,10 @@ func TestAggregateOnePreCommitExpires(t *testing.T) {
v, _ = vm.AdvanceByDeadlineTillEpoch(t, v, minerAddrs.IDAddress, dlInfo.Close)
// Assert that precommit should not yet be cleaned up. This makes fixing this test easier if parameters change.
require.True(t, proveTime < earlyPreCommitTime+miner.MaxProveCommitDuration[sealProof]+miner.ExpiredPreCommitCleanUpDelay)
// Assert that we have a valid aggregate batch size
aggSectorsCount, err := sectorNosBf.Count()
require.NoError(t, err)
require.True(t, aggSectorsCount >= miner.MinAggregatedSectors && aggSectorsCount < miner.MaxAggregatedSectors)

proveCommitAggregateParams := miner.ProveCommitAggregateParams{
SectorNumbers: sectorNosBf,
Expand All @@ -611,6 +615,7 @@ func TestAggregateOnePreCommitExpires(t *testing.T) {
{To: builtin.RewardActorAddr, Method: builtin.MethodsReward.ThisEpochReward},
{To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.CurrentTotalPower},
{To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.UpdatePledgeTotal},
{To: builtin.BurntFundsActorAddr, Method: builtin.MethodSend},
},
}.Matches(t, v.LastInvocation())

Expand All @@ -620,6 +625,69 @@ func TestAggregateOnePreCommitExpires(t *testing.T) {

}

func TestAggregateSizeLimits(t *testing.T) {
overSizedBatch := 820
ctx := context.Background()
blkStore := ipld.NewBlockStoreInMemory()
v := vm.NewVMWithSingletons(ctx, t, blkStore)
addrs := vm.CreateAccounts(ctx, t, v, 1, big.Mul(big.NewInt(10_000), big.NewInt(1e18)), 93837778)

// create miner
sealProof := abi.RegisteredSealProof_StackedDrg32GiBV1_1
wPoStProof, err := sealProof.RegisteredWindowPoStProof()
require.NoError(t, err)
owner, worker := addrs[0], addrs[0]
minerAddrs := createMiner(t, v, owner, worker, wPoStProof, big.Mul(big.NewInt(10_000), vm.FIL))

// advance vm so we can have seal randomness epoch in the past
v, err = v.WithEpoch(abi.ChainEpoch(200))
require.NoError(t, err)

//
// precommit sectors
//
firstSectorNo := abi.SectorNumber(100)
precommits := preCommitSectors(t, v, overSizedBatch, miner.PreCommitSectorBatchMaxSize, addrs[0], minerAddrs.IDAddress, sealProof, firstSectorNo, true)
balances := vm.GetMinerBalances(t, v, minerAddrs.IDAddress)
assert.True(t, balances.PreCommitDeposit.GreaterThan(big.Zero()))

// advance time to max seal duration
proveTime := v.GetEpoch() + miner.MaxProveCommitDuration[sealProof]
v, _ = vm.AdvanceByDeadlineTillEpoch(t, v, minerAddrs.IDAddress, proveTime)

//
// attempt proving with invalid args
//

// Fail with too many sectors
v, err = v.WithEpoch(proveTime)
require.NoError(t, err)
sectorNosBf := precommitSectorNumbers(precommits)

proveCommitAggregateTooManyParams := miner.ProveCommitAggregateParams{
SectorNumbers: sectorNosBf,
}
res := v.ApplyMessage(addrs[0], minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.ProveCommitAggregate, &proveCommitAggregateTooManyParams)
assert.Equal(t, exitcode.ErrIllegalArgument, res.Code) // fail with too many aggregates

// Fail with too few sectors
tooFewSectorNosBf := precommitSectorNumbers(precommits[:miner.MinAggregatedSectors-1])
proveCommitAggregateTooFewParams := miner.ProveCommitAggregateParams{
SectorNumbers: tooFewSectorNosBf,
}
res = v.ApplyMessage(addrs[0], minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.ProveCommitAggregate, &proveCommitAggregateTooFewParams)
assert.Equal(t, exitcode.ErrIllegalArgument, res.Code)

// Fail with proof too big
justRightSectorNosBf := precommitSectorNumbers(precommits[:miner.MaxAggregatedSectors])
proveCommitAggregateTooBigProofParams := miner.ProveCommitAggregateParams{
SectorNumbers: justRightSectorNosBf,
AggregateProof: make([]byte, miner.MaxAggregateProofSize+1),
}
res = v.ApplyMessage(addrs[0], minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.ProveCommitAggregate, &proveCommitAggregateTooBigProofParams)
assert.Equal(t, exitcode.ErrIllegalArgument, res.Code)
}

func TestMeasureAggregatePorepGas(t *testing.T) {
sectorCount := 819
fmt.Printf("batch size = %d\n", sectorCount)
Expand Down Expand Up @@ -673,6 +741,7 @@ func TestMeasureAggregatePorepGas(t *testing.T) {
{To: builtin.RewardActorAddr, Method: builtin.MethodsReward.ThisEpochReward},
{To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.CurrentTotalPower},
{To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.UpdatePledgeTotal},
{To: builtin.BurntFundsActorAddr, Method: builtin.MethodSend},
},
}.Matches(t, v.LastInvocation())

Expand Down Expand Up @@ -790,6 +859,7 @@ func proveCommitSectors(t *testing.T, v *vm.VM, worker, actor address.Address, p
{To: builtin.RewardActorAddr, Method: builtin.MethodsReward.ThisEpochReward},
{To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.CurrentTotalPower},
{To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.UpdatePledgeTotal},
{To: builtin.BurntFundsActorAddr, Method: builtin.MethodSend},
},
}.Matches(t, v.LastInvocation())
}
Expand Down
1 change: 1 addition & 0 deletions support/mock/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ func (b RuntimeBuilder) Build(t testing.TB) *Runtime {
miner: addr.Address{},
idAddresses: make(map[addr.Address]addr.Address),
circulatingSupply: abi.NewTokenAmount(0),
baseFee: abi.NewTokenAmount(0),

state: cid.Undef,
store: make(map[cid.Cid][]byte),
Expand Down
6 changes: 6 additions & 0 deletions support/mock/mockrt.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Runtime struct {
actorCodeCIDs map[addr.Address]cid.Cid
newActorAddr addr.Address
circulatingSupply abi.TokenAmount
baseFee abi.TokenAmount

// Actor state
state cid.Cid
Expand Down Expand Up @@ -256,6 +257,11 @@ func (rt *Runtime) CurrentBalance() abi.TokenAmount {
return rt.balance
}

func (rt *Runtime) BaseFee() abi.TokenAmount {
rt.requireInCall()
return rt.baseFee
}

func (rt *Runtime) ResolveAddress(address addr.Address) (ret addr.Address, ok bool) {
rt.requireInCall()
if address.Protocol() == addr.ID {
Expand Down
5 changes: 5 additions & 0 deletions support/vm/invocation_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ func (ic *invocationContext) CurrEpoch() abi.ChainEpoch {
return ic.rt.currentEpoch
}

func (ic *invocationContext) BaseFee() abi.TokenAmount {
// for now test vm always runs with zero base fee
return big.Zero()
}

func (ic *invocationContext) CurrentBalance() abi.TokenAmount {
// load balance
act, found, err := ic.rt.GetActor(ic.msg.to)
Expand Down

0 comments on commit a9f9f95

Please sign in to comment.