diff --git a/chain/vm/burn.go b/chain/vm/burn.go new file mode 100644 index 000000000..7aee35b34 --- /dev/null +++ b/chain/vm/burn.go @@ -0,0 +1,18 @@ +package vm + +const ( + gasOveruseNum = 3 + gasOveruseDenom = 10 +) + +// ComputeGasOutputs 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) { + allowedGasOverUsed := gasUsed + (gasUsed*gasOveruseNum)/gasOveruseDenom + gasToBurn := gasLimit - allowedGasOverUsed + if gasToBurn < 0 { + gasToBurn = 0 + } + + return gasLimit - gasUsed - gasToBurn, gasToBurn +} diff --git a/chain/vm/burn_test.go b/chain/vm/burn_test.go new file mode 100644 index 000000000..d0ef1e780 --- /dev/null +++ b/chain/vm/burn_test.go @@ -0,0 +1,34 @@ +package vm + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGasBurn(t *testing.T) { + tests := []struct { + used int64 + limit int64 + refund int64 + burn int64 + }{ + {100, 200, 30, 70}, + {1000, 1300, 300, 0}, + {500, 700, 150, 50}, + {200, 200, 0, 0}, + {20000, 21000, 1000, 0}, + {0, 2000, 0, 2000}, + {500, 651, 150, 1}, + } + + for _, test := range tests { + test := test + t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { + refund, toBurn := ComputeGasOutputs(test.used, test.limit) + assert.Equal(t, test.burn, toBurn) + assert.Equal(t, test.refund, refund) + }) + } +} diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 2ebd42f2a..be357a6c9 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -37,11 +37,6 @@ var log = logging.Logger("vm") var actorLog = logging.Logger("actors") var gasOnActorExec = newGasCharge("OnActorExec", 0, 0) -const ( - gasOveruseNum = 3 - gasOveruseDenom = 10 -) - // ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`. func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, aerrors.ActorError) { if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 { @@ -459,15 +454,10 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, if gasUsed < 0 { gasUsed = 0 } - - allowedGasOverUsed := gasUsed + (gasUsed*gasOveruseNum)/gasOveruseDenom - gasToBurn := msg.GasLimit - allowedGasOverUsed - if gasToBurn < 0 { - gasToBurn = 0 - } + gasRefund, gasToBurn := ComputeGasOutputs(gasUsed, msg.GasLimit) // refund unused gas - refund := types.BigMul(types.NewInt(uint64(msg.GasLimit-gasUsed-gasToBurn)), msg.GasPrice) + 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") }