Compute correct base burns, miner tip and so on
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
722d6e8ffb
commit
b384ac6943
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -9,9 +10,21 @@ const (
|
||||
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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
})
|
||||
|
@ -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"
|
||||
@ -196,6 +197,7 @@ type ApplyRet struct {
|
||||
types.MessageReceipt
|
||||
ActorErr aerrors.ActorError
|
||||
Penalty types.BigInt
|
||||
MinerTip types.BigInt
|
||||
ExecutionTrace types.ExecutionTrace
|
||||
Duration time.Duration
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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 {
|
||||
@ -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)
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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{
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder,
|
||||
gasOutputs.BaseFeeBurn); err != nil {
|
||||
return nil, xerrors.Errorf("failed to burn base fee: %w", err)
|
||||
}
|
||||
|
||||
if err := vm.transferFromGasHolder(builtin.RewardActorAddr, gasHolder, gasOutputs.MinerTip); 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
|
||||
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 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")
|
||||
}
|
||||
}
|
||||
|
||||
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(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 {
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user