Skip to content

Commit a812752

Browse files
common: allow specifying eip-7840 blobSchedule via geth genesis (#3835)
* common: allow specifying eip-7840 blobSchedule via geth genesis * add test and fix the hardforkchanges override issue * add to spell dict * update cspell.ts * common: update checks for blobs and add tests * common: remove old code --------- Co-authored-by: Jochem Brouwer <[email protected]>
1 parent a1f5de0 commit a812752

File tree

4 files changed

+179
-5
lines changed

4 files changed

+179
-5
lines changed

config/cspell-ts.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@
629629
"Unsnappy",
630630
"unsnappy",
631631
"ethportal",
632-
"bytevector"
632+
"bytevector",
633+
"blobschedule"
633634
]
634635
}

packages/common/src/common.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ export class Common {
6666
// Assign hardfork changes in the sequence of the applied hardforks
6767
this.HARDFORK_CHANGES = this.hardforks().map((hf) => [
6868
hf.name,
69-
hardforksDict[hf.name] ??
70-
(this._chainParams.customHardforks && this._chainParams.customHardforks[hf.name]),
69+
// Allow to even override an existing hardfork specification
70+
(this._chainParams.customHardforks && this._chainParams.customHardforks[hf.name]) ??
71+
hardforksDict[hf.name],
7172
])
7273
this._hardfork = this.DEFAULT_HARDFORK
7374
this._params = opts.params ? JSON.parse(JSON.stringify(opts.params)) : {} // copy
@@ -322,7 +323,7 @@ export class Common {
322323
this._mergeWithParamsCache(this._params[eip] ?? {})
323324
}
324325
}
325-
// Parameter-inlining HF config (e.g. for istanbul)
326+
// Parameter-inlining HF config (e.g. for istanbul or custom blobSchedule)
326327
this._mergeWithParamsCache(hfChanges[1].params ?? {})
327328
if (hfChanges[0] === hardfork) break
328329
}

packages/common/src/utils.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { intToHex, isHexString, stripHexPrefix } from '@ethereumjs/util'
22

33
import { Holesky, Kaustinen6, Mainnet, Sepolia } from './chains.js'
44
import { Hardfork } from './enums.js'
5+
import { hardforksDict } from './hardforks.js'
56

7+
import type { HardforksDict } from './types.js'
68
import type { PrefixedHexString } from '@ethereumjs/util'
79

810
type ConfigHardfork =
@@ -83,6 +85,42 @@ function parseGethParams(json: any) {
8385
)
8486
}
8587

88+
let customHardforks: HardforksDict | undefined = undefined
89+
if (config.blobSchedule !== undefined) {
90+
customHardforks = {}
91+
const blobGasPerBlob = 131072
92+
for (const [hfKey, hfSchedule] of Object.entries(config.blobSchedule)) {
93+
const hfConfig = hardforksDict[hfKey]
94+
if (hfConfig === undefined) {
95+
throw new Error(`unknown hardfork=${hfKey} specified in blobSchedule`)
96+
}
97+
const {
98+
target,
99+
max,
100+
baseFeeUpdateFraction: blobGasPriceUpdateFraction,
101+
} = hfSchedule as { target?: number; max?: number; baseFeeUpdateFraction?: undefined }
102+
if (target === undefined || max === undefined || blobGasPriceUpdateFraction === undefined) {
103+
throw new Error(
104+
`undefined target, max or baseFeeUpdateFraction specified in blobSchedule for hardfork=${hfKey}`,
105+
)
106+
}
107+
108+
// copy current hardfork info to custom and add blob config
109+
const customHfConfig = JSON.parse(JSON.stringify(hfConfig))
110+
customHfConfig.params = {
111+
...customHardforks.params,
112+
// removes blobGasPriceUpdateFraction key to prevent undefined overriding if undefined
113+
...{
114+
targetBlobGasPerBlock: blobGasPerBlob * target,
115+
maxBlobGasPerBlock: blobGasPerBlob * max,
116+
blobGasPriceUpdateFraction,
117+
},
118+
}
119+
120+
customHardforks[hfKey] = customHfConfig
121+
}
122+
}
123+
86124
const params = {
87125
name,
88126
chainId,
@@ -101,6 +139,7 @@ function parseGethParams(json: any) {
101139
},
102140
hardfork: undefined as string | undefined,
103141
hardforks: [] as ConfigHardfork[],
142+
customHardforks,
104143
bootstrapNodes: [],
105144
consensus:
106145
config.clique !== undefined

packages/common/test/utils.spec.ts

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe('[Utils/Parse]', () => {
7979

8080
it('should correctly parse deposit contract address', async () => {
8181
// clone json out to not have side effects
82-
const customData = postMergeHardforkData
82+
const customData = JSON.parse(JSON.stringify(postMergeHardforkData))
8383
Object.assign(customData.config, {
8484
depositContractAddress: '0x4242424242424242424242424242424242424242',
8585
})
@@ -122,4 +122,137 @@ describe('[Utils/Parse]', () => {
122122
-1,
123123
)
124124
})
125+
126+
it('should assign correct blob schedule', () => {
127+
// clone json out to not have side effects
128+
const customData = JSON.parse(JSON.stringify(postMergeHardforkData))
129+
const customConfigData = {
130+
chainId: 3151908,
131+
homesteadBlock: 0,
132+
eip150Block: 0,
133+
eip155Block: 0,
134+
eip158Block: 0,
135+
byzantiumBlock: 0,
136+
constantinopleBlock: 0,
137+
petersburgBlock: 0,
138+
istanbulBlock: 0,
139+
berlinBlock: 0,
140+
londonBlock: 0,
141+
mergeNetsplitBlock: 0,
142+
depositContractAddress: '0x4242424242424242424242424242424242424242',
143+
terminalTotalDifficulty: 0,
144+
terminalTotalDifficultyPassed: true,
145+
shanghaiTime: 0,
146+
cancunTime: 0,
147+
blobSchedule: {
148+
prague: {
149+
target: 61,
150+
max: 91,
151+
baseFeeUpdateFraction: 13338477,
152+
},
153+
},
154+
pragueTime: 1736942378,
155+
}
156+
Object.assign(customData.config, customConfigData)
157+
158+
const common = createCommonFromGethGenesis(customData, {
159+
chain: 'customChain',
160+
})
161+
const paramsTx = {
162+
4844: {
163+
blobCommitmentVersionKzg: 1, // The number indicated a versioned hash is a KZG commitment
164+
blobGasPerBlob: 131072, // The base fee for blob gas per blob
165+
maxBlobGasPerBlock: 786432, // The max blob gas allowable per block
166+
blobGasPriceUpdateFraction: 3338477,
167+
targetBlobGasPerBlock: 393216,
168+
},
169+
7691: {
170+
maxBlobGasPerBlock: 1179648, // The max blob gas allowable per block
171+
},
172+
}
173+
common.updateParams(paramsTx)
174+
175+
const blobGasPerBlob = common.param('blobGasPerBlob')
176+
177+
const testCases = [
178+
// should be picked from eip params
179+
[Hardfork.Cancun, blobGasPerBlob * BigInt(3), blobGasPerBlob * BigInt(6), 3338477n],
180+
// from the genesis blobschedule
181+
[
182+
Hardfork.Prague,
183+
blobGasPerBlob * BigInt(customConfigData.blobSchedule.prague.target),
184+
blobGasPerBlob * BigInt(customConfigData.blobSchedule.prague.max),
185+
13338477,
186+
],
187+
]
188+
for (const [testHf, testTarget, testMax, testUpdateFraction] of testCases) {
189+
common.setHardfork(testHf as Hardfork)
190+
191+
const targetBlobGasPerBlock = common.param('targetBlobGasPerBlock')
192+
const maxBlobGasPerBlock = common.param('maxBlobGasPerBlock')
193+
const blobGasPriceUpdateFraction = common.param('blobGasPriceUpdateFraction')
194+
195+
assert.equal(targetBlobGasPerBlock, testTarget, 'target blob gas should match')
196+
assert.equal(maxBlobGasPerBlock, testMax, 'max blob gas should match')
197+
assert.equal(blobGasPriceUpdateFraction, testUpdateFraction, 'update fraction should match')
198+
}
199+
})
200+
201+
it('should throw on invalid blob schedules', () => {
202+
const customData = JSON.parse(JSON.stringify(postMergeHardforkData))
203+
const customConfigData = {
204+
chainId: 3151908,
205+
homesteadBlock: 0,
206+
eip150Block: 0,
207+
eip155Block: 0,
208+
eip158Block: 0,
209+
byzantiumBlock: 0,
210+
constantinopleBlock: 0,
211+
petersburgBlock: 0,
212+
istanbulBlock: 0,
213+
berlinBlock: 0,
214+
londonBlock: 0,
215+
mergeNetsplitBlock: 0,
216+
depositContractAddress: '0x4242424242424242424242424242424242424242',
217+
terminalTotalDifficulty: 0,
218+
terminalTotalDifficultyPassed: true,
219+
shanghaiTime: 0,
220+
cancunTime: 0,
221+
pragueTime: 1736942378,
222+
blobSchedule: undefined,
223+
}
224+
Object.assign(customData.config, customConfigData)
225+
const invalidBlobSchedules = [
226+
{
227+
prague: {
228+
max: 91,
229+
baseFeeUpdateFraction: 13338477,
230+
},
231+
},
232+
{
233+
prague: {
234+
target: 61,
235+
baseFeeUpdateFraction: 13338477,
236+
},
237+
},
238+
{
239+
prague: {
240+
target: 61,
241+
max: 91,
242+
},
243+
},
244+
{
245+
unknownHardfork: {
246+
target: 61,
247+
max: 91,
248+
baseFeeUpdateFraction: 13338477,
249+
},
250+
},
251+
]
252+
253+
for (const schedule of invalidBlobSchedules) {
254+
customData.config.blobSchedule = schedule
255+
assert.throws(() => createCommonFromGethGenesis(customData, {}))
256+
}
257+
})
125258
})

0 commit comments

Comments
 (0)