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

Sequencer Fee Pricing Part 2: Electric Boogaloo: Override EstimateGas to take data price into account #273

Merged
merged 24 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4290b08
fix: add nil check when estimating gas to avoid panic during contract…
ben-chain Mar 11, 2021
ad78282
fix: revert DoEstimateGas changes introduced as a temp fix in #22
gakonst Mar 11, 2021
a1dabb6
Tweak fudge factor for Geth gas estimation (#292)
smartcontracts Mar 29, 2021
486d555
feat(api): make eth_gasPrice always return 1 gwei
gakonst Mar 10, 2021
e99c376
feat: overload estimateGas to return the data+execution fee
gakonst Mar 10, 2021
0abd730
feat: implement static L1 Gas Price oracle
gakonst Mar 10, 2021
eb3e487
feat: allow configuring the L1GasPrice via CLI at node startup
gakonst Mar 10, 2021
40fe63a
feat: allow configuring the L1GasPrice remotely over a new private RP…
gakonst Mar 10, 2021
4c78233
Sequencer Fee Pricing Part 3, feat: Pull L1Gasprice from the Data Ser…
gakonst Mar 18, 2021
a7eead8
chore: expose L1Gpo in the sync service
gakonst Mar 18, 2021
0603746
refactor: create helper function for calculating the rollup fee
gakonst Mar 18, 2021
b7a2c6c
docs: add doc for rollup tx size constant
gakonst Mar 18, 2021
147b81c
chore(console_test): add rollup_personal to test
gakonst Mar 18, 2021
68ba95a
chore: remove empty line
gakonst Mar 18, 2021
ea47616
chore: adjust review comments
gakonst Mar 23, 2021
32a4e5d
chore: re-order imports
gakonst Mar 27, 2021
9113ae9
fix: skip txpool max gas check for rollup txs
gakonst Mar 30, 2021
42c8e30
chore: debug log
gakonst Mar 30, 2021
bcbbfb4
fix(rollup_fee): normalize charged gas by the charged gas price
gakonst Mar 30, 2021
e02931d
Merge branch 'master' into feat/fee-pricing
smartcontracts Apr 5, 2021
45b3516
remove intrinsic gas checks
smartcontracts Apr 6, 2021
4b78e4e
move intrinsic gas check behind non-ovm codepath
smartcontracts Apr 6, 2021
f5eb534
remove fudging code
smartcontracts Apr 6, 2021
65f2d58
fix wrong gas limit
smartcontracts Apr 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/geth/consolecmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
)

const (
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rollup:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rollup:1.0 rollup_personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
)

Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ var (
utils.RollupStateDumpPathFlag,
utils.RollupDiffDbFlag,
utils.RollupMaxCalldataSizeFlag,
utils.RollupL1GasPriceFlag,
}

rpcFlags = []cli.Flag{
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.RollupStateDumpPathFlag,
utils.RollupDiffDbFlag,
utils.RollupMaxCalldataSizeFlag,
utils.RollupL1GasPriceFlag,
},
},
{
Expand Down
9 changes: 9 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,12 @@ var (
Value: eth.DefaultConfig.Rollup.MaxCallDataSize,
EnvVar: "ROLLUP_MAX_CALLDATA_SIZE",
}
RollupL1GasPriceFlag = BigFlag{
Name: "rollup.l1gasprice",
Usage: "The L1 gas price to use for the sequencer fees",
Value: eth.DefaultConfig.Rollup.L1GasPrice,
EnvVar: "ROLLUP_L1_GASPRICE",
}
)

// MakeDataDir retrieves the currently requested data directory, terminating
Expand Down Expand Up @@ -1152,6 +1158,9 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) {
if ctx.GlobalIsSet(RollupTimstampRefreshFlag.Name) {
cfg.TimestampRefreshThreshold = ctx.GlobalDuration(RollupTimstampRefreshFlag.Name)
}
if ctx.GlobalIsSet(RollupL1GasPriceFlag.Name) {
cfg.L1GasPrice = GlobalBig(ctx, RollupL1GasPriceFlag.Name)
}
}

// setLes configures the les server and ultra light client settings from the command line flags.
Expand Down
22 changes: 22 additions & 0 deletions core/rollup_fee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package core

import (
"math/big"
)

/// ROLLUP_BASE_TX_SIZE is the encoded rollup transaction's compressed size excluding
/// the variable length data.
/// Ref: https://github.com/ethereum-optimism/contracts/blob/409f190518b90301db20d0d4f53760021bc203a8/contracts/optimistic-ethereum/OVM/precompiles/OVM_SequencerEntrypoint.sol#L47
const ROLLUP_BASE_TX_SIZE int = 96

/// CalculateFee calculates the fee that must be paid to the Rollup sequencer, taking into
/// account the cost of publishing data to L1.
/// Returns: (ROLLUP_BASE_TX_SIZE + len(data)) * dataPrice + executionPrice * gasUsed
func CalculateRollupFee(data []byte, gasUsed uint64, dataPrice, executionPrice *big.Int) *big.Int {
dataLen := int64(ROLLUP_BASE_TX_SIZE + len(data))
// get the data fee
dataFee := new(big.Int).Mul(dataPrice, big.NewInt(dataLen))
executionFee := new(big.Int).Mul(executionPrice, new(big.Int).SetUint64(gasUsed))
fee := new(big.Int).Add(dataFee, executionFee)
return fee
}
34 changes: 34 additions & 0 deletions core/rollup_fee_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package core

import (
"math/big"
"testing"
)

var feeTests = map[string]struct {
dataLen int
gasUsed uint64
dataPrice int64
executionPrice int64
}{
"simple": {10000, 10, 20, 30},
"zero gas used": {10000, 0, 20, 30},
"zero data price": {10000, 0, 0, 30},
"zero execution price": {10000, 0, 0, 0},
}

func TestCalculateRollupFee(t *testing.T) {
for name, tt := range feeTests {
t.Run(name, func(t *testing.T) {
data := make([]byte, 0, tt.dataLen)
fee := CalculateRollupFee(data, tt.gasUsed, big.NewInt(tt.dataPrice), big.NewInt(tt.executionPrice))

dataFee := uint64((ROLLUP_BASE_TX_SIZE + len(data)) * int(tt.dataPrice))
executionFee := uint64(tt.executionPrice) * tt.gasUsed
expectedFee := dataFee + executionFee
if fee.Cmp(big.NewInt(int64(expectedFee))) != 0 {
t.Errorf("rollup fee check failed: expected %d, got %s", expectedFee, fee.String())
}
})
}
}
2 changes: 1 addition & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
}
} else {
decompressor := config.StateDump.Accounts["OVM_SequencerEntrypoint"]
msg, err = AsOvmMessage(tx, types.MakeSigner(config, header.Number), decompressor.Address)
msg, err = AsOvmMessage(tx, types.MakeSigner(config, header.Number), decompressor.Address, header.GasLimit)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions core/state_transition_ovm.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func toExecutionManagerRun(evm *vm.EVM, msg Message) (Message, error) {
return outputmsg, nil
}

func AsOvmMessage(tx *types.Transaction, signer types.Signer, decompressor common.Address) (Message, error) {
func AsOvmMessage(tx *types.Transaction, signer types.Signer, decompressor common.Address, gasLimit uint64) (Message, error) {
msg, err := tx.AsMessage(signer)
if err != nil {
// This should only be allowed to pass if the transaction is in the ctc
Expand All @@ -85,7 +85,7 @@ func AsOvmMessage(tx *types.Transaction, signer types.Signer, decompressor commo
msg.From(),
&decompressor,
tx.GetMeta().RawTransaction,
msg.Gas(),
gasLimit,
)

if err != nil {
Expand Down
29 changes: 18 additions & 11 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ var (
)

var (
evictionInterval = time.Minute // Time interval to check for evictable transactions
statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
evictionInterval = time.Minute // Time interval to check for evictable transactions
statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
gwei = big.NewInt(params.GWei) // 1 gwei, used as a flag for "rollup" transactions
)

var (
Expand Down Expand Up @@ -537,10 +538,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if tx.Value().Sign() < 0 {
return ErrNegativeValue
}

// Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas < tx.Gas() {
// We skip this condition check if the transaction's gasPrice is set to 1gwei,
// which indicates a "rollup" transaction that's paying for its data.
if pool.currentMaxGas < tx.Gas() && tx.GasPrice().Cmp(gwei) != 0 {
return ErrGasLimit
}

// Make sure the transaction is signed properly
from, err := types.Sender(pool.signer, tx)
if err != nil {
Expand All @@ -565,14 +570,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
return ErrInsufficientFunds
}
}
// Ensure the transaction has more gas than the basic tx fee.
intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
if err != nil {
return err
}
if tx.Gas() < intrGas {
return ErrIntrinsicGas
// Ensure the transaction has more gas than the basic tx fee.
intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, true, pool.istanbul)
if err != nil {
return err
}
if tx.Gas() < intrGas {
return ErrIntrinsicGas
}
}
return nil
}
Expand All @@ -585,13 +590,15 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// whitelisted, preventing any associated transaction from being dropped out of the pool
// due to pricing constraints.
func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err error) {
log.Debug("received tx", "gas", tx.Gas(), "gasprice", tx.GasPrice().Uint64())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transactions are not added to the TxPool so this should never log

// If the transaction is already known, discard it
hash := tx.Hash()
if pool.all.Get(hash) != nil {
log.Trace("Discarding already known transaction", "hash", hash)
knownTxMeter.Mark(1)
return false, fmt.Errorf("known transaction: %x", hash)
}

// If the transaction fails basic validation, discard it
if err := pool.validateTx(tx, local); err != nil {
log.Trace("Discarding invalid transaction", "hash", hash, "err", err)
Expand Down
9 changes: 9 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type EthAPIBackend struct {
extRPCEnabled bool
eth *Ethereum
gpo *gasprice.Oracle
l1gpo *gasprice.L1Oracle
verifier bool
gasLimit uint64
UsingOVM bool
Expand Down Expand Up @@ -371,6 +372,14 @@ func (b *EthAPIBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
return b.gpo.SuggestPrice(ctx)
}

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

func (b *EthAPIBackend) SetL1GasPrice(ctx context.Context, gasPrice *big.Int) {
b.l1gpo.SetL1GasPrice(gasPrice)
}

func (b *EthAPIBackend) ChainDb() ethdb.Database {
return b.eth.ChainDb()
}
Expand Down
1 change: 1 addition & 0 deletions eth/api_backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func TestGasLimit(t *testing.T) {
extRPCEnabled: false,
eth: nil,
gpo: nil,
l1gpo: nil,
verifier: false,
gasLimit: 0,
UsingOVM: true,
Expand Down
2 changes: 1 addition & 1 deletion eth/api_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
if !vm.UsingOVM {
msg, _ = tx.AsMessage(signer)
} else {
msg, err = core.AsOvmMessage(tx, signer, common.HexToAddress("0x4200000000000000000000000000000000000005"))
msg, err = core.AsOvmMessage(tx, signer, common.HexToAddress("0x4200000000000000000000000000000000000005"), block.Header().GasLimit)
if err != nil {
return nil, vm.Context{}, nil, err
}
Expand Down
8 changes: 6 additions & 2 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,17 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))

log.Info("Backend Config", "max-calldata-size", config.Rollup.MaxCallDataSize, "gas-limit", config.Rollup.GasLimit, "is-verifier", config.Rollup.IsVerifier, "using-ovm", vm.UsingOVM)
eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil, config.Rollup.IsVerifier, config.Rollup.GasLimit, vm.UsingOVM, config.Rollup.MaxCallDataSize}
log.Info("Backend Config", "max-calldata-size", config.Rollup.MaxCallDataSize, "gas-limit", config.Rollup.GasLimit, "is-verifier", config.Rollup.IsVerifier, "using-ovm", vm.UsingOVM, "l1-gasprice", config.Rollup.L1GasPrice)
eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil, nil, config.Rollup.IsVerifier, config.Rollup.GasLimit, vm.UsingOVM, config.Rollup.MaxCallDataSize}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
// create the L1 GPO and allow the API backend and the sync service to access it
l1Gpo := gasprice.NewL1Oracle(config.Rollup.L1GasPrice)
eth.APIBackend.l1gpo = l1Gpo
eth.syncService.L1gpo = l1Gpo
return eth, nil
}

Expand Down
1 change: 1 addition & 0 deletions eth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var DefaultConfig = Config{
// is additional overhead that is unaccounted. Round down to 127000 for
// safety.
MaxCallDataSize: 127000,
L1GasPrice: big.NewInt(100 * params.GWei),
},
DiffDbCache: 256,
}
Expand Down
24 changes: 24 additions & 0 deletions eth/gasprice/l1_gasprice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package gasprice

import (
"context"
"math/big"
)

type L1Oracle struct {
gasPrice *big.Int
}

func NewL1Oracle(gasPrice *big.Int) *L1Oracle {
return &L1Oracle{gasPrice}
}

/// SuggestDataPrice returns the gas price which should be charged per byte of published
/// data by the sequencer.
func (gpo *L1Oracle) SuggestDataPrice(ctx context.Context) (*big.Int, error) {
return gpo.gasPrice, nil
}

func (gpo *L1Oracle) SetL1GasPrice(gasPrice *big.Int) {
gpo.gasPrice = gasPrice
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
github.com/huin/goupnp v1.0.0
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458
github.com/jarcoal/httpmock v1.0.8
github.com/jmoiron/sqlx v1.2.0
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883 h1:FSeK4fZCo
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k=
github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
Expand Down
Loading