diff --git a/packages/block/src/header.ts b/packages/block/src/header.ts index 0965c531b9..c2b1d0d238 100644 --- a/packages/block/src/header.ts +++ b/packages/block/src/header.ts @@ -249,7 +249,15 @@ export class BlockHeader { if (this._common.isActivatedEIP(1559)) { if (baseFeePerGas === undefined) { - baseFeePerGas = new BN(7) + const londonHfBlock = this._common.hardforkBlockBN(Hardfork.London) + const isInitialEIP1559Block = londonHfBlock && number.eq(londonHfBlock) + if (isInitialEIP1559Block) { + baseFeePerGas = new BN(this._common.param('gasConfig', 'initialBaseFee')) + } else { + // Minimum possible value for baseFeePerGas is 7, + // so we use it as the default if the field is missing. + baseFeePerGas = new BN(7) + } } } else { if (baseFeePerGas) { @@ -455,7 +463,7 @@ export class BlockHeader { // We use a ! here as TS cannot follow this hardfork-dependent logic, but it always gets assigned let dif!: BN - if (this._common.hardforkGteHardfork(hardfork, 'byzantium')) { + if (this._common.hardforkGteHardfork(hardfork, Hardfork.Byzantium)) { // max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99) (EIP100) const uncleAddend = parentBlockHeader.uncleHash.equals(KECCAK256_RLP_ARRAY) ? 1 : 2 let a = blockTs.sub(parentTs).idivn(9).ineg().iaddn(uncleAddend) @@ -467,13 +475,13 @@ export class BlockHeader { dif = parentDif.add(offset.mul(a)) } - if (this._common.hardforkGteHardfork(hardfork, 'byzantium')) { + if (this._common.hardforkGteHardfork(hardfork, Hardfork.Byzantium)) { // Get delay as parameter from common num.isubn(this._common.param('pow', 'difficultyBombDelay')) if (num.ltn(0)) { num = new BN(0) } - } else if (this._common.hardforkGteHardfork(hardfork, 'homestead')) { + } else if (this._common.hardforkGteHardfork(hardfork, Hardfork.Homestead)) { // 1 - (block_timestamp - parent_timestamp) // 10 let a = blockTs.sub(parentTs).idivn(10).ineg().iaddn(1) const cutoff = new BN(-99) @@ -558,7 +566,7 @@ export class BlockHeader { let parentGasLimit = parentBlockHeader.gasLimit // EIP-1559: assume double the parent gas limit on fork block // to adopt to the new gas target centered logic - const londonHardforkBlock = this._common.hardforkBlockBN('london') + const londonHardforkBlock = this._common.hardforkBlockBN(Hardfork.London) if (londonHardforkBlock && this.number.eq(londonHardforkBlock)) { const elasticity = new BN(this._common.param('gasConfig', 'elasticityMultiplier')) parentGasLimit = parentGasLimit.mul(elasticity) @@ -708,8 +716,8 @@ export class BlockHeader { const msg = this._errorMsg('EIP1559 block has no base fee field') throw new Error(msg) } - const block = this._common.hardforkBlockBN('london') - const isInitialEIP1559Block = block && this.number.eq(block) + const londonHfBlock = this._common.hardforkBlockBN(Hardfork.London) + const isInitialEIP1559Block = londonHfBlock && this.number.eq(londonHfBlock) if (isInitialEIP1559Block) { const initialBaseFee = new BN(this._common.param('gasConfig', 'initialBaseFee')) if (!this.baseFeePerGas!.eq(initialBaseFee)) { diff --git a/packages/block/test/block.spec.ts b/packages/block/test/block.spec.ts index 91adaf678e..b0cda5abd1 100644 --- a/packages/block/test/block.spec.ts +++ b/packages/block/test/block.spec.ts @@ -78,7 +78,7 @@ tape('[Block]: block functions', function (t) { }, { common, hardforkByBlockNumber: true } ) - st.equal(block._common.hardfork(), 'berlin', 'should use hardforkByBlockNumber option') + st.equal(block._common.hardfork(), Hardfork.Berlin, 'should use hardforkByBlockNumber option') block = Block.fromBlockData( { @@ -88,7 +88,11 @@ tape('[Block]: block functions', function (t) { }, { common, hardforkByTD: 5001 } ) - st.equal(block._common.hardfork(), 'merge', 'should use hardforkByTD option (td > threshold)') + st.equal( + block._common.hardfork(), + Hardfork.Merge, + 'should use hardforkByTD option (td > threshold)' + ) block = Block.fromBlockData( { @@ -100,7 +104,7 @@ tape('[Block]: block functions', function (t) { ) st.equal( block._common.hardfork(), - 'berlin', + Hardfork.Berlin, 'should work with hardforkByTD option (td < threshold)' ) @@ -522,7 +526,7 @@ tape('[Block]: block functions', function (t) { const common = new Common({ chain: Chain.Mainnet }) common.setHardfork(Hardfork.Berlin) - const mainnetForkBlock = common.hardforkBlockBN('london') + const mainnetForkBlock = common.hardforkBlockBN(Hardfork.London) const rootBlock = Block.fromBlockData({ header: { number: mainnetForkBlock!.subn(3), @@ -552,10 +556,10 @@ tape('[Block]: block functions', function (t) { await blockchain.putBlock(forkBlock) await preForkBlock.validate(blockchain) - st.ok(common.hardfork() === 'london', 'validation did not change common hardfork') + st.ok(common.hardfork() === Hardfork.London, 'validation did not change common hardfork') await forkBlock2.validate(blockchain) - st.ok(common.hardfork() === 'london', 'validation did not change common hardfork') + st.ok(common.hardfork() === Hardfork.London, 'validation did not change common hardfork') const forkBlock2HeaderData = forkBlock2.header.toJSON() const uncleHeaderData = unclePreFork.header.toJSON() @@ -578,8 +582,8 @@ tape('[Block]: block functions', function (t) { await forkBlock_ValidCommon.validate(blockchain) - st.pass('succesfully validated a pre-london uncle on a london block') - st.ok(common.hardfork() === 'london', 'validation did not change common hardfork') + st.pass('successfully validated a pre-london uncle on a london block') + st.ok(common.hardfork() === Hardfork.London, 'validation did not change common hardfork') const forkBlock_InvalidCommon = Block.fromBlockData( { @@ -602,7 +606,7 @@ tape('[Block]: block functions', function (t) { ) } - st.ok(common.hardfork() === 'london', 'validation did not change common hardfork') + st.ok(common.hardfork() === Hardfork.London, 'validation did not change common hardfork') } ) diff --git a/packages/block/test/eip1559block.spec.ts b/packages/block/test/eip1559block.spec.ts index 62ac74c1b7..f2134f3593 100644 --- a/packages/block/test/eip1559block.spec.ts +++ b/packages/block/test/eip1559block.spec.ts @@ -40,9 +40,9 @@ tape('EIP1559 tests', function (t) { st.end() }) - t.test('Header -> Initialization', async function (st) { - try { - const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) + t.test('Header -> Initialization', function (st) { + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) + st.throws(() => { BlockHeader.fromHeaderData( { number: new BN(1), @@ -54,11 +54,9 @@ tape('EIP1559 tests', function (t) { { common, } - ) - } catch (e: any) { - const expectedError = 'A base fee for a block can only be set with EIP1559 being activated' - st.ok(e.message.includes(expectedError), 'should throw with EIP1559 not being activated') - } + ), + 'should throw when setting baseFeePerGas with EIP1559 not being activated' + }) st.end() }) @@ -69,6 +67,7 @@ tape('EIP1559 tests', function (t) { parentHash: genesis.hash(), gasLimit: genesis.header.gasLimit.muln(2), // Special case on EIP-1559 transition block timestamp: new BN(1), + baseFeePerGas: 100, }, { calcDifficultyFromHeader: genesis.header, @@ -79,7 +78,7 @@ tape('EIP1559 tests', function (t) { try { await header.validate(blockchain1) - st.fail('should throw') + st.fail('should throw when baseFeePerGas is not set to initial base fee') } catch (e: any) { const expectedError = 'Initial EIP1559 block does not have initial base fee' st.ok( diff --git a/packages/block/test/util.ts b/packages/block/test/util.ts index 0e5c7ec56f..05465a1de3 100644 --- a/packages/block/test/util.ts +++ b/packages/block/test/util.ts @@ -1,4 +1,4 @@ -import Common, { Chain } from '@ethereumjs/common' +import Common, { Chain, Hardfork } from '@ethereumjs/common' import { BN, rlp, keccak256 } from 'ethereumjs-util' import { Block, BlockHeader } from '../src' @@ -21,15 +21,23 @@ function createBlock( throw new Error('extra data graffiti must be 32 bytes or less') } + const number = parentBlock.header.number.addn(1) + const timestamp = parentBlock.header.timestamp.addn(1) + + const londonHfBlock = common.hardforkBlockBN(Hardfork.London) + const baseFeePerGas = + londonHfBlock && number.gt(londonHfBlock) ? parentBlock.header.calcNextBaseFee() : undefined + return Block.fromBlockData( { header: { - number: parentBlock.header.number.addn(1), + number, parentHash: parentBlock.hash(), - timestamp: parentBlock.header.timestamp.addn(1), + timestamp, gasLimit: new BN(5000), extraData: Buffer.from(extraData), uncleHash: keccak256(rlp.encode(uncles.map((uh) => uh.raw()))), + baseFeePerGas, }, uncleHeaders: uncles, }, diff --git a/packages/common/README.md b/packages/common/README.md index 19627b3102..1f35569138 100644 --- a/packages/common/README.md +++ b/packages/common/README.md @@ -115,6 +115,7 @@ Supported chains: - `rinkeby` (`Chain.Rinkeby`) - `kovan` (`Chain.Kovan`) - `goerli` (`Chain.Goerli`) +- `sepolia` (`Chain.Sepolia`) - Private/custom chain parameters The following chain-specific parameters are provided: diff --git a/packages/common/src/chains/index.ts b/packages/common/src/chains/index.ts index cd64d08f79..b61c4e0fb1 100644 --- a/packages/common/src/chains/index.ts +++ b/packages/common/src/chains/index.ts @@ -4,6 +4,7 @@ import ropsten from './ropsten.json' import rinkeby from './rinkeby.json' import kovan from './kovan.json' import goerli from './goerli.json' +import sepolia from './sepolia.json' /** * @hidden @@ -15,6 +16,7 @@ export function _getInitializedChains(customChains?: Chain[]) { '4': 'rinkeby', '42': 'kovan', '5': 'goerli', + '11155111': 'sepolia', } const chains: any = { mainnet, @@ -22,6 +24,7 @@ export function _getInitializedChains(customChains?: Chain[]) { rinkeby, kovan, goerli, + sepolia, } if (customChains) { for (const chain of customChains) { diff --git a/packages/common/src/chains/sepolia.json b/packages/common/src/chains/sepolia.json new file mode 100644 index 0000000000..79f3b91417 --- /dev/null +++ b/packages/common/src/chains/sepolia.json @@ -0,0 +1,106 @@ +{ + "name": "sepolia", + "chainId": 11155111, + "networkId": 11155111, + "defaultHardfork": "istanbul", + "consensus": { + "type": "pow", + "algorithm": "ethash", + "ethash": {} + }, + "comment": "PoW test network to replace Ropsten", + "url": "https://github.com/ethereum/go-ethereum/pull/23730", + "genesis": { + "hash": "0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9", + "timestamp": "0x6159af19", + "gasLimit": 30000000, + "difficulty": 131072, + "nonce": "0x0000000000000000", + "extraData": "0x5365706f6c69612c20417468656e732c204174746963612c2047726565636521", + "stateRoot": "0x5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "homestead", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "tangerineWhistle", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "spuriousDragon", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "byzantium", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "constantinople", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "petersburg", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "istanbul", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "muirGlacier", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "berlin", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "london", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "merge", + "block": null, + "forkHash": null + }, + { + "name": "shanghai", + "block": null, + "forkHash": null + } + ], + "bootstrapNodes": [ + { + "ip": "18.168.182.86", + "port": 30303, + "id": "9246d00bc8fd1742e5ad2428b80fc4dc45d786283e05ef6edbd9002cbc335d40998444732fbe921cb88e1d2c73d1b1de53bae6a2237996e9bfe14f871baf7066", + "location": "", + "comment": "geth" + }, + { + "ip": "52.14.151.177", + "port": 30303, + "id": "ec66ddcf1a974950bd4c782789a7e04f8aa7110a72569b6e65fcd51e937e74eed303b1ea734e4d19cfaec9fbff9b6ee65bf31dcb50ba79acce9dd63a6aca61c7", + "location": "", + "comment": "besu" + } + ], + "dnsNetworks": [] +} diff --git a/packages/common/src/genesisStates/index.ts b/packages/common/src/genesisStates/index.ts index 5fb4a08b7d..c170b0e141 100644 --- a/packages/common/src/genesisStates/index.ts +++ b/packages/common/src/genesisStates/index.ts @@ -7,12 +7,14 @@ const genesisStates: genesisStatesType = { '4': 'rinkeby', '42': 'kovan', '5': 'goerli', + '11155111': 'sepolia', }, mainnet: require('./mainnet.json'), ropsten: require('./ropsten.json'), rinkeby: require('./rinkeby.json'), kovan: require('./kovan.json'), goerli: require('./goerli.json'), + sepolia: require('./sepolia.json'), } /** diff --git a/packages/common/src/genesisStates/sepolia.json b/packages/common/src/genesisStates/sepolia.json new file mode 100644 index 0000000000..5052d62ddb --- /dev/null +++ b/packages/common/src/genesisStates/sepolia.json @@ -0,0 +1,17 @@ +{ + "0xa2A6d93439144FFE4D27c9E088dCD8b783946263": "0xD3C21BCECCEDA1000000", + "0xBc11295936Aa79d594139de1B2e12629414F3BDB": "0xD3C21BCECCEDA1000000", + "0x7cF5b79bfe291A67AB02b393E456cCc4c266F753": "0xD3C21BCECCEDA1000000", + "0xaaec86394441f915bce3e6ab399977e9906f3b69": "0xD3C21BCECCEDA1000000", + "0xF47CaE1CF79ca6758Bfc787dbD21E6bdBe7112B8": "0xD3C21BCECCEDA1000000", + "0xd7eDDB78ED295B3C9629240E8924fb8D8874ddD8": "0xD3C21BCECCEDA1000000", + "0x8b7F0977Bb4f0fBE7076FA22bC24acA043583F5e": "0xD3C21BCECCEDA1000000", + "0xe2e2659028143784d557bcec6ff3a0721048880a": "0xD3C21BCECCEDA1000000", + "0xd9a5179f091d85051d3c982785efd1455cec8699": "0xD3C21BCECCEDA1000000", + "0xbeef32ca5b9a198d27B4e02F4c70439fE60356Cf": "0xD3C21BCECCEDA1000000", + "0x0000006916a87b82333f4245046623b23794c65c": "0x84595161401484A000000", + "0xb21c33de1fab3fa15499c62b59fe0cc3250020d1": "0x52B7D2DCC80CD2E4000000", + "0x10F5d45854e038071485AC9e402308cF80D2d2fE": "0x52B7D2DCC80CD2E4000000", + "0xd7d76c58b3a519e9fA6Cc4D22dC017259BC49F1E": "0x52B7D2DCC80CD2E4000000", + "0x799D329e5f583419167cD722962485926E338F4a": "0xDE0B6B3A7640000" +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index ef11d9e4f3..98e4386a25 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -62,6 +62,7 @@ export enum Chain { Rinkeby = 4, Kovan = 42, Goerli = 5, + Sepolia = 11155111, } export enum Hardfork { @@ -1013,6 +1014,8 @@ export default class Common extends EventEmitter { return require('./genesisStates/kovan.json') case 'goerli': return require('./genesisStates/goerli.json') + case 'sepolia': + return require('./genesisStates/sepolia.json') } // Custom chains with genesis state provided