Skip to content

Commit 4ff89e8

Browse files
authored
vm: add guard for EIP-3607 (#1691)
* add guard for EIP-3607 and tests * 3607: update minimumHardfork to chainstart, since older HFs were added (see https://github.com/ethereum/tests/blob/develop/GeneralStateTests/stEIP3607/transactionCollidingWithNonEmptyAccount_calls.json#L114) * enable EIP-3607 for blockchain tests to pass ethereum/tests * organize lines * fix comment typos * simplify stripping hex prefix from testData.lastbockhash (uses `isHexPrefixed` which should be faster than `subtr(0, 2)`)
1 parent 3d9a181 commit 4ff89e8

File tree

9 files changed

+94
-26
lines changed

9 files changed

+94
-26
lines changed

packages/common/src/eips/3607.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "EIP-3607",
3+
"number": 3607,
4+
"comment": "Reject transactions from senders with deployed code",
5+
"url": "https://eips.ethereum.org/EIPS/eip-3607",
6+
"status": "Draft",
7+
"minimumHardfork": "chainstart",
8+
"requiredEIPs": [],
9+
"gasConfig": {},
10+
"gasPrices": {},
11+
"vm": {},
12+
"pow": {}
13+
}

packages/common/src/eips/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const EIPs: eipsType = {
1212
3529: require('./3529.json'),
1313
3541: require('./3541.json'),
1414
3554: require('./3554.json'),
15+
3607: require('./3607.json'),
1516
3675: require('./3675.json'),
1617
3855: require('./3855.json'),
1718
4345: require('./4345.json'),

packages/vm/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ export default class VM extends AsyncEventEmitter {
194194
}
195195

196196
if (opts.common) {
197-
//EIPs
198-
const supportedEIPs = [1559, 2315, 2537, 2565, 2718, 2929, 2930, 3198, 3529, 3541, 3855]
197+
// Supported EIPs
198+
const supportedEIPs = [1559, 2315, 2537, 2565, 2718, 2929, 2930, 3198, 3529, 3541, 3607, 3855]
199199
for (const eip of opts.common.eips()) {
200200
if (!supportedEIPs.includes(eip)) {
201-
throw new Error(`${eip} is not supported by the VM`)
201+
throw new Error(`EIP-${eip} is not supported by the VM`)
202202
}
203203
}
204204

packages/vm/src/runTx.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,18 @@ async function _runTx(this: VM, opts: RunTxOpts): Promise<RunTxResult> {
303303
const { nonce, balance } = fromAccount
304304

305305
// EIP-3607: Reject transactions from senders with deployed code
306-
if (!fromAccount.codeHash.equals(KECCAK256_NULL)) {
307-
const msg = _errorMsg('invalid sender address, address is not EOA (EIP-3607)', this, block, tx)
308-
throw new Error(msg)
306+
if (this._common.isActivatedEIP(3607)) {
307+
if (!fromAccount.codeHash.equals(KECCAK256_NULL)) {
308+
const msg = _errorMsg(
309+
'invalid sender address, address is not EOA (EIP-3607)',
310+
this,
311+
block,
312+
tx
313+
)
314+
throw new Error(msg)
315+
}
309316
}
317+
310318
if (!opts.skipBalance) {
311319
const cost = tx.getUpfrontCost(block.header.baseFeePerGas)
312320
if (balance.lt(cost)) {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import tape from 'tape'
2+
import Common, { Chain, Hardfork } from '@ethereumjs/common'
3+
import { Transaction } from '@ethereumjs/tx'
4+
import { Address } from 'ethereumjs-util'
5+
import VM from '../../../src'
6+
7+
tape('EIP-3607 tests', (t) => {
8+
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Berlin, eips: [3607] })
9+
const commonNoEIP3607 = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Berlin, eips: [] })
10+
const precompileAddr = Address.fromString('0x0000000000000000000000000000000000000001')
11+
12+
t.test('should reject txs from senders with deployed code when EIP is enabled', async (st) => {
13+
const vm = new VM({ common })
14+
await vm.stateManager.putContractCode(precompileAddr, Buffer.alloc(32, 1))
15+
const tx = Transaction.fromTxData({ gasLimit: 100000 }, { freeze: false })
16+
tx.getSenderAddress = () => precompileAddr
17+
try {
18+
await vm.runTx({ tx })
19+
st.fail('runTx should have thrown')
20+
} catch (error: any) {
21+
if (error.message.includes('EIP-3607')) {
22+
st.pass('threw correct error')
23+
} else {
24+
st.fail('did not throw correct error')
25+
}
26+
}
27+
st.end()
28+
})
29+
30+
t.test(
31+
'should not reject txs from senders with deployed code when EIP is not enabled',
32+
async (st) => {
33+
const vm = new VM({ common: commonNoEIP3607 })
34+
await vm.stateManager.putContractCode(precompileAddr, Buffer.alloc(32, 1))
35+
const tx = Transaction.fromTxData({ gasLimit: 100000 }, { freeze: false })
36+
tx.getSenderAddress = () => precompileAddr
37+
try {
38+
await vm.runTx({ tx })
39+
st.ok('runTx successfully ran')
40+
} catch (error: any) {
41+
st.fail('threw an unexpected error')
42+
}
43+
st.end()
44+
}
45+
)
46+
})

packages/vm/tests/tester/config.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ export const SKIP_BROKEN = [
2929
* Tests skipped due to system specifics / design considerations
3030
*/
3131
export const SKIP_PERMANENT = [
32-
'SuicidesMixingCoinbase', // sucides to the coinbase, since we run a blockLevel we create coinbase account.
33-
'static_SuicidesMixingCoinbase', // sucides to the coinbase, since we run a blockLevel we create coinbase account.
34-
'ForkUncle', // Only BlockchainTest, correct behaviour unspecified (?)
35-
'UncleFromSideChain', // Only BlockchainTest, same as ForkUncle, the TD is the same for two diffent branches so its not clear which one should be the finally chain
32+
'SuicidesMixingCoinbase', // suicides to the coinbase, since we run a blockLevel we create coinbase account.
33+
'static_SuicidesMixingCoinbase', // suicides to the coinbase, since we run a blockLevel we create coinbase account.
34+
'ForkUncle', // Only BlockchainTest, correct behavior unspecified (?)
35+
'UncleFromSideChain', // Only BlockchainTest, same as ForkUncle, the TD is the same for two different branches so its not clear which one should be the finally chain
3636
]
3737

3838
/**
@@ -298,10 +298,13 @@ export function getCommon(targetNetwork: string) {
298298
})
299299
}
300300
}
301-
const common = Common.custom({
302-
hardforks: testHardforks,
303-
defaultHardfork: hfName,
304-
})
301+
const common = Common.custom(
302+
{
303+
hardforks: testHardforks,
304+
defaultHardfork: hfName,
305+
},
306+
{ eips: [3607] }
307+
)
305308
const eips = targetNetwork.match(/(?<=\+)(.\d+)/g)
306309
if (eips) {
307310
common.setEIPs(eips.map((e: string) => parseInt(e)))

packages/vm/tests/tester/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ import blockchainTestsRunner from './runners/BlockchainTestsRunner'
2222
* --state: run state tests
2323
* --blockchain: run blockchain tests
2424
* --fork: fork to use for these tests
25-
* --skip: comma seperated list of tests to skip. choices of: all,broken,permanent,slow. Defaults to all
26-
* --runSkipped: comma seperated list of tests to skip if --skip is not set. choices of: all,broken,permanent,slow. Defaults to none
25+
* --skip: comma-separated list of tests to skip. choices of: all,broken,permanent,slow. Defaults to all
26+
* --runSkipped: comma-separated list of tests to skip if --skip is not set. choices of: all,broken,permanent,slow. Defaults to none
2727
* --file: test file to run
2828
* --test: test name to run
2929
* --dir: test directory to look for tests
30-
* --excludeDir: test directory to exlude from testing
30+
* --excludeDir: test directory to exclude from testing
3131
* --testsPath: root directory of tests to look (default: '../ethereum-tests')
3232
* --customTestsPath: custom directory to look for tests (e.g. '../../my_custom_test_folder')
3333
* --customStateTest: run a file with a custom state test (not in test directory)

packages/vm/tests/tester/runners/BlockchainTestsRunner.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Block } from '@ethereumjs/block'
33
import Blockchain from '@ethereumjs/blockchain'
44
import Common, { ConsensusAlgorithm } from '@ethereumjs/common'
55
import { TransactionFactory } from '@ethereumjs/tx'
6-
import { addHexPrefix, BN, toBuffer, rlp } from 'ethereumjs-util'
6+
import { addHexPrefix, BN, toBuffer, rlp, stripHexPrefix } from 'ethereumjs-util'
77
import { SecureTrie as Trie } from 'merkle-patricia-tree'
88
import { setupPreConditions, verifyPostConditions } from '../../util'
99

@@ -17,10 +17,8 @@ export default async function runBlockchainTest(options: any, testData: any, t:
1717
return
1818
}
1919

20-
if (testData.lastblockhash.substr(0, 2) === '0x') {
21-
// fix for BlockchainTests/GeneralStateTests/stRandom/*
22-
testData.lastblockhash = testData.lastblockhash.substr(2)
23-
}
20+
// fix for BlockchainTests/GeneralStateTests/stRandom/*
21+
testData.lastblockhash = stripHexPrefix(testData.lastblockhash)
2422

2523
const blockchainDB = levelMem()
2624
const cacheDB = level('./.cachedb')

packages/vm/tests/tester/runners/GeneralStateTestsRunner.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,12 @@ async function runTestCase(options: any, testData: any, t: tape.Test) {
6767
VM = require('../../../src').default
6868
}
6969
const begin = Date.now()
70-
const state = new Trie()
71-
const hardfork = options.forkConfigVM
72-
73-
const eips: number[] = []
7470

71+
const hardfork = options.forkConfigVM
72+
const eips: number[] = [3607]
7573
const common = new Common({ chain: Chain.Mainnet, hardfork, eips })
7674

75+
const state = new Trie()
7776
const vm = new VM({ state, common })
7877

7978
await setupPreConditions(vm.stateManager._trie, testData)

0 commit comments

Comments
 (0)