diff --git a/packages/vm/lib/index.ts b/packages/vm/lib/index.ts index 5f6cf07185..955b548e4d 100644 --- a/packages/vm/lib/index.ts +++ b/packages/vm/lib/index.ts @@ -89,6 +89,13 @@ export interface VMOpts { * Default: `false` [ONLY set to `true` during debugging] */ allowUnlimitedContractSize?: boolean + + /** + * Select hardfork based upon block number. This automatically switches to the right hard fork based upon the block number. + * + * Default: `true` + */ + selectHardforkByBlockNumber?: boolean } /** @@ -113,6 +120,7 @@ export default class VM extends AsyncEventEmitter { protected _isInitialized: boolean = false protected readonly _allowUnlimitedContractSize: boolean protected _opcodes: OpcodeList + protected readonly _selectHardforkByBlockNumber: boolean /** * Cached emit() function, not for public usage @@ -203,6 +211,8 @@ export default class VM extends AsyncEventEmitter { this._allowUnlimitedContractSize = opts.allowUnlimitedContractSize || false + this._selectHardforkByBlockNumber = opts.selectHardforkByBlockNumber ?? true + if (this._common.eips().includes(2537)) { if (IS_BROWSER) { throw new Error('EIP-2537 is currently not supported in browsers') diff --git a/packages/vm/lib/runBlock.ts b/packages/vm/lib/runBlock.ts index ac5925cc9a..037c5c8829 100644 --- a/packages/vm/lib/runBlock.ts +++ b/packages/vm/lib/runBlock.ts @@ -122,6 +122,14 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise { t.end() }) +tape('should correctly use the selectHardforkByBlockNumber option', async (t) => { + const common1 = new Common({ + chain: 'mainnet', + hardfork: 'chainstart', + }) + + // Have to use an unique common, otherwise the HF will be set to muirGlacier and then will not change back to chainstart. + const common2 = new Common({ + chain: 'mainnet', + hardfork: 'chainstart', + }) + + const privateKey = Buffer.from( + 'e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', + 'hex' + ) + + function getBlock(common: Common): Block { + return Block.fromBlockData( + { + header: { + number: new BN(10000000), + }, + transactions: [ + Transaction.fromTxData( + { + data: '0x600154', // PUSH 01 SLOAD + gasLimit: new BN(100000), + }, + { common } + ).sign(privateKey), + ], + }, + { common } + ) + } + + const vm = new VM({ common: common1 }) + const vm_noSelect = new VM({ common: common2, selectHardforkByBlockNumber: false }) + + const txResultMuirGlacier = await vm.runBlock({ + block: getBlock(common1), + skipBlockValidation: true, + generate: true, + }) + const txResultChainstart = await vm_noSelect.runBlock({ + block: getBlock(common2), + skipBlockValidation: true, + generate: true, + }) + t.ok( + txResultChainstart.results[0].gasUsed.toNumber() == 21000 + 68 * 3 + 3 + 50, + 'tx charged right gas on chainstart hard fork' + ) + t.ok( + txResultMuirGlacier.results[0].gasUsed.toNumber() == 21000 + 32000 + 16 * 3 + 3 + 800, + 'tx charged right gas on muir glacier hard fork' + ) + t.end() +}) + tape('should run valid block', async (t) => { const vm = setupVM() const suite = setup(vm) diff --git a/packages/vm/tests/api/utils.ts b/packages/vm/tests/api/utils.ts index 2812ce4df6..1eef42c185 100644 --- a/packages/vm/tests/api/utils.ts +++ b/packages/vm/tests/api/utils.ts @@ -22,5 +22,8 @@ export function setupVM(opts: VMOpts & { genesisBlock?: Block } = {}) { genesisBlock, }) } - return new VM(opts) + return new VM({ + selectHardforkByBlockNumber: false, + ...opts, + }) }