Skip to content

Commit

Permalink
Compute correct base burns, miner tip and so on
Browse files Browse the repository at this point in the history
Signed-off-by: Jakub Sztandera <[email protected]>
  • Loading branch information
Jakub Sztandera committed Aug 6, 2020
1 parent 722d6e8 commit b384ac6
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 28 deletions.
2 changes: 1 addition & 1 deletion chain/stmgr/stmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
}

receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, big.Mul(m.GasPrice, big.NewInt(r.GasUsed)))
gasReward = big.Add(gasReward, r.MinerTip)
penalty = big.Add(penalty, r.Penalty)

if cb != nil {
Expand Down
8 changes: 5 additions & 3 deletions chain/validation/applier.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,11 @@ func toLotusMsg(msg *vtypes.Message) *types.Message {
Nonce: msg.CallSeqNum,
Method: msg.Method,

Value: msg.Value,
GasPrice: msg.GasPrice,
GasLimit: msg.GasLimit,
Value: msg.Value,
GasPrice: msg.GasPrice,
GasLimit: msg.GasLimit,
GasFeeCap: msg.GasPrice, // TODO: update chian val to use GasFeeCap
GasPremium: big.Zero(),

Params: msg.Params,
}
Expand Down
63 changes: 58 additions & 5 deletions chain/vm/burn.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
package vm

import (
"math/big"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
)

const (
gasOveruseNum = 11
gasOveruseDenom = 10
)

// ComputeGasOutputs computes amount of gas to be refunded and amount of gas to be burned
type GasOutputs struct {
BaseFeeBurn abi.TokenAmount
OverEstimationBurn abi.TokenAmount

MinerPenalty abi.TokenAmount
MinerTip abi.TokenAmount
Refund abi.TokenAmount

GasRefund int64
GasBurned int64
}

// ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned
// Result is (refund, burn)
func ComputeGasOutputs(gasUsed, gasLimit int64) (int64, int64) {
func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
if gasUsed == 0 {
return 0, gasLimit
}
Expand All @@ -37,8 +50,48 @@ func ComputeGasOutputs(gasUsed, gasLimit int64) (int64, int64) {

// needs bigint, as it overflows in pathological case gasLimit > 2^32 gasUsed = gasLimit / 2
gasToBurn := big.NewInt(gasLimit - gasUsed)
gasToBurn = gasToBurn.Mul(gasToBurn, big.NewInt(over))
gasToBurn = gasToBurn.Div(gasToBurn, big.NewInt(gasUsed))
gasToBurn = big.Mul(gasToBurn, big.NewInt(over))
gasToBurn = big.Div(gasToBurn, big.NewInt(gasUsed))

return gasLimit - gasUsed - gasToBurn.Int64(), gasToBurn.Int64()
}

func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs {
gasUsedBig := big.NewInt(gasUsed)
out := GasOutputs{
BaseFeeBurn: big.Zero(),
OverEstimationBurn: big.Zero(),
MinerPenalty: big.Zero(),
MinerTip: big.Zero(),
Refund: big.Zero(),
}

baseFeeToPay := baseFee
if baseFee.Cmp(feeCap.Int) > 0 {
baseFeeToPay = feeCap
out.MinerPenalty = big.Mul(big.Sub(baseFee, feeCap), gasUsedBig)
}
out.BaseFeeBurn = big.Mul(baseFeeToPay, big.NewInt(gasUsed))

minerTip := gasPremium
if big.Cmp(big.Add(baseFeeToPay, minerTip), feeCap) > 0 {
minerTip = big.Sub(feeCap, baseFeeToPay)
}
out.MinerTip = big.Mul(minerTip, big.NewInt(gasLimit))

out.GasRefund, out.GasBurned = ComputeGasOverestimationBurn(gasUsed, gasLimit)

if out.GasBurned != 0 {
gasBurnedBig := big.NewInt(out.GasBurned)
out.OverEstimationBurn = big.Mul(baseFeeToPay, gasBurnedBig)
minerPenalty := big.Mul(big.Sub(baseFee, baseFeeToPay), gasBurnedBig)
out.MinerPenalty = big.Add(out.MinerPenalty, minerPenalty)
}

requiredFunds := big.Mul(big.NewInt(gasLimit), feeCap)
refund := big.Sub(requiredFunds, out.BaseFeeBurn)
refund = big.Sub(refund, out.MinerTip)
refund = big.Sub(refund, out.OverEstimationBurn)
out.Refund = refund
return out
}
2 changes: 1 addition & 1 deletion chain/vm/burn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestGasBurn(t *testing.T) {
for _, test := range tests {
test := test
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
refund, toBurn := ComputeGasOutputs(test.used, test.limit)
refund, toBurn := ComputeGasOverestimationBurn(test.used, test.limit)
assert.Equal(t, test.refund, refund, "refund")
assert.Equal(t, test.burn, toBurn, "burned")
})
Expand Down
49 changes: 31 additions & 18 deletions chain/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

bstore "github.com/filecoin-project/lotus/lib/blockstore"

"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin"

block "github.com/ipfs/go-block-format"
Expand Down Expand Up @@ -196,6 +197,7 @@ type ApplyRet struct {
types.MessageReceipt
ActorErr aerrors.ActorError
Penalty types.BigInt
MinerTip types.BigInt
ExecutionTrace types.ExecutionTrace
Duration time.Duration
}
Expand Down Expand Up @@ -315,6 +317,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0),
MinerTip: types.NewInt(0),
Duration: time.Since(start),
}, actorErr
}
Expand Down Expand Up @@ -347,14 +350,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ExitCode: exitcode.SysErrOutOfGas,
GasUsed: 0,
},
Penalty: types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost))),
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

st := vm.cstate

minerPenaltyAmount := types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost)))
minerPenaltyAmount := types.BigMul(vm.baseFee, abi.NewTokenAmount(msg.GasLimit))
fromActor, err := st.GetActor(msg.From)
// this should never happen, but is currently still exercised by some tests
if err != nil {
Expand All @@ -367,6 +371,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
Penalty: minerPenaltyAmount,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}
return nil, xerrors.Errorf("failed to look up from actor: %w", err)
Expand All @@ -382,6 +387,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
Penalty: minerPenaltyAmount,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

Expand All @@ -395,10 +401,11 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
Penalty: minerPenaltyAmount,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasPrice)
gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap)
if fromActor.Balance.LessThan(gascost) {
return &ApplyRet{
MessageReceipt: types.MessageReceipt{
Expand All @@ -409,6 +416,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
Penalty: minerPenaltyAmount,
Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil
}

Expand Down Expand Up @@ -468,25 +476,25 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
if gasUsed < 0 {
gasUsed = 0
}
gasRefund, gasToBurn := ComputeGasOutputs(gasUsed, msg.GasLimit)
gasOutputs := ComputeGasOutputs(gasUsed, msg.GasLimit, vm.baseFee, msg.GasFeeCap, msg.GasPremium)

// refund unused gas
refund := types.BigMul(types.NewInt(uint64(gasRefund)), msg.GasPrice)
if err := vm.transferFromGasHolder(msg.From, gasHolder, refund); err != nil {
return nil, xerrors.Errorf("failed to refund gas")
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder,
gasOutputs.BaseFeeBurn); err != nil {
return nil, xerrors.Errorf("failed to burn base fee: %w", err)
}

if gasToBurn > 0 {
// burn overallocated gas
burn := types.BigMul(types.NewInt(uint64(gasToBurn)), msg.GasPrice)
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder, burn); err != nil {
return nil, xerrors.Errorf("failed to burn over estimated gas")
}
if err := vm.transferFromGasHolder(builtin.RewardActorAddr, gasHolder, gasOutputs.MinerTip); err != nil {
return nil, xerrors.Errorf("failed to give miner gas reward: %w", err)
}

gasReward := types.BigMul(msg.GasPrice, types.NewInt(uint64(gasUsed)))
if err := vm.transferFromGasHolder(builtin.RewardActorAddr, gasHolder, gasReward); err != nil {
return nil, xerrors.Errorf("failed to give miner gas reward: %w", err)
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder,
gasOutputs.OverEstimationBurn); err != nil {
return nil, xerrors.Errorf("failed to burn overestimation fee: %w", err)
}

// refund unused gas
if err := vm.transferFromGasHolder(msg.From, gasHolder, gasOutputs.Refund); err != nil {
return nil, xerrors.Errorf("failed to refund gas: %w", err)
}

if types.BigCmp(types.NewInt(0), gasHolder.Balance) != 0 {
Expand All @@ -501,7 +509,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
},
ActorErr: actorErr,
ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0),
Penalty: gasOutputs.MinerPenalty,
MinerTip: gasOutputs.MinerTip,
Duration: time.Since(start),
}, nil
}
Expand Down Expand Up @@ -780,6 +789,10 @@ func (vm *VM) transferFromGasHolder(addr address.Address, gasHolder *types.Actor
return xerrors.Errorf("attempted to transfer negative value from gas holder")
}

if amt.Equals(big.NewInt(0)) {
return nil
}

return vm.cstate.MutateActor(addr, func(a *types.Actor) error {
if err := deductFunds(gasHolder, amt); err != nil {
return err
Expand Down

0 comments on commit b384ac6

Please sign in to comment.