Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

l2geth: updated calculate rollup fee #906

Merged
merged 18 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Next Next commit
l2geth: updated calculate rollup fee
  • Loading branch information
tynes committed May 19, 2021
commit 6636805d0977f609ac6d369e49a84e16fbd6e250
49 changes: 37 additions & 12 deletions l2geth/core/rollup_fee.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,50 @@ import (
"github.com/ethereum/go-ethereum/params"
)

// RollupBaseTxSize is the encoded rollup transaction's compressed size excluding
// the variable length data.
// Ref: https://github.com/ethereum-optimism/optimism/blob/91a9a3dcddf534ae1c906133b6d8e015a23c463b/packages/contracts/contracts/optimistic-ethereum/OVM/predeploys/OVM_SequencerEntrypoint.sol#L47
const RollupBaseTxSize uint64 = 96
// RollupBatchOverhead is the number of additional bytes of overhead that a
// transaction batch requires in addition to the transactions.

var (
// Assuming 200 txs in a batch, 2688 gas per transaction
// Assuming 250 stateroots in a batch, 1473 gas per stateroot
overhead = new(big.Int).SetUint64(2688 + 1473)
maxGasLimit = new(big.Int).SetUint64(10_000_000)
scalarValue = new(big.Int).SetUint64(1)
scalarDecimals = new(big.Int).SetUint64(0)
big10 = new(big.Int).SetUint64(10)
)

// CalculateFee calculates the fee that must be paid to the Rollup sequencer, taking into
// account the cost of publishing data to L1.
// Returns: (4 * zeroDataBytes + 16 * (nonZeroDataBytes + RollupBaseTxSize)) * dataPrice + executionPrice * gasUsed
func CalculateRollupFee(data []byte, gasUsed uint64, dataPrice, executionPrice *big.Int) *big.Int {
// The following formula is used:
// overhead = 2688 + 1473
// dataCost = (4 * zeroDataBytes) + (16 * nonZeroDataBytes)
// l1GasCost = dataCost + overhead
// l1Fee = l1GasCost * l1GasPrice
// executionFee = executionPrice * gasLimit
// scalar = scalarValue / 10 ** scalarDecimals
// estimateGas = scalar * (l1Fee + executionFee) * (maxGasLimit + gasLimit)
// final fee = estimateGas * gasPrice
func CalculateRollupFee(data []byte, gasUsed, dataPrice, executionPrice *big.Int) uint64 {
zeroes, ones := zeroesAndOnes(data)
zeroesCost := new(big.Int).SetUint64(zeroes * params.TxDataZeroGas)
onesCost := new(big.Int).SetUint64((RollupBaseTxSize + ones) * params.TxDataNonZeroGasEIP2028)
onesCost := new(big.Int).SetUint64(ones * params.TxDataNonZeroGasEIP2028)
dataCost := new(big.Int).Add(zeroesCost, onesCost)
l1GasCost := new(big.Int).Add(dataCost, overhead)

// dataPrice is l1GasPrice
l1Fee := new(big.Int).Mul(l1GasCost, dataPrice)
executionFee := new(big.Int).Mul(executionPrice, gasUsed)

fee1 := new(big.Int).Mul(l1Fee, executionFee)
fee2 := new(big.Int).Mul(maxGasLimit, gasUsed)
fee := new(big.Int).Add(fee1, fee2)

scalar := new(big.Int).Exp(big10, scalarDecimals, nil)
scalar = scalar.Mul(scalar, scalarValue)
result := new(big.Int).Mul(fee, scalar)

// get the data fee
dataFee := new(big.Int).Mul(dataPrice, dataCost)
executionFee := new(big.Int).Mul(executionPrice, new(big.Int).SetUint64(gasUsed))
fee := new(big.Int).Add(dataFee, executionFee)
return fee
return result.Uint64()
}

func zeroesAndOnes(data []byte) (uint64, uint64) {
Expand Down
33 changes: 19 additions & 14 deletions l2geth/core/rollup_fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,36 @@ import (
var feeTests = map[string]struct {
dataLen int
gasUsed uint64
dataPrice int64
executionPrice int64
dataPrice uint64
executionPrice uint64
maxGasLimit uint64
}{
"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},
"simple": {10000000, 10, 20, 30, 10_000_000},
"zero gas used": {10000, 0, 20, 30, 10_000_000},
"zero data price": {10000, 0, 0, 30, 10_000_000},
"zero execution price": {10000, 0, 0, 0, 10_000_000},
}

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))
gasUsed, dataPrice := new(big.Int).SetUint64(tt.gasUsed), new(big.Int).SetUint64(tt.dataPrice)
fee := CalculateRollupFee(data, gasUsed, dataPrice, new(big.Int).SetUint64(tt.executionPrice))

zeroes, ones := zeroesAndOnes(data)
zeroesCost := zeroes * 4
onesCost := (96 + ones) * 16
dataCost := zeroesCost + onesCost
dataFee := int64(dataCost) * tt.dataPrice
onesCost := ones * 16
dataCost := zeroesCost + onesCost + overhead.Uint64()
l1Fee := dataCost * tt.dataPrice

executionFee := uint64(tt.executionPrice) * tt.gasUsed
expectedFee := uint64(dataFee) + executionFee
if fee.Cmp(big.NewInt(int64(expectedFee))) != 0 {
t.Errorf("rollup fee check failed: expected %d, got %s", expectedFee, fee.String())
executionFee := tt.executionPrice * tt.gasUsed
fee1 := l1Fee * executionFee
fee2 := tt.maxGasLimit * gasUsed.Uint64()
expectedFee := fee1 + fee2

if fee != expectedFee {
t.Errorf("rollup fee check failed: expected %d, got %d", expectedFee, fee)
}
})
}
Expand Down
9 changes: 5 additions & 4 deletions l2geth/internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1045,11 +1045,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
}

// 3. calculate the fee and normalize by the default gas price
fee := core.CalculateRollupFee(*args.Data, uint64(gasUsed), dataPrice, executionPrice).Uint64() / defaultGasPrice
if fee < 21000 {
fee = 21000
fee := core.CalculateRollupFee(*args.Data, new(big.Int).SetUint64(uint64(gasUsed)), dataPrice, executionPrice)
normalizedFee := fee / defaultGasPrice
if normalizedFee < 21000 {
normalizedFee = 21000
}
tynes marked this conversation as resolved.
Show resolved Hide resolved
return (hexutil.Uint64)(fee), nil
return (hexutil.Uint64)(normalizedFee), nil
}

func legacyDoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap *big.Int) (hexutil.Uint64, error) {
Expand Down