Skip to content

Update EIP-7907: Reduce code limit, increase cost per word, fix EXTCODESIZE issue #9910

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
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lightclient
Copy link
Member

@lightclient lightclient commented Jun 19, 2025

Updating with a few things we discussed at interop:

  • 48kb limit for contract code size
  • 96kb limit for initcode size
  • increase the cost per word to align with current cost of 24kb code at 2600 gas -> ceil(2600 / (24676//32)) = 4
  • charge for additional db load during of code size index during EXTCODESIZE

@lightclient lightclient requested a review from eth-bot as a code owner June 19, 2025 13:18
@github-actions github-actions bot added c-update Modifies an existing proposal s-draft This EIP is a Draft t-core labels Jun 19, 2025
@eth-bot
Copy link
Collaborator

eth-bot commented Jun 19, 2025

File EIPS/eip-7907.md

Requires 1 more reviewers from @charles-cooper, @qizhou

@eth-bot eth-bot added the a-review Waiting on author to review label Jun 19, 2025
@eth-bot eth-bot changed the title Reduce code limit, increase cost per word, fix EXTCODESIZE issue Update EIP-7907: Reduce code limit, increase cost per word, fix EXTCODESIZE issue Jun 19, 2025
Copy link

The commit d082da4 (as a parent of b037684) contains errors.
Please inspect the Run Summary for details.


## Rationale

The gas cost of 2 per word was chosen in-line with [EIP-3860](./eip-3860.md). This accounts for:
The gas cost of 4 per word was chosen in-line with the per word code defined by [EIP-2929](./eip-2929.md)'s `COLD_ACCOUNT_ACCESS_COST. The value is derived from the current gas per word code of `ceil(2600 / (24676//32)) = 4` where `2600` is the current cold account load cost and `24676` is the maximum allow code size at that price. In general, this accounts for:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should reuse 2600 in the excess gas calculation. One thought is whether the excess gas should include the cost of reading account from MPT.

The original 2600 gas accounts for:

  • cost for reading the account from MPT
  • cost for reading the code via codehash (from account)
  • jump analysis, memory, etc

When reading a large contract, since the first 2600 already covers the cost of reading the account, should the excess gas include the cost of reading the account or not? It is not, the 2600 per extra 24KB (or 3072 of 24KB using 4 gas per word) may be too conservative? (But I am fine if such a conservative design is intended.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is hard to say conclusively. This I err on the side of caution until we have empirical data to guide us. At a 3072 per additional 24KB, it should be pretty close to parity when you consider the overhead of preparing calls to other contracts in something like diamond standard.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the marginal per-word cost of loading data should be lower than the initial 2600 gas per 24kb (which works out to about 3.38 gas per word). i am under the impression that a more comprehensive gas tuning across all opcodes is being prepared. but it still feels weird to price the marginal cost per word over the cost per-word of the initial 24kb, since it's a sequential load and no additional db access needs to be done. if 2 gas per word is considered too cheap, maybe 3 gas per word is better?

2. Change the gas schedule for opcodes which load code. Specifically, the opcodes `CALL`, `STATICCALL`, `DELEGATECALL`, `CALLCODE` and `EXTCODECOPY` are modified so that `largeContractCost = ceil32(excess_contract_size) * GAS_INIT_CODE_WORD_COST // 32` gas is added to the access cost if the code is cold, where `excess_contract_size = max(0, contract_size - 0x6000)`, and `GAS_INIT_CODE_WORD_COST = 2`. (Cf. initcode metering: [EELS](https://github.com/ethereum/execution-specs/blob/1a587803e3e698407d204888b02342393f8b4fe5/src/ethereum/cancun/vm/gas.py#L269)). This introduces a new warm state for contract code - warm if the code has been loaded, cold if not.
1. Update the [EIP-170](./eip-170.md) contract code size limit of 24KB (`0x6000` bytes) to 48KB (`0xc000` bytes).
2. Change the gas schedule for opcodes which load code. Specifically, the opcodes `CALL`, `STATICCALL`, `DELEGATECALL`, `CALLCODE` and `EXTCODECOPY` are modified so that `largeContractCost = ceil32(excess_contract_size) * GAS_CODE_LOAD_WORD_COST // 32` gas is added to the access cost if the code is cold, where `excess_contract_size = max(0, contract_size - 0x6000)`, and `GAS_CODE_LOAD_WORD_COST = 4`. (Cf. initcode metering: [EELS](https://github.com/ethereum/execution-specs/blob/1a587803e3e698407d204888b02342393f8b4fe5/src/ethereum/cancun/vm/gas.py#L269)). This introduces a new warm state for contract code - warm if the code has been loaded, cold if not.
3. The cost for `EXTCODESIZE` is updated to acknowlege the potential for two database reads: once for the code hash and once for the code size associated with the code hash.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would EXTCODESIZE charge exactly? I may miss the info somewhere.

@leeederek
Copy link

Hey there, I'm Derek from Offchain Labs. Speaking on behalf of Arbitrum teams and developers, we'd very much like to see the original 256 KiB max contract size code rather than the proposed reduction to 48 KiB here in this PR. Devnet-02 will have the original specification and I'd be curious to know what numbers/metrics we're looking for to make the call for reducing the max contract size from 256 KiB to 48 KiB (or other value). Thanks!

Copy link
Member

@jochem-brouwer jochem-brouwer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR. It seems upon a first read that we now have 3 categories of "warm";

  • Cold/warm account
  • Cold/warm extcodesize
  • Cold/warm code

Is this correct? When do these get warm? What about current account warming (coinbase, precompiles, sender account, target account, 7702-delegated account (if targeted by tx))? I think this should be specified to self-contain the EIP.

1. Update the [EIP-170](./eip-170.md) contract code size limit of 24KB (`0x6000` bytes) to 48KB (`0xc000` bytes).
2. Change the gas schedule for opcodes which load code. Specifically, the opcodes `CALL`, `STATICCALL`, `DELEGATECALL`, `CALLCODE` and `EXTCODECOPY` are modified so that `largeContractCost = ceil32(excess_contract_size) * GAS_CODE_LOAD_WORD_COST // 32` gas is added to the access cost if the code is cold, where `excess_contract_size = max(0, contract_size - 0x6000)`, and `GAS_CODE_LOAD_WORD_COST = 4`. (Cf. initcode metering: [EELS](https://github.com/ethereum/execution-specs/blob/1a587803e3e698407d204888b02342393f8b4fe5/src/ethereum/cancun/vm/gas.py#L269)). This introduces a new warm state for contract code - warm if the code has been loaded, cold if not.
3. The cost for `EXTCODESIZE` is updated to acknowlege the potential for two database reads: once for the code hash and once for the code size associated with the code hash.
with the hash. In addition to the current pricing scheme defined under [EIP-2929](./eip-2929.md), the instruction will also be subject to regular storage pricing, e.g. `COLD_SLOAD_COST` and `WARM_SLOAD_COST`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does querying EXTCODESIZE make the account "code-warm", or is this another category? (warm account, warm code, warm extcodesize (?))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it would make the account warm and code size for the account warm, but leave the code cold.

@jochem-brouwer
Copy link
Member

Can further specifications be added to the EIP:

  • Can it be specified what warm code is present at the start of the transaction? I would assume that everything which is marked as "warm" in the current situation now is a "warm account" (but not warm code). The exception is the to field of the transaction, this has warm code. This also means that if the target is 7702-delegated, it means that the account it is delegated to (so the 0xef0100 || address -> the address) also has warm code.
  • 7702 reads code from trie (this is a potential DoS vector, but this assumes that we have the pkey of a smart contract, which is practically not possible). Should it be added that 7702-authorizations thus also warm the code of the target?
  • I think 7702 situations should be made explicit here: If an address is called which is 7702-delegated to address A then costs should be charged and A should be put into code warm list (just like the address which is 7702 delegated)
  • EXTCODECOPY on a 7702-delegated address should not warm code of what it is delegated to
  • What about call frames reverting/invalidating? This would also mark any address which got marked "warm code" here cold, just like 2929? (I think it would be helpful to specify this also).
  • Maybe too explicit but after each transaction the warm code addresses are now cold again (just like how 2929-accesses are now cold again)

@zerosnacks
Copy link
Contributor

zerosnacks commented Jun 20, 2025

Hi @lightclient, would you mind summarizing the concerns / blockers that caused the decision to reduce the contract size limit increase to 48KB bytecode / 96KB initcode?

As an outsider I have a hard time following from ACDE + chat logs what the exact blockers are and whether there is still a pathway to 256KB after opcode repricing / gas limit increase.

Thanks!

@marioevz
Copy link
Member

* Can it be specified what warm code is present at the start of the transaction? I would assume that everything which is marked as "warm" in the current situation now is a "warm account" (but not warm code). The exception is the `to` field of the transaction, this has warm code. This also means that if the target is 7702-delegated, it means that the account it is delegated to (so the `0xef0100 || address` -> the address) also has warm code.

Echo this point by @jochem-brouwer. Current tests expect the code to be warm for the to address of the transaction currently executing, but I think this is a current undespecification of the EIP, and should be explicitly stated somewhere.

@charles-cooper
Copy link
Contributor

* Can it be specified what warm code is present at the start of the transaction? I would assume that everything which is marked as "warm" in the current situation now is a "warm account" (but not warm code). The exception is the `to` field of the transaction, this has warm code. This also means that if the target is 7702-delegated, it means that the account it is delegated to (so the `0xef0100 || address` -> the address) also has warm code.

Echo this point by @jochem-brouwer. Current tests expect the code to be warm for the to address of the transaction currently executing, but I think this is a current undespecification of the EIP, and should be explicitly stated somewhere.

i think that tx.to is actually cold at the beginning of the transaction. otherwise there is a DoS vector, the initial 21000 gas may not fairly pay for loading of the code at tx.to if it is very large.

@charles-cooper
Copy link
Contributor

What about call frames reverting/invalidating? This would also mark any address which got marked "warm code" here cold, just like 2929? (I think it would be helpful to specify this also).

i think the implementation is cleaner if there is no interaction between the revert journal and the warm code list (i.e., reverts do not clean the warm code list). but if it's better to keep consistency with 2929, that's fine - maybe ACDE should vote here or something.

@rakita
Copy link
Contributor

rakita commented Jun 23, 2025

to should be marked warm as it is loaded when the transaction starts (currently it is left as cold), but the question is, should we account a fee for this loading (currently this is not added) or is it initial gas enough to cover it( Napkin math: (49152-24000)/32*4=3144 3k is max additional gas for 48KiB contract). Maybe it is fine not to account for this.

On another topic, not journaling code warming looks okay to do.

@marioevz
Copy link
Member

to should be marked warm as it is loaded when the transaction starts (currently it is left as cold), but the question is, should we account a fee for this loading (currently this is not added) or is it initial gas enough to cover it( Napkin math: (49152-24000)/32*4=3144 3k is max additional gas for 48KiB contract). Maybe it is fine not to account for this.

On another topic, not journaling code warming looks okay to do.

It feels to me like we should charge this, otherwise it won't scale I think.

What about charging it at the start of the transaction execution, and failing with OOG before executing any code if the starting gas is not enough to cover this large-contract extra cost?

@rakita
Copy link
Contributor

rakita commented Jun 23, 2025

It feels to me like we should charge this, otherwise it won't scale I think.

True, we should probably introduce the fee.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a-review Waiting on author to review c-update Modifies an existing proposal s-draft This EIP is a Draft t-core w-ci Waiting on CI to pass
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants