Check memory limit before copy dynamic array from storage to memory(gas optimization)
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 29
Description
## Description
## Environment
- Compiler version: *
- Target EVM version (as per compiler settings): *
- Framework/IDE (e.g. Truffle or Remix): Visual studio code
- EVM execution environment / backend / blockchain client: *
- Operating system: linux
## Steps to Reproduce
When compiling the following function in Solidity, when the line `uint[] memory ma = a;` is compiled, the operation of copying the value from storage to memory is executed first, and then the memory usage length check is performed. When `uint[] a` is relatively long, it consumes more gas. **To optimize gas usage, it is recommended to perform the memory check based on the array length before the copy operation.**
```
contract TestMemory{
uint[] a;
function b() public{
uint[] memory ma = a;
}
}
```
Here is yul code:
```
function abi_encode_t_array$_t_uint256_$dyn_storage_to_t_array$_t_uint256_$dyn_memory_ptr(value, pos) -> end {
let length := array_length_t_array$_t_uint256_$dyn_storage(value)
pos := array_storeLengthForEncoding_t_array$_t_uint256_$dyn_memory_ptr(pos, length)
let baseRef := array_dataslot_t_array$_t_uint256_$dyn_storage(value)
let srcPtr := baseRef
for { let i := 0 } lt(i, length) { i := add(i, 1) }
{
let elementValue0 := read_from_storage_offset_0_t_uint256(srcPtr)
pos := abi_encodeUpdatedPos_t_uint256_to_t_uint256(elementValue0, pos)
srcPtr := array_nextElement_t_array$_t_uint256_$dyn_storage(srcPtr)
}
end := pos
}
function abi_encodeUpdatedPos_t_array$_t_uint256_$dyn_storage_to_t_array$_t_uint256_$dyn_memory_ptr(value0, pos) -> updatedPos {
updatedPos := abi_encode_t_array$_t_uint256_$dyn_storage_to_t_array$_t_uint256_$dyn_memory_ptr(value0, pos)
}
function finalize_allocation(memPtr, size) {
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
// protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr)
}
function copy_array_from_storage_to_memory_t_array$_t_uint256_$dyn_storage(slot) -> memPtr {
memPtr := allocate_unbounded()
let end := abi_encodeUpdatedPos_t_array$_t_uint256_$dyn_storage_to_t_array$_t_uint256_$dyn_memory_ptr(slot, memPtr)
finalize_allocation(memPtr, sub(end, memPtr))
}
```
Contributor guide
Research direction
No repository files or tests are named. Start by reproducing the Solidity example and inspecting the generated Yul path for copying a dynamic storage array into memory, especially allocation and finalization. Done means the memory limit is checked from the array length before the storage-to-memory copy, with the gas optimization covered by regression testing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, solidity
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100