Skip to content

Commit

Permalink
disable gas burning for window post messages
Browse files Browse the repository at this point in the history
While over-estimation fees and miner tips are still paid, gas is no longer burnt
for direct, successful window PoSt messages.

Usually, gas is burnt to prevent an attacker from spamming the network and to
allow clients to "price" messages (using the base fee cap) based on how urgently
they need them to be processed. However:

1. Window PoSt is already a "proof of work".
2. Miners need to submit WindowedPoSts on-time so all window post messages are urgent.
3. Work is already under way to move window post verification off-chain (making
it effectively free). This change simply introduces the "free" part a bit earlier.
  • Loading branch information
Stebalien committed Dec 16, 2020
1 parent 46e5cc9 commit 5b3336b
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 4 deletions.
1 change: 1 addition & 0 deletions build/params_2k.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var UpgradeLiftoffHeight = abi.ChainEpoch(-5)
const UpgradeKumquatHeight = 15
const UpgradeCalicoHeight = 20
const UpgradePersianHeight = 25
const UpgradeClausHeight = 30

var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
Expand Down
2 changes: 2 additions & 0 deletions build/params_mainnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const UpgradeKumquatHeight = 170000
const UpgradeCalicoHeight = 265200
const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60)

const UpgradeClausHeight = 343200

func init() {
policy.SetConsensusMinerMinPower(abi.NewStoragePower(10 << 40))

Expand Down
1 change: 1 addition & 0 deletions build/params_testground.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ var (
UpgradeKumquatHeight abi.ChainEpoch = -6
UpgradeCalicoHeight abi.ChainEpoch = -7
UpgradePersianHeight abi.ChainEpoch = -8
UpgradeClausHeight abi.ChainEpoch = -9

DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
Expand Down
9 changes: 7 additions & 2 deletions chain/vm/burn.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
return gasLimit - gasUsed - gasToBurn.Int64(), gasToBurn.Int64()
}

func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs {
func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount, burn bool) GasOutputs {
gasUsedBig := big.NewInt(gasUsed)
out := ZeroGasOutputs()

Expand All @@ -76,7 +76,12 @@ func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.
baseFeeToPay = feeCap
out.MinerPenalty = big.Mul(big.Sub(baseFee, feeCap), gasUsedBig)
}
out.BaseFeeBurn = big.Mul(baseFeeToPay, gasUsedBig)

// If burning is disabled, just skip computing the BaseFeeBurn. However,
// we charge all the other fees regardless.
if burn {
out.BaseFeeBurn = big.Mul(baseFeeToPay, gasUsedBig)
}

minerTip := gasPremium
if big.Cmp(big.Add(baseFeeToPay, minerTip), feeCap) > 0 {
Expand Down
2 changes: 1 addition & 1 deletion chain/vm/burn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestGasOutputs(t *testing.T) {
for _, test := range tests {
test := test
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
output := ComputeGasOutputs(test.used, test.limit, baseFee, types.NewInt(test.feeCap), types.NewInt(test.premium))
output := ComputeGasOutputs(test.used, test.limit, baseFee, types.NewInt(test.feeCap), types.NewInt(test.premium), true)
i2s := func(i uint64) string {
return fmt.Sprintf("%d", i)
}
Expand Down
37 changes: 36 additions & 1 deletion chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/actors/builtin/account"
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/actors/builtin/reward"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/types"
Expand Down Expand Up @@ -561,7 +562,13 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
if gasUsed < 0 {
gasUsed = 0
}
gasOutputs := ComputeGasOutputs(gasUsed, msg.GasLimit, vm.baseFee, msg.GasFeeCap, msg.GasPremium)

burn, err := vm.shouldBurn(st, msg, errcode)
if err != nil {
return nil, xerrors.Errorf("deciding whether should burn failed: %w", err)
}

gasOutputs := ComputeGasOutputs(gasUsed, msg.GasLimit, vm.baseFee, msg.GasFeeCap, msg.GasPremium, burn)

if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder,
gasOutputs.BaseFeeBurn); err != nil {
Expand Down Expand Up @@ -599,6 +606,34 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
}, nil
}

func (vm *VM) shouldBurn(st *state.StateTree, msg *types.Message, errcode exitcode.ExitCode) (bool, error) {
// Check to see if we should burn funds. We avoid burning on successful
// window post. This won't catch _indirect_ window post calls, but this
// is the best we can get for now.
//
// This implements FIP-0009: https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0009.md
//
// NOTE: This is a stopgap measure and is intended to be reverted once a better solution such as
// https://github.com/filecoin-project/FIPs/issues/42 has been is ready.
if vm.blockHeight > build.UpgradeClausHeight && errcode == exitcode.Ok && msg.Method == miner.Methods.SubmitWindowedPoSt {
// Ok, we've checked the _method_, but we still need to check
// the target actor. It would be nice if we could just look at
// the trace, but I'm not sure if that's safe?
if toActor, err := st.GetActor(msg.To); err != nil {
// If the actor wasn't found, we probably deleted it or something. Move on.
if !xerrors.Is(err, types.ErrActorNotFound) {
// Otherwise, this should never fail and something is very wrong.
return false, xerrors.Errorf("failed to lookup target actor: %w", err)
}
} else if builtin.IsStorageMinerActor(toActor.Code) {
// Ok, this is a storage miner and we've processed a window post. Remove the burn.
return false, nil
}
}

return true, nil
}

func (vm *VM) ActorBalance(addr address.Address) (types.BigInt, aerrors.ActorError) {
act, err := vm.cstate.GetActor(addr)
if err != nil {
Expand Down

0 comments on commit 5b3336b

Please sign in to comment.