EIP-7686: Linear EVM memory limits

Add a hard memory limit equal to the gas limit of the current context. Make the maximum gas cost of a sub-call depend on the memory used in the current context. The two rules together ensure that a transaction with N gas can use at most N bytes of memory.

3 Likes

Consider the quine program:

CODECOPY(0,0,CODESIZE)
RETURN(0,CODESIZE)

This program would normally need 32 bytes of memory to return seven bytes of data because MSIZE increases by word, but it only needs 19 gas to execute. So your change will require 32 gas provided but only needs 19. It is cases like this that demonstrate that this limit harms small memory users not large ones.

Concerns about memory abuse are already addressed by the quadratic term. There does not need to be an additional limit.
Edit: This EIP actually removes the quadratic term which is nice.

1 Like

I am glad to see this EIP to improve the EVM memory limit. This is very helpful in ERC-4804 which turns EVM into a decentralized HTTP server - the EVM can process much larger HTTP request/response with the increased memory limit.

One security concern is the potential out-of-memory (OOM) attack using eth_call JSON-RPC - e.g., Infura allows eth_call to accept 10x gas limit, i.e., 300e6 given the current block limit 30e6. That means an eth_call JSON-RPC can use up to ~300MB of memory. Depending on the concurrency of a client allowed (e.g., Erigon supports 4k/s, and reth supports 10k/s, See Releasing Reth!), 1k concurrent eth_call calls will consume 1k * 300MB = 300 GB in the worst case, which may exceed the memory size of most of the nodes.

I think it is worth noting in the Security Considerations that a client should implement a proper rate limit of eth_call (and eth_estimateGas) to prevent the OOM attack.

BTW: from

def max_call_gas(gas, memory_byte_size):
    return gas - max(gas // 64, memory_byte_size)

It is possible that max_call_gas become negative?

1 Like

It is possible that max_call_gas become negative?

If this is true, then the call should fail. But you’re right that it’s worth specifying explicitly.

One security concern is the potential out-of-memory (OOM) attack using eth_call JSON-RPC - e.g., Infura allows eth_call to accept 10x gas limit, i.e., 300e6 given the current block limit 30e6

This is also true today, right? I suppose today technically the memory limit is some weird function approximately proportional to sqrt rather than linear, so the memory consumption increases more slowly?

Are there any actual use cases of eth_call with supersized gas limits? Could the gas limit cap be decreased?

I make a lookup table below, and the current memory limit of 300e6 gas limit is about 12MB.

Size (KB) Linear Gas Term Quadratic Gas Term Sum
1 96 2 98
4 384 32 416
16 1,536 512 2,048
32 3,072 2,048 5,120
64 6,144 8,192 14,336
128 12,288 32,768 45,056
256 24,576 131,072 155,648
512 49,152 524,288 573,440
1,024 98,304 2,097,152 2,195,456
3,849 369,504 29,629,602 29,999,106
12,223 1,173,408 298,803,458 299,976,866

Note that, one interesting attack to bypass the existing quadratic term is to spread the memory to multiple call stacks. E.g., I can allocate 1MB to two call stacks, each allocating 512KB instead of 1MB in one call stack. As a result, the memory gas cost is reduced from 2,915,456 to 573,440 * 2 = 1,146,880.

Taking gas limit = 300e6 as an example, recursively calling a contract that allocates 256KB in each call stack can allocate 54MB of total memory, which is still much smaller than 300MB of this EIP.

gas_limit = 300 * 10 ** 6
mem_size = 0
while gas_limit >= 155648:
    mem_size = mem_size + 256 * 1024
    gas_limit = (gas_limit - 155648) * 63 // 64
mem_size # return 57409536 ~ 54MB

The 10x cap of Infura can be found here. Alchemy has an even higher gas limit of 550M.

One application as I mentioned is EVM as a decentralized HTTP server in ERC-4804/6860, where an eth_call may return a large composed HTML from EVM (potentially call an L2 to have lower storage cost). There may be other applications that I am not aware of.