Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block, VM: Unify hardforkBy Options #2800

Merged
merged 6 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
31 changes: 12 additions & 19 deletions packages/block/src/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class Block {
for (const txData of txsData ?? []) {
const tx = TransactionFactory.fromTxData(txData, {
...opts,
// Use header common in case of hardforkByBlockNumber being activated
// Use header common in case of setHardfork being activated
common: header._common,
} as TxOptions)
transactions.push(tx)
Expand All @@ -106,18 +106,15 @@ export class Block {
// parse uncle headers
const uncleHeaders = []
const uncleOpts: BlockOptions = {
hardforkByBlockNumber: true,
...opts,
// Use header common in case of hardforkByBlockNumber being activated
// Use header common in case of setHardfork being activated
common: header._common,
// Disable this option here (all other options carried over), since this overwrites the provided Difficulty to an incorrect value
calcDifficultyFromHeader: undefined,
// This potentially overwrites hardforkBy options but we will set them cleanly just below
hardforkByTTD: undefined,
}
// Uncles are obsolete post-merge, any hardfork by option implies hardforkByBlockNumber
if (opts?.hardforkByTTD !== undefined) {
uncleOpts.hardforkByBlockNumber = true
// Uncles are obsolete post-merge, any hardfork by option implies setHardfork
if (opts?.setHardfork !== undefined) {
uncleOpts.setHardfork = true
}
for (const uhData of uhsData ?? []) {
const uh = BlockHeader.fromHeaderData(uhData, uncleOpts)
Expand Down Expand Up @@ -156,7 +153,7 @@ export class Block {
throw new Error('invalid block. More values than expected were received')
}

// First try to load header so that we can use its common (in case of hardforkByBlockNumber being activated)
// First try to load header so that we can use its common (in case of setHardfork being activated)
// to correctly make checks on the hardforks
const [headerData, txsData, uhsData, withdrawalBytes] = values
const header = BlockHeader.fromValuesArray(headerData, opts)
Expand All @@ -176,7 +173,7 @@ export class Block {
transactions.push(
TransactionFactory.fromBlockBodyData(txData, {
...opts,
// Use header common in case of hardforkByBlockNumber being activated
// Use header common in case of setHardfork being activated
common: header._common,
})
)
Expand All @@ -185,18 +182,15 @@ export class Block {
// parse uncle headers
const uncleHeaders = []
const uncleOpts: BlockOptions = {
hardforkByBlockNumber: true,
...opts,
// Use header common in case of hardforkByBlockNumber being activated
// Use header common in case of setHardfork being activated
common: header._common,
// Disable this option here (all other options carried over), since this overwrites the provided Difficulty to an incorrect value
calcDifficultyFromHeader: undefined,
// This potentially overwrites hardforkBy options but we will set them cleanly just below
hardforkByTTD: undefined,
}
// Uncles are obsolete post-merge, any hardfork by option implies hardforkByBlockNumber
if (opts?.hardforkByTTD !== undefined) {
uncleOpts.hardforkByBlockNumber = true
// Uncles are obsolete post-merge, any hardfork by option implies setHardfork
if (opts?.setHardfork !== undefined) {
uncleOpts.setHardfork = true
}
for (const uncleHeaderData of uhsData ?? []) {
uncleHeaders.push(BlockHeader.fromValuesArray(uncleHeaderData, uncleOpts))
Expand Down Expand Up @@ -333,8 +327,7 @@ export class Block {
coinbase,
}

// we are not setting hardforkByBlockNumber or hardforkByTTD as common is already
// correctly set to the correct hf
// we are not setting setHardfork as common is already set to the correct hf
const block = Block.fromBlockData({ header, transactions: txs, withdrawals }, options)
// Verify blockHash matches payload
if (!equalsBytes(block.hash(), hexStringToBytes(payload.blockHash))) {
Expand Down
19 changes: 10 additions & 9 deletions packages/block/src/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { fakeExponential, valuesArrayToHeaderData } from './helpers.js'

import type { BlockHeaderBytes, BlockOptions, HeaderData, JsonHeader } from './types.js'
import type { CliqueConfig } from '@ethereumjs/common'
import type { BigIntLike } from '@ethereumjs/util'

interface HeaderCache {
hash: Uint8Array | undefined
Expand Down Expand Up @@ -136,12 +137,6 @@ export class BlockHeader {
})
}

if (options.hardforkByBlockNumber !== undefined && options.hardforkByTTD !== undefined) {
throw new Error(
`The hardforkByBlockNumber and hardforkByTTD options can't be used in conjunction`
)
}

const skipValidateConsensusFormat = options.skipConsensusFormatValidation ?? false

const defaults = {
Expand Down Expand Up @@ -182,11 +177,17 @@ export class BlockHeader {
const mixHash = toType(headerData.mixHash, TypeOutput.Uint8Array) ?? defaults.mixHash
const nonce = toType(headerData.nonce, TypeOutput.Uint8Array) ?? defaults.nonce

const hardforkByBlockNumber = options.hardforkByBlockNumber ?? false
if (hardforkByBlockNumber || options.hardforkByTTD !== undefined) {
const setHardfork = options.setHardfork ?? false
if (setHardfork === true) {
this._common.setHardforkBy({
blockNumber: number,
timestamp,
})
}
if (typeof setHardfork !== 'boolean') {
holgerd77 marked this conversation as resolved.
Show resolved Hide resolved
this._common.setHardforkBy({
blockNumber: number,
td: options.hardforkByTTD,
td: setHardfork as BigIntLike,
timestamp,
})
}
Expand Down
19 changes: 6 additions & 13 deletions packages/block/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,15 @@ export interface BlockOptions {
*/
common?: Common
/**
* Determine the HF by the block number
* Set the hardfork either by timestamp (for HFs from Shanghai onwards) or by block number
* for older Hfs.
*
* Default: `false` (HF is set to whatever default HF is set by the {@link Common} instance)
*/
hardforkByBlockNumber?: boolean
/**
* Determine the HF by total difficulty (Merge HF)
* Additionally it is possible to pass in a specific TD value to support live-Merge-HF
* transitions. Note that this should only be needed in very rare and specific scenarios.
*
* This option is a superset of `hardforkByBlockNumber` (so only use one of both options)
* and determines the HF by both the block number and the TD.
*
* Since the TTD is only a threshold the block number will in doubt take precedence (imagine
* e.g. both Merge and Shanghai HF blocks set and the block number from the block provided
* pointing to a Shanghai block: this will lead to set the HF as Shanghai and not the Merge).
* Default: `false` (HF is set to whatever default HF is set by the {@link Common} instance)
*/
hardforkByTTD?: BigIntLike
setHardfork?: boolean | BigIntLike
/**
* If a preceding {@link BlockHeader} (usually the parent header) is given the preceding
* header will be used to calculate the difficulty for this block and the calculated
Expand Down
32 changes: 7 additions & 25 deletions packages/block/test/block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('[Block]: block functions', () => {
)
})

it('initialization -> hardforkByBlockNumber option', () => {
it('initialization -> setHardfork option', () => {
const customChains = [testnetMerge]
const common = new Common({
chain: 'testnetMerge',
Expand All @@ -86,26 +86,22 @@ describe('[Block]: block functions', () => {
extraData: new Uint8Array(97),
},
},
{ common, hardforkByBlockNumber: true }
)
assert.equal(
block._common.hardfork(),
Hardfork.Berlin,
'should use hardforkByBlockNumber option'
{ common, setHardfork: true }
)
assert.equal(block._common.hardfork(), Hardfork.Berlin, 'should use setHardfork option')

block = Block.fromBlockData(
{
header: {
number: 20, // Future block
},
},
{ common, hardforkByTTD: 5001 }
{ common, setHardfork: 5001 }
)
assert.equal(
block._common.hardfork(),
Hardfork.Paris,
'should use hardforkByTTD option (td > threshold)'
'should use setHardfork option (td > threshold)'
)

block = Block.fromBlockData(
Expand All @@ -115,27 +111,13 @@ describe('[Block]: block functions', () => {
extraData: new Uint8Array(97),
},
},
{ common, hardforkByTTD: 3000 }
{ common, setHardfork: 3000 }
)
assert.equal(
block._common.hardfork(),
Hardfork.Berlin,
'should work with hardforkByTTD option (td < threshold)'
'should work with setHardfork option (td < threshold)'
)

try {
Block.fromBlockData({}, { common, hardforkByBlockNumber: true, hardforkByTTD: 3000 })
assert.fail('should not reach this')
} catch (e: any) {
const msg =
'should throw if hardforkByBlockNumber and hardforkByTTD options are used in conjunction'
assert.ok(
e.message.includes(
`The hardforkByBlockNumber and hardforkByTTD options can't be used in conjunction`
),
msg
)
}
})

it('should initialize with undefined parameters without throwing', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/block/test/difficulty.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('[Header]: difficulty tests', () => {
for (const testName in testData.default) {
const test = testData[testName]
const common = new Common({ chain })
const blockOpts = { common, hardforkByBlockNumber: true }
const blockOpts = { common, setHardfork: true }
const uncleHash = test.parentUncles === '0x00' ? undefined : test.parentUncles
const parentBlock = Block.fromBlockData(
{
Expand Down
8 changes: 4 additions & 4 deletions packages/block/test/from-rpc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,21 @@ describe('[fromRPC] - Alchemy/Infura API block responses', () => {

it('should create pre and post merge blocks from Infura API responses to eth_getBlockByHash and eth_getBlockByNumber', () => {
const common = new Common({ chain: Chain.Mainnet })
let block = blockFromRpc(infura2000004woTxs, [], { common, hardforkByBlockNumber: true })
let block = blockFromRpc(infura2000004woTxs, [], { common, setHardfork: true })
assert.equal(
bytesToPrefixedHexString(block.hash()),
infura2000004woTxs.hash,
'created premerge block w/o txns'
)
block = blockFromRpc(infura2000004wTxs, [], { common, hardforkByBlockNumber: true })
block = blockFromRpc(infura2000004wTxs, [], { common, setHardfork: true })
assert.equal(
bytesToPrefixedHexString(block.hash()),
infura2000004wTxs.hash,
'created premerge block with txns'
)
block = blockFromRpc(infura15571241woTxs, [], {
common,
hardforkByTTD: 58750000000000000000000n,
setHardfork: 58750000000000000000000n,
})
assert.equal(
bytesToPrefixedHexString(block.hash()),
Expand All @@ -146,7 +146,7 @@ describe('[fromRPC] - Alchemy/Infura API block responses', () => {

block = blockFromRpc(infura15571241wTxs, [], {
common,
hardforkByTTD: 58750000000000000000000n,
setHardfork: 58750000000000000000000n,
})
assert.equal(
bytesToPrefixedHexString(block.hash()),
Expand Down
6 changes: 3 additions & 3 deletions packages/block/test/header.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,18 @@ describe('[Block]: Header functions', () => {
BlockHeader.fromRLPSerializedHeader(rlpHeader, {
common,
freeze: false,
hardforkByTTD: 1n, // Added to bypass defaulting hardforkByBlockNumber to true in static constructor
setHardfork: 1n, // Added to bypass defaulting setHardfork to true in static constructor
}),
'A base fee',
undefined,
'throws when RLP serialized block with no base fee on default hardfork (london) and hardforkByBlockNumber left undefined'
'throws when RLP serialized block with no base fee on default hardfork (london) and setHardfork left undefined'
)

header = BlockHeader.fromRLPSerializedHeader(
hexStringToBytes(
'f90214a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000850400000000808213888080a011bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82faa00000000000000000000000000000000000000000000000000000000000000000880000000000000042'
),
{ common, hardforkByBlockNumber: false }
{ common, setHardfork: false }
)
assert.equal(
bytesToHex(header.hash()),
Expand Down
2 changes: 1 addition & 1 deletion packages/blockchain/src/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class Blockchain implements BlockchainInterface {
for (const blockData of blocksData) {
const block = Block.fromBlockData(blockData, {
common: blockchain._common,
hardforkByBlockNumber: true,
setHardfork: true,
})
await blockchain.putBlock(block)
}
Expand Down
8 changes: 4 additions & 4 deletions packages/blockchain/src/db/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ export class DBManager {
const blockData = [header.raw(), ...body] as BlockBytes
const opts: BlockOptions = { common: this._common }
if (number === BigInt(0)) {
opts.hardforkByTTD = await this.getTotalDifficulty(hash, BigInt(0))
opts.setHardfork = await this.getTotalDifficulty(hash, BigInt(0))
} else {
opts.hardforkByTTD = await this.getTotalDifficulty(header.parentHash, number - BigInt(1))
opts.setHardfork = await this.getTotalDifficulty(header.parentHash, number - BigInt(1))
}
return Block.fromValuesArray(blockData, opts)
}
Expand All @@ -156,13 +156,13 @@ export class DBManager {

const opts: BlockOptions = { common: this._common }
if (blockNumber === BigInt(0)) {
opts.hardforkByTTD = await this.getTotalDifficulty(blockHash, BigInt(0))
opts.setHardfork = await this.getTotalDifficulty(blockHash, BigInt(0))
} else {
// Lets fetch the parent hash but not by number since this block might not
// be in canonical chain
const headerData = valuesArrayToHeaderData(headerValues as Uint8Array[])
const parentHash = headerData.parentHash as Uint8Array
opts.hardforkByTTD = await this.getTotalDifficulty(parentHash, blockNumber - BigInt(1))
opts.setHardfork = await this.getTotalDifficulty(parentHash, blockNumber - BigInt(1))
}
return BlockHeader.fromValuesArray(headerValues as Uint8Array[], opts)
}
Expand Down
5 changes: 3 additions & 2 deletions packages/blockchain/test/blockValidation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ describe('[Blockchain]: Block validation tests', () => {
* Pre-fork block can have legacy uncles
* London block has london uncles
* London block has legacy uncles
* London block has legacy uncles, where hardforkByBlockNumber set to false (this should not throw)
* London block has legacy uncles, where setHardfork set to false (this should not throw)
* In this situation, the london block creates a london uncle, but this london uncle should be
* a berlin block, and therefore has no base fee. Since common will report london as active hardfork,
* evaluation of uncle header will initialize base fee to 7 per default header constructor rules for
Expand Down Expand Up @@ -354,6 +354,7 @@ describe('[Blockchain]: Block validation tests', () => {
},
{
common,
setHardfork: false,
}
)

Expand All @@ -373,7 +374,7 @@ describe('[Blockchain]: Block validation tests', () => {
},
{
common,
hardforkByBlockNumber: false,
setHardfork: false,
}
),
'should create block even with pre-London uncle and common evaluated with london since uncle is given default base fee'
Expand Down
2 changes: 1 addition & 1 deletion packages/blockchain/test/pos.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const buildChain = async (blockchain: Blockchain, common: Common, height: number
{
calcDifficultyFromHeader: blocks[number - 1].header,
common,
hardforkByTTD: await blockchain.getTotalDifficulty(blocks[number - 1].hash()),
setHardfork: await blockchain.getTotalDifficulty(blocks[number - 1].hash()),
}
)
blocks.push(block)
Expand Down
2 changes: 1 addition & 1 deletion packages/client/bin/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ async function startClient(config: Config, customGenesisState?: GenesisState) {
try {
const block = Block.fromValuesArray(buf.data as BlockBytes, {
common: config.chainCommon,
hardforkByBlockNumber: true,
setHardfork: true,
})
blocks.push(block)
buf = RLP.decode(buf.remainder, true)
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/blockchain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ export class Chain {

const block = Block.fromValuesArray(b.raw(), {
common: this.config.chainCommon,
hardforkByTTD: td,
setHardfork: td,
})

await this.blockchain.putBlock(block)
Expand Down Expand Up @@ -453,7 +453,7 @@ export class Chain {
}
const header = BlockHeader.fromValuesArray(h.raw(), {
common: this.config.chainCommon,
hardforkByTTD: this.headers.td,
setHardfork: this.headers.td,
})
await this.blockchain.putHeader(header)
numAdded++
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/miner/miner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export class Miner {
},
blockOpts: {
cliqueSigner,
hardforkByBlockNumber: true,
setHardfork: true,
calcDifficultyFromHeader,
putBlockIntoBlockchain: false,
},
Expand Down
Loading