Skip to content

Commit a7bb5ba

Browse files
authored
common: Fix hardfork changes (#2331)
* common: Fix hardfork changes * fix the spec hfs
1 parent 70c5077 commit a7bb5ba

File tree

5 files changed

+124
-28
lines changed

5 files changed

+124
-28
lines changed

packages/client/test/integration/merge.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ tape('[Integration:Merge]', async (t) => {
3232
},
3333
},
3434
hardforks: [
35+
{ name: 'chainstart', block: 0 },
3536
{ name: 'london', block: 0 },
3637
{
3738
name: 'merge',
@@ -52,6 +53,7 @@ tape('[Integration:Merge]', async (t) => {
5253
extraData: '0x3535353535353535353535353535353535353535353535353535353535353535',
5354
},
5455
hardforks: [
56+
{ name: 'chainstart', block: 0 },
5557
{ name: 'london', block: 0 },
5658
{
5759
name: 'merge',

packages/common/src/common.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as ropsten from './chains/ropsten.json'
99
import * as sepolia from './chains/sepolia.json'
1010
import { EIPs } from './eips'
1111
import { Chain, CustomChain, Hardfork } from './enums'
12-
import { hardforks as HARDFORK_CHANGES } from './hardforks'
12+
import { hardforks as HARDFORK_SPECS } from './hardforks'
1313
import { parseGethGenesis } from './utils'
1414

1515
import type { ConsensusAlgorithm, ConsensusType } from './enums'
@@ -29,6 +29,8 @@ import type {
2929
} from './types'
3030
import type { BigIntLike } from '@ethereumjs/util'
3131

32+
type HardforkSpecKeys = keyof typeof HARDFORK_SPECS
33+
type HardforkSpecValues = typeof HARDFORK_SPECS[HardforkSpecKeys]
3234
/**
3335
* Common class to access chain and hardfork parameters and to provide
3436
* a unified and shared view on the network and hardfork state.
@@ -45,6 +47,8 @@ export class Common extends EventEmitter {
4547
private _eips: number[] = []
4648
private _customChains: ChainConfig[]
4749

50+
private HARDFORK_CHANGES: [HardforkSpecKeys, HardforkSpecValues][]
51+
4852
/**
4953
* Creates a {@link Common} object for a custom chain, based on a standard one.
5054
*
@@ -214,6 +218,11 @@ export class Common extends EventEmitter {
214218
this._customChains = opts.customChains ?? []
215219
this._chainParams = this.setChain(opts.chain)
216220
this.DEFAULT_HARDFORK = this._chainParams.defaultHardfork ?? Hardfork.Merge
221+
// Assign hardfork changes in the sequence of the applied hardforks
222+
this.HARDFORK_CHANGES = this.hardforks().map((hf) => [
223+
hf.name as HardforkSpecKeys,
224+
HARDFORK_SPECS[hf.name as HardforkSpecKeys],
225+
])
217226
this._hardfork = this.DEFAULT_HARDFORK
218227
if (opts.hardfork !== undefined) {
219228
this.setHardfork(opts.hardfork)
@@ -262,7 +271,7 @@ export class Common extends EventEmitter {
262271
*/
263272
setHardfork(hardfork: string | Hardfork): void {
264273
let existing = false
265-
for (const hfChanges of HARDFORK_CHANGES) {
274+
for (const hfChanges of this.HARDFORK_CHANGES) {
266275
if (hfChanges[0] === hardfork) {
267276
if (this._hardfork !== hardfork) {
268277
this._hardfork = hardfork
@@ -432,7 +441,7 @@ export class Common extends EventEmitter {
432441
*/
433442
paramByHardfork(topic: string, name: string, hardfork: string | Hardfork): bigint {
434443
let value = null
435-
for (const hfChanges of HARDFORK_CHANGES) {
444+
for (const hfChanges of this.HARDFORK_CHANGES) {
436445
// EIP-referencing HF file (e.g. berlin.json)
437446
if ('eips' in hfChanges[1]) {
438447
const hfEIPs = hfChanges[1]['eips']
@@ -504,7 +513,7 @@ export class Common extends EventEmitter {
504513
if (this.eips().includes(eip)) {
505514
return true
506515
}
507-
for (const hfChanges of HARDFORK_CHANGES) {
516+
for (const hfChanges of this.HARDFORK_CHANGES) {
508517
const hf = hfChanges[1]
509518
if (this.gteHardfork(hf['name']) && 'eips' in hf) {
510519
if ((hf['eips'] as number[]).includes(eip)) {
@@ -591,7 +600,7 @@ export class Common extends EventEmitter {
591600
* @returns Block number or null if unscheduled
592601
*/
593602
eipBlock(eip: number): bigint | null {
594-
for (const hfChanges of HARDFORK_CHANGES) {
603+
for (const hfChanges of this.HARDFORK_CHANGES) {
595604
const hf = hfChanges[1]
596605
if ('eips' in hf) {
597606
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
@@ -834,7 +843,7 @@ export class Common extends EventEmitter {
834843
const hardfork = this.hardfork()
835844

836845
let value
837-
for (const hfChanges of HARDFORK_CHANGES) {
846+
for (const hfChanges of this.HARDFORK_CHANGES) {
838847
if ('consensus' in hfChanges[1]) {
839848
value = hfChanges[1]['consensus']['type']
840849
}
@@ -856,7 +865,7 @@ export class Common extends EventEmitter {
856865
const hardfork = this.hardfork()
857866

858867
let value
859-
for (const hfChanges of HARDFORK_CHANGES) {
868+
for (const hfChanges of this.HARDFORK_CHANGES) {
860869
if ('consensus' in hfChanges[1]) {
861870
value = hfChanges[1]['consensus']['algorithm']
862871
}
@@ -883,7 +892,7 @@ export class Common extends EventEmitter {
883892
const hardfork = this.hardfork()
884893

885894
let value
886-
for (const hfChanges of HARDFORK_CHANGES) {
895+
for (const hfChanges of this.HARDFORK_CHANGES) {
887896
if ('consensus' in hfChanges[1]) {
888897
// The config parameter is named after the respective consensus algorithm
889898
value = hfChanges[1]['consensus'][hfChanges[1]['consensus']['algorithm']]
Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
export const hardforks = [
2-
['chainstart', require('./chainstart.json')],
3-
['homestead', require('./homestead.json')],
4-
['dao', require('./dao.json')],
5-
['tangerineWhistle', require('./tangerineWhistle.json')],
6-
['spuriousDragon', require('./spuriousDragon.json')],
7-
['byzantium', require('./byzantium.json')],
8-
['constantinople', require('./constantinople.json')],
9-
['petersburg', require('./petersburg.json')],
10-
['istanbul', require('./istanbul.json')],
11-
['muirGlacier', require('./muirGlacier.json')],
12-
['berlin', require('./berlin.json')],
13-
['london', require('./london.json')],
14-
['shanghai', require('./shanghai.json')],
15-
['arrowGlacier', require('./arrowGlacier.json')],
16-
['grayGlacier', require('./grayGlacier.json')],
17-
['mergeForkIdTransition', require('./mergeForkIdTransition.json')],
18-
['merge', require('./merge.json')],
19-
]
1+
export const hardforks = {
2+
chainstart: require('./chainstart.json'),
3+
homestead: require('./homestead.json'),
4+
dao: require('./dao.json'),
5+
tangerineWhistle: require('./tangerineWhistle.json'),
6+
spuriousDragon: require('./spuriousDragon.json'),
7+
byzantium: require('./byzantium.json'),
8+
constantinople: require('./constantinople.json'),
9+
petersburg: require('./petersburg.json'),
10+
istanbul: require('./istanbul.json'),
11+
muirGlacier: require('./muirGlacier.json'),
12+
berlin: require('./berlin.json'),
13+
london: require('./london.json'),
14+
shanghai: require('./shanghai.json'),
15+
arrowGlacier: require('./arrowGlacier.json'),
16+
grayGlacier: require('./grayGlacier.json'),
17+
mergeForkIdTransition: require('./mergeForkIdTransition.json'),
18+
merge: require('./merge.json'),
19+
}

packages/common/tests/hardforks.spec.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,4 +395,78 @@ tape('[Common]: Hardfork logic', function (t: tape.Test) {
395395

396396
st.end()
397397
})
398+
399+
t.test('Should correctly apply hardfork changes', function (st: tape.Test) {
400+
// For sepolia MergeForkIdTransition happens AFTER merge
401+
let c = new Common({ chain: Chain.Sepolia, hardfork: Hardfork.London })
402+
st.equal(
403+
c['HARDFORK_CHANGES'][11][0],
404+
Hardfork.Merge,
405+
'should correctly apply hardfork changes'
406+
)
407+
st.equal(
408+
c['HARDFORK_CHANGES'][12][0],
409+
Hardfork.MergeForkIdTransition,
410+
'should correctly apply hardfork changes'
411+
)
412+
413+
// Should give correct ConsensusType pre and post merge
414+
st.equal(
415+
c.consensusType(),
416+
ConsensusType.ProofOfWork,
417+
'should provide the correct initial chain consensus type'
418+
)
419+
c.setHardfork(Hardfork.Merge)
420+
st.equal(
421+
c.consensusType(),
422+
ConsensusType.ProofOfStake,
423+
`should switch to ProofOfStake consensus on merge`
424+
)
425+
c.setHardfork(Hardfork.MergeForkIdTransition)
426+
st.equal(
427+
c.consensusType(),
428+
ConsensusType.ProofOfStake,
429+
`should stay on ProofOfStake consensus post merge`
430+
)
431+
432+
// For kiln MergeForkIdTransition happens BEFORE Merge
433+
const json = require(`../../blockchain/test/testdata/geth-genesis-kiln.json`)
434+
c = Common.fromGethGenesis(json, {
435+
chain: 'kiln',
436+
})
437+
438+
// MergeForkIdTransition change should be before Merge
439+
st.equal(
440+
c['HARDFORK_CHANGES'][10][0],
441+
Hardfork.MergeForkIdTransition,
442+
'should correctly apply hardfork changes'
443+
)
444+
st.equal(
445+
c['HARDFORK_CHANGES'][11][0],
446+
Hardfork.Merge,
447+
'should correctly apply hardfork changes'
448+
)
449+
450+
// Should give correct ConsensusType pre and post merge
451+
c.setHardfork(Hardfork.London)
452+
st.equal(
453+
c.consensusType(),
454+
ConsensusType.ProofOfWork,
455+
'should provide the correct initial chain consensus type'
456+
)
457+
c.setHardfork(Hardfork.Merge)
458+
st.equal(
459+
c.consensusType(),
460+
ConsensusType.ProofOfStake,
461+
`should switch to ProofOfStake consensus on merge`
462+
)
463+
c.setHardfork(Hardfork.MergeForkIdTransition)
464+
st.equal(
465+
c.consensusType(),
466+
ConsensusType.ProofOfWork,
467+
`should give pow consensus as MergeForkIdTransition is pre-merge`
468+
)
469+
470+
st.end()
471+
})
398472
})

packages/common/tests/mergePOS.spec.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ tape('[Common]: Merge/POS specific logic', function (t: tape.Test) {
181181

182182
t.test('Pure POS testnet', function (st: tape.Test) {
183183
const customChains = [testnetPOS]
184-
const c = new Common({ chain: 'testnetPOS', hardfork: Hardfork.Istanbul, customChains })
184+
const c = new Common({ chain: 'testnetPOS', hardfork: Hardfork.Chainstart, customChains })
185185

186186
st.equal(c.hardforkTTD(Hardfork.Chainstart), BigInt(0), 'should get the HF total difficulty')
187187

@@ -190,6 +190,17 @@ tape('[Common]: Merge/POS specific logic', function (t: tape.Test) {
190190
st.end()
191191
})
192192

193+
t.test('Should fail setting invalid hardfork', function (st: tape.Test) {
194+
const customChains = [testnetPOS]
195+
try {
196+
new Common({ chain: 'testnetPOS', hardfork: Hardfork.Istanbul, customChains })
197+
st.fail(`should have failed setting absent hardfork instanbul`)
198+
} catch (e) {
199+
st.pass(`failed setting absent hardfork instanbul`)
200+
}
201+
st.end()
202+
})
203+
193204
t.test('should get the correct merge hardfork at genesis', async (st) => {
194205
const json = require(`../../client/test/testdata/geth-genesis/post-merge.json`)
195206
const c = Common.fromGethGenesis(json, { chain: 'post-merge' })

0 commit comments

Comments
 (0)