Skip to content

Commit

Permalink
Merge pull request #2011 from OffchainLabs/fix-float-to-big-overflow
Browse files Browse the repository at this point in the history
Fix FloatToBig overflowing on values greater than an int64
  • Loading branch information
joshuacolvin0 authored Dec 12, 2023
2 parents 69bc63a + 00ca260 commit acba239
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 8 deletions.
27 changes: 21 additions & 6 deletions arbnode/dataposter/data_poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"crypto/x509"
"errors"
"fmt"
"math"
"math/big"
"net/http"
"os"
Expand Down Expand Up @@ -379,13 +380,27 @@ func (p *DataPoster) evalMaxFeeCapExpr(backlogOfBatches uint64, elapsed time.Dur
"ElapsedTimeBase": float64(config.ElapsedTimeBase),
"ElapsedTimeImportance": config.ElapsedTimeImportance,
"TargetPriceGWei": config.TargetPriceGwei,
"GWei": params.GWei,
}
result, err := p.maxFeeCapExpression.Evaluate(parameters)
if err != nil {
return nil, fmt.Errorf("error evaluating maxFeeCapExpression: %w", err)
}
return arbmath.FloatToBig(result.(float64)), nil
resultFloat, ok := result.(float64)
if !ok {
// This shouldn't be possible because we only pass in float64s as arguments
return nil, fmt.Errorf("maxFeeCapExpression evaluated to non-float64: %v", result)
}
// 1e9 gwei gas price is practically speaking an infinite gas price, so we cap it there.
// This also allows the formula to return positive infinity safely.
resultFloat = math.Min(resultFloat, 1e9)
resultBig := arbmath.FloatToBig(resultFloat * params.GWei)
if resultBig == nil {
return nil, fmt.Errorf("maxFeeCapExpression evaluated to float64 not convertible to integer: %v", resultFloat)
}
if resultBig.Sign() < 0 {
return nil, fmt.Errorf("maxFeeCapExpression evaluated < 0: %v", resultFloat)
}
return resultBig, nil
}

func (p *DataPoster) feeAndTipCaps(ctx context.Context, nonce uint64, gasLimit uint64, lastFeeCap *big.Int, lastTipCap *big.Int, dataCreatedAt time.Time, backlogOfBatches uint64) (*big.Int, *big.Int, error) {
Expand Down Expand Up @@ -854,9 +869,9 @@ func DataPosterConfigAddOptions(prefix string, f *pflag.FlagSet, defaultDataPost
f.Bool(prefix+".use-db-storage", defaultDataPosterConfig.UseDBStorage, "uses database storage when enabled")
f.Bool(prefix+".use-noop-storage", defaultDataPosterConfig.UseNoOpStorage, "uses noop storage, it doesn't store anything")
f.Bool(prefix+".legacy-storage-encoding", defaultDataPosterConfig.LegacyStorageEncoding, "encodes items in a legacy way (as it was before dropping generics)")
f.String(prefix+".max-fee-cap-formula", defaultDataPosterConfig.MaxFeeCapFormula, "mathematical formula to calculate maximum fee cap the result of which would be float64.\n"+
f.String(prefix+".max-fee-cap-formula", defaultDataPosterConfig.MaxFeeCapFormula, "mathematical formula to calculate maximum fee cap gwei the result of which would be float64.\n"+
"This expression is expected to be evaluated please refer https://github.com/Knetic/govaluate/blob/master/MANUAL.md to find all available mathematical operators.\n"+
"Currently available variables to construct the formula are BacklogOfBatches, UrgencyGWei, ElapsedTime, ElapsedTimeBase, ElapsedTimeImportance, TargetPriceGWei and GWei")
"Currently available variables to construct the formula are BacklogOfBatches, UrgencyGWei, ElapsedTime, ElapsedTimeBase, ElapsedTimeImportance, and TargetPriceGWei")
f.Duration(prefix+".elapsed-time-base", defaultDataPosterConfig.ElapsedTimeBase, "unit to measure the time elapsed since creation of transaction used for maximum fee cap calculation")
f.Float64(prefix+".elapsed-time-importance", defaultDataPosterConfig.ElapsedTimeImportance, "weight given to the units of time elapsed used for maximum fee cap calculation")

Expand Down Expand Up @@ -893,7 +908,7 @@ var DefaultDataPosterConfig = DataPosterConfig{
LegacyStorageEncoding: false,
Dangerous: DangerousConfig{ClearDBStorage: false},
ExternalSigner: ExternalSignerCfg{Method: "eth_signTransaction"},
MaxFeeCapFormula: "(((BacklogOfBatches * UrgencyGWei) ** 2) + ((ElapsedTime/ElapsedTimeBase) ** 2) * ElapsedTimeImportance + TargetPriceGWei) * GWei",
MaxFeeCapFormula: "((BacklogOfBatches * UrgencyGWei) ** 2) + ((ElapsedTime/ElapsedTimeBase) ** 2) * ElapsedTimeImportance + TargetPriceGWei",
ElapsedTimeBase: 10 * time.Minute,
ElapsedTimeImportance: 10,
}
Expand All @@ -919,7 +934,7 @@ var TestDataPosterConfig = DataPosterConfig{
UseNoOpStorage: false,
LegacyStorageEncoding: false,
ExternalSigner: ExternalSignerCfg{Method: "eth_signTransaction"},
MaxFeeCapFormula: "(((BacklogOfBatches * UrgencyGWei) ** 2) + ((ElapsedTime/ElapsedTimeBase) ** 2) * ElapsedTimeImportance + TargetPriceGWei) * GWei",
MaxFeeCapFormula: "((BacklogOfBatches * UrgencyGWei) ** 2) + ((ElapsedTime/ElapsedTimeBase) ** 2) * ElapsedTimeImportance + TargetPriceGWei",
ElapsedTimeBase: 10 * time.Minute,
ElapsedTimeImportance: 10,
}
Expand Down
11 changes: 10 additions & 1 deletion arbnode/dataposter/dataposter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -262,6 +263,14 @@ func TestMaxFeeCapFormulaCalculation(t *testing.T) {
t.Fatalf("Error evaluating MaxFeeCap expression: %v", err)
}
if result.Cmp(common.Big0) != 0 {
t.Fatalf("Unexpected result. Got: %d, want: 0", result.Uint64())
t.Fatalf("Unexpected result. Got: %d, want: 0", result)
}

result, err = p.evalMaxFeeCapExpr(0, time.Since(time.Time{}))
if err != nil {
t.Fatalf("Error evaluating MaxFeeCap expression: %v", err)
}
if result.Cmp(big.NewInt(params.GWei)) <= 0 {
t.Fatalf("Unexpected result. Got: %d, want: >0", result)
}
}
7 changes: 6 additions & 1 deletion util/arbmath/math.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,13 @@ func UintToBig(value uint64) *big.Int {
}

// FloatToBig casts a float to a huge
// Returns nil when passed NaN or Infinity
func FloatToBig(value float64) *big.Int {
return new(big.Int).SetInt64(int64(value))
if math.IsNaN(value) {
return nil
}
result, _ := new(big.Float).SetFloat64(value).Int(nil)
return result
}

// UintToBigFloat casts a uint to a big float
Expand Down

0 comments on commit acba239

Please sign in to comment.