Commit 735ef774 authored by Mark Tyneway's avatar Mark Tyneway

l2geth: prevent too low of fees from getting through

There was a bug in the floating point math that allowed
for transactions with extremely low fees to get through.
This PR fixes that bug as well as adds additional test
cases.
parent fc297257
---
'@eth-optimism/l2geth': patch
---
Fix a bug in the fee logic that allowed for fees that were too low to get through
......@@ -3,6 +3,7 @@ package fees
import (
"errors"
"fmt"
"math"
"math/big"
"github.com/ethereum/go-ethereum/common"
......@@ -115,7 +116,7 @@ func PaysEnough(opts *PaysEnoughOpts) error {
return fmt.Errorf("%w: no expected fee", errMissingInput)
}
fee := opts.ExpectedFee
fee := new(big.Int).Set(opts.ExpectedFee)
// Allow for a downward buffer to protect against L1 gas price volatility
if opts.ThresholdDown != nil {
fee = mulByFloat(fee, opts.ThresholdDown)
......@@ -129,7 +130,7 @@ func PaysEnough(opts *PaysEnoughOpts) error {
if opts.ThresholdUp != nil {
// overpaying = user fee - expected fee
overpaying := new(big.Int).Sub(opts.UserFee, opts.ExpectedFee)
threshold := mulByFloat(overpaying, opts.ThresholdUp)
threshold := mulByFloat(opts.ExpectedFee, opts.ThresholdUp)
// if overpaying > threshold, return error
if overpaying.Cmp(threshold) == 1 {
return ErrFeeTooHigh
......@@ -140,9 +141,10 @@ func PaysEnough(opts *PaysEnoughOpts) error {
func mulByFloat(num *big.Int, float *big.Float) *big.Int {
n := new(big.Float).SetUint64(num.Uint64())
n = n.Mul(n, float)
value, _ := float.Uint64()
return new(big.Int).SetUint64(value)
product := n.Mul(n, float)
pfloat, _ := product.Float64()
rounded := math.Ceil(pfloat)
return new(big.Int).SetUint64(uint64(rounded))
}
// calculateL1GasLimit computes the L1 gasLimit based on the calldata and
......
......@@ -157,13 +157,40 @@ func TestPaysEnough(t *testing.T) {
},
"fee-threshold-up": {
opts: &PaysEnoughOpts{
UserFee: common.Big3,
UserFee: common.Big256,
ExpectedFee: common.Big1,
ThresholdUp: new(big.Float).SetFloat64(1.5),
ThresholdDown: nil,
},
err: ErrFeeTooHigh,
},
"fee-too-low-high": {
opts: &PaysEnoughOpts{
UserFee: new(big.Int).SetUint64(10_000),
ExpectedFee: new(big.Int).SetUint64(1),
ThresholdUp: new(big.Float).SetFloat64(3),
ThresholdDown: new(big.Float).SetFloat64(0.8),
},
err: ErrFeeTooHigh,
},
"fee-too-low-down": {
opts: &PaysEnoughOpts{
UserFee: new(big.Int).SetUint64(1),
ExpectedFee: new(big.Int).SetUint64(10_000),
ThresholdUp: new(big.Float).SetFloat64(3),
ThresholdDown: new(big.Float).SetFloat64(0.8),
},
err: ErrFeeTooLow,
},
"fee-too-low-down-2": {
opts: &PaysEnoughOpts{
UserFee: new(big.Int).SetUint64(0),
ExpectedFee: new(big.Int).SetUint64(10_000),
ThresholdUp: new(big.Float).SetFloat64(3),
ThresholdDown: new(big.Float).SetFloat64(0.8),
},
err: ErrFeeTooLow,
},
}
for name, tt := range tests {
......
......@@ -858,9 +858,6 @@ func (s *SyncService) verifyFee(tx *types.Transaction) error {
// Only count the calldata here as the overhead of the fully encoded
// RLP transaction is handled inside of EncodeL2GasLimit
expectedTxGasLimit := fees.EncodeTxGasLimit(tx.Data(), l1GasPrice, l2GasLimit, l2GasPrice)
if err != nil {
return err
}
// This should only happen if the unscaled transaction fee is greater than 18.44 ETH
if !expectedTxGasLimit.IsUint64() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment