diff --git a/lib/evm/eei.ts b/lib/evm/eei.ts index 6158338235c..e0000e9d3fc 100644 --- a/lib/evm/eei.ts +++ b/lib/evm/eei.ts @@ -262,6 +262,14 @@ export default class EEI { return new BN(this._env.block.header.gasLimit) } + /** + * Returns the chain ID for current chain. Introduced for the + * CHAINID opcode proposed in [EIP-1344](https://eips.ethereum.org/EIPS/eip-1344). + */ + getChainId(): BN { + return new BN(this._common.chainId()) + } + /** * Returns Gets the hash of one of the 256 most recent complete blocks. * @param num - Number of block diff --git a/lib/evm/opFns.ts b/lib/evm/opFns.ts index 3b2b66c8374..043d685b078 100644 --- a/lib/evm/opFns.ts +++ b/lib/evm/opFns.ts @@ -456,6 +456,13 @@ export const handlers: { [k: string]: OpHandler } = { GASLIMIT: function(runState: RunState) { runState.stack.push(runState.eei.getBlockGasLimit()) }, + CHAINID: function(runState: RunState) { + if (!runState._common.gteHardfork('istanbul')) { + trap(ERROR.INVALID_OPCODE) + } + + runState.stack.push(runState.eei.getChainId()) + }, // 0x50 range - 'storage' and execution POP: function(runState: RunState) { runState.stack.pop() diff --git a/lib/evm/opcodes.ts b/lib/evm/opcodes.ts index 5ac48a89210..f2071d960bd 100644 --- a/lib/evm/opcodes.ts +++ b/lib/evm/opcodes.ts @@ -66,6 +66,7 @@ const codes: any = { 0x43: ['NUMBER', 2, true], 0x44: ['DIFFICULTY', 2, true], 0x45: ['GASLIMIT', 2, true], + 0x46: ['CHAINID', 2, false], // 0x50 range - 'storage' and execution 0x50: ['POP', 2, false], diff --git a/tests/api/istanbul/eip-1344.js b/tests/api/istanbul/eip-1344.js new file mode 100644 index 00000000000..a5209d3c78c --- /dev/null +++ b/tests/api/istanbul/eip-1344.js @@ -0,0 +1,38 @@ +const tape = require('tape') +const BN = require('bn.js') +const Common = require('ethereumjs-common').default +const VM = require('../../../dist/index').default +const { ERROR } = require('../../../dist/exceptions') + +const testCases = [ + { chain: 'mainnet', hardfork: 'istanbul', chainId: new BN(1) }, + { chain: 'mainnet', hardfork: 'constantinople', err: ERROR.INVALID_OPCODE }, + { chain: 'ropsten', hardfork: 'istanbul', chainId: new BN(3) } +] + +// CHAINID PUSH8 0x00 MSTORE8 PUSH8 0x01 PUSH8 0x00 RETURN +const code = ['46', '60', '00', '53', '60', '01', '60', '00', 'f3'] +tape('Istanbul: EIP-1344 CHAINID', async (t) => { + const runCodeArgs = { + code: Buffer.from(code.join(''), 'hex'), + gasLimit: new BN(0xffff) + } + + for (const testCase of testCases) { + const common = new Common(testCase.chain, testCase.hardfork) + const vm = new VM({ common }) + try { + const res = await vm.runCode(runCodeArgs) + if (testCase.err) { + t.equal(res.exceptionError.error, testCase.err) + } else { + t.assert(res.exceptionError === undefined) + t.assert(testCase.chainId.eq(new BN(res.returnValue))) + } + } catch (e) { + t.fail(e.message) + } + } + + t.end() +})