EIP-5656 Memory copy instruction MCOPY (MCOPY - Memory copying instruction)

Final · EVM & execution · EIP status Final · created 2021-02-01

Adds MCOPY (0x5E), a dedicated instruction for copying memory regions, to the EVM. A 256-byte copy can be done for 27 gas, without a precompile call or repeated MLOAD/MSTORE.

Why it is needed

Copying memory is a very basic operation in smart contracts, but until now the EVM had no dedicated instruction for it. Developers therefore used workarounds. One is to CALL the identity precompile, which returns its input unchanged, but the cost of the call itself is high, so it is inefficient. The other is to move 32 bytes at a time by hand with the MLOAD and MSTORE instructions, which costs at least 12 gas per word and, when the length is not an exact multiple of 32 bytes, needs extra work to read the last piece, mask it and store it back. For example, copying 256 bytes costs at least 157 gas with the identity precompile (after EIP-2929) and at least 96 gas with unrolled MLOAD/MSTORE, but only 27 gas with MCOPY. An analysis of real blocks (blocks 10537502 to 10538702) also showed that about 10.5% of memory copies would have performed better had MCOPY existed. Languages such as Solidity and Vyper use memory copies heavily, so a dedicated instruction has a large effect.

What changes

Today

After EIP-5656

Who is affected

In depth

Opcode number and stack inputs

MCOPY is assigned opcode 0x5E. It pops three values from the top of the stack: dst (the memory location where the copy goes), src (the source location) and length (the length in bytes), and returns nothing to the stack. This order is aligned with existing copy instructions such as CALLDATACOPY and RETURNDATACOPY, so compiler and assembly authors can use it the same way as the existing copy instructions.

Gas cost calculation

By the Yellow Paper, MCOPY belongs to the W_copy group and follows that group's gas calculation. As of the time the EIP text was written, the formula is words_copied = (length + 31) // 32 and gas_cost = g_verylow + 3 * words_copied + memory_expansion_cost, where g_verylow is 3. So copying one word (32 bytes) costs the base 3 gas plus 3 gas for copying, for 6 gas. If length is greater than 0 and src + length or dst + length exceeds the current memory length, memory is expanded and the corresponding gas is charged on top. The EIP text states that the Yellow Paper calculation is the final reference.

Copy semantics that are safe for overlapping ranges

MCOPY copies length bytes from the src location in memory to the dst location. It is defined to behave as if an intermediate buffer were used, so the result is correct even when the source and destination ranges overlap. The test cases in the EIP text show this. MCOPY 0 1 8 (copy 8 bytes at offset 1 to offset 0) and MCOPY 1 0 8 (copy 8 bytes at offset 0 to offset 1) both handle overlapping ranges and each produce the correct result for 6 gas. MCOPY 0 0 32, which copies to the same location, is also allowed.

Cost comparison with existing copy methods

The cost of the identity precompile is 15 + 3 * (length / 32) gas plus call overhead. When the CALL cost rose to 700 it became effectively useless, and EIP-2929 lowered it to 100, but the EIP text still judges it too expensive to be a reasonable alternative. The MLOAD/MSTORE approach is fairly efficient at a minimum of 12 gas per word when offsets are known in advance and the loop can be unrolled, but copying with arbitrary offsets at execution time adds at least 6 more gas per word for the 32 ADD that advances the offset. There is a special case where, if the last piece is a single byte, it can be stored efficiently with MSTORE8, but handling partial words is costly overall. For a 256-byte copy, the identity precompile costs at least 757 gas before EIP-2929 and at least 157 gas after, unrolled MLOAD/MSTORE costs at least 96 gas, and MCOPY costs 27 gas.

Ease of static analysis and preparation for future gas changes

CALL can in general cause any side effect, so static analyzers and optimizers have to treat it conservatively. Even if a special case is made for precompiles, a future hard fork could change the effect of CALL, so analysis results for code that uses the identity precompile are valid only for a particular block range. MCOPY, by contrast, is known at the instruction level to affect only memory. A dedicated instruction also means that memory copy costs are unaffected if the gas costs of the CALL family change in the future. The EIP text also cites as grounds that memory copying was found to be a large overhead in computation-heavy work such as EVM384.

Backward compatibility and tests

MCOPY is a new instruction that did not exist before. The EIP text therefore notes that for already deployed contracts whose code contains the 0x5E byte, behavior may change after this EIP. The full test suite for verifying implementations is in the MCOPY suite of the ethereum/execution-spec-tests repository, and the body of the EIP text also includes four representative test cases, including overlapping copies, along with the pre- and post-execution memory states and gas usage (6 gas each).

Security considerations: no actual intermediate buffer

The specification defines the behavior as if an intermediate buffer were used, but client implementations must not actually allocate one. Allocating a real buffer could become a channel for denial-of-service (DoS) attacks. The EIP text gives the C standard library function memmove, which handles overlap without an intermediate buffer, as an example, and explains that the built-in byte-moving functions and standard libraries of most languages have the right performance characteristics. Analysis of other DoS and memory exhaustion attacks is the same as for other opcodes that touch memory, because memory expansion follows the same pricing rules. The status of this EIP is finalized as Final.

Original EIP · ← EIPs