EIP-2 홈스테드 하드포크 변경 (Homestead Hard-fork Changes)

최종 확정 · 기타 · 원문 상태 Final · 2015-11-15 작성

홈스테드 하드포크로 적용된 네 가지 규칙 변경입니다. 트랜잭션 계약 생성 가스 인상, 높은 s값 서명 무효화, 계약 생성 실패 규칙 정리, 채굴 난이도 조정 공식 교체를 담았습니다.

왜 필요한가

지금은 트랜잭션으로 계약을 만들면 21,000 가스가 들어 계약 안에서 CREATE 명령어로 만들 때의 32,000보다 쌉니다. 여기에 셀프디스트럭트(suicide) 환불까지 이용하면 11,664 가스만으로 이더를 보낼 수 있어 수수료 체계에 구멍이 생깁니다. 서명의 s값을 뒤집어도 서명이 그대로 유효하기 때문에 공격자가 트랜잭션 해시를 바꿀 수 있고 해시로 거래를 추적하는 지갑 화면이 꼬입니다. 계약 생성이 마지막 단계에서 가스가 모자라면 빈 계약이 남아 성공도 실패도 아닌 어정쩡한 상태가 됩니다. 또 일부 채굴자가 타임스탬프를 부모 블록보다 1초만 늦게 찍는 방식으로 채굴하면서 블록 시간 분포가 왜곡됐고 이런 채굴이 51%를 넘으면 평균 블록 시간이 무한히 늘어날 수 있었습니다. 홈스테드 하드포크는 이 네 가지 문제를 한꺼번에 고칩니다.

무엇이 바뀌나

지금

EIP-2 이후

누구에게 영향이 있나

심층 설명

트랜잭션 계약 생성 가스를 21,000에서 53,000으로 인상

to 주소가 빈 문자열인 트랜잭션, 즉 트랜잭션으로 직접 계약을 생성하는 경우 초기 차감 가스가 21,000에서 53,000으로 오릅니다. 여기에 트랜잭션 데이터의 가스 비용이 더해지는 구조는 그대로입니다. 계약 코드 안에서 CREATE 명령어로 계약을 만드는 경로는 영향을 받지 않습니다. 배경은 비용 역전입니다. 트랜잭션 경로(21,000)가 CREATE 경로(32,000)보다 싸서 트랜잭션으로 계약을 만들 과도한 유인이 있었고 suicide 환불을 결합하면 11,664 가스만으로 이더 전송이 가능했습니다. 원문은 심각한 문제는 아니지만 버그에 가깝다고 평가합니다.

secp256k1n/2를 넘는 s값 서명 무효화

s값이 secp256k1n/2보다 큰 트랜잭션 서명은 모두 무효로 처리합니다. 다만 ECDSA 복구 프리컴파일 컨트랙트(ecrecover)는 바뀌지 않고 높은 s값도 계속 받아들입니다. 계약이 오래된 비트코인 서명을 복구하는 경우 등에 쓸 수 있기 때문입니다. 이 변경은 서명 가변성(malleability) 문제를 막습니다. 임의의 트랜잭션에서 s를 secp256k1n - s로 바꾸고 v를 27에서 28로(또는 그 반대로) 뒤집으면 여전히 유효한 서명이 됩니다. 이더리움은 트랜잭션 해시가 아니라 주소를 송금 입력으로 쓰므로 심각한 보안 결함은 아니지만 블록에 확정된 트랜잭션의 해시가 사용자가 보낸 것과 달라져 해시를 추적 ID로 쓰는 인터페이스를 방해합니다.

계약 생성의 코드 저장 가스 부족 시 전체 실패

계약 생성 과정에서 계약 코드를 상태에 추가하는 마지막 가스 비용을 치를 가스가 모자라면, 빈 계약을 남기는 대신 계약 생성 자체가 실패(out-of-gas)합니다. 원문은 세 가지 이점을 듭니다. 첫째, 성공·실패·빈 계약의 세 갈래 결과가 성공 아니면 실패라는 직관적인 두 갈래로 정리됩니다. 둘째, 계약 생성이 완전히 성공하지 않으면 계약 계정이 아예 만들어지지 않으므로 실패를 감지하기 쉬워집니다. 셋째, 이더를 함께 보내는(endowment) 계약 생성이 더 안전해집니다. 초기화 과정 전체가 끝나거나, 트랜잭션이 실패하고 보낸 이더가 환불되거나 둘 중 하나만 일어나기 때문입니다.

난이도 조정 공식 교체

기존 공식 block_diff = parent_diff + parent_diff // 2048 * (1 if block_timestamp - parent_timestamp < 13 else -1) + int(2**((block.number // 100000) - 2))를 block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99) + int(2**((block.number // 100000) - 2))로 바꿉니다. //는 정수 나눗셈이고 minDifficulty가 정하는 최소 난이도 아래로는 내려가지 않습니다. 기존 공식은 중앙값 13초를 목표로 해서 채굴자들이 타임스탬프를 parent_timestamp + 1로 찍자 중앙값은 유지돼도 평균이 늘어났고 이런 채굴이 51%에 이르면 평균이 무한대로 커질 수 있었습니다. 새 공식은 대략 평균을 목표로 하며 장기적으로 평균 블록 시간이 24초를 넘는 것이 수학적으로 불가능함을 증명할 수 있습니다. 시간 차이를 그대로 쓰지 않고 (block_timestamp - parent_timestamp) // 10을 입력으로 쓰는 것은 알고리즘의 거친 단위를 유지해 시간 차이를 정확히 1로 맞춰 약간 높은 난이도의 블록을 만들 유인을 막기 위해서입니다. -99 하한은 클라이언트 보안 버그 같은 돌발 상황으로 두 블록 사이가 매우 벌어져도 난이도가 극단적으로 떨어지지 않게 하는 장치입니다.

활성화 블록과 상태

네 가지 변경은 block.number가 HOMESTEAD_FORK_BLKNUM 이상일 때 적용됩니다. 메인넷은 1,150,000, Morden 테스트넷은 494,000, 이후 테스트넷은 0입니다. 이 EIP는 홈스테드 하드포크를 정의한 메타 문서인 EIP-606이 참조하는 핵심 변경 목록이며 상태는 Final로 확정됐습니다. 원문은 파이썬 구현(pyethereum)의 해당 코드 위치 네 곳을 구현 근거로 제시합니다.

EIP 원문 · ← EIPs