EIP-170 컨트랙트 코드 크기 제한 (Contract code size limit)
최종 확정 · EVM·실행 · 원문 상태 Final · 2016-11-04 작성
블록체인에 배포할 수 있는 컨트랙트 코드의 최대 크기를 24,576바이트(0x6000)로 제한합니다. 이보다 큰 코드를 배포하려 하면 컨트랙트 생성이 실패합니다.
왜 필요한가
이더리움에서 컨트랙트를 호출할 때 호출 자체에는 정해진 양의 가스만 듭니다. 그런데 호출된 컨트랙트의 코드가 크면, 노드가 그 코드를 디스크에서 읽고 가상머신(VM)에서 실행할 수 있게 준비하고 블록이 올바르다는 증명(머클 증명)에 코드 데이터를 넣는 비용이 코드 길이에 비례해 커집니다. 내는 수수료는 그대로인데 네트워크가 치르는 비용은 코드가 클수록 늘어나는 불균형이 있었던 것입니다. 원문은 당시 가스 수준에서는 견딜 만하지만, 가스 한도가 올라가면 더 큰 문제가 되고, 특히 블록의 유효성 증명을 검증해야 하는 미래의 라이트 클라이언트에게 불편해진다고 지적합니다. 그래서 블록체인에 저장할 수 있는 코드 크기에 상한을 두되, 당시 가스 한도로 실제 만들 수 있는 것보다 약간 높은 값으로 정해 기존 사용에 지장이 없게 했습니다.
무엇이 바뀌나
지금
- 컨트랙트 코드 크기에 상한이 없어서 이론상 아주 큰 코드도 배포할 수 있었습니다
- 코드가 큰 컨트랙트를 호출하면 노드가 코드 길이에 비례하는 숨은 비용을 치렀습니다
- 라이트 클라이언트가 검증해야 할 증명 데이터가 코드 크기만큼 커질 수 있었습니다
EIP-170 이후
- 배포되는 컨트랙트 코드는 24,576바이트를 넘을 수 없습니다
- 이 크기를 넘는 코드를 만들려는 컨트랙트 생성은 가스 부족(out of gas) 오류로 실패합니다
- 노드와 라이트 클라이언트가 컨트랙트 하나당 처리해야 하는 코드량의 상한이 보장됩니다
누구에게 영향이 있나
- 컨트랙트 개발자: 배포하려는 코드가 24,576바이트를 넘으면 생성이 실패하므로, 큰 컨트랙트는 크기를 줄이거나 나눠서 설계해야 합니다.
- 클라이언트 팀: 컨트랙트 생성 시 반환 코드 길이를 검사하고 초과하면 out of gas로 실패시키는 규칙을 구현해야 합니다.
- 노드 운영자와 라이트 클라이언트: 컨트랙트 하나를 읽고 검증하는 비용에 상한이 생겨, 코드 크기로 인한 과도한 부하를 걱정하지 않아도 됩니다.
심층 설명
MAX_CODE_SIZE와 발효 조건
상한값 MAX_CODE_SIZE는 0x6000, 즉 2**14 + 2**13 = 24,576바이트입니다. 적용 시점은 FORK_BLKNUM 2,675,000이고 대상은 CHAIN_ID 1(메인넷)입니다. block.number >= FORK_BLKNUM일 때, 컨트랙트 생성의 초기화(initialization) 코드가 MAX_CODE_SIZE바이트보다 긴 데이터를 반환하면 컨트랙트 생성은 out of gas 오류로 실패합니다. 검사 대상은 초기화 코드 자체의 길이가 아니라 초기화가 반환하는 데이터, 즉 실제로 저장될 코드의 길이입니다.
막으려는 문제: O(n) 비용의 2차(quadratic) 취약점
컨트랙트 호출(call)은 일정한 가스만 소모하지만 호출이 유발하는 실제 작업은 코드 길이 n에 비례합니다. 원문이 꼽는 세 가지는 디스크에서 코드를 읽는 비용, VM 실행을 위해 코드를 전처리하는 비용, 블록의 유효성 증명(proof-of-validity)용 머클 증명에 O(n) 데이터가 추가되는 비용입니다. 지불하는 가스는 상수인데 유발 비용은 선형이므로, 이를 반복하면 네트워크 부담이 비례 이상으로 커질 수 있는 구조였습니다.
당시에는 왜 급하지 않았고, 왜 미리 막았나
원문은 당시 가스 수준에서는 이 비용이 최적은 아니어도 수용 가능하다고 평가합니다. 다만 동적 가스 한도 규칙 때문에 가스 한도가 곧 크게 오를 수 있고 그 경우 문제가 커진다고 봤습니다. 당시의 서비스 거부(DoS) 공격만큼 심각하지는 않지만 유효성·무효성 증명을 검증할 미래의 라이트 클라이언트에게 특히 불편한 문제라고 지적합니다.
비파괴적 도입 방식
해결책으로 블록체인에 저장할 수 있는 객체 크기에 하드 캡을 뒀습니다. 상한값을 당시 가스 한도로 실제 배포 가능한 크기보다 약간 높게 잡아, 기존에 가능하던 배포를 막지 않으면서(non-disruptively) 미래의 위험만 차단하도록 설계했습니다.
적용 포크와 상태
이 EIP는 Spurious Dragon 하드포크(EIP-607)에 포함되어 블록 2,675,000부터 적용되었습니다. 상태는 Final로, 명세가 확정되어 더 이상 바뀌지 않습니다.