Skip to content

Commit

Permalink
block: fix the param resolution for excess gas and blob fee compute (#…
Browse files Browse the repository at this point in the history
…3841)

* block: fix the param resolution for excess gas and blob fee compute

* lint

* feedback fix

* test lint in CI

* apply biome lint

* add blob fee params to vm

* apply feedback

---------

Co-authored-by: Jochem Brouwer <[email protected]>
  • Loading branch information
g11tech and jochem-brouwer authored Jan 24, 2025
1 parent 5ba37f3 commit 020ceec
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 31 deletions.
2 changes: 1 addition & 1 deletion packages/block/src/block/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ export class Block {
const blobGasPerBlob = this.common.param('blobGasPerBlob')
let blobGasUsed = BIGINT_0

const expectedExcessBlobGas = parentHeader.calcNextExcessBlobGas()
const expectedExcessBlobGas = parentHeader.calcNextExcessBlobGas(this.common)
if (this.header.excessBlobGas !== expectedExcessBlobGas) {
throw new Error(
`block excessBlobGas mismatch: have ${this.header.excessBlobGas}, want ${expectedExcessBlobGas}`,
Expand Down
24 changes: 6 additions & 18 deletions packages/block/src/header/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
CLIQUE_EXTRA_VANITY,
cliqueIsEpochTransition,
} from '../consensus/clique.js'
import { fakeExponential } from '../helpers.js'
import { computeBlobGasPrice } from '../helpers.js'
import { paramsBlock } from '../params.js'

import type { BlockHeaderBytes, BlockOptions, HeaderData, JSONHeader } from '../types.js'
Expand Down Expand Up @@ -532,19 +532,7 @@ export class BlockHeader {
if (this.excessBlobGas === undefined) {
throw new Error('header must have excessBlobGas field populated')
}
return this._getBlobGasPrice(this.excessBlobGas)
}

/**
* Returns the blob gas price depending upon the `excessBlobGas` value
* @param excessBlobGas
*/
private _getBlobGasPrice(excessBlobGas: bigint) {
return fakeExponential(
this.common.param('minBlobGas'),
excessBlobGas,
this.common.param('blobGasPriceUpdateFraction'),
)
return computeBlobGasPrice(this.excessBlobGas, this.common)
}

/**
Expand All @@ -564,10 +552,10 @@ export class BlockHeader {
/**
* Calculates the excess blob gas for next (hopefully) post EIP 4844 block.
*/
public calcNextExcessBlobGas(): bigint {
public calcNextExcessBlobGas(childCommon: Common): bigint {
// The validation of the fields and 4844 activation is already taken care in BlockHeader constructor
const targetGasConsumed = (this.excessBlobGas ?? BIGINT_0) + (this.blobGasUsed ?? BIGINT_0)
const targetBlobGasPerBlock = this.common.param('targetBlobGasPerBlock')
const targetBlobGasPerBlock = childCommon.param('targetBlobGasPerBlock')

if (targetGasConsumed <= targetBlobGasPerBlock) {
return BIGINT_0
Expand All @@ -580,8 +568,8 @@ export class BlockHeader {
* Calculate the blob gas price of the block built on top of this one
* @returns The blob gas price
*/
public calcNextBlobGasPrice(): bigint {
return this._getBlobGasPrice(this.calcNextExcessBlobGas())
public calcNextBlobGasPrice(childCommon: Common): bigint {
return computeBlobGasPrice(this.calcNextExcessBlobGas(childCommon), childCommon)
}

/**
Expand Down
15 changes: 14 additions & 1 deletion packages/block/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { Blob4844Tx } from '@ethereumjs/tx'
import { BIGINT_0, BIGINT_1, TypeOutput, concatBytes, isHexString, toType } from '@ethereumjs/util'

import type { BlockHeaderBytes, HeaderData } from './types.js'
import type { Common } from '@ethereumjs/common'
import type { TypedTransaction } from '@ethereumjs/tx'
import type { CLRequest, CLRequestType, PrefixedHexString, Withdrawal } from '@ethereumjs/util'

/**
* Returns a 0x-prefixed hex number string from a hex string or string integer.
* @param {string} input string to check, convert, and return
Expand Down Expand Up @@ -119,6 +119,19 @@ export const fakeExponential = (factor: bigint, numerator: bigint, denominator:
return output / denominator
}

/**
* Returns the blob gas price depending upon the `excessBlobGas` value
* @param excessBlobGas
* @param common
*/
export const computeBlobGasPrice = (excessBlobGas: bigint, common: Common) => {
return fakeExponential(
common.param('minBlobGas'),
excessBlobGas,
common.param('blobGasPriceUpdateFraction'),
)
}

/**
* Returns the withdrawals trie root for array of Withdrawal.
* @param wts array of Withdrawal to compute the root of
Expand Down
10 changes: 5 additions & 5 deletions packages/block/test/eip4844block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('blob gas tests', () => {
{ common: new Common({ chain: Mainnet, hardfork: Hardfork.Shanghai }) },
)

let excessBlobGas = preShardingHeader.calcNextExcessBlobGas()
let excessBlobGas = preShardingHeader.calcNextExcessBlobGas(common)
assert.equal(
excessBlobGas,
0n,
Expand All @@ -129,15 +129,15 @@ describe('blob gas tests', () => {
{ common, skipConsensusFormatValidation: true },
)

excessBlobGas = lowGasHeader.calcNextExcessBlobGas()
excessBlobGas = lowGasHeader.calcNextExcessBlobGas(common)
let blobGasPrice = lowGasHeader.getBlobGasPrice()
assert.equal(excessBlobGas, 0n, 'excess blob gas should be 0 for small parent header blob gas')
assert.equal(blobGasPrice, 1n, 'blob gas price should be 1n when low or no excess blob gas')
const highGasHeader = createBlockHeader(
{ number: 1, excessBlobGas: 6291456, blobGasUsed: BigInt(6) * blobGasPerBlob },
{ common, skipConsensusFormatValidation: true },
)
excessBlobGas = highGasHeader.calcNextExcessBlobGas()
excessBlobGas = highGasHeader.calcNextExcessBlobGas(common)
blobGasPrice = highGasHeader.getBlobGasPrice()
assert.equal(excessBlobGas, 6684672n)
assert.equal(blobGasPrice, 6n, 'computed correct blob gas price')
Expand All @@ -146,7 +146,7 @@ describe('blob gas tests', () => {
assert.equal(highGasHeader.calcDataFee(4), 3145728n, 'compute data fee correctly')
assert.equal(highGasHeader.calcDataFee(6), 4718592n, 'compute data fee correctly')

const nextBlobGas = highGasHeader.calcNextBlobGasPrice()
const nextBlobGas = highGasHeader.calcNextBlobGasPrice(common)
assert.equal(nextBlobGas, BigInt(7)) // TODO verify that this is correct
})
})
Expand Down Expand Up @@ -194,7 +194,7 @@ describe('transaction validation tests', () => {
{ number: 1n, excessBlobGas: 4194304, blobGasUsed: 0 },
{ common, skipConsensusFormatValidation: true },
)
const excessBlobGas = parentHeader.calcNextExcessBlobGas()
const excessBlobGas = parentHeader.calcNextExcessBlobGas(common)

// eslint-disable-next-line no-inner-declarations
function getBlock(transactions: TypedTransaction[]) {
Expand Down
2 changes: 1 addition & 1 deletion packages/blockchain/src/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ export class Blockchain implements BlockchainInterface {
}

if (header.common.isActivatedEIP(4844)) {
const expectedExcessBlobGas = parentHeader.calcNextExcessBlobGas()
const expectedExcessBlobGas = parentHeader.calcNextExcessBlobGas(header.common)
if (header.excessBlobGas !== expectedExcessBlobGas) {
throw new Error(`expected blob gas: ${expectedExcessBlobGas}, got: ${header.excessBlobGas}`)
}
Expand Down
8 changes: 6 additions & 2 deletions packages/client/src/rpc/modules/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,10 @@ export class Eth {

if (this._chain.blockchain.common.isActivatedEIP(4844)) {
baseFeePerBlobGas.push(
requestedBlocks[requestedBlocks.length - 1].header.calcNextBlobGasPrice(),
// use the last blocks common for fee estimation
requestedBlocks[requestedBlocks.length - 1].header.calcNextBlobGasPrice(
requestedBlocks[requestedBlocks.length - 1].header.common,
),
)
} else {
// TODO (?): known bug
Expand Down Expand Up @@ -1461,6 +1464,7 @@ export class Eth {
*/
async blobBaseFee() {
const headBlock = await this._chain.getCanonicalHeadHeader()
return bigIntToHex(headBlock.calcNextBlobGasPrice())
// use headBlock's common to estimate the next blob fee
return bigIntToHex(headBlock.calcNextBlobGasPrice(headBlock.common))
}
}
2 changes: 1 addition & 1 deletion packages/client/test/rpc/eth/getFeeHistory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ describe(method, () => {
expBlobGas.push(bigIntToHex(block.header.getBlobGasPrice()))
}

expBlobGas.push(bigIntToHex(head.header.calcNextBlobGasPrice()))
expBlobGas.push(bigIntToHex(head.header.calcNextBlobGasPrice(head.common)))

assert.deepEqual(res.result.baseFeePerBlobGas, expBlobGas)
assert.deepEqual(res.result.blobGasUsedRatio, expRatio)
Expand Down
2 changes: 1 addition & 1 deletion packages/vm/src/buildBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export class BlockBuilder {
this.vm.common.isActivatedEIP(4844) &&
typeof this.headerData.excessBlobGas === 'undefined'
) {
this.headerData.excessBlobGas = opts.parentBlock.header.calcNextExcessBlobGas()
this.headerData.excessBlobGas = opts.parentBlock.header.calcNextExcessBlobGas(this.vm.common)
}
}

Expand Down
9 changes: 9 additions & 0 deletions packages/vm/src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const paramsVM: ParamsDict = {
maxRefundQuotient: 2, // Maximum refund quotient; max tx refund is min(tx.gasUsed/maxRefundQuotient, tx.gasRefund)
blobGasPerBlob: 0,
maxBlobGasPerBlock: 0,
targetBlobGasPerBlock: 0,
// pow
minerReward: '5000000000000000000', // the amount a miner get rewarded for mining a block
},
Expand Down Expand Up @@ -54,8 +55,13 @@ export const paramsVM: ParamsDict = {
. * Shard Blob Transactions
. */
4844: {
// gasConfig
targetBlobGasPerBlock: 393216, // The target blob gas consumed per block
blobGasPerBlob: 131072, // The base fee for blob gas per blob
maxBlobGasPerBlock: 786432, // The max blob gas allowable per block
blobGasPriceUpdateFraction: 3338477, // The denominator used in the exponential when calculating a blob gas price
// gasPrices
minBlobGas: 1, // The minimum fee per blob gas
},
/**
. * Beacon block root in the EVM
Expand Down Expand Up @@ -94,6 +100,9 @@ export const paramsVM: ParamsDict = {
. * Shard Blob Transactions
. */
7691: {
// gasConfig
targetBlobGasPerBlock: 786432, // The target blob gas consumed per block
maxBlobGasPerBlock: 1179648, // The max blob gas allowable per block
blobGasPriceUpdateFraction: 5007716, // The denominator used in the exponential when calculating a blob gas price
},
}
2 changes: 1 addition & 1 deletion packages/vm/test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ export function makeBlockHeader(data: any, opts?: BlockOptions) {
if (opts?.common && opts.common.gteHardfork('cancun')) {
headerData['excessBlobGas'] = currentExcessBlobGas
if (currentExcessBlobGas === undefined) {
headerData['excessBlobGas'] = parentBlockHeader.calcNextExcessBlobGas()
headerData['excessBlobGas'] = parentBlockHeader.calcNextExcessBlobGas(opts.common)
}
}
return createBlockHeader(headerData, opts)
Expand Down

0 comments on commit 020ceec

Please sign in to comment.