-
EIP-3855 : EVM의 새로운 Opcode PUSH0을 소개합니다evm 2024. 2. 10. 17:34
Author : 최원혁
Intro
한국 시간 2023년 4월 13일 목요일, 이더리움은 상하이 업그레이드를 통해 실행 레이어(execution layer)에 새로운 표준(EIP)를 반영한다. 이 중에서도 EIP-3855가 추가되어 새로운 Opcode PUSH0를 이더리움 가상 머신(EVM)에 도입한다.
Opcode PUSH0
상하이 업데이트 이후, geth Github의 opcodes.go를 보면 PUSH0(0x5f)를 확인할 수 있다. 기능은 아주 간단하다. EVM Stack 최상단에 0(0x00)을 추가한다.
Bytescode로 컴파일(compile)된 코드에서 Stack 최상단에 0을 추가해야하는 경우는 생각보다 굉장히 빈번하다. 특히, memory나 storage의 offset을 정의할때 0이 필요하다. 예를들어 Opcode MLOAD(offset)는 stack의 최상단(top) 값를 offset 인자로 받아, offset ~ 32bytes 데이터를 memory로 부터 조회한다. 이런 경우는 MLOAD뿐만이 아니다. PC, MSIZE, CALLDATASIZE, RETURNDATASIZE, CODESIZE, CALLVALUE, SELFBALANCE 등등 굉장히 많은 OPCODE에서 빈번하게 사용된다.
Motivation
EIP-3855가 등장하게된 이유는 스마트 컨트랙트 배포의 가스비를 최적화 하기 위함이다.
PUSH0가 추가되기전, EVM은 PUSH1 00을 통해 Stack 최상단에 0을 넣을 수 있었다. Bytescode 레벨에서 봤을 때 PUSH1 00는 2 length를 차지한다.
이더리움의 백서 yellow paper의 27번 페이지를 보면, 스마트 컨트렉트 배포 시, Bytescode 길이(length) 당 200 gas가 측정된다.
We have conducted an analysis on Mainnet (block ranges 8,567,259…8,582,058 and 12,205,970…12,817,405), and ~11.5% of all the PUSH* instructions executed push a value of zero.
메인넷(블록 범위 8,567,259...8,582,058 및 12,205,970...12,817,405)을 분석한 결과, 실행된 모든 PUSH* 명령 중 약 11.5%가 0값을 푸시했습니다.
출처 EIP-3855 | https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3855.md#motivationEIP-3855에 나와있는 내용을 보면, Mainnet에 배포된 모든 컨트랙트를 합친 코드에서 PUSH1 00는 무려 11.5%차지했다. 때문에 EIP-3855는 Bytescode에서 2 length를 차지하는 PUSH1 00대신, 1 length만 차지하는 PUSH0로 대체하여 스마트 컨트랙트 배포의 가스비를 최적화하자는 내용이 담겨있다.
Test Cases
EIP-3855를 통해 PUSH0가 생기기전과 생긴 후의 Bytescode length와 컨트랙트 배포 가스비를 Remix를 통해 비교해보자.
remix code >
더보기// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "<https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.9/contracts/token/ERC20/ERC20.sol>"; import "<https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.9/contracts/token/ERC20/extensions/ERC20Permit.sol>"; contract MyToken is ERC20, ERC20Permit { constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {} } contract test { function at(address _addr) public view returns (uint256) { return _addr.code.length; } }
PUSH0는 Solidity ^0.8.20에 반영이 되었다. OpenZeppelin에서 지원하는 ERC20 코드를 0.8.10와 0.8.20 버전으로 컴파일(compile)했을 때, 결과는 아래와 같다.
Solidity 0.8.10
Solidity 0.8.20
Result
- Deploy cost : 1905383 gas → 1753138 gas
- Bytescode length : 9279 → 8517
PUSH0가 반영되기 전과 후에 따라 bytescode 길이(length)와 배포 비용이 크게 개선된것을 확인할 수 있다.
마무리
EIP-3855가 상하이 업그레이드에 선정된 이유는 블록에 저장되는 공간 및 데이터를 최적화 시켜 확장성을 향상시키겠다는 이더리움의 목표에 적합하기 때문이다.
이더리움 공식 문서의 “BLOCK SIZE”에 대한 내용을 보면 블록이 수용할 수 있는 용량을 물리적인 데이터 사이즈가 아닌 소비된 가스양으로 제한한다. 각 블록의 목표 크기는 1,500만 가스이지만, 블록의 크기는 네트워크 수요에 따라 최대 3,000만 가스까지 증가하거나 감소할 수 있다.
트랜잭션에 사용되는 가스비가 줄어들 수록, 블록에 데이터를 저장할 수 있는 공간이 창출된다. 이는 블록체인 네트워크의 확장성을 향상시키는 요인 중 하나이며 상하이 업그레이드 내역에 해당 내용이 포함된 이유이다.
'evm' 카테고리의 다른 글
EIP-150 : 이더리움의 63/64 Rule (0) 2024.02.22 EIP-2718 : 이더리움의 트랜잭션 유형별 Type & Payload (1) 2024.02.20 Deploy Smart Contract 원리 및 Opcode 해석 : Creation Code & Runtime Code (0) 2024.02.07