Skip to content

Commit

Permalink
VM: add selectHardforkByBlockNumber option (#966)
Browse files Browse the repository at this point in the history
* vm: add selectHardforkByBlockNumber option
  • Loading branch information
jochem-brouwer committed Nov 26, 2020
1 parent a61be5d commit 93b476e
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 1 deletion.
10 changes: 10 additions & 0 deletions packages/vm/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

/**
Expand All @@ -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
Expand Down Expand Up @@ -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')
Expand Down
8 changes: 8 additions & 0 deletions packages/vm/lib/runBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ export default async function runBlock(this: VM, opts: RunBlockOpts): Promise<Ru
*/
await this._emit('beforeBlock', block)

if (this._selectHardforkByBlockNumber) {
const currentHf = this._common.hardfork()
this._common.setHardforkByBlockNumber(block.header.number.toNumber())
if (this._common.hardfork() != currentHf) {
this._updateOpcodes()
}
}

// Set state root if provided
if (root) {
await state.setStateRoot(root)
Expand Down
1 change: 1 addition & 0 deletions packages/vm/tests/BlockchainTestsRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default async function runBlockchainTest(options: any, testData: any, t:
state,
blockchain,
common,
selectHardforkByBlockNumber: false,
})

// set up pre-state
Expand Down
62 changes: 62 additions & 0 deletions packages/vm/tests/api/runBlock.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DefaultStateManager } from '../../lib/state'
import runBlock from '../../lib/runBlock'
import { setupPreConditions, getDAOCommon } from '../util'
import { setupVM, createAccount } from './utils'
import VM from '../../lib/index'

const testData = require('./testdata.json')

Expand Down Expand Up @@ -110,6 +111,67 @@ tape('should fail when tx gas limit higher than block gas limit', async (t) => {
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)
Expand Down
5 changes: 4 additions & 1 deletion packages/vm/tests/api/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ export function setupVM(opts: VMOpts & { genesisBlock?: Block } = {}) {
genesisBlock,
})
}
return new VM(opts)
return new VM({
selectHardforkByBlockNumber: false,
...opts,
})
}

0 comments on commit 93b476e

Please sign in to comment.