-
Notifications
You must be signed in to change notification settings - Fork 827
evm: add eip-7907 to osaka (wip) #4052
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
Open
jgresham
wants to merge
7
commits into
ethereumjs:master
Choose a base branch
from
jgresham:evm/eip-7907-max-code-size
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
256b107
evm: add eip-7907 to osaka (wip)
jgresham 9932bfd
3860 active implies common.isActivatedEIP 7907
jgresham c5bb893
add excess code size gas for cold access
jgresham d2011c6
eip7907: add warm code address set to journal and opcodes/eip7907
jgresham 963bbbe
fix 7907: warm newly created contract from factory with test
jgresham a8940ab
revert warm newly created contract from CREATE. new tests at maxInitC…
jgresham 6e73e70
minor cleanup EIP7907.ts and add param to tx/src/params
jgresham File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
import { Common, Hardfork, Mainnet } from '@ethereumjs/common' | ||
import { | ||
Address, | ||
concatBytes, | ||
// createAddressFromString, | ||
// equalsBytes, | ||
hexToBytes, | ||
privateToAddress, | ||
} from '@ethereumjs/util' | ||
import { assert, describe, it } from 'vitest' | ||
|
||
import { createEVM } from '../../src/index.ts' | ||
|
||
const pkey = hexToBytes(`0x${'20'.repeat(32)}`) | ||
const sender = new Address(privateToAddress(pkey)) | ||
|
||
describe('EIP 7907 initcode size tests', () => { | ||
it('code 512KB exceeds max initcode size', async () => { | ||
const common = new Common({ | ||
chain: Mainnet, | ||
hardfork: Hardfork.Osaka, | ||
eips: [7907], | ||
}) | ||
const evm = await createEVM({ | ||
common, | ||
}) | ||
|
||
// 524,288 (512KB) length, 8 bit array, filled | ||
const buffer = new Uint8Array(524288).fill(0x60) | ||
|
||
// setup the call arguments | ||
const runCallArgs = { | ||
sender, // call address | ||
gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas | ||
// Simple test, PUSH <big number> PUSH 0 RETURN | ||
// It tries to deploy a contract too large, where the code is all zeros | ||
// (since memory which is not allocated/resized to yet is always defaulted to 0) | ||
data: concatBytes( | ||
hexToBytes( | ||
'0x7F6000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060005260206000F3', | ||
), | ||
buffer, | ||
), | ||
} | ||
const result = await evm.runCall(runCallArgs) | ||
assert.isTrue( | ||
(result.execResult.exceptionError?.error as string) === 'initcode exceeds max initcode size', | ||
'initcode exceeds max size', | ||
) | ||
}) | ||
|
||
it('code 512KB - 100 bytes does not exceed max initcode size', async () => { | ||
const common = new Common({ | ||
chain: Mainnet, | ||
hardfork: Hardfork.Osaka, | ||
eips: [7907], | ||
}) | ||
const evm = await createEVM({ | ||
common, | ||
}) | ||
|
||
// 524288 - 100("512K-100") length, 8 bit array, filled | ||
const buffer = new Uint8Array(524188).fill(0x60) | ||
|
||
// setup the call arguments | ||
const runCallArgs = { | ||
sender, // call address | ||
gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas | ||
// Simple test, PUSH <big number> PUSH 0 RETURN | ||
// It tries to deploy a contract too large, where the code is all zeros | ||
// (since memory which is not allocated/resized to yet is always defaulted to 0) | ||
data: concatBytes( | ||
hexToBytes( | ||
'0x7F6000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060005260206000F3', | ||
), | ||
buffer, | ||
), | ||
} | ||
const result = await evm.runCall(runCallArgs) | ||
assert.isTrue( | ||
result.execResult.exceptionError === undefined, | ||
'successfully created a contract with data size 250KB (> 24KB and < 256KB)', | ||
) | ||
}) | ||
|
||
// it('ensure EIP-7907 gas is applied on CREATE calls', async () => { | ||
// // Transaction/Contract data taken from https://github.com/ethereum/tests/pull/990 | ||
// const commonWith7907 = new Common({ | ||
// chain: Mainnet, | ||
// hardfork: Hardfork.Osaka, | ||
// eips: [7907], | ||
// }) | ||
// const commonWithout7907 = new Common({ | ||
// chain: Mainnet, | ||
// hardfork: Hardfork.Osaka, | ||
// eips: [], | ||
// }) | ||
// const caller = createAddressFromString('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b') | ||
// const evm = await createEVM({ | ||
// common: commonWith7907, | ||
// }) | ||
// const evmWithout7907 = await createEVM({ | ||
// common: commonWithout7907, | ||
// }) | ||
// const contractFactory = createAddressFromString('0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b') | ||
// const contractAccount = await evm.stateManager.getAccount(contractFactory) | ||
// await evm.stateManager.putAccount(contractFactory, contractAccount!) | ||
// await evmWithout7907.stateManager.putAccount(contractFactory, contractAccount!) | ||
// const factoryCode = hexToBytes( | ||
// '0x7f600a80600080396000f3000000000000000000000000000000000000000000006000526000355a8160006000f05a8203600a55806000556001600155505050', | ||
// ) | ||
|
||
// await evm.stateManager.putCode(contractFactory, factoryCode) | ||
// await evmWithout7907.stateManager.putCode(contractFactory, factoryCode) | ||
// const data = hexToBytes('0x000000000000000000000000000000000000000000000000000000000000c000') | ||
// const runCallArgs = { | ||
// from: caller, | ||
// to: contractFactory, | ||
// data, | ||
// gasLimit: BigInt(0xfffffffff), | ||
// } | ||
// const res = await evm.runCall(runCallArgs) | ||
// const res2 = await evmWithout7907.runCall(runCallArgs) | ||
// assert.isTrue( | ||
// res.execResult.executionGasUsed > res2.execResult.executionGasUsed, | ||
// 'execution gas used is higher with EIP 7907 active', | ||
// ) | ||
// }) | ||
|
||
// it('ensure EIP-7907 gas is applied on CREATE2 calls', async () => { | ||
// // Transaction/Contract data taken from https://github.com/ethereum/tests/pull/990 | ||
// const commonWith7907 = new Common({ | ||
// chain: Mainnet, | ||
// hardfork: Hardfork.Osaka, | ||
// eips: [7907], | ||
// }) | ||
// const commonWithout7907 = new Common({ | ||
// chain: Mainnet, | ||
// hardfork: Hardfork.Osaka, | ||
// eips: [], | ||
// }) | ||
// const caller = createAddressFromString('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b') | ||
// const evm = await createEVM({ | ||
// common: commonWith7907, | ||
// }) | ||
// const evmWithout7907 = await createEVM({ | ||
// common: commonWithout7907, | ||
// }) | ||
// const contractFactory = createAddressFromString('0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b') | ||
// const contractAccount = await evm.stateManager.getAccount(contractFactory) | ||
// await evm.stateManager.putAccount(contractFactory, contractAccount!) | ||
// await evmWithout7907.stateManager.putAccount(contractFactory, contractAccount!) | ||
// const factoryCode = hexToBytes( | ||
// '0x7f600a80600080396000f3000000000000000000000000000000000000000000006000526000355a60008260006000f55a8203600a55806000556001600155505050', | ||
// ) | ||
|
||
// await evm.stateManager.putCode(contractFactory, factoryCode) | ||
// await evmWithout7907.stateManager.putCode(contractFactory, factoryCode) | ||
// const data = hexToBytes('0x000000000000000000000000000000000000000000000000000000000000c000') | ||
// const runCallArgs = { | ||
// from: caller, | ||
// to: contractFactory, | ||
// data, | ||
// gasLimit: BigInt(0xfffffffff), | ||
// } | ||
// const res = await evm.runCall(runCallArgs) | ||
// const res2 = await evmWithout7907.runCall(runCallArgs) | ||
// assert.isTrue( | ||
// res.execResult.executionGasUsed > res2.execResult.executionGasUsed, | ||
// 'execution gas used is higher with EIP 7907 active', | ||
// ) | ||
// }) | ||
|
||
it('code exceeds max initcode size: allowUnlimitedInitCodeSize active', async () => { | ||
const common = new Common({ | ||
chain: Mainnet, | ||
hardfork: Hardfork.Osaka, | ||
eips: [7907], | ||
}) | ||
const evm = await createEVM({ | ||
common, | ||
allowUnlimitedInitCodeSize: true, | ||
}) | ||
|
||
const bytes = new Uint8Array(1000000).fill(0x60) | ||
|
||
// setup the call arguments | ||
const runCallArgs = { | ||
sender, // call address | ||
gasLimit: BigInt(0xffffffffff), // ensure we pass a lot of gas, so we do not run out of gas | ||
// Simple test, PUSH <big number> PUSH 0 RETURN | ||
// It tries to deploy a contract too large, where the code is all zeros | ||
// (since memory which is not allocated/resized to yet is always defaulted to 0) | ||
data: concatBytes( | ||
hexToBytes(`0x${'00'.repeat(Number(common.param('maxInitCodeSize')) + 1)}`), | ||
bytes, | ||
), | ||
} | ||
const result = await evm.runCall(runCallArgs) | ||
assert.isTrue( | ||
result.execResult.exceptionError === undefined, | ||
'successfully created a contract with data size > MAX_INITCODE_SIZE and allowUnlimitedInitCodeSize active', | ||
) | ||
}) | ||
|
||
// it('CREATE with MAX_INITCODE_SIZE+1, allowUnlimitedContractSize active', async () => { | ||
// const commonWith7907 = new Common({ | ||
// chain: Mainnet, | ||
// hardfork: Hardfork.Osaka, | ||
// eips: [7907], | ||
// }) | ||
// const caller = createAddressFromString('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b') | ||
// for (const code of ['F0', 'F5']) { | ||
// const evm = await createEVM({ | ||
// common: commonWith7907, | ||
|
||
// allowUnlimitedInitCodeSize: true, | ||
// }) | ||
// const evmDisabled = await createEVM({ | ||
// common: commonWith7907, | ||
// allowUnlimitedInitCodeSize: false, | ||
// }) | ||
// const contractFactory = createAddressFromString('0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b') | ||
// const contractAccount = await evm.stateManager.getAccount(contractFactory) | ||
// await evm.stateManager.putAccount(contractFactory, contractAccount!) | ||
// await evmDisabled.stateManager.putAccount(contractFactory, contractAccount!) | ||
// // This factory code: | ||
// // -> reads 32 bytes from the calldata (X) | ||
// // Attempts to create a contract of X size | ||
// // (the initcode of this contract is just zeros, so STOP opcode | ||
// // It stores the topmost stack item of this CREATE(2) at slot 0 | ||
// // This is either the contract address if it was successful, or 0 in case of error | ||
// const factoryCode = hexToBytes(`0x600060003560006000${code}600055`) | ||
|
||
// await evm.stateManager.putCode(contractFactory, factoryCode) | ||
// await evmDisabled.stateManager.putCode(contractFactory, factoryCode) | ||
|
||
// const runCallArgs = { | ||
// from: caller, | ||
// to: contractFactory, | ||
// gasLimit: BigInt(0xfffffffff), | ||
// data: hexToBytes(`0x${'00'.repeat(30)}C001`), | ||
// } | ||
|
||
// const res = await evm.runCall(runCallArgs) | ||
// await evmDisabled.runCall(runCallArgs) | ||
|
||
// const key0 = hexToBytes(`0x${'00'.repeat(32)}`) | ||
// const storageActive = await evm.stateManager.getStorage(contractFactory, key0) | ||
// const storageInactive = await evmDisabled.stateManager.getStorage(contractFactory, key0) | ||
|
||
// assert.isTrue( | ||
// !equalsBytes(storageActive, new Uint8Array()), | ||
// 'created contract with MAX_INITCODE_SIZE + 1 length, allowUnlimitedInitCodeSize=true', | ||
// ) | ||
// assert.isTrue( | ||
// equalsBytes(storageInactive, new Uint8Array()), | ||
// 'did not create contract with MAX_INITCODE_SIZE + 1 length, allowUnlimitedInitCodeSize=false', | ||
// ) | ||
|
||
// // gas check | ||
|
||
// const runCallArgs2 = { | ||
// from: caller, | ||
// to: contractFactory, | ||
// gasLimit: BigInt(0xfffffffff), | ||
// data: hexToBytes(`0x${'00'.repeat(30)}C000`), | ||
// } | ||
|
||
// // Test: | ||
// // On the `allowUnlimitedInitCodeSize = true`, create contract with MAX_INITCODE_SIZE + 1 | ||
// // On `allowUnlimitedInitCodeSize = false`, create contract with MAX_INITCODE_SIZE | ||
// // Verify that the gas cost on the prior one is higher than the first one | ||
// const res2 = await evmDisabled.runCall(runCallArgs2) | ||
|
||
// assert.isTrue( | ||
// res.execResult.executionGasUsed > res2.execResult.executionGasUsed, | ||
// 'charged initcode analysis gas cost on both allowUnlimitedCodeSize=true, allowUnlimitedInitCodeSize=false', | ||
// ) | ||
// } | ||
// }) | ||
}) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.