Skip to content
This repository has been archived by the owner on Dec 5, 2021. It is now read-only.

Allow previous gas limit #462

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
16 changes: 16 additions & 0 deletions l2geth/eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,14 @@ func (b *EthAPIBackend) SuggestL2GasPrice(ctx context.Context) (*big.Int, error)
return b.rollupGpo.SuggestL2GasPrice(ctx)
}

func (b *EthAPIBackend) SuggestPreviousL1GasPrice(ctx context.Context) (*big.Int, error) {
return b.rollupGpo.SuggestPreviousL1GasPrice(ctx)
}

func (b *EthAPIBackend) SuggestPreviousL2GasPrice(ctx context.Context) (*big.Int, error) {
return b.rollupGpo.SuggestPreviousL2GasPrice(ctx)
}

func (b *EthAPIBackend) SetL1GasPrice(ctx context.Context, gasPrice *big.Int) error {
return b.rollupGpo.SetL1GasPrice(gasPrice)
}
Expand All @@ -385,6 +393,14 @@ func (b *EthAPIBackend) SetL2GasPrice(ctx context.Context, gasPrice *big.Int) er
return b.rollupGpo.SetL2GasPrice(gasPrice)
}

func (b *EthAPIBackend) SetPreviousL1GasPrice(ctx context.Context, gasPrice *big.Int) error {
return b.rollupGpo.SetPreviousL1GasPrice(gasPrice)
}

func (b *EthAPIBackend) SetPreviousL2GasPrice(ctx context.Context, gasPrice *big.Int) error {
return b.rollupGpo.SetPreviousL2GasPrice(gasPrice)
}

func (b *EthAPIBackend) ChainDb() ethdb.Database {
return b.eth.ChainDb()
}
Expand Down
58 changes: 50 additions & 8 deletions l2geth/eth/gasprice/rollup_gasprice.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,27 @@ import (

// RollupOracle holds the L1 and L2 gas prices for fee calculation
type RollupOracle struct {
l1GasPrice *big.Int
l2GasPrice *big.Int
l1GasPriceLock sync.RWMutex
l2GasPriceLock sync.RWMutex
l1GasPrice *big.Int
l2GasPrice *big.Int
previousL1GasPrice *big.Int
previousL2GasPrice *big.Int
l1GasPriceLock sync.RWMutex
l2GasPriceLock sync.RWMutex
previousL1GasPriceLock sync.RWMutex
previousL2GasPriceLock sync.RWMutex
}

// NewRollupOracle returns an initialized RollupOracle
func NewRollupOracle() *RollupOracle {
return &RollupOracle{
l1GasPrice: new(big.Int),
l2GasPrice: new(big.Int),
l1GasPriceLock: sync.RWMutex{},
l2GasPriceLock: sync.RWMutex{},
l1GasPrice: new(big.Int),
l2GasPrice: new(big.Int),
previousL1GasPrice: new(big.Int),
previousL2GasPrice: new(big.Int),
l1GasPriceLock: sync.RWMutex{},
l2GasPriceLock: sync.RWMutex{},
previousL1GasPriceLock: sync.RWMutex{},
previousL2GasPriceLock: sync.RWMutex{},
}
}

Expand All @@ -43,6 +51,23 @@ func (gpo *RollupOracle) SetL1GasPrice(gasPrice *big.Int) error {
return nil
}

// SuggestL1GasPrice returns the gas price which should be charged per byte of published
// data by the sequencer.
func (gpo *RollupOracle) SuggestPreviousL1GasPrice(ctx context.Context) (*big.Int, error) {
gpo.previousL1GasPriceLock.RLock()
defer gpo.previousL1GasPriceLock.RUnlock()
return gpo.previousL1GasPrice, nil
}

// SetL1GasPrice returns the current L1 gas price
func (gpo *RollupOracle) SetPreviousL1GasPrice(gasPrice *big.Int) error {
gpo.previousL1GasPriceLock.Lock()
defer gpo.previousL1GasPriceLock.Unlock()
gpo.previousL1GasPrice = gasPrice
log.Info("Set Previous L1 Gas Price", "gasprice", gpo.previousL1GasPrice)
return nil
}

// SuggestL2GasPrice returns the gas price which should be charged per unit of gas
// set manually by the sequencer depending on congestion
func (gpo *RollupOracle) SuggestL2GasPrice(ctx context.Context) (*big.Int, error) {
Expand All @@ -59,3 +84,20 @@ func (gpo *RollupOracle) SetL2GasPrice(gasPrice *big.Int) error {
log.Info("Set L2 Gas Price", "gasprice", gpo.l2GasPrice)
return nil
}

// SuggestL2GasPrice returns the gas price which should be charged per unit of gas
// set manually by the sequencer depending on congestion
func (gpo *RollupOracle) SuggestPreviousL2GasPrice(ctx context.Context) (*big.Int, error) {
gpo.previousL2GasPriceLock.RLock()
defer gpo.previousL2GasPriceLock.RUnlock()
return gpo.previousL2GasPrice, nil
}

// SetL2GasPrice returns the current L2 gas price
func (gpo *RollupOracle) SetPreviousL2GasPrice(gasPrice *big.Int) error {
gpo.previousL2GasPriceLock.Lock()
defer gpo.previousL2GasPriceLock.Unlock()
gpo.previousL2GasPrice = gasPrice
log.Info("Set Previous L2 Gas Price", "gasprice", gpo.previousL2GasPrice)
return nil
}
11 changes: 11 additions & 0 deletions l2geth/internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,17 @@ func (api *PrivateRollupAPI) SetL2GasPrice(ctx context.Context, gasPrice hexutil
return api.b.SetL2GasPrice(ctx, (*big.Int)(&gasPrice))
}

// SetPreviousL1GasPrice sets the gas price to be used when quoting calldata publishing costs
// to users
func (api *PrivateRollupAPI) SetPreviousL1GasPrice(ctx context.Context, gasPrice hexutil.Big) error {
return api.b.SetPreviousL1GasPrice(ctx, (*big.Int)(&gasPrice))
}

// SetPreviousL2GasPrice sets the gas price to be used when executing transactions on
func (api *PrivateRollupAPI) SetPreviousL2GasPrice(ctx context.Context, gasPrice hexutil.Big) error {
return api.b.SetPreviousL2GasPrice(ctx, (*big.Int)(&gasPrice))
}

// PublicDebugAPI is the collection of Ethereum APIs exposed over the public
// debugging endpoint.
type PublicDebugAPI struct {
Expand Down
4 changes: 4 additions & 0 deletions l2geth/internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ type Backend interface {
SetL1GasPrice(context.Context, *big.Int) error
SuggestL2GasPrice(context.Context) (*big.Int, error)
SetL2GasPrice(context.Context, *big.Int) error
SuggestPreviousL1GasPrice(ctx context.Context) (*big.Int, error)
SetPreviousL1GasPrice(context.Context, *big.Int) error
SuggestPreviousL2GasPrice(context.Context) (*big.Int, error)
SetPreviousL2GasPrice(context.Context, *big.Int) error
IngestTransactions([]*types.Transaction) error
}

Expand Down
20 changes: 20 additions & 0 deletions l2geth/les/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,26 @@ func (b *LesApiBackend) SetL2GasPrice(ctx context.Context, gasPrice *big.Int) er
panic("SetExecutionPrice is not implemented")
}

// NB: Non sequencer nodes cannot suggest L1 gas prices.
func (b *LesApiBackend) SuggestPreviousL1GasPrice(ctx context.Context) (*big.Int, error) {
panic("SuggestPreviousL1GasPrice not implemented")
}

// NB: Non sequencer nodes cannot suggest L2 execution gas prices.
func (b *LesApiBackend) SuggestPreviousL2GasPrice(ctx context.Context) (*big.Int, error) {
panic("SuggestPreviousL2GasPrice not implemented")
}

// NB: Non sequencer nodes cannot set Previous L1 gas prices.
func (b *LesApiBackend) SetPreviousL1GasPrice(ctx context.Context, gasPrice *big.Int) error {
panic("SetDataPrice is not implemented")
}

// NB: Non sequencer nodes cannot set Previous L2 execution prices.
func (b *LesApiBackend) SetPreviousL2GasPrice(ctx context.Context, gasPrice *big.Int) error {
panic("SetExecutionPrice is not implemented")
}

func (b *LesApiBackend) ChainDb() ethdb.Database {
return b.eth.chainDb
}
Expand Down
23 changes: 18 additions & 5 deletions l2geth/rollup/fees/rollup_fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ func DecodeL2GasLimitU64(gasLimit uint64) uint64 {

// PaysEnoughOpts represent the options to PaysEnough
type PaysEnoughOpts struct {
UserFee, ExpectedFee *big.Int
ThresholdUp, ThresholdDown *big.Float
UserFee, ExpectedFee, ExpectedPreviousFee *big.Int
ThresholdUp, ThresholdDown *big.Float
}

// PaysEnough returns an error if the fee is not large enough
Expand All @@ -118,24 +118,37 @@ func PaysEnough(opts *PaysEnoughOpts) error {
if opts.ExpectedFee == nil {
return fmt.Errorf("%w: no expected fee", errMissingInput)
}
if opts.ExpectedPreviousFee == nil {
return fmt.Errorf("%w: no expected previous fee", errMissingInput)
}

fee := new(big.Int).Set(opts.ExpectedFee)
previousFee := new(big.Int).Set(opts.ExpectedPreviousFee)

// Allow for a downward buffer to protect against L1 gas price volatility
if opts.ThresholdDown != nil {
fee = mulByFloat(fee, opts.ThresholdDown)
previousFee = mulByFloat(previousFee, opts.ThresholdDown)
}
// Protect the sequencer from being underpaid
// if user fee < expected fee, return error
if opts.UserFee.Cmp(fee) == -1 {
if opts.UserFee.Cmp(fee) == -1 && opts.UserFee.Cmp(previousFee) == -1 {
return ErrFeeTooLow
}
// Protect users from overpaying by too much
if opts.ThresholdUp != nil {
// overpaying = user fee - expected fee
overpaying := new(big.Int).Sub(opts.UserFee, opts.ExpectedFee)
threshold := mulByFloat(opts.ExpectedFee, opts.ThresholdUp)
// if overpaying > threshold, return error
if overpaying.Cmp(threshold) == 1 {

// also allow previous value
overpayingPrevious := new(big.Int).Sub(opts.UserFee, opts.ExpectedPreviousFee)
thresholdPrevious := mulByFloat(opts.ExpectedPreviousFee, opts.ThresholdUp)

// if overpaying > threshold &&
// overpayingPrevious > thresholdPrevious, return error
if (overpaying.Cmp(threshold) == 1 &&
overpayingPrevious.cmp(thresholdPrevious) == 1) {
return ErrFeeTooHigh
}
}
Expand Down
81 changes: 45 additions & 36 deletions l2geth/rollup/fees/rollup_fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,82 +112,91 @@ func TestPaysEnough(t *testing.T) {
}{
"missing-gas-price": {
opts: &PaysEnoughOpts{
UserFee: nil,
ExpectedFee: new(big.Int),
ThresholdUp: nil,
ThresholdDown: nil,
UserFee: nil,
ExpectedFee: new(big.Int),
ExpectedPreviousFee: new(big.Int),
ThresholdUp: nil,
ThresholdDown: nil,
},
err: errMissingInput,
},
"missing-fee": {
opts: &PaysEnoughOpts{
UserFee: nil,
ExpectedFee: nil,
ThresholdUp: nil,
ThresholdDown: nil,
UserFee: nil,
ExpectedFee: nil,
ExpectedPreviousFee: nil,
ThresholdUp: nil,
ThresholdDown: nil,
},
err: errMissingInput,
},
"equal-fee": {
opts: &PaysEnoughOpts{
UserFee: common.Big1,
ExpectedFee: common.Big1,
ThresholdUp: nil,
ThresholdDown: nil,
UserFee: common.Big1,
ExpectedFee: common.Big1,
ExpectedPreviousFee: common.Big1,
ThresholdUp: nil,
ThresholdDown: nil,
},
err: nil,
},
"fee-too-low": {
opts: &PaysEnoughOpts{
UserFee: common.Big1,
ExpectedFee: common.Big2,
ThresholdUp: nil,
ThresholdDown: nil,
UserFee: common.Big1,
ExpectedFee: common.Big2,
ExpectedPreviousFee: common.Big2,
ThresholdUp: nil,
ThresholdDown: nil,
},
err: ErrFeeTooLow,
},
"fee-threshold-down": {
opts: &PaysEnoughOpts{
UserFee: common.Big1,
ExpectedFee: common.Big2,
ThresholdUp: nil,
ThresholdDown: new(big.Float).SetFloat64(0.5),
UserFee: common.Big1,
ExpectedFee: common.Big2,
ExpectedPreviousFee: common.Big2,
ThresholdUp: nil,
ThresholdDown: new(big.Float).SetFloat64(0.5),
},
err: nil,
},
"fee-threshold-up": {
opts: &PaysEnoughOpts{
UserFee: common.Big256,
ExpectedFee: common.Big1,
ThresholdUp: new(big.Float).SetFloat64(1.5),
ThresholdDown: nil,
UserFee: common.Big256,
ExpectedFee: common.Big1,
ExpectedPreviousFee: 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),
UserFee: new(big.Int).SetUint64(10_000),
ExpectedFee: new(big.Int).SetUint64(1),
ExpectedPreviousFee: 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),
UserFee: new(big.Int).SetUint64(1),
ExpectedFee: new(big.Int).SetUint64(10_000),
ExpectedPreviousFee: 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),
UserFee: new(big.Int).SetUint64(0),
ExpectedFee: new(big.Int).SetUint64(10_000),
ExpectedPreviousFee: new(big.Int).SetUint64(10_000),
ThresholdUp: new(big.Float).SetFloat64(3),
ThresholdDown: new(big.Float).SetFloat64(0.8),
},
err: ErrFeeTooLow,
},
Expand Down
Loading