EIP-8038 상태 접근 가스비 갱신 (State-Access Gas Cost Update)
콜 결정 없음 · 수수료·가스 · 원문 상태 Last Call · 2025-10-03 작성
계정이나 저장 슬롯을 읽고 쓰는 명령어의 가스비를 올립니다. 이더리움 상태가 커져 이 작업들이 느려진 만큼, 비용을 접근·쓰기·생성 세 요소로 나누어 다시 매깁니다.
왜 필요한가
가스는 노드가 거래를 처리하는 데 드는 시간과 자원을 값으로 환산한 것입니다. 계정 잔액이나 컨트랙트 저장 공간처럼 디스크에 있는 상태(state)를 읽고 쓰는 작업의 가격은 EIP-2929가 2021년 3월 베를린 포크에서 올린 뒤로 그대로였습니다. 그 사이 이더리움 상태는 크게 늘었고 상태를 읽고 쓰는 속도는 그만큼 느려졌습니다. 가격은 그대로인데 실제 시간은 더 걸리니 다른 명령어와 비교해 상태 접근이 너무 싸진 셈입니다. 또 EXTCODESIZE와 EXTCODECOPY는 계정 정보를 한 번 읽고 코드 크기나 바이트코드를 한 번 더 읽어 데이터베이스를 두 번 거치는데도, 한 번만 읽는 BALANCE나 EXTCODEHASH와 같은 값을 냈습니다. 이 제안은 클라이언트별로 실제 측정한 실행 시간을 바탕으로 이런 가격을 다시 맞추고 복합 상수 안에 섞여 있던 쓰기 비용을 이름 있는 상수로 따로 떼어 냅니다.
무엇이 바뀌나
지금
- 계정을 거래 안에서 처음 읽을 때(cold) 2,600 가스를 냅니다.
- 저장 슬롯 값을 바꾸는 비용이 SSTORE 복합 상수(5,000) 안에 섞여 있어 따로 보이지 않습니다.
- EXTCODESIZE·EXTCODECOPY는 데이터베이스를 두 번 읽어도 BALANCE와 같은 값을 냅니다.
- 컨트랙트 배포는 GAS_CREATE 32,000 하나로 묶어 냅니다.
EIP-8038 이후
- 계정 처음 읽기는 3,000 가스로 오릅니다. 저장 슬롯 처음 읽기(2,100)와 이미 읽은 것 다시 읽기(100)는 그대로입니다.
- 쓰기 비용이 ACCOUNT_WRITE 9,000, STORAGE_WRITE 10,000이라는 별도 상수로 분리됩니다.
- EXTCODESIZE·EXTCODECOPY는 두 번째 읽기 몫으로 WARM_ACCESS 100을 더 냅니다.
- 배포는 CREATE_ACCESS 12,000을 실행 가스로 내고, 새 계정 생성 비용은 EIP-8037의 상태 가스로 넘어갑니다.
누구에게 영향이 있나
- 사용자: 거래 수수료 계산 방식이 바뀌지만 지갑과 RPC가 갱신되면 평소대로 쓸 수 있습니다. 저장 슬롯 값을 바꾸는 비용은 크게 오릅니다.
- 지갑·앱 개발자: eth_estimateGas 처리를 새 파라미터에 맞게 반드시 갱신해야 합니다. 그대로 두면 가스를 적게 잡아 거래가 실패할 수 있습니다.
- 노드 운영자·클라이언트 팀: RPC의 가스 추정 공식에 새 값을 넣어야 합니다. 수치는 08.13 ACDE #243에서 최종 확정돼 그 뒤 스펙 변경이 없습니다.
- dApp 운영자: 상태 접근 비용 변화가 특정 앱의 사용성에 영향을 줄 수 있으며 영향 범위는 더 분석이 필요하다고 원문에 적혀 있습니다.
심층 설명
비용을 이루는 세 요소: 접근, 쓰기, 상태 생성
상태를 건드리는 연산의 가스비를 최대 세 가지 독립 요소의 합으로 봅니다. 첫째는 접근(Access)으로, 계정이나 저장 슬롯을 데이터베이스에서 읽어 오는 비용입니다. COLD_ACCOUNT_ACCESS, COLD_STORAGE_ACCESS, WARM_ACCESS가 여기 속하며 EIP-2929 파라미터의 이름을 바꾼 것입니다. 이 EIP는 COLD_ACCOUNT_ACCESS만 올리고 나머지 둘과 콜드·웜 판정 규칙은 그대로 둡니다. 둘째는 쓰기(Write)로, 값이 바뀔 때 리프를 쓰는 비용입니다. 저장 슬롯은 STORAGE_WRITE, 계정의 논스·잔액·코드 해시는 ACCOUNT_WRITE를 내며 둘 다 이 EIP가 새로 만든 상수입니다. 기존 체계에는 이 몫이 GAS_STORAGE_UPDATE, CALL_VALUE, GAS_CREATE 같은 복합 상수 안에 녹아 있었습니다. STORAGE_WRITE는 거래 단위로 순액 계산합니다. 슬롯을 거래 시작 값에서 벗어나게 하는 SSTORE가 내고 나중에 되돌리는 SSTORE가 환불받습니다. ACCOUNT_WRITE는 연산마다 냅니다. 같은 수신자에게 값을 보내는 CALL을 두 번 하면 두 번 냅니다. EIP-7702 authorization 처리에서 권한자당 한 번만 내는 규칙은 EIP-2780에만 있습니다. 셋째는 상태 생성(State creation)으로, 새 슬롯은 GAS_STORAGE_SET, 새 계정은 GAS_NEW_ACCOUNT입니다. 이 EIP는 이 값을 바꾸지 않고 EIP-8037이 상태 가스 차원에서 다시 매깁니다.
바뀌는 파라미터와 기존 값의 환산
값은 이렇게 바뀝니다. COLD_ACCOUNT_ACCESS(옛 COLD_ACCOUNT_ACCESS_COST) 2,600에서 3,000으로 +15%. COLD_STORAGE_ACCESS(옛 COLD_SLOAD_COST) 2,100 유지. WARM_ACCESS(옛 WARM_STORAGE_READ_COST) 100 유지. ACCOUNT_WRITE 6,700 상당에서 9,000으로 +34%. STORAGE_WRITE 2,800 상당에서 10,000으로 +257%. CREATE_ACCESS 7,000 상당에서 12,000으로 +71%. STORAGE_CLEAR_REFUND(옛 SSTORE_CLEARS_SCHEDULE) 4,800에서 11,616으로 +142%. ACCESS_LIST_STORAGE_KEY_COST 1,900에서 2,000으로 +5%. ACCESS_LIST_ADDRESS_COST 2,400에서 2,900으로 +21%. 새 상수 세 개의 현재 값은 기존 복합 상수에서 뽑아낸 근사치입니다. 6,700은 CALL_VALUE 9,000에서 CALL_STIPEND 2,300을 뺀 값, 2,800은 GAS_STORAGE_UPDATE 5,000에서 GAS_COLD_SLOAD 2,100과 GAS_WARM_ACCESS 100을 뺀 값, 7,000은 GAS_CREATE 32,000에서 GAS_NEW_ACCOUNT 25,000을 뺀 값입니다. 기존 체계는 이 요소들로 딱 떨어지게 나뉘지 않습니다. 웜 SSTORE 2,900은 100 + 2,800으로 맞지만 콜드 SSTORE 5,000은 요소 합보다 100 많습니다. 컨트랙트 생성 거래와 CREATE·CREATE2는 CREATE_ACCESS 한 번만 내고 COLD_ACCOUNT_ACCESS나 ACCOUNT_WRITE를 따로 내지 않습니다. EOA 위임 설정은 EIP-8037의 EXECUTION_PER_AUTH_BASE_COST 안에서만 과금되고 위임 해석은 실행 중에 대상 코드를 읽는 것이라 일반 콜드·웜 접근 비용을 냅니다.
SSTORE 가격 공식과 환불 규칙
EIP-2200과 같이 원래 값은 거래 시작 시점의 슬롯 값, 현재 값은 SSTORE 직전의 값입니다. 비용은 세 요소의 합입니다. 접근 요소는 슬롯이 콜드면 COLD_STORAGE_ACCESS, 웜이면 WARM_ACCESS입니다. 쓰기 요소 STORAGE_WRITE는 새 값이 현재 값과 다르고 현재 값이 원래 값과 같을 때, 즉 슬롯을 처음 거래 시작 값에서 벗어나게 할 때만 냅니다. 상태 생성 요소 GAS_STORAGE_SET은 원래 값과 현재 값이 0이고 새 값이 0이 아닐 때 EIP-8037의 상태 가스로 냅니다. 환불 규칙은 SSTORE마다 평가합니다. 첫째, 원래 값과 현재 값이 0이 아니고 새 값이 0이면 STORAGE_CLEAR_REFUND를 더합니다. 둘째, 원래 값이 0이 아니고 현재 값이 0이고 새 값이 0이 아니면 STORAGE_CLEAR_REFUND를 뺍니다. 같은 거래에서 지웠다가 다시 채우는 일이 이득이 되지 않게 첫째 규칙을 되돌리는 것입니다. 셋째, 새 값이 원래 값과 같고 현재 값과 다르면 STORAGE_WRITE를 환불합니다. 이 되돌림이 없으면 x에서 0으로, 다시 x로 가는 왕복이 슬롯은 그대로인데 순환불을 남깁니다. 거래 전체로 보면 바뀐 값으로 끝나는 슬롯은 쓰기와 생성 요소를 딱 한 번, 원래 값으로 끝나는 슬롯은 접근 비용만 냅니다. 환불은 거래 환불 카운터에 쌓이고 총 사용 가스의 20%까지만 적용됩니다. 상태 가스의 환급(refill) 규칙은 EIP-8037에 있습니다.
계정 접근 연산별 규칙
CALL과 CALLCODE에서 CALL_VALUE는 ACCOUNT_WRITE + CALL_STIPEND로 다시 정의되고 CALL_STIPEND 2,300은 그대로입니다. ACCOUNT_WRITE는 수신자 잔액 리프를 쓰는 값이라 값을 보내는 호출마다 냅니다. EIP-161의 죽은 계정에 값을 보내는 CALL은 GAS_NEW_ACCOUNT를 상태 가스로 더 내며 CALLCODE는 수신자가 자기 자신이라 이 비용이 없습니다. CREATE와 CREATE2는 콜드·웜 구분 없이 고정 GAS_CREATE 32,000을 내던 것을 실행 가스 CREATE_ACCESS(ACCOUNT_WRITE + COLD_ACCOUNT_ACCESS)와 상태 가스 GAS_NEW_ACCOUNT로 나눕니다. 이 정의는 각주 3의 7,000과 맞지 않는데, 기존 회계가 애초에 일관되지 않아 그 차이를 그대로 둡니다. SELFDESTRUCT는 수혜자가 콜드면 보내는 잔액과 무관하게 COLD_ACCOUNT_ACCESS를 내고 웜이면 접근 비용이 없습니다. 수혜자가 실행 중인 계정 자신이거나 프리컴파일이어도 EIP-2929의 WARM_ACCESS 면제가 유지됩니다. 양의 잔액을 죽은 계정에 보내면 ACCOUNT_WRITE를 더 내고 GAS_NEW_ACCOUNT는 상태 가스로 그대로 남습니다. EXTCODESIZE와 EXTCODECOPY는 기존 접근 비용에 WARM_ACCESS를 하나 더 냅니다. 계정 객체(nonce, balance, codeHash, storageRoot)를 읽은 뒤 코드 크기나 바이트코드를 또 읽는데, 두 번째 읽기는 이미 웜인 계정 대상이라 WARM_ACCESS로 맞춘 것입니다. DELEGATECALL, STATICCALL, BALANCE, EXTCODEHASH는 쓰기 요소가 없습니다.
측정 방법: 클라이언트 벤치마크와 회귀 모델
가스값은 각 실행 클라이언트가 벤치마크를 실제로 도는 시간에서 나왔습니다. 특정 EVM 연산을 반복하는 합성 블록을 연산 횟수와 인자를 바꿔 가며 만들고(EEST 벤치마크 스위트), Benchmarkoor 도구로 블록 실행 시간과 연산 횟수를 잽니다. 모든 벤치마크는 2026년 3월 메인넷과 같은 크기의 스냅샷 위에서 클라이언트마다 여러 번 돌렸습니다. 연산 하나의 시간은 비음수 최소제곱 회귀(runtime = intercept + slope × operation_count)로 추정합니다. R²가 0.5 이상이고 p값이 0.05 미만인 모델만 씁니다. 테스트에 딸린 보조(glue) 옵코드 시간은 adjusted_slope = slope - sum(ratio_i * glue_runtime_i)로 빼되, 기준을 못 넘긴 glue 추정치는 빼지 않고 결과는 0 아래로 자릅니다. 클라이언트마다 결과가 다르면 최적화할 수 없는 가장 느린 클라이언트 값을 네트워크 전체 기준으로 삼습니다. 대응 관계는 test_account_access(NO_CACHE)의 value_sent=0이 COLD_ACCOUNT_ACCESS, value_sent=1이 COLD_ACCOUNT_WRITE, test_sload_bloated와 test_sstore_bloated(write_new_value=False)가 COLD_STORAGE_ACCESS, write_new_value=True가 COLD_STORAGE_WRITE, test_sload_same_key_benchmark와 test_ext_account_query_warm이 WARM_ACCESS입니다. 쓰기 비용은 쓰기 포함 추정치에서 접근 추정치를 빼서 구합니다. bloated 테스트는 메인넷 최대 컨트랙트와 같은 10기가바이트 저장소를 가진 컨트랙트가 대상입니다. 상태 생성 요소는 실행 시간이 아니라 상태 증가를 매기는 것이라 여기서 추정하지 않습니다.
가스 환산 공식과 파생 값
실행 시간은 목표 처리량 75 Mgas/s를 기준으로 raw_gas = ceil(anchor_rate * runtime_ms / 1000)으로 가스로 바꿉니다. anchor_rate는 초당 가스(75_000_000), runtime_ms는 회귀에서 나온 연산당 밀리초이며 올림해 정수 가스로 만듭니다. 쓰기 비용은 올림한 추정치끼리 빼서 구합니다. STORAGE_WRITE = max(0, COLD_STORAGE_WRITE - COLD_STORAGE_ACCESS), ACCOUNT_WRITE = max(0, COLD_ACCOUNT_CODE_WRITE - COLD_ACCOUNT_CODE_ACCESS, COLD_ACCOUNT_NOCODE_WRITE - COLD_ACCOUNT_NOCODE_ACCESS)입니다. 나머지는 EIP에서 고른 값에서 파생합니다. STORAGE_CLEAR_REFUND = (STORAGE_WRITE + COLD_STORAGE_ACCESS) * (4800/5000), ACCESS_LIST_STORAGE_KEY_COST = COLD_STORAGE_ACCESS - WARM_ACCESS, ACCESS_LIST_ADDRESS_COST = COLD_ACCOUNT_ACCESS - WARM_ACCESS, CREATE_ACCESS = ACCOUNT_WRITE + COLD_ACCOUNT_ACCESS입니다. 접근 목록 두 값에서 WARM_ACCESS를 빼는 이유는, 목록에 적힌 슬롯이나 계정은 거래가 건드릴 때 이미 웜이라 그 시점에 WARM_ACCESS를 또 내기 때문입니다. 빼지 않으면 한 번만 쓰는 항목이 COLD_ACCESS + WARM_ACCESS가 되어 목록을 쓰는 쪽이 항상 더 비쌉니다. EIP-7928 블록 수준 접근 목록이 가능하게 하는 병렬 디스크 읽기, 병렬 거래 검증, 실행 없는 상태 갱신 같은 최적화는 그 최적화를 구현한 클라이언트에서 벤치마크를 돌려 이미 반영했습니다.
호환성과 보안 고려 사항
하위 호환되지 않는 가스 재조정이라 예정된 네트워크 업그레이드가 필요합니다. 지갑은 eth_estimateGas를 쓸 때 새 가스 파라미터를 제대로 반영하도록 반드시 갱신해야 합니다. 그러지 않으면 가스를 적게 잡아 거래가 실패할 수 있습니다. 노드 소프트웨어의 eth_estimateGas 같은 RPC 메서드도 새 상태 접근 비용이 들어간 공식을 반드시 포함해야 합니다. 사용자는 지갑과 RPC가 갱신되면 평소 방식 그대로 쓸 수 있습니다. 보안 측면에서는 상태 접근 비용 변경이 특정 애플리케이션의 사용성에 영향을 줄 수 있으며 여러 dApp과 사용자 행동에 미치는 효과를 이해하려면 더 분석이 필요하다고 적혀 있습니다.
원문 상태와 코어 개발자 콜 결정
원문 상태는 Last Call이며 마감(last-call-deadline)은 2026-11-01입니다. EIP-8037을 요구(requires)합니다. 코어 개발자 콜 기록은 이렇습니다. 07.06 ACDT #86에서 프리즈 이후에는 EIP-8038과 2780의 가스비 같은 파라미터 단독 변경만 허용하고 구조 변경은 막기로 확정했습니다. 상수 값은 손봐도 설계는 바꾸지 않는다는 뜻입니다. 08.03 ACDT #90에서 SLOAD는 현행 2,100 유지, 계정 쓰기는 9K, 앵커는 75 Mgas/s로 고정하기로 하고 모든 EL 클라이언트가 승인했습니다. 옵코드 사이 상대 가격을 지금 확정하고 앞으로는 블록 한도만 조정한다는 뜻입니다. 08.13 ACDE #243에서 가스 재조정 수치가 최종 확정됐고 스펙 변경이 필요 없으며 글램스테르담(Glamsterdam)의 200M 가스 한도가 확인됐습니다. 클라이언트는 코드를 바꾸지 않아도 됩니다. 09.14 ACDT #96에서 SELFDESTRUCT 수혜자 관련 PR EIPs#12317을 EIP 문구 명확화로 승인했으며 스펙이나 클라이언트 동작은 바뀌지 않습니다. 07.02 ACDE #240과 10.26 ACDT #102에서는 논의만 있었고 결정은 없었습니다.