EIP-1014 스키니 CREATE2 (Skinny CREATE2)
최종 확정 · EVM·실행 · 원문 상태 Final · 2018-04-20 작성
컨트랙트 주소를 보낸 계정의 논스 대신 솔트와 초기화 코드의 해시로 계산하는 새 명령어 CREATE2(0xf5)를 추가합니다. 배포 전에도 주소를 미리 확정할 수 있습니다.
왜 필요한가
기존 방식에서 컨트랙트 주소는 만든 계정의 주소와 그 계정이 보낸 거래 수(논스, nonce)를 섞어 정해집니다. 논스는 거래를 보낼 때마다 바뀌므로, 아직 배포하지 않은 컨트랙트의 주소를 미리 확정해 두기 어렵습니다. 그런데 상태 채널(state channel)처럼 체인 밖에서 먼저 약속하고 필요할 때만 체인에 올리는 사용 사례에서는, 아직 체인에 존재하지 않는 주소라도 '그 주소에는 특정 초기화 코드로 만든 컨트랙트만 생길 수 있다'는 보장이 필요합니다. 이 EIP는 주소를 논스가 아니라 고정된 재료, 즉 만드는 계정의 주소, 솔트(salt), 초기화 코드(init code)의 해시만으로 계산하는 새 명령어를 더해 이 문제를 풉니다.
무엇이 바뀌나
지금
- 컨트랙트 주소는 만든 계정의 주소와 논스로 정해집니다
- 논스가 계속 바뀌므로 배포 전에 주소를 확정하기 어렵습니다
- 아직 없는 컨트랙트 주소를 믿고 체인 밖에서 약속하기 어렵습니다
EIP-1014 이후
- CREATE2 명령어가 주소를 만드는 계정, 솔트, 초기화 코드 해시로 계산합니다
- 배포하기 전에 주소를 미리 계산해 쓸 수 있습니다
- 그 주소에는 정해진 초기화 코드로 만든 컨트랙트만 생길 수 있습니다
누구에게 영향이 있나
- 지갑·앱 개발자: 배포 전에 컨트랙트 주소를 미리 계산해 쓰는 설계가 가능해집니다. 원문은 상태 채널의 반사실적(counterfactual) 상호작용을 핵심 용도로 듭니다.
- 클라이언트 팀: 새 옵코드 0xf5와 초기화 코드 해시에 대한 추가 가스 비용(hashcost)을 구현해야 합니다.
- 사용자: 직접 체감하는 변화는 없지만 체인 밖에서 먼저 약속하고 필요할 때만 배포하는 서비스의 기반이 됩니다.
심층 설명
새 옵코드 CREATE2(0xf5)와 주소 공식
CREATE2는 0xf5에 추가되는 옵코드로, 스택 인자 4개(endowment, memory_start, memory_length, salt)를 받습니다. 동작은 CREATE(0xf0)와 동일하되, 컨트랙트가 초기화되는 주소만 기존의 보낸 주소와 논스 해시 대신 keccak256(0xff ++ address ++ salt ++ keccak256(init_code))[12:]로 계산합니다. 0xff는 1바이트, address는 항상 20바이트, salt는 항상 32바이트(스택 아이템)이므로 마지막 해시의 프리이미지는 항상 정확히 85바이트로 고정됩니다.
가스 비용과 hashcost
CREATE2의 가스 체계는 CREATE와 같지만 주소 계산에 필요한 해싱 비용으로 GSHA3WORD * ceil(len(init_code) / 32)의 hashcost가 추가됩니다. 이 비용은 메모리 확장 가스와 CreateGas가 차감되는 시점, 즉 결과 주소 계산과 init_code 실행 전에 차감됩니다. 주소 계산이 init_code 해싱에 의존하는데 메모리 확장 비용은 한 번만 내므로, 큰 init_code를 반복 해싱하게 만드는 DoS 공격에 클라이언트가 노출될 수 있습니다. 그래서 SHA3 옵코드와 같은 워드당 비용을 적용합니다.
왜 0xff로 시작하는가
프리이미지의 첫 바이트를 0xff로 두면 기존 공식 keccak256(rlp([sender, nonce]))로 만든 주소와 충돌할 수 없습니다. 0xff가 RLP의 시작 바이트가 되려면 데이터가 수 페타바이트 길이여야 하기 때문입니다. 또 address 20바이트, salt 32바이트로 길이를 못 박아 해시 프리이미지 크기가 항상 고정되도록 했습니다.
주소 충돌 시 동작
이 EIP로 같은 주소에 다시 생성을 시도하는 충돌이 가능해집니다. 충돌 시 동작은 EIP-684가 정합니다. 생성 거래든 CREATE(또는 CREATE2) 옵코드든, 대상 주소에 0이 아닌 논스나 비어 있지 않은 코드가 이미 있으면 생성은 즉시 실패합니다. init_code의 첫 바이트가 잘못된 옵코드인 경우와 똑같이 동작하며 제네시스부터 소급 적용됩니다. 또 EIP-161에 따라 생성 시 init_code 실행 전에 논스가 1 올라가므로, 컨트랙트가 거래 안에서 만들어지면 논스는 곧바로 0이 아니게 되고 같은 거래 안의 충돌은 init_code 안에서 시도해도 항상 실패합니다. SELFDESTRUCT(0xff)는 논스나 코드에 즉시 영향을 주지 않으므로, 한 거래 안에서 컨트랙트를 파괴하고 다시 만들 수는 없습니다.
init_code의 의미와 예시 벡터
init_code는 실행되면 상태에 올라갈 런타임 바이트코드를 만들어 내는 코드로, 고수준 언어에서 보통 생성자(constructor) 구현에 쓰입니다. 원문에는 테스트 벡터 7개가 실려 있습니다. 예를 들어 주소 0x0000000000000000000000000000000000000000, 솔트 0, init_code 0x00이면 가스는 32006(메모리 확장 없음 가정), 결과 주소는 0x4D1A2e2bB4F88F0250f26Ffff098B0b30B26BF38입니다. init_code가 빈 값 0x이면 가스는 32000입니다.
상태와 콜 결정
이 EIP의 상태는 Final로, 명세가 확정되어 더는 바뀌지 않습니다. 주소 공식은 2018-08-10 coredev-call에서 위 공식을 쓰기로 결정했다고 원문에 기록되어 있습니다.