EIP-7923 선형 페이지 기반 메모리 과금 (Linear, Page-Based Memory Costing)

Hegota 포함 제외 (DFI) · EVM·실행 · 원문 상태 Draft · 2025-03-27 작성

EVM 메모리 비용을 지금의 2차식에서 페이지(4096바이트) 단위 선형 과금으로 바꿉니다. 처음 건드리는 페이지마다 100가스를 받고, 트랜잭션 전체에 64MB 하드 상한을 둡니다.

왜 필요한가

EVM은 메모리를 쓸수록 비용이 제곱에 가깝게 불어나는 2차식 모델을 씁니다. 처음에는 서비스 거부(DoS) 공격을 막으려는 장치였지만 지금 보면 낡았습니다. 가스 한도 3,000만에서도 한 번의 메시지 호출이 쓸 수 있는 메모리는 3MB에 그치고 그마저 가스를 전부 태워야 합니다. 2차항이 724바이트부터 붙기 때문에 1980년대 초 PC 수준인 64KB를 쓰는 데만 14,336가스가 듭니다. 트랜잭션이 최대 얼마나 메모리를 쓸 수 있는지 알려면 콜 스택 한도와 EIP-150의 63/64 규칙까지 넣은 최적화 문제를 풀어야 해서 추론도 어렵습니다. 또 Vyper나 Solidity 같은 언어는 힙은 아래에서 위로, 콜 스택은 위에서 아래로 키우는 현대적 가상 메모리 구조를 쓸 수 없어 메모리 모델에 비효율이 생깁니다. 이 EIP는 오늘날 하드웨어처럼 메모리를 페이지 단위로 필요할 때만 할당하고 그 값을 선형으로 받는 모델을 제안합니다.

무엇이 바뀌나

지금

EIP-7923 이후

누구에게 영향이 있나

심층 설명

과금 알고리즘 세 가지 변경

첫째, 명령이 건드리는 각 페이지에 대해 이 메시지 호출에서 처음 건드리는 경우 ALLOCATE_PAGE_COST(100가스)를 부과합니다. 페이지 0은 예외로 무료입니다. 둘째, MLOAD·MSTORE 등 모든 메모리 명령의 기본 가스 비용은 3으로 유지됩니다. 셋째, 기존 메모리 확장 비용의 선형 항과 2차 항을 제거합니다. 상수는 ALLOCATE_PAGE_COST = 100, PAGE_SIZE = 4096, MAXIMUM_MEMORY_SIZE = 64 * 1024 * 1024입니다.

32비트 주소 제한과 트랜잭션 전역 상한

메모리 주소는 32비트로 제한됩니다. 주소가 2**32 - 1보다 크면 예외 중단을 일으켜야 합니다. 또 트랜잭션에서 할당한 페이지 수가 MAXIMUM_MEMORY_SIZE // PAGE_SIZE, 즉 16384를 넘으면 역시 예외 중단입니다. 이 상한은 메시지 호출 단위가 아니라 트랜잭션 전역 단위입니다. 호출별 상한(예: 2MB)도 대안으로 검토됐지만 구현 복잡도를 크게 줄이지 못한다는 이유로 트랜잭션 전역으로 정해졌습니다. 2**32바이트라는 주소 상한은 다양한 운영체제와 아키텍처에서 64비트 컴퓨터가 그만큼의 가상 주소 공간을 쉽게 확보할 수 있게 하려는 선택이며 가스 한도나 클라이언트 메모리가 크게 늘면 재검토할 수 있다고 적혀 있습니다.

MSIZE 의미는 그대로

MSIZE의 동작은 바뀌지 않습니다. 메모리 명령이 건드린 최대 바이트를 32 단위로 올림해 반환합니다. 기존 컨트랙트가 MSIZE가 선형으로 자란다고 가정하고 있어 하위 호환을 지키기 위한 선택입니다. 다만 새 가상 주소 방식을 활용하는 컨트랙트는 메모리 할당에 MSIZE를 의존하지 말아야 한다고 원문은 권고합니다.

100가스라는 가격의 벤치마크 근거

2019년형 CPU에서 keccak256을 초당 약 256MB 처리할 수 있다는 점(32바이트당 6가스)에서 1가스당 20ns라는 비율을 잡고 벤치마크를 돌렸습니다. 새 페이지 할당에 1~2us, 2MB 범위 무작위 읽기에 1.8ns, 32MB 범위에 7ns, 4GB 범위에 40ns, mmap 시스템 콜에 230ns가 걸렸습니다. 여기서 페이지 할당 100가스가 나왔습니다. mmap 실행 비용(약 11가스)은 CALL 계열 명령의 기본 비용 100가스가 이미 충분히 지불하고 있고 같은 이유로 페이지 0을 무료로 두었습니다. 덕분에 첫 페이지 안에서는 접근 비용이 기존과 같거나 더 싸져 하위 호환성도 좋아집니다.

두 가지 구현 경로

mmap이 없는 시스템은 가상 주소를 직접 구현합니다. page_id(주소를 12비트 오른쪽 시프트한 정수)를 키로 하는 map[page_id -> char[4096]]을 유지하고 페이지 경계를 걸치는 읽기·쓰기는 두 페이지를 모두 불러 결과를 합칩니다. POSIX mmap(윈도우의 VirtualAlloc)이 있는 시스템은 더 쉽습니다. 2**32바이트 영역을 익명 mmap으로 잡으면 운영체제가 실제로 건드린 페이지만 할당해 주므로, 메모리 읽기·쓰기는 이 버퍼에 대한 단순 접근이 됩니다. 이때 pages 맵은 데이터를 담지 않고 어떤 페이지가 할당됐는지 과금용으로만 추적합니다. 원문에는 py-evm에 대한 약 60줄짜리 패치 형태의 참조 구현이 실려 있습니다.

메모리 상한을 가스 한도와 분리한 이유

클라이언트 구현 쪽에는 DoS 방지를 위해 가스 한도와 별개로 전역 한도를 강제하고 싶다는 요구가 있습니다. 예를 들어 RPC 제공자는 메인넷보다 훨씬 높은 가스 한도로 많은 eth_call을 동시에 처리하도록 설계될 수 있는데, 메모리 한도를 가스 한도에 암묵적으로 묶지 않으면 설정 실수가 생길 통로가 하나 줄어듭니다. 미래에 가스 한도의 제곱근에 비례하는 식으로 하드웨어 발전에 맞춰 한도를 키우는 공식을 만들 수도 있지만 이 EIP의 검토 범위를 좁히기 위해 일단 하드 리밋을 도입했다고 설명합니다.

보안과 하위 호환성 분석

원문은 두 가지를 검토합니다. 첫째, 기존 컨트랙트가 깨지는가. 가스 과금을 빼면 기존 컨트랙트는 가스 부족으로 실패하던 실행이 끝까지 완료될 수 있을 뿐, 하위 호환성은 깨지지 않습니다. 둘째, 클라이언트에 대한 메모리 DoS가 가능해지는가. 지금도 가스 한도 3,000만에서 호출 스택마다 256KB를 할당하는 컨트랙트를 재귀 호출하면 총 54MB를 할당할 수 있어 이 EIP의 64MB 상한과 크게 다르지 않습니다. 트랜잭션 전역 상한 덕분에 앞으로 콜 스택 한도가 바뀌어도 한 트랜잭션이 쓸 수 있는 총 메모리는 변하지 않는다는 불변 조건도 생깁니다.

현재 상태와 포크 논의

이 EIP는 Draft 상태라 명세의 상수와 세부 규칙이 아직 바뀔 수 있습니다. 코어 개발자 콜에서는 2026년 8월 13일 ACDE #243에서 헤고타(Hegota) 포크 후보(PFI)로 접수됐으나, 2026년 9월 10일 ACDE #245에서 제외(DFI)됐습니다. 개선점은 인정됐지만 우선순위가 아니라는 판단이었고 여유가 생기면 재검토할 수 있다는 단서가 붙었습니다.

EIP 원문 · ← EIPs