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)
|
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)
|
penalty = big.Add(penalty, r.Penalty)
|
||||||
|
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
|
@ -189,9 +189,11 @@ func toLotusMsg(msg *vtypes.Message) *types.Message {
|
|||||||
Nonce: msg.CallSeqNum,
|
Nonce: msg.CallSeqNum,
|
||||||
Method: msg.Method,
|
Method: msg.Method,
|
||||||
|
|
||||||
Value: msg.Value,
|
Value: msg.Value,
|
||||||
GasPrice: msg.GasPrice,
|
GasPrice: msg.GasPrice,
|
||||||
GasLimit: msg.GasLimit,
|
GasLimit: msg.GasLimit,
|
||||||
|
GasFeeCap: msg.GasPrice, // TODO: update chian val to use GasFeeCap
|
||||||
|
GasPremium: big.Zero(),
|
||||||
|
|
||||||
Params: msg.Params,
|
Params: msg.Params,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
||||||
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -9,9 +10,21 @@ const (
|
|||||||
gasOveruseDenom = 10
|
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)
|
// Result is (refund, burn)
|
||||||
func ComputeGasOutputs(gasUsed, gasLimit int64) (int64, int64) {
|
func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
|
||||||
if gasUsed == 0 {
|
if gasUsed == 0 {
|
||||||
return 0, gasLimit
|
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
|
// needs bigint, as it overflows in pathological case gasLimit > 2^32 gasUsed = gasLimit / 2
|
||||||
gasToBurn := big.NewInt(gasLimit - gasUsed)
|
gasToBurn := big.NewInt(gasLimit - gasUsed)
|
||||||
gasToBurn = gasToBurn.Mul(gasToBurn, big.NewInt(over))
|
gasToBurn = big.Mul(gasToBurn, big.NewInt(over))
|
||||||
gasToBurn = gasToBurn.Div(gasToBurn, big.NewInt(gasUsed))
|
gasToBurn = big.Div(gasToBurn, big.NewInt(gasUsed))
|
||||||
|
|
||||||
return gasLimit - gasUsed - gasToBurn.Int64(), gasToBurn.Int64()
|
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 {
|
for _, test := range tests {
|
||||||
test := test
|
test := test
|
||||||
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
|
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.refund, refund, "refund")
|
||||||
assert.Equal(t, test.burn, toBurn, "burned")
|
assert.Equal(t, test.burn, toBurn, "burned")
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
bstore "github.com/filecoin-project/lotus/lib/blockstore"
|
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"
|
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||||
|
|
||||||
block "github.com/ipfs/go-block-format"
|
block "github.com/ipfs/go-block-format"
|
||||||
@ -196,6 +197,7 @@ type ApplyRet struct {
|
|||||||
types.MessageReceipt
|
types.MessageReceipt
|
||||||
ActorErr aerrors.ActorError
|
ActorErr aerrors.ActorError
|
||||||
Penalty types.BigInt
|
Penalty types.BigInt
|
||||||
|
MinerTip types.BigInt
|
||||||
ExecutionTrace types.ExecutionTrace
|
ExecutionTrace types.ExecutionTrace
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
}
|
}
|
||||||
@ -315,6 +317,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
|
|||||||
ActorErr: actorErr,
|
ActorErr: actorErr,
|
||||||
ExecutionTrace: rt.executionTrace,
|
ExecutionTrace: rt.executionTrace,
|
||||||
Penalty: types.NewInt(0),
|
Penalty: types.NewInt(0),
|
||||||
|
MinerTip: types.NewInt(0),
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
}, actorErr
|
}, actorErr
|
||||||
}
|
}
|
||||||
@ -347,14 +350,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
ExitCode: exitcode.SysErrOutOfGas,
|
ExitCode: exitcode.SysErrOutOfGas,
|
||||||
GasUsed: 0,
|
GasUsed: 0,
|
||||||
},
|
},
|
||||||
Penalty: types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost))),
|
Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
|
MinerTip: big.Zero(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
st := vm.cstate
|
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)
|
fromActor, err := st.GetActor(msg.From)
|
||||||
// this should never happen, but is currently still exercised by some tests
|
// this should never happen, but is currently still exercised by some tests
|
||||||
if err != nil {
|
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),
|
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
|
||||||
Penalty: minerPenaltyAmount,
|
Penalty: minerPenaltyAmount,
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
|
MinerTip: big.Zero(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return nil, xerrors.Errorf("failed to look up from actor: %w", err)
|
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),
|
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
|
||||||
Penalty: minerPenaltyAmount,
|
Penalty: minerPenaltyAmount,
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
|
MinerTip: big.Zero(),
|
||||||
}, nil
|
}, 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),
|
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
|
||||||
Penalty: minerPenaltyAmount,
|
Penalty: minerPenaltyAmount,
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
|
MinerTip: big.Zero(),
|
||||||
}, nil
|
}, 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) {
|
if fromActor.Balance.LessThan(gascost) {
|
||||||
return &ApplyRet{
|
return &ApplyRet{
|
||||||
MessageReceipt: types.MessageReceipt{
|
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)),
|
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
|
||||||
Penalty: minerPenaltyAmount,
|
Penalty: minerPenaltyAmount,
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
|
MinerTip: big.Zero(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,25 +476,25 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
|
|||||||
if gasUsed < 0 {
|
if gasUsed < 0 {
|
||||||
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 unused gas
|
||||||
refund := types.BigMul(types.NewInt(uint64(gasRefund)), msg.GasPrice)
|
if err := vm.transferFromGasHolder(msg.From, gasHolder, gasOutputs.Refund); err != nil {
|
||||||
if err := vm.transferFromGasHolder(msg.From, gasHolder, refund); err != nil {
|
return nil, xerrors.Errorf("failed to refund gas: %w", err)
|
||||||
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 types.BigCmp(types.NewInt(0), gasHolder.Balance) != 0 {
|
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,
|
ActorErr: actorErr,
|
||||||
ExecutionTrace: rt.executionTrace,
|
ExecutionTrace: rt.executionTrace,
|
||||||
Penalty: types.NewInt(0),
|
Penalty: gasOutputs.MinerPenalty,
|
||||||
|
MinerTip: gasOutputs.MinerTip,
|
||||||
Duration: time.Since(start),
|
Duration: time.Since(start),
|
||||||
}, nil
|
}, 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")
|
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 {
|
return vm.cstate.MutateActor(addr, func(a *types.Actor) error {
|
||||||
if err := deductFunds(gasHolder, amt); err != nil {
|
if err := deductFunds(gasHolder, amt); err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user