Commit 8ac47db2 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #2381 from ethereum-optimism/feat/gasusage-compression-ratio

tasks: compute calldata cost diff in `fetch-batches`
parents f1586e3a 5cb3a5f7
---
'@eth-optimism/core-utils': patch
---
Add a `calldataCost` function that computes the cost of calldata
import { ethers } from 'ethers' import { ethers } from 'ethers'
import { task } from 'hardhat/config' import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes' import * as types from 'hardhat/internal/core/params/argumentTypes'
import { BatchType, SequencerBatch } from '@eth-optimism/core-utils' import {
BatchType,
SequencerBatch,
calldataCost,
} from '@eth-optimism/core-utils'
import { names } from '../src/address-names' import { names } from '../src/address-names'
import { getContractFromArtifact } from '../src/deploy-utils' import { getContractFromArtifact } from '../src/deploy-utils'
...@@ -52,28 +56,42 @@ task('fetch-batches') ...@@ -52,28 +56,42 @@ task('fetch-batches')
const tx = await provider.getTransaction(event.transactionHash) const tx = await provider.getTransaction(event.transactionHash)
const batch = (SequencerBatch as any).fromHex(tx.data) const batch = (SequencerBatch as any).fromHex(tx.data)
// Add an extra field to the resulting json // Add extra fields to the resulting json
// so that the serialization sizes can be observed // so that the serialization sizes and gas usage can be observed
const json = batch.toJSON() const json = batch.toJSON()
json.sizes = { json.sizes = {
legacy: 0, legacy: 0,
zlib: 0, zlib: 0,
} }
json.gasUsage = {
legacy: 0,
zlib: 0,
}
// Create a copy of the batch to serialize in // Create a copy of the batch to serialize in
// the alternative format // the alternative format
const copy = (SequencerBatch as any).fromHex(tx.data) const copy = (SequencerBatch as any).fromHex(tx.data)
let legacy: Buffer
let zlib: Buffer
if (batch.type === BatchType.ZLIB) { if (batch.type === BatchType.ZLIB) {
copy.type = BatchType.LEGACY copy.type = BatchType.LEGACY
json.sizes.legacy = copy.encode().length legacy = copy.encode()
json.sizes.zlib = batch.encode().length zlib = batch.encode()
} else { } else {
copy.type = BatchType.ZLIB copy.type = BatchType.ZLIB
json.sizes.zlib = copy.encode().length zlib = copy.encode()
json.sizes.legacy = batch.encode().length legacy = batch.encode()
} }
json.compressionRatio = json.sizes.zlib / json.sizes.legacy json.sizes.legacy = legacy.length
json.sizes.zlib = zlib.length
json.sizes.compressionRatio = json.sizes.zlib / json.sizes.legacy
json.gasUsage.legacy = calldataCost(legacy).toNumber()
json.gasUsage.zlib = calldataCost(zlib).toNumber()
json.gasUsage.compressionRatio =
json.gasUsage.zlib / json.gasUsage.legacy
batches.push(json) batches.push(json)
} }
......
...@@ -6,8 +6,8 @@ import { BigNumber } from 'ethers' ...@@ -6,8 +6,8 @@ import { BigNumber } from 'ethers'
import { remove0x } from '../common' import { remove0x } from '../common'
const txDataZeroGas = 4 export const txDataZeroGas = 4
const txDataNonZeroGasEIP2028 = 16 export const txDataNonZeroGasEIP2028 = 16
const big10 = BigNumber.from(10) const big10 = BigNumber.from(10)
export const scaleDecimals = ( export const scaleDecimals = (
...@@ -63,3 +63,17 @@ export const zeroesAndOnes = (data: Buffer | string): Array<number> => { ...@@ -63,3 +63,17 @@ export const zeroesAndOnes = (data: Buffer | string): Array<number> => {
} }
return [zeros, ones] return [zeros, ones]
} }
/**
* Computes the L1 calldata cost of bytes based
* on the London hardfork.
*
* @param data {Buffer|string} Bytes
* @returns {BigNumber} Gas consumed by the bytes
*/
export const calldataCost = (data: Buffer | string): BigNumber => {
const [zeros, ones] = zeroesAndOnes(data)
const zeroCost = BigNumber.from(zeros).mul(txDataZeroGas)
const nonZeroCost = BigNumber.from(ones).mul(txDataNonZeroGasEIP2028)
return zeroCost.add(nonZeroCost)
}
import { zeroesAndOnes } from '../src' import './setup'
import { BigNumber } from 'ethers'
import { zeroesAndOnes, calldataCost } from '../src'
describe('Fees', () => { describe('Fees', () => {
it('should count zeros and ones', () => { it('should count zeros and ones', () => {
...@@ -15,4 +19,19 @@ describe('Fees', () => { ...@@ -15,4 +19,19 @@ describe('Fees', () => {
ones.should.eq(test.ones) ones.should.eq(test.ones)
} }
}) })
it('should compute calldata costs', () => {
const cases = [
{ input: '0x', output: BigNumber.from(0) },
{ input: '0x00', output: BigNumber.from(4) },
{ input: '0xff', output: BigNumber.from(16) },
{ input: Buffer.alloc(32), output: BigNumber.from(4 * 32) },
{ input: Buffer.alloc(32, 0xff), output: BigNumber.from(16 * 32) },
]
for (const test of cases) {
const cost = calldataCost(test.input)
cost.should.deep.eq(test.output)
}
})
}) })
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