프로젝트 관련 컨트랙트를 작성하고 컴파일 하는 도중, 아래와 같은 에러를 마주하게 되었다.
컨트랙트 코드의 사이즈가 24618 바이트이고, 24576 바이트를 넘었다. 이 컨트랙트는 메인넷에 배포가 불가능할 것으로 보인다. 옵티마이저를 활성화 또는 사용하지 않도록 하거나, revert 의 string 문자를 줄이거나 라이브러리를 사용해라.
라고 오류를 설명하고 있다.
일단 노란색의 warning error 메시지이고, goerli 테스트 넷이기 때문에, 배포를 시도해보았다.
경고 메시지를 무시하고 Force Send 를 눌렀다.
가스비를 추정할 수 없다는 에러가 뜬다. 이러한 경우에는 100%에 가까운 확률로 배포가 실패하기에, 첫 번째 에러 메시지의 EIP-170
에 대해 알아보기로 했다.
EIP-170 이란?
Ethereum Improvement Proposals 의 170번째 제안으로, Contract code size limit
가 안건의 제목이다.
Spurious Dragon 하드포크 때 EIP-170 이 적용 되었다.
MAX_CODE_SIZE: 0x6000 (214 + 213)
FORK_BLKNUM: 2,675,000
CHAIN_ID: 1 (Mainnet)
코드의 최대 사이즈는 10진수로 24567 바이트이다.
적용된 블록의 넘버는 2,675,000 번째 블록.
체인은 메인넷.
Specification
If block.number >= FORK_BLKNUM, then if contract creation initialization returns data with length of more than MAX_CODE_SIZE bytes, contract creation fails with an out of gas error.
2,675,000 번째 블록부터는, 컨트랙트를 생성할 때 컨트랙트 코드의 길이를 받아서, 24567 바이트 이상이라면, 컨트랙트 배포는 가스 에러와 함께 실패할 것이다. 라고 설명하고 있다.
Rationale
Currently, there remains one slight quadratic vulnerability in Ethereum: when a contract is called, even though the call takes a constant amount of gas, the call can trigger O(n) cost in terms of reading the code from disk, preprocessing the code for VM execution, and also adding O(n) data to the Merkle proof for the block’s proof-of-validity. At current gas levels, this is acceptable even if suboptimal. At the higher gas levels that could be triggered in the future, possibly very soon due to dynamic gas limit rules, this would become a greater concern—not nearly as serious as recent denial of service attacks, but still inconvenient especially for future light clients verifying proofs of validity or invalidity. The solution is to put a hard cap on the size of an object that can be saved to the blockchain, and do so non-disruptively by setting the cap at a value slightly higher than what is feasible with current gas limits.
간단하게 요약하자면...
현재 이더리움의 취약점 중 하나는, 호출 시 코드를 읽어오고 가스 한도에 따른 추가 비용이 발생하는 문제이다. 동적 가스 리밋은 미래의 가스비 상승에 의해 문제가 될 수 있으며, 유효성 또는 무효성을 증명하는 미래의 경량 클라이언트에게 불편함을 초래할 수 있다. 해결책은 블록체인에 저장할 수 있는 객체의 크기에 하드 캡을 설정하는 것이다.
따라서 EIP-170 은 코드를 읽어올 때 소모되는 가스비가 미래의 가스비 상승에 의해 문제가 될 수 있고, 이는 미래의 경량 클라이언트에게 불편함을 준다. 따라서 코드의 사이즈에 한계를 둠으로 써 이를 해결하고자 한 제안이라고 볼 수 있겠다..
위의 첫 번째 warning 메시지에서 설명한대로, revert 에 들어가는 string 값을 지워보았다.
아래는 코드의 if문에서 처리한 revert 이다. 여기에 들어가는 string 값이 컨트랙트 코드의 사이즈를 크게 증가시킨다.
else {
revert("It is wrong approach.");
}
이러한 revert 처리 부분 3개를 지워보았더니 문제 없이 컴파일링 된다.
이러한 에러를 만나면 컨트랙트 코드의 사이즈를 많이 차지하는 string 형태의 값 부터 줄여주면 되겠다.
EIP-170 을 읽어보니 컨트랙트 코드 뿐만 아니라, 이더리움의 자료구조와 EVM 의 작동방식에 대해 더 공부해야겠다는 생각이 든다..
컨트랙트 코드를 잘 짜는것보다는 컨트랙트 코드의 뒤에서 동작하는 부분의 이해가 더 중요함을 느낀다..