Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
35 changes: 25 additions & 10 deletions packages/block/src/header/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,15 +560,32 @@ export class BlockHeader {
* Calculates the excess blob gas for next (hopefully) post EIP 4844 block.
*/
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 = childCommon.param('targetBlobGasPerBlock')
const excessBlobGas = this.excessBlobGas ?? 0n
Copy link
Member

Choose a reason for hiding this comment

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

Please do not use the n notation for BigInts (compatibility reasons) + we have these predefined constants (like BIGINT_1) for various commonly used BigInt values, which gives a performance benefit and which you can use on various occasions in this PR.

const blobGasUsed = this.blobGasUsed ?? 0n

if (targetGasConsumed <= targetBlobGasPerBlock) {
return BIGINT_0
} else {
return targetGasConsumed - targetBlobGasPerBlock
const targetPerBlock = childCommon.param('targetBlobGasPerBlock')
const maxPerBlock = childCommon.param('maxBlobGasPerBlock')

// Early exit (strictly < per spec)
if (excessBlobGas + blobGasUsed < targetPerBlock) {
return 0n
}

// EIP-7918 reserve price check
if (childCommon.isActivatedEIP(7918)) {
const blobBaseCost = childCommon.param('blobBaseCost')
const gasPerBlob = childCommon.param('blobGasPerBlob')
const baseFee = this.baseFeePerGas ?? 0n
const blobFee = this.getBlobGasPrice()

if (blobBaseCost * baseFee > gasPerBlob * blobFee) {
const increase = (blobGasUsed * (maxPerBlock - targetPerBlock)) / maxPerBlock
return excessBlobGas + increase
}
}

// Original 4844 path
return excessBlobGas + blobGasUsed - targetPerBlock
}

/**
Expand Down Expand Up @@ -635,9 +652,7 @@ export class BlockHeader {
*/
hash(): Uint8Array {
if (Object.isFrozen(this)) {
if (!this.cache.hash) {
this.cache.hash = this.keccakFunction(RLP.encode(this.raw())) as Uint8Array
}
this.cache.hash ??= this.keccakFunction(RLP.encode(this.raw())) as Uint8Array
Copy link
Member

Choose a reason for hiding this comment

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

Did you also had this strange random (?) linter stuff !?

return this.cache.hash
}
return this.keccakFunction(RLP.encode(this.raw()))
Expand Down
1 change: 1 addition & 0 deletions packages/block/src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const paramsBlock: ParamsDict = {
blobGasPriceUpdateFraction: 3338477, // The denominator used in the exponential when calculating a blob gas price
// gasPrices
minBlobGas: 1, // The minimum fee per blob gas
blobBaseCost: 8192, // EIP-7918: Blob base fee bounded by execution cost (2^13)
},
/**
* Delaying Difficulty Bomb to mid-September 2022
Expand Down
99 changes: 99 additions & 0 deletions packages/block/test/eip4844block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,105 @@ describe('blob gas tests', () => {
const nextBlobGas = highGasHeader.calcNextBlobGasPrice(common)
assert.strictEqual(nextBlobGas, BigInt(7)) // TODO verify that this is correct
})

describe('EIP-7918: Blob base fee bounded by execution cost', () => {
const osakaCommon = createCommonFromGethGenesis(eip4844GethGenesis, {
chain: 'customChain',
hardfork: Hardfork.Cancun,
params: paramsBlock,
customCrypto: { kzg },
eips: [7918],
})

it('applies reserve price when exec cost dominates', () => {
const highBaseFee = 1_000_000_000_000_000n
const target = osakaCommon.param('targetBlobGasPerBlock')
const max = osakaCommon.param('maxBlobGasPerBlock')
const BLOB_BASE_COST = osakaCommon.param('blobBaseCost')
const GAS_PER_BLOB = osakaCommon.param('blobGasPerBlob')

const header = createBlockHeader(
{
number: 1,
baseFeePerGas: highBaseFee,
excessBlobGas: 0n,
blobGasUsed: target,
},
{ common: osakaCommon, skipConsensusFormatValidation: true },
)

assert.isTrue(BLOB_BASE_COST * highBaseFee > GAS_PER_BLOB * header.getBlobGasPrice())

const got = header.calcNextExcessBlobGas(osakaCommon)
const expected = (target * (max - target)) / max
assert.strictEqual(got, expected)
})

it('should use original EIP-4844 logic when reserve price condition is not met', () => {
// Create a header with low base fee and high blob gas price
const lowBaseFee = 1n // Very low base fee (1 wei)

// Set excessBlobGas to a high value to get high blob gas price
const highExcessBlobGas = 1000000000n
const header = createBlockHeader(
{
number: 1,
baseFeePerGas: lowBaseFee,
excessBlobGas: highExcessBlobGas,
blobGasUsed: blobGasPerBlob * 2n, // 2 blobs used
},
{ common: osakaCommon, skipConsensusFormatValidation: true },
)

const excessBlobGas = header.calcNextExcessBlobGas(osakaCommon)

// Should use original EIP-4844 logic
const blobBaseCost = osakaCommon.param('blobBaseCost')
const currentBlobGasPrice = header.getBlobGasPrice()

// Check that reserve price condition is not met
assert.isTrue(
blobBaseCost * lowBaseFee <= blobGasPerBlob * currentBlobGasPrice,
'reserve price condition should not be met',
)

const targetGasConsumed = highExcessBlobGas + blobGasPerBlob * 2n
const targetBlobGasPerBlock = osakaCommon.param('targetBlobGasPerBlock')
const expectedExcessBlobGas = targetGasConsumed - targetBlobGasPerBlock

assert.strictEqual(
excessBlobGas,
expectedExcessBlobGas,
'should use original EIP-4844 logic when reserve price condition is not met',
)
})

it('should not apply EIP-7918 logic when EIP is not activated', () => {
// Use Cancun hardfork where EIP-7918 is not activated
const header = createBlockHeader(
{
number: 1,
baseFeePerGas: 1000000000n,
excessBlobGas: 1000000n,
blobGasUsed: blobGasPerBlob,
},
{ common, skipConsensusFormatValidation: true },
)

const excessBlobGas = header.calcNextExcessBlobGas(common)

// Should use original EIP-4844 logic since EIP-7918 is not activated
const targetGasConsumed = 1000000n + blobGasPerBlob
const targetBlobGasPerBlock = common.param('targetBlobGasPerBlock')
const expectedExcessBlobGas = targetGasConsumed - targetBlobGasPerBlock

assert.strictEqual(
excessBlobGas,
expectedExcessBlobGas,
'should use original EIP-4844 logic when EIP-7918 is not activated',
)
})
})
Copy link
Member

Choose a reason for hiding this comment

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

Just for informational purposes: is this AI or partly or not?

Copy link
Member

Choose a reason for hiding this comment

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

Not matter who to praise for: these are really nicely readable tests! 😄 😂

})

describe('transaction validation tests', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ The following EIPs are currently supported:
- [EIP-7516](https://eips.ethereum.org/EIPS/eip-7516) - BLOBBASEFEE opcode (Cancun)
- [EIP-7623](https://eips.ethereum.org/EIPS/eip-7623) - Increase calldata cost (Prague)
- [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685) - General purpose execution layer requests (Prague)
- [EIP-7918](https://eips.ethereum.org/EIPS/eip-7918) - Blob base fee bounded by execution cost (Osaka)
- [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691) - Blob throughput increase (Prague)
- [EIP-7692](https://eips.ethereum.org/EIPS/eip-7692) - EVM Object Format (EOF) v1 (`experimental`)
- [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) - Set EOA account code (Prague)
Expand Down
9 changes: 9 additions & 0 deletions packages/common/src/eips.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,15 @@ export const eipsDict: EIPsDict = {
minimumHardfork: Hardfork.Paris,
requiredEIPs: [4844],
},
/**
* Description : Blob base fee bounded by execution cost
* URL : https://eips.ethereum.org/EIPS/eip-7918
* Status : Last Call
*/
7918: {
minimumHardfork: Hardfork.Paris,
requiredEIPs: [4844],
},
/**
* Description : EVM Object Format (EOFv1) Meta
* URL : https://github.com/ethereum/EIPs/blob/4153e95befd0264082de3c4c2fe3a85cc74d3152/EIPS/eip-7692.md
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/hardforks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export const hardforksDict: HardforksDict = {
* Status : Draft
*/
osaka: {
eips: [7594, 7823, 7825, 7883, 7939, 7951],
eips: [7594, 7823, 7825, 7883, 7939, 7951, 7918],
},
/**
* Description: Next feature hardfork after osaka, internally used for verkle testing/implementation (incomplete/experimental)
Expand Down
1 change: 1 addition & 0 deletions packages/vm/src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const paramsVM: ParamsDict = {
blobGasPriceUpdateFraction: 3338477, // The denominator used in the exponential when calculating a blob gas price
// gasPrices
minBlobGas: 1, // The minimum fee per blob gas
blobBaseCost: 8192, // EIP-7918: Blob base fee bounded by execution cost (2^13)
Copy link
Member

Choose a reason for hiding this comment

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

This can be removed (I guess?).

},
/**
. * Beacon block root in the EVM
Expand Down
Loading