From f0c6e4be9be82d7e35386ae4520a6ab5c8b08f35 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 15 Nov 2022 22:23:30 +0530 Subject: [PATCH 01/18] correctly set hf order --- packages/common/src/utils.ts | 37 +++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index d4ab9f353c..c363e658ac 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -98,18 +98,37 @@ function parseGethParams(json: any) { [Hardfork.MergeForkIdTransition]: 'mergeForkBlock', [Hardfork.Shanghai]: 'shanghaiBlock', } - params.hardforks = Object.values(Hardfork) - .map((name) => ({ - name, - block: name === Hardfork.Chainstart ? 0 : config[forkMap[name]] ?? null, + const forkMapRev = Object.keys(forkMap).reduce((acc, elem) => { + acc[forkMap[elem]] = elem + return acc + }, {} as { [key: string]: string }) + const configHardforks = Object.keys(config).filter((key) => forkMapRev[key] !== undefined) + + params.hardforks = configHardforks + .map((nameBlock) => ({ + name: forkMapRev[nameBlock], + block: config[nameBlock], })) .filter((fork) => fork.block !== null) + const mergeConfig = { + name: Hardfork.Merge, + ttd: config.terminalTotalDifficulty, + block: null, + } + params.hardforks.unshift({ name: Hardfork.Chainstart, block: 0 }) + const nonzeroIndex = params.hardforks.findIndex((hf: any) => hf.block > 0) + if ( + (config.terminalTotalDifficultyPassed === true || + config.terminalTotalDifficultyPassed === 'true') && + nonzeroIndex !== -1 + ) { + // find index where block > 0 + params.hardforks.splice(nonzeroIndex, 0, mergeConfig) + } else { + params.hardforks.push(mergeConfig) + } if (config.terminalTotalDifficulty !== undefined) { - params.hardforks.push({ - name: Hardfork.Merge, - ttd: config.terminalTotalDifficulty, - block: null, - }) + params.hardforks.push() } return params } From 01b0ac18112ae57d1bd25779e6b4bca8887f7133 Mon Sep 17 00:00:00 2001 From: harkamal Date: Thu, 17 Nov 2022 16:37:46 +0530 Subject: [PATCH 02/18] test specs --- .../common/test/data/post-merge-hardfork.json | 44 +++++++++++++++++++ packages/common/test/utils.spec.ts | 43 ++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 packages/common/test/data/post-merge-hardfork.json diff --git a/packages/common/test/data/post-merge-hardfork.json b/packages/common/test/data/post-merge-hardfork.json new file mode 100644 index 0000000000..edb8d0435a --- /dev/null +++ b/packages/common/test/data/post-merge-hardfork.json @@ -0,0 +1,44 @@ +{ + "config": { + "chainId": 1, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "shanghaiBlock": 8, + "clique": { + "period": 5, + "epoch": 30000 + }, + "terminalTotalDifficulty": 2, + "terminalTotalDifficultyPassed": true + }, + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x1C9C380", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x6d6172697573766477000000" + }, + "0x8A04d14125D0FDCDc742F4A05C051De07232EDa4": { + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a714610044578063228951181461008c578063621fd130146101a2578063c5f2892f1461022c575b600080fd5b34801561005057600080fd5b506100786004803603602081101561006757600080fd5b50356001600160e01b031916610253565b604080519115158252519081900360200190f35b6101a0600480360360808110156100a257600080fd5b8101906020810181356401000000008111156100bd57600080fd5b8201836020820111156100cf57600080fd5b803590602001918460018302840111640100000000831117156100f157600080fd5b91939092909160208101903564010000000081111561010f57600080fd5b82018360208201111561012157600080fd5b8035906020019184600183028401116401000000008311171561014357600080fd5b91939092909160208101903564010000000081111561016157600080fd5b82018360208201111561017357600080fd5b8035906020019184600183028401116401000000008311171561019557600080fd5b91935091503561028a565b005b3480156101ae57600080fd5b506101b7610ce6565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101f15781810151838201526020016101d9565b50505050905090810190601f16801561021e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023857600080fd5b50610241610cf8565b60408051918252519081900360200190f35b60006001600160e01b031982166301ffc9a760e01b148061028457506001600160e01b03198216638564090760e01b145b92915050565b603086146102c95760405162461bcd60e51b81526004018080602001828103825260268152602001806112516026913960400191505060405180910390fd5b602084146103085760405162461bcd60e51b81526004018080602001828103825260368152602001806111e86036913960400191505060405180910390fd5b606082146103475760405162461bcd60e51b81526004018080602001828103825260298152602001806112c46029913960400191505060405180910390fd5b670de0b6b3a764000034101561038e5760405162461bcd60e51b815260040180806020018281038252602681526020018061129e6026913960400191505060405180910390fd5b633b9aca003406156103d15760405162461bcd60e51b815260040180806020018281038252603381526020018061121e6033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff81111561041f5760405162461bcd60e51b81526004018080602001828103825260278152602001806112776027913960400191505060405180910390fd5b606061042a82610fc6565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a61045f602054610fc6565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f01601f191690910187810386528c815260200190508c8c808284376000838201819052601f909101601f191690920188810386528c5181528c51602091820193918e019250908190849084905b838110156104f65781810151838201526020016104de565b50505050905090810190601f1680156105235780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f909101601f19169092018881038452895181528951602091820193918b019250908190849084905b8381101561057f578181015183820152602001610567565b50505050905090810190601f1680156105ac5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284376fffffffffffffffffffffffffffffffff199094169190930190815260408051600f19818403018152601090920190819052815191955093508392506020850191508083835b602083106106415780518252601f199092019160209182019101610622565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610680573d6000803e3d6000fd5b5050506040513d602081101561069557600080fd5b5051905060006002806106ab6040848a8c61114a565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106107015780518252601f1990920191602091820191016106e2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610740573d6000803e3d6000fd5b5050506040513d602081101561075557600080fd5b50516002610766896040818d61114a565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106107c15780518252601f1990920191602091820191016107a2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610800573d6000803e3d6000fd5b5050506040513d602081101561081557600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b6020831061086b5780518252601f19909201916020918201910161084c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa1580156108aa573d6000803e3d6000fd5b5050506040513d60208110156108bf57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b6020831061092e5780518252601f19909201916020918201910161090f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa15801561096d573d6000803e3d6000fd5b5050506040513d602081101561098257600080fd5b50516040518651600291889160009188916020918201918291908601908083835b602083106109c25780518252601f1990920191602091820191016109a3565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610a495780518252601f199092019160209182019101610a2a565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610a88573d6000803e3d6000fd5b5050506040513d6020811015610a9d57600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610af35780518252601f199092019160209182019101610ad4565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610b32573d6000803e3d6000fd5b5050506040513d6020811015610b4757600080fd5b50519050858114610b895760405162461bcd60e51b81526004018080602001828103825260548152602001806111946054913960600191505060405180910390fd5b60205463ffffffff11610bcd5760405162461bcd60e51b81526004018080602001828103825260218152602001806111736021913960400191505060405180910390fd5b602080546001019081905560005b6020811015610cda578160011660011415610c0d578260008260208110610bfe57fe5b015550610cdd95505050505050565b600260008260208110610c1c57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610c745780518252601f199092019160209182019101610c55565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610cb3573d6000803e3d6000fd5b5050506040513d6020811015610cc857600080fd5b50519250600282049150600101610bdb565b50fe5b50505050505050565b6060610cf3602054610fc6565b905090565b6020546000908190815b6020811015610ea9578160011660011415610ddb57600260008260208110610d2657fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610d7e5780518252601f199092019160209182019101610d5f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610dbd573d6000803e3d6000fd5b5050506040513d6020811015610dd257600080fd5b50519250610e9b565b60028360218360208110610deb57fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610e425780518252601f199092019160209182019101610e23565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610e81573d6000803e3d6000fd5b5050506040513d6020811015610e9657600080fd5b505192505b600282049150600101610d02565b50600282610eb8602054610fc6565b600060401b6040516020018084815260200183805190602001908083835b60208310610ef55780518252601f199092019160209182019101610ed6565b51815160209384036101000a600019018019909216911617905267ffffffffffffffff199590951692019182525060408051808303600719018152601890920190819052815191955093508392850191508083835b60208310610f695780518252601f199092019160209182019101610f4a565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610fa8573d6000803e3d6000fd5b5050506040513d6020811015610fbd57600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b8260008151811061100057fe5b60200101906001600160f81b031916908160001a9053508060061a60f81b8260018151811061102b57fe5b60200101906001600160f81b031916908160001a9053508060051a60f81b8260028151811061105657fe5b60200101906001600160f81b031916908160001a9053508060041a60f81b8260038151811061108157fe5b60200101906001600160f81b031916908160001a9053508060031a60f81b826004815181106110ac57fe5b60200101906001600160f81b031916908160001a9053508060021a60f81b826005815181106110d757fe5b60200101906001600160f81b031916908160001a9053508060011a60f81b8260068151811061110257fe5b60200101906001600160f81b031916908160001a9053508060001a60f81b8260078151811061112d57fe5b60200101906001600160f81b031916908160001a90535050919050565b60008085851115611159578182fd5b83861115611165578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a164736f6c634300060b000a", + "balance": "0x0" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x7" +} diff --git a/packages/common/test/utils.spec.ts b/packages/common/test/utils.spec.ts index df6c0b9fac..934fa54323 100644 --- a/packages/common/test/utils.spec.ts +++ b/packages/common/test/utils.spec.ts @@ -1,6 +1,7 @@ import * as tape from 'tape' import { Common } from '../src/common' +import { Hardfork } from '../src/enums' import { parseGethGenesis } from '../src/utils' tape('[Utils/Parse]', (t) => { @@ -71,6 +72,48 @@ tape('[Utils/Parse]', (t) => { st.equal(hf.forkHash, kilnForkHashes[hf.name], `${hf.name} forkHash should match`) } }) + + t.test('should successfully parse genesis with hardfork scheduled post merge', async (st) => { + const json = require(`./data/post-merge-hardfork.json`) + const common = Common.fromGethGenesis(json, { + chain: 'customChain', + }) + st.deepEqual( + common.hardforks().map((hf) => hf.name), + [ + 'chainstart', + 'homestead', + 'tangerineWhistle', + 'spuriousDragon', + 'byzantium', + 'constantinople', + 'petersburg', + 'istanbul', + 'muirGlacier', + 'berlin', + 'london', + 'merge', + 'shanghai', + ], + 'hardfork parse order should be correct' + ) + st.equal(common.getHardforkByBlockNumber(0), Hardfork.London, 'london at genesis') + // Merge could be at genesis or 1 depending on td, ttd here is 2 + st.equal(common.getHardforkByBlockNumber(0, BigInt(2)), Hardfork.Merge, 'merge at genesis') + st.equal(common.getHardforkByBlockNumber(1, BigInt(2)), Hardfork.Merge, 'merge at block 1') + // shanghai is at 8 + st.equal(common.getHardforkByBlockNumber(8), Hardfork.Shanghai, 'shanghai at block 8') + // should be post merge at shanghai + st.equal(common.getHardforkByBlockNumber(8, BigInt(2)), Hardfork.Shanghai, 'london at genesis') + // if not post merge, then should error + try { + common.getHardforkByBlockNumber(8, BigInt(1)) + st.fail('should have failed since merge not compeleted before shanghai') + } catch (e) { + st.pass('correctly fails if merge not compeleted before shanghai') + } + st.end() + }) }) const kilnForkHashes: any = { From 80e4f560b503e5ff6470ff76197047fe2a574fb3 Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 18 Nov 2022 15:56:41 +0530 Subject: [PATCH 03/18] fix the merge hf push condition --- packages/common/src/utils.ts | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index c363e658ac..96f068b92f 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -110,25 +110,27 @@ function parseGethParams(json: any) { block: config[nameBlock], })) .filter((fork) => fork.block !== null) - const mergeConfig = { - name: Hardfork.Merge, - ttd: config.terminalTotalDifficulty, - block: null, - } + params.hardforks.unshift({ name: Hardfork.Chainstart, block: 0 }) - const nonzeroIndex = params.hardforks.findIndex((hf: any) => hf.block > 0) - if ( - (config.terminalTotalDifficultyPassed === true || - config.terminalTotalDifficultyPassed === 'true') && - nonzeroIndex !== -1 - ) { - // find index where block > 0 - params.hardforks.splice(nonzeroIndex, 0, mergeConfig) - } else { - params.hardforks.push(mergeConfig) - } + if (config.terminalTotalDifficulty !== undefined) { - params.hardforks.push() + const mergeConfig = { + name: Hardfork.Merge, + ttd: config.terminalTotalDifficulty, + block: null, + } + + const nonzeroIndex = params.hardforks.findIndex((hf: any) => hf.block > 0) + if ( + (config.terminalTotalDifficultyPassed === true || + config.terminalTotalDifficultyPassed === 'true') && + nonzeroIndex !== -1 + ) { + // find index where block > 0 + params.hardforks.splice(nonzeroIndex, 0, mergeConfig) + } else { + params.hardforks.push(mergeConfig) + } } return params } From 421040a55f0dbaf9d2833d268697387b973e52f5 Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 18 Nov 2022 19:53:37 +0530 Subject: [PATCH 04/18] try placing merge block in better wat --- packages/common/src/common.ts | 4 +-- packages/common/src/types.ts | 1 + packages/common/src/utils.ts | 55 +++++++++++++++--------------- packages/common/test/utils.spec.ts | 1 + 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/packages/common/src/common.ts b/packages/common/src/common.ts index a951198873..3577f78df4 100644 --- a/packages/common/src/common.ts +++ b/packages/common/src/common.ts @@ -176,9 +176,9 @@ export class Common extends EventEmitter { */ static fromGethGenesis( genesisJson: any, - { chain, genesisHash, hardfork }: GethConfigOpts + { chain, genesisHash, hardfork, mergeForkIdPostMerge }: GethConfigOpts ): Common { - const genesisParams = parseGethGenesis(genesisJson, chain) + const genesisParams = parseGethGenesis(genesisJson, chain, mergeForkIdPostMerge) const common = new Common({ chain: genesisParams.name ?? 'custom', customChains: [genesisParams], diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index 92488e707d..0b9667b076 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -118,4 +118,5 @@ export interface GethConfigOpts { chain?: string hardfork?: string | Hardfork genesisHash?: Buffer + mergeForkIdPostMerge?: boolean } diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index 96f068b92f..d2dff55c9e 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -22,7 +22,7 @@ function formatNonce(nonce: string): string { * @param json object representing the Geth genesis file * @returns genesis parameters in a `CommonOpts` compliant object */ -function parseGethParams(json: any) { +function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { const { name, config, difficulty, mixHash, gasLimit, coinbase, baseFeePerGas } = json let { extraData, timestamp, nonce } = json const { chainId } = config @@ -83,28 +83,30 @@ function parseGethParams(json: any) { }, } - const forkMap: { [key: string]: string } = { - [Hardfork.Homestead]: 'homesteadBlock', - [Hardfork.Dao]: 'daoForkBlock', - [Hardfork.TangerineWhistle]: 'eip150Block', - [Hardfork.SpuriousDragon]: 'eip155Block', - [Hardfork.Byzantium]: 'byzantiumBlock', - [Hardfork.Constantinople]: 'constantinopleBlock', - [Hardfork.Petersburg]: 'petersburgBlock', - [Hardfork.Istanbul]: 'istanbulBlock', - [Hardfork.MuirGlacier]: 'muirGlacierBlock', - [Hardfork.Berlin]: 'berlinBlock', - [Hardfork.London]: 'londonBlock', - [Hardfork.MergeForkIdTransition]: 'mergeForkBlock', - [Hardfork.Shanghai]: 'shanghaiBlock', + const forkMap: { [key: string]: { name: string; postMerge?: boolean } } = { + [Hardfork.Homestead]: { name: 'homesteadBlock' }, + [Hardfork.Dao]: { name: 'daoForkBlock' }, + [Hardfork.TangerineWhistle]: { name: 'eip150Block' }, + [Hardfork.SpuriousDragon]: { name: 'eip155Block' }, + [Hardfork.Byzantium]: { name: 'byzantiumBlock' }, + [Hardfork.Constantinople]: { name: 'constantinopleBlock' }, + [Hardfork.Petersburg]: { name: 'petersburgBlock' }, + [Hardfork.Istanbul]: { name: 'istanbulBlock' }, + [Hardfork.MuirGlacier]: { name: 'muirGlacierBlock' }, + [Hardfork.Berlin]: { name: 'berlinBlock' }, + [Hardfork.London]: { name: 'londonBlock' }, + [Hardfork.MergeForkIdTransition]: { name: 'mergeForkBlock', postMerge: mergeForkIdPostMerge }, + [Hardfork.Shanghai]: { name: 'shanghaiBlock', postMerge: true }, } + + // forkMapRev is the map from config field name to Hardfork const forkMapRev = Object.keys(forkMap).reduce((acc, elem) => { - acc[forkMap[elem]] = elem + acc[forkMap[elem].name] = elem return acc }, {} as { [key: string]: string }) - const configHardforks = Object.keys(config).filter((key) => forkMapRev[key] !== undefined) + const configHardforkNames = Object.keys(config).filter((key) => forkMapRev[key] !== undefined) - params.hardforks = configHardforks + params.hardforks = configHardforkNames .map((nameBlock) => ({ name: forkMapRev[nameBlock], block: config[nameBlock], @@ -120,14 +122,11 @@ function parseGethParams(json: any) { block: null, } - const nonzeroIndex = params.hardforks.findIndex((hf: any) => hf.block > 0) - if ( - (config.terminalTotalDifficultyPassed === true || - config.terminalTotalDifficultyPassed === 'true') && - nonzeroIndex !== -1 - ) { - // find index where block > 0 - params.hardforks.splice(nonzeroIndex, 0, mergeConfig) + const postMergeIndex = params.hardforks.findIndex( + (hf: any) => forkMap[hf.name]?.postMerge === true + ) + if (postMergeIndex !== -1) { + params.hardforks.splice(postMergeIndex, 0, mergeConfig) } else { params.hardforks.push(mergeConfig) } @@ -141,7 +140,7 @@ function parseGethParams(json: any) { * @param name optional chain name * @returns parsed params */ -export function parseGethGenesis(json: any, name?: string) { +export function parseGethGenesis(json: any, name?: string, mergeForkIdPostMerge?: boolean) { try { if (['config', 'difficulty', 'gasLimit', 'alloc'].some((field) => !(field in json))) { throw new Error('Invalid format, expected geth genesis fields missing') @@ -149,7 +148,7 @@ export function parseGethGenesis(json: any, name?: string) { if (name !== undefined) { json.name = name } - return parseGethParams(json) + return parseGethParams(json, mergeForkIdPostMerge) } catch (e: any) { throw new Error(`Error parsing parameters file: ${e.message}`) } diff --git a/packages/common/test/utils.spec.ts b/packages/common/test/utils.spec.ts index 934fa54323..e29d4b85e4 100644 --- a/packages/common/test/utils.spec.ts +++ b/packages/common/test/utils.spec.ts @@ -66,6 +66,7 @@ tape('[Utils/Parse]', (t) => { '51c7fe41be669f69c45c33a56982cbde405313342d9e2b00d7c91a7b284dd4f8', 'hex' ), + mergeForkIdPostMerge: false, }) for (const hf of common.hardforks()) { /* eslint-disable @typescript-eslint/no-use-before-define */ From d81ef6faddf6df2028f242e4c07d3e23557d216a Mon Sep 17 00:00:00 2001 From: harkamal Date: Fri, 18 Nov 2022 20:00:18 +0530 Subject: [PATCH 05/18] fix test spec for kiln --- packages/common/test/hardforks.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/common/test/hardforks.spec.ts b/packages/common/test/hardforks.spec.ts index 029cc9f3ec..62039de0a3 100644 --- a/packages/common/test/hardforks.spec.ts +++ b/packages/common/test/hardforks.spec.ts @@ -433,6 +433,7 @@ tape('[Common]: Hardfork logic', function (t: tape.Test) { const json = require(`../../blockchain/test/testdata/geth-genesis-kiln.json`) c = Common.fromGethGenesis(json, { chain: 'kiln', + mergeForkIdPostMerge: false, }) // MergeForkIdTransition change should be before Merge From d897836440cf2ef9fe8eee93741775f36e2316d8 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 12:48:52 +0530 Subject: [PATCH 06/18] alternate fix of skipping only pos validation on genesis --- packages/block/src/header.ts | 4 ++-- packages/evm/src/evm.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block/src/header.ts b/packages/block/src/header.ts index 839c6a2f06..fc2c7392e5 100644 --- a/packages/block/src/header.ts +++ b/packages/block/src/header.ts @@ -347,7 +347,7 @@ export class BlockHeader { * @throws if any check fails */ _consensusFormatValidation() { - const { nonce, uncleHash, difficulty, extraData } = this + const { nonce, uncleHash, difficulty, extraData, number } = this const hardfork = this._common.hardfork() // Consensus type dependent checks @@ -394,7 +394,7 @@ export class BlockHeader { } } // Validation for PoS blocks (EIP-3675) - if (this._common.consensusType() === ConsensusType.ProofOfStake) { + if (this._common.consensusType() === ConsensusType.ProofOfStake && number > BigInt(0)) { let error = false let errorMsg = '' diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 8b6b50b01b..45f9507c61 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -263,6 +263,7 @@ export class EVM implements EVMInterface { Hardfork.GrayGlacier, Hardfork.MergeForkIdTransition, Hardfork.Merge, + Hardfork.Shanghai, ] if (!supportedHardforks.includes(this._common.hardfork() as Hardfork)) { throw new Error( From 50b04ab836764b41d6449e4bd63c8d904024dcb1 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 13:39:02 +0530 Subject: [PATCH 07/18] move merge validations to non genesis --- packages/block/test/mergeBlock.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/block/test/mergeBlock.spec.ts b/packages/block/test/mergeBlock.spec.ts index c5ccb4e36e..84b9b4a242 100644 --- a/packages/block/test/mergeBlock.spec.ts +++ b/packages/block/test/mergeBlock.spec.ts @@ -44,6 +44,7 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { uncleHash: Buffer.from('123abc', 'hex'), + number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -54,6 +55,7 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { difficulty: BigInt(123456), + number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -64,6 +66,7 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { extraData: Buffer.alloc(33).fill(1), + number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -74,6 +77,7 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { mixHash: Buffer.alloc(30).fill(1), + number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -84,6 +88,7 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { nonce: Buffer.alloc(8).fill(1), + number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') From 3aa344a98920f2f8871f9748b4c3404ff4b73bec Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 14:01:05 +0530 Subject: [PATCH 08/18] fix unsupported test case --- packages/evm/src/evm.ts | 40 +++++++++++++++--------------- packages/vm/test/api/index.spec.ts | 22 ++++++++++++++++ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/packages/evm/src/evm.ts b/packages/evm/src/evm.ts index 45f9507c61..d153b8ffe8 100644 --- a/packages/evm/src/evm.ts +++ b/packages/evm/src/evm.ts @@ -139,6 +139,25 @@ export interface EVMOpts { * @ignore */ export class EVM implements EVMInterface { + private static supportedHardforks = [ + Hardfork.Chainstart, + Hardfork.Homestead, + Hardfork.Dao, + Hardfork.TangerineWhistle, + Hardfork.SpuriousDragon, + Hardfork.Byzantium, + Hardfork.Constantinople, + Hardfork.Petersburg, + Hardfork.Istanbul, + Hardfork.MuirGlacier, + Hardfork.Berlin, + Hardfork.London, + Hardfork.ArrowGlacier, + Hardfork.GrayGlacier, + Hardfork.MergeForkIdTransition, + Hardfork.Merge, + Hardfork.Shanghai, + ] protected _tx?: { gasPrice: bigint origin: Address @@ -246,26 +265,7 @@ export class EVM implements EVMInterface { } } - const supportedHardforks = [ - Hardfork.Chainstart, - Hardfork.Homestead, - Hardfork.Dao, - Hardfork.TangerineWhistle, - Hardfork.SpuriousDragon, - Hardfork.Byzantium, - Hardfork.Constantinople, - Hardfork.Petersburg, - Hardfork.Istanbul, - Hardfork.MuirGlacier, - Hardfork.Berlin, - Hardfork.London, - Hardfork.ArrowGlacier, - Hardfork.GrayGlacier, - Hardfork.MergeForkIdTransition, - Hardfork.Merge, - Hardfork.Shanghai, - ] - if (!supportedHardforks.includes(this._common.hardfork() as Hardfork)) { + if (!EVM.supportedHardforks.includes(this._common.hardfork() as Hardfork)) { throw new Error( `Hardfork ${this._common.hardfork()} not set as supported in supportedHardforks` ) diff --git a/packages/vm/test/api/index.spec.ts b/packages/vm/test/api/index.spec.ts index 07dd69eb18..a9a1b78f48 100644 --- a/packages/vm/test/api/index.spec.ts +++ b/packages/vm/test/api/index.spec.ts @@ -1,6 +1,7 @@ // explicitly import util and buffer, // needed for karma-typescript bundling import { Chain, Common, Hardfork } from '@ethereumjs/common' +import { EVM } from '@ethereumjs/evm' import { Account, Address, KECCAK256_RLP } from '@ethereumjs/util' import { Buffer } from 'buffer' import * as tape from 'tape' @@ -59,12 +60,33 @@ tape('VM -> basic instantiation / boolean switches', (t) => { tape('VM -> supportedHardforks', (t) => { t.test('should throw when common is set to an unsupported hardfork', async (st) => { const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Shanghai }) + const prevSupported = EVM['supportedHardforks'] + EVM['supportedHardforks'] = [ + Hardfork.Chainstart, + Hardfork.Homestead, + Hardfork.Dao, + Hardfork.TangerineWhistle, + Hardfork.SpuriousDragon, + Hardfork.Byzantium, + Hardfork.Constantinople, + Hardfork.Petersburg, + Hardfork.Istanbul, + Hardfork.MuirGlacier, + Hardfork.Berlin, + Hardfork.London, + Hardfork.ArrowGlacier, + Hardfork.GrayGlacier, + Hardfork.MergeForkIdTransition, + Hardfork.Merge, + ] try { await VM.create({ common }) st.fail('should have failed for unsupported hardfork') } catch (e: any) { st.ok(e.message.includes('supportedHardforks')) } + // restore supported hardforks + EVM['supportedHardforks'] = prevSupported st.end() }) From c27fc981555a0a3ef732c04dddf445207f3866a8 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 14:07:32 +0530 Subject: [PATCH 09/18] correctly set hardfork --- packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts b/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts index e280324f5b..a1555ff21d 100644 --- a/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts @@ -182,6 +182,7 @@ tape('EIP4895 tests', (t) => { t.test('should build a block correctly with withdrawals', async (st) => { const common = Common.fromGethGenesis(genesisJSON, { chain: 'custom' }) + common.setHardforkByBlockNumber(0) const genesisState = parseGethGenesisState(genesisJSON) const blockchain = await Blockchain.create({ common, From a9566e5ed48f198496e7255ceabf1006dea37cac Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 15:03:55 +0530 Subject: [PATCH 10/18] resolve test genesis poisioning --- packages/client/test/rpc/util/CLConnectionManager.spec.ts | 4 ++-- packages/common/src/utils.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/test/rpc/util/CLConnectionManager.spec.ts b/packages/client/test/rpc/util/CLConnectionManager.spec.ts index 512cfed100..14035934ab 100644 --- a/packages/client/test/rpc/util/CLConnectionManager.spec.ts +++ b/packages/client/test/rpc/util/CLConnectionManager.spec.ts @@ -42,8 +42,9 @@ tape('[CLConnectionManager]', (t) => { st.ok(manager.running, 'should start') manager.stop() st.ok(!manager.running, 'should stop') + const prevMergeForkBlock = (genesisJSON.config as any).mergeForkBlock ;(genesisJSON.config as any).mergeForkBlock = 0 - const params = parseGethGenesis(genesisJSON, 'post-merge') + const params = parseGethGenesis(genesisJSON, 'post-merge', false) let common = new Common({ chain: params.name, customChains: [params], @@ -53,7 +54,6 @@ tape('[CLConnectionManager]', (t) => { manager = new CLConnectionManager({ config }) st.ok(manager.running, 'starts on instantiation if hardfork is MergeForkBlock') manager.stop() - const prevMergeForkBlock = (genesisJSON.config as any).mergeForkBlock ;(genesisJSON.config as any).mergeForkBlock = 10 common = new Common({ chain: params.name, diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index d2dff55c9e..693bb1a2ff 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -111,7 +111,7 @@ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { name: forkMapRev[nameBlock], block: config[nameBlock], })) - .filter((fork) => fork.block !== null) + .filter((fork) => fork.block !== null && fork.block !== undefined) params.hardforks.unshift({ name: Hardfork.Chainstart, block: 0 }) From e54b1f7e896549dbbb17e5891ba6660b8bddc285 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 15:26:10 +0530 Subject: [PATCH 11/18] add comment --- packages/common/src/utils.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index 693bb1a2ff..034460d119 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -20,6 +20,9 @@ function formatNonce(nonce: string): string { /** * Converts Geth genesis parameters to an EthereumJS compatible `CommonOpts` object * @param json object representing the Geth genesis file + * @param optional mergeForkIdPostMerge which clarifies the placement of MergeForkIdTransition + * hardfork, which by default is post merge as with the merged eth networks but could also come + * before merge like in kiln genesis * @returns genesis parameters in a `CommonOpts` compliant object */ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { From 4d125bdf74c5c8d96ff19c49481b5bb5a8d6d068 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sat, 19 Nov 2022 17:35:39 +0530 Subject: [PATCH 12/18] cli arg for mergeforkid placement --- packages/client/bin/cli.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/client/bin/cli.ts b/packages/client/bin/cli.ts index 5177b24025..810165ea87 100755 --- a/packages/client/bin/cli.ts +++ b/packages/client/bin/cli.ts @@ -70,6 +70,12 @@ const args = yargs(hideBin(process.argv)) describe: 'Import a geth genesis file for running a custom network', coerce: (arg: string) => (arg ? path.resolve(arg) : undefined), }) + .option('mergeForkIdPostMerge', { + describe: + 'Place mergeForkIdTransition hardfork before (false) or after (true) Merge hardfork in the custom gethGenesis', + boolean: true, + default: true, + }) .option('transports', { describe: 'Network transports', default: Config.TRANSPORTS_DEFAULT, @@ -608,7 +614,10 @@ async function run() { // Use geth genesis parameters file if specified const genesisFile = JSON.parse(readFileSync(args.gethGenesis, 'utf-8')) const chainName = path.parse(args.gethGenesis).base.split('.')[0] - common = Common.fromGethGenesis(genesisFile, { chain: chainName }) + common = Common.fromGethGenesis(genesisFile, { + chain: chainName, + mergeForkIdPostMerge: args.mergeForkIdPostMerge, + }) customGenesisState = parseGethGenesisState(genesisFile) } From 6b5d7dff95b1f39f2f41fdf13965d1964aa4e54f Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 20 Nov 2022 13:33:00 +0530 Subject: [PATCH 13/18] place merge only after genesis --- packages/block/src/header.ts | 4 ++-- packages/block/test/mergeBlock.spec.ts | 4 ---- packages/common/src/utils.ts | 4 +++- packages/common/test/utils.spec.ts | 2 -- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/block/src/header.ts b/packages/block/src/header.ts index fc2c7392e5..839c6a2f06 100644 --- a/packages/block/src/header.ts +++ b/packages/block/src/header.ts @@ -347,7 +347,7 @@ export class BlockHeader { * @throws if any check fails */ _consensusFormatValidation() { - const { nonce, uncleHash, difficulty, extraData, number } = this + const { nonce, uncleHash, difficulty, extraData } = this const hardfork = this._common.hardfork() // Consensus type dependent checks @@ -394,7 +394,7 @@ export class BlockHeader { } } // Validation for PoS blocks (EIP-3675) - if (this._common.consensusType() === ConsensusType.ProofOfStake && number > BigInt(0)) { + if (this._common.consensusType() === ConsensusType.ProofOfStake) { let error = false let errorMsg = '' diff --git a/packages/block/test/mergeBlock.spec.ts b/packages/block/test/mergeBlock.spec.ts index 84b9b4a242..751ad0aca6 100644 --- a/packages/block/test/mergeBlock.spec.ts +++ b/packages/block/test/mergeBlock.spec.ts @@ -44,7 +44,6 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { uncleHash: Buffer.from('123abc', 'hex'), - number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -55,7 +54,6 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { difficulty: BigInt(123456), - number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -77,7 +75,6 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { mixHash: Buffer.alloc(30).fill(1), - number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') @@ -88,7 +85,6 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { nonce: Buffer.alloc(8).fill(1), - number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index 034460d119..f4b1bb7259 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -125,8 +125,10 @@ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { block: null, } + // Merge hardfork has to be placed before first non-zero blockhard fork that is dependent + // on merge, as genesis block can never be a PoS block const postMergeIndex = params.hardforks.findIndex( - (hf: any) => forkMap[hf.name]?.postMerge === true + (hf: any) => forkMap[hf.name]?.postMerge === true && hf.block > 0 ) if (postMergeIndex !== -1) { params.hardforks.splice(postMergeIndex, 0, mergeConfig) diff --git a/packages/common/test/utils.spec.ts b/packages/common/test/utils.spec.ts index e29d4b85e4..e026ee66f1 100644 --- a/packages/common/test/utils.spec.ts +++ b/packages/common/test/utils.spec.ts @@ -99,8 +99,6 @@ tape('[Utils/Parse]', (t) => { 'hardfork parse order should be correct' ) st.equal(common.getHardforkByBlockNumber(0), Hardfork.London, 'london at genesis') - // Merge could be at genesis or 1 depending on td, ttd here is 2 - st.equal(common.getHardforkByBlockNumber(0, BigInt(2)), Hardfork.Merge, 'merge at genesis') st.equal(common.getHardforkByBlockNumber(1, BigInt(2)), Hardfork.Merge, 'merge at block 1') // shanghai is at 8 st.equal(common.getHardforkByBlockNumber(8), Hardfork.Shanghai, 'shanghai at block 8') From c5dd4c98fa2a1aab3b3219a01c0eea8cf2114b0f Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 20 Nov 2022 15:01:04 +0530 Subject: [PATCH 14/18] fix tests --- packages/client/lib/miner/pendingBlock.ts | 2 +- packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/client/lib/miner/pendingBlock.ts b/packages/client/lib/miner/pendingBlock.ts index db03b437bc..c3122f21dc 100644 --- a/packages/client/lib/miner/pendingBlock.ts +++ b/packages/client/lib/miner/pendingBlock.ts @@ -56,7 +56,6 @@ export class PendingBlock { throw new Error('cannot get iterator head: blockchain has no getTotalDifficulty function') } const td = await vm.blockchain.getTotalDifficulty(parentBlock.hash()) - vm._common.setHardforkByBlockNumber(parentBlock.header.number, td) const builder = await vm.buildBlock({ parentBlock, @@ -69,6 +68,7 @@ export class PendingBlock { withdrawals, blockOpts: { putBlockIntoBlockchain: false, + hardforkByTTD: td, }, }) diff --git a/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts b/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts index a1555ff21d..175fa5f3df 100644 --- a/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts +++ b/packages/vm/test/api/EIPs/eip-4895-withdrawals.spec.ts @@ -189,6 +189,7 @@ tape('EIP4895 tests', (t) => { validateBlocks: false, validateConsensus: false, genesisState, + hardforkByHeadBlockNumber: true, }) const genesisBlock = blockchain.genesisBlock st.equal( @@ -204,11 +205,16 @@ tape('EIP4895 tests', (t) => { const withdrawals = (gethBlockBufferArray[3] as WithdrawalBuffer[]).map((wa) => Withdrawal.fromValuesArray(wa) ) + const td = await blockchain.getTotalDifficulty(genesisBlock.hash()) const blockBuilder = await vm.buildBlock({ parentBlock: genesisBlock, withdrawals, - blockOpts: { calcDifficultyFromHeader: genesisBlock.header, freeze: false }, + blockOpts: { + calcDifficultyFromHeader: genesisBlock.header, + freeze: false, + hardforkByTTD: td, + }, }) const block = await blockBuilder.build() From 94b8c9d7fcbd2d0b439475ef008d1d3644d1b088 Mon Sep 17 00:00:00 2001 From: harkamal Date: Sun, 20 Nov 2022 15:06:49 +0530 Subject: [PATCH 15/18] restore test --- packages/block/test/mergeBlock.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block/test/mergeBlock.spec.ts b/packages/block/test/mergeBlock.spec.ts index 751ad0aca6..c5ccb4e36e 100644 --- a/packages/block/test/mergeBlock.spec.ts +++ b/packages/block/test/mergeBlock.spec.ts @@ -64,7 +64,6 @@ tape('[Header]: Casper PoS / The Merge Functionality', function (t) { try { const headerData = { extraData: Buffer.alloc(33).fill(1), - number: BigInt(1), } BlockHeader.fromHeaderData(headerData, { common }) st.fail('should throw') From 5ae2e1659247a9849d8025b06b6e283670b842ad Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 22 Nov 2022 17:54:42 +0530 Subject: [PATCH 16/18] address another case for merge just post genesis --- packages/common/src/utils.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index f4b1bb7259..58b1a02585 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -2,6 +2,7 @@ import { intToHex, isHexPrefixed, stripHexPrefix } from '@ethereumjs/util' import { Hardfork } from './enums' +type ConfigHardfork = { name: string; block: number } /** * Transforms Geth formatted nonce (i.e. hex string) to 8 byte 0x-prefixed string used internally * @param nonce string parsed from the Geth genesis file @@ -116,6 +117,10 @@ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { })) .filter((fork) => fork.block !== null && fork.block !== undefined) + // sort with block + params.hardforks.sort(function (a: ConfigHardfork, b: ConfigHardfork) { + return a.block - b.block + }) params.hardforks.unshift({ name: Hardfork.Chainstart, block: 0 }) if (config.terminalTotalDifficulty !== undefined) { @@ -125,10 +130,18 @@ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { block: null, } - // Merge hardfork has to be placed before first non-zero blockhard fork that is dependent - // on merge, as genesis block can never be a PoS block + // If any of the genesis block require merge, then we need merge just right after genesis + const isMergeJustPostGenesis: boolean = params.hardforks + .filter((hf: ConfigHardfork) => hf.block === 0) + .reduce( + (acc: boolean, hf: ConfigHardfork) => acc || forkMap[hf.name]?.postMerge === true, + false + ) + + // Merge hardfork has to be placed before first non-zero block hardfork that is dependent + // on merge or first non zero block hardfork if any of genesis hardforks require merge const postMergeIndex = params.hardforks.findIndex( - (hf: any) => forkMap[hf.name]?.postMerge === true && hf.block > 0 + (hf: any) => (isMergeJustPostGenesis || forkMap[hf.name]?.postMerge === true) && hf.block > 0 ) if (postMergeIndex !== -1) { params.hardforks.splice(postMergeIndex, 0, mergeConfig) From b0f1092247a199a2c4ee2d82f573c5d54a7bc2a4 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 22 Nov 2022 18:10:46 +0530 Subject: [PATCH 17/18] test case for the new edge case --- packages/common/test/utils.spec.ts | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/common/test/utils.spec.ts b/packages/common/test/utils.spec.ts index e026ee66f1..dc4ccd6e84 100644 --- a/packages/common/test/utils.spec.ts +++ b/packages/common/test/utils.spec.ts @@ -68,10 +68,58 @@ tape('[Utils/Parse]', (t) => { ), mergeForkIdPostMerge: false, }) + st.deepEqual( + common.hardforks().map((hf) => hf.name), + [ + 'chainstart', + 'homestead', + 'tangerineWhistle', + 'spuriousDragon', + 'byzantium', + 'constantinople', + 'petersburg', + 'istanbul', + 'berlin', + 'london', + 'mergeForkIdTransition', + 'merge', + ], + 'hardfork parse order should be correct' + ) for (const hf of common.hardforks()) { /* eslint-disable @typescript-eslint/no-use-before-define */ st.equal(hf.forkHash, kilnForkHashes[hf.name], `${hf.name} forkHash should match`) } + + // Ok lets schedule shanghai at block 0, this should force merge to be scheduled at just after + // genesis if even mergeForkIdTransition is not confirmed to be post merge + // This will also check if the forks are being correctly sorted based on block + Object.assign(json.config, { shanghaiBlock: 0 }) + const common1 = Common.fromGethGenesis(json, { + chain: 'customChain', + mergeForkIdPostMerge: false, + }) + // merge hardfork is now scheduled just after shanghai even if mergeForkIdTransition is not confirmed + // to be post merge + st.deepEqual( + common1.hardforks().map((hf) => hf.name), + [ + 'chainstart', + 'homestead', + 'tangerineWhistle', + 'spuriousDragon', + 'byzantium', + 'constantinople', + 'petersburg', + 'istanbul', + 'berlin', + 'london', + 'shanghai', + 'merge', + 'mergeForkIdTransition', + ], + 'hardfork parse order should be correct' + ) }) t.test('should successfully parse genesis with hardfork scheduled post merge', async (st) => { From 5c4f5d884a3ba1c05df0ff27c57bfeb68bf9a980 Mon Sep 17 00:00:00 2001 From: harkamal Date: Tue, 22 Nov 2022 18:16:45 +0530 Subject: [PATCH 18/18] add comment --- packages/common/src/utils.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/common/src/utils.ts b/packages/common/src/utils.ts index 58b1a02585..920aa7f5de 100644 --- a/packages/common/src/utils.ts +++ b/packages/common/src/utils.ts @@ -124,6 +124,11 @@ function parseGethParams(json: any, mergeForkIdPostMerge: boolean = true) { params.hardforks.unshift({ name: Hardfork.Chainstart, block: 0 }) if (config.terminalTotalDifficulty !== undefined) { + // Following points need to be considered for placement of merge hf + // - Merge hardfork can't be placed at genesis + // - Place merge hf before any hardforks that require CL participation for e.g. withdrawals + // - Merge hardfork has to be placed just after genesis if any of the genesis hardforks make CL + // necessary for e.g. withdrawals const mergeConfig = { name: Hardfork.Merge, ttd: config.terminalTotalDifficulty,