EIP-8279 블록 접근 목록 바이트 하한 (Block Access List Byte Floor)

Hegota 포함 검토 (CFI) · 수수료·가스 · 원문 상태 Draft · 2026-05-23 작성

실행 중 블록 접근 목록(BAL)에 더해지는 바이트를 거래마다 세어 바이트당 64가스로 EIP-7623 하한 요금에 합칩니다. 60M 가스 블록의 최악 크기가 약 1.55MiB에서 약 0.89MiB로 줄어듭니다.

왜 필요한가

노드는 평균 블록이 아니라 공격자가 만들 수 있는 가장 큰 블록을 처리할 수 있어야 합니다. 이더리움은 호출 데이터(calldata) 한 바이트에 최소 64가스를 물리는 EIP-7623으로 최악의 블록 크기를 눌러 왔고 EIP-7981과 EIP-8131이 그 하한 요금(floor)을 접근 목록, 위임 서명, 블롭 해시 등 거래 안의 모든 내용으로 넓혔습니다. 그런데 EIP-7928의 블록 접근 목록(Block Access List, BAL)은 거래 내용과 달리 실행 중 명령어가 채우는 새 바이트 공급원이라 이런 고정 하한이 전혀 닿지 않습니다. 가장 싼 경로는 거래 안에서 처음 읽는 저장소 슬롯(콜드 SLOAD)으로, 2,100가스에 BAL 32바이트를 더합니다. 공격자가 호출 데이터를 전부 0이 아닌 값으로 채워 고유 가스(intrinsic gas)를 하한 위로 올려 두면, 호출 데이터는 바이트당 16가스에 사고 나머지 블록은 SLOAD 키로 채울 수 있습니다. 60M 가스 블록에서 순수 호출 데이터 공격은 0.894MiB에 그치지만 EIP-8131만 있을 때 위임 서명 우회는 1.067MiB, EIP-7928 아래 콜드 SLOAD 우회는 1.548MiB까지 커집니다. SSTORE, 주소 접근, CREATE, 성공한 EIP-7702 위임도 같은 구멍입니다.

무엇이 바뀌나

지금

EIP-8279 이후

누구에게 영향이 있나

심층 설명

상수와 거래별 계측기

요율과 단위는 상수입니다. FLOOR_GAS_PER_BYTE = 64(EIP-7976), TX_MAX_GAS_LIMIT = 16_777_216(EIP-7825), BAL_BYTES_PER_ADDRESS = 20, BAL_BYTES_PER_STORAGE_KEY = 32, BAL_BYTES_PER_STORAGE_VALUE = 32, BAL_BYTES_PER_BALANCE = 32, BAL_BYTES_PER_NONCE = 8, DELEGATION_CODE_BYTES = 23입니다. 클라이언트는 거래가 끝날 때까지 카운터 2개와 집합 3개를 둡니다. bal_data_bytes는 실행이 BAL에 더한 바이트 수, floor_gas_used는 고정 시드에 계측 바이트를 더한 하한 누산기이고 metered_addresses, metered_storage_keys, metered_storage_values는 이미 계측한 주소와 (storage_address, key) 쌍을 기억해 중복 계측을 막습니다. 어느 것도 서명된 거래에 들어가지 않고 RLP 인코딩, 전파, 저장도 되지 않으며 새 거래 필드나 타입도 없습니다. meter_bal_data는 new_floor = static_floor + new_bal_data_bytes × FLOOR_GAS_PER_BYTE를 구해 execution_budget = min(tx.gas, TX_MAX_GAS_LIMIT)를 넘으면 OutOfGasError를 냅니다. 실행 가스 예산에서 가스를 떼거나 빼지는 않습니다. 계측은 반드시 해당 BAL 삽입이나 상태 변경 전에, EIP-7928이 요구하는 사전 상태 실행 가스 검증이 통과한 뒤에 합니다. 사전 검증에 실패한 접근은 아무것도 계측하지 않고 계측 단계의 OutOfGasError는 값을 내지 않은 BAL 바이트가 생기기 전에 멈춥니다. 계측값은 실제 BAL 기여의 의도적 상한이라 과대 계산은 하한을 올릴 뿐 낮추지 않습니다.

고정 하한 시드와 위임 서명의 정적 처리

거래 내용 몫의 하한 tx_floor는 EIP-8131이 정의합니다. 이 EIP는 위임 서명을 처리할 때 생기는 BAL 몫을 정적으로 더합니다. auth_bal_bytes = 20(권한자 주소) + 23(위임 표시 코드) + 8(권한자 논스) = 51이고 static_floor = tx_floor + FLOOR_GAS_PER_BYTE × auth_bal_bytes × num_authorizations입니다. 실행 시작 시 floor_gas_used를 이 값으로, bal_data_bytes를 0으로 둡니다. 정적으로 처리하는 이유는 set_delegation이 EVM의 예외 처리기 밖에서 실행되기 때문입니다. 거기서 meter_bal_data가 OutOfGasError를 내면 잡히지 않고 퍼져 블록 처리가 멈춥니다. EIP-8131이 매기는 108바이트 튜플에 51바이트를 더한 159바이트를 미리 하한에 넣으면 set_delegation이 상태를 자유롭게 바꿀 수 있고 예산이 모자라는 거래는 검증 단계에서 이미 거절됩니다. 명령어가 놓지 않는 BAL 항목도 있습니다. 발신자, 코인베이스, 최상위 대상 주소, 발신자와 코인베이스 잔액, 발신자 논스, 최상위 값 전송의 수신자 잔액, 최상위 생성 대상 논스, 선택적인 최상위 EIP-7702 위임 대상으로 합쳐서 최대 184바이트이며 TX_BASE에 이미 있는 TX_BASE / FLOOR_GAS_PER_BYTE = 328바이트 여유가 모두 덮습니다. 거래 검증은 계속 execution_budget >= max(intrinsic, static_floor)를 요구합니다.

실행 중 계측 트리거

각 트리거는 해당 BAL 항목이 추가되기 전에 정해진 바이트를 계측합니다. 거래 안에서 계정을 처음 만지는 BALANCE, EXT*, CALL*, SELFDESTRUCT 수혜자, CREATE/CREATE2 배포 주소는 20바이트, SLOAD나 SSTORE로 저장소 키를 처음 만지면 32바이트입니다. current == original이고 new != original인 SSTORE는 그 (storage_address, key) 쌍이 아직 계측되지 않았을 때만 +32바이트입니다. 다른 계정으로 값을 보내는 CALL은 호출자와 수신자 잔액으로 64바이트, 잔액이 있는 SELFDESTRUCT가 다른 수혜자로 가면 64바이트입니다. CREATE/CREATE2는 생성자 논스 증가 전 8바이트, 충돌 검사 뒤 새 계약 논스 8바이트, 기부금이 있으면 +64바이트이고 배포에 성공하면 set_code 직전에 len(deployed_code)를 계측합니다. CALLCODE, DELEGATECALL, STATICCALL은 실행 계정 밖으로 값을 보내지 않아 잔액 바이트가 없습니다. 첫 접촉 집합은 EVM의 warm 상태와 무관합니다. EIP-2930 접근 목록으로 미리 데워진 주소나 키도 실행이 처음 만지면 EIP-7928이 BAL에 넣으므로 다시 계측합니다. 저장소 값 32바이트는 슬롯당 거래당 최대 한 번만 계측하고 metered_storage_values는 되감지 않으며 나중에 원래 값으로 되돌려도 환불하지 않습니다. storage_address는 현재 실행 컨텍스트가 저장소를 수정하는 계정이므로 CALLCODE와 DELEGATECALL에서는 코드를 실행하는 계정이 아닙니다.

최종 청구, 예산 상한, 블록 크기 상한

tx.gasUsed = max(execution_gas_used, tx_env.floor_gas_used)입니다. 실행 중 장치는 예약이 아니라 카운터입니다. 실행 예산에서 가스를 빼거나 미리 묶지 않고 bal_data_bytes와 floor_gas_used만 늘리며 하한이 execution_budget 이하인지 확인합니다. 하한 누산기는 선불로 뗀 tx.gas × gas_price 중 얼마를 남기고 얼마를 돌려줄지만 정합니다. 상한을 tx.gas 대신 min(tx.gas, TX_MAX_GAS_LIMIT)로 두는 이유는 EIP-8037 때문입니다. 그 아래서는 tx.gas가 EIP-7825 상한을 넘을 수 있고 초과분은 상태 요금만 쓰는 상태 가스 저장소에 들어갑니다. 하한을 tx.gas까지 허용하면 저장소가 큰 배포 거래가 코드 예치 바이트로 하한을 TX_MAX_GAS_LIMIT 너머로 밀어 검증이 정적으로 강제한 거래당 실행 상한과 블록이 확보한 실행 용량을 넘기게 됩니다. EIP-8037이 없으면 tx.gas가 TX_MAX_GAS_LIMIT를 넘지 않아 예산은 tx.gas와 같습니다. 시스템 컨트랙트 호출(EIP-2935, EIP-4788, EIP-7002, EIP-7251)과 인출은 거래별 하한을 쓰지 않고 EIP-7928의 블록 단위 버퍼 bal_items <= block_gas_limit / ITEM_COST(60M 기준 약 1,428개)가 흡수합니다. 그래서 거래당 block_bytes_per_tx × FLOOR_GAS_PER_BYTE ≤ tx_env.floor_gas_used ≤ tx.gasUsed가 성립하고 사용자 거래를 모두 더하면 sum(block_bytes) ≤ sum(tx.gasUsed) / 64 ≤ block_gas_limit / 64입니다.

왜 하한 쪽에 물리고 요율을 하나로 두는가

실행 요금을 올리면 우회를 하지 않는 사용자까지 손해를 봅니다. 하한은 실행이 너무 싸서 하한을 못 덮을 때만 작동하고 그것이 바로 우회 상황입니다. 고유 가스에 SLOAD당 X를 더하는 방식은 블록을 gas_limit / 64로 묶지 못합니다. 최적 우회가 여전히 B = gas_limit / 64 + 24 · gas_limit / (2100 + X)바이트를 내고 잔여항은 X가 아주 커져야 사라집니다. 하한 쪽 청구는 닫힌 상한을 바로 줍니다. 모든 BAL 바이트를 0이 아닌 호출 데이터와 같은 FLOOR_GAS_PER_BYTE로 매기면 호출 데이터, 위임 서명, 저장소 키, 주소, 코드, 잔액 어느 것을 골라도 하한에서 가스당 1/64바이트라 공격자의 선택과 무관해지고 최적값은 B = gas_limit / 64로 수렴합니다. 실행 중 확장은 실행 가스가 구속하지 않을 때도 하한을 구속시킬 수 있어 실행 가스 예산과 대조합니다. EIP-2930으로 데워진 계정 첫 접촉은 하한 1,280 대 실행 100, 데워진 SLOAD는 2,048 대 100, 데워졌지만 미계측인 수혜자로 가는 SELFDESTRUCT는 84 × 64 = 5,376 대 5,000입니다. 배포 코드는 바이트당 64 대 200이고 EIP-8037 아래서는 코드 예치 실행 요금이 워드당 6가스로 바이트당 0.2가스 미만이 되어 하한 초과 폭이 가장 넓은 트리거가 됩니다. 그래도 주된 대량 사례는 EIP-8131의 고정 시드가 이미 실행 예산에 가까운 호출 데이터 + SLOAD 우회입니다.

계측은 먼저, 환불은 없음: 되돌리기와 반복 쓰기

EIP-7928은 호출 프레임이 되돌려져도 접근한 주소와 저장소 키를 BAL에 남깁니다. 삽입 전에 계측하면 모든 BAL 바이트가 빠짐없이 계산되고 계측 단계의 OOG는 삽입 전에 멈춥니다. 되돌려진 프레임의 잔액, 논스, 코드, 저장소 값 변경은 버려지지만 bal_data_bytes, floor_gas_used, 세 집합은 되감지 않고 저장소 값 요금도 환불하지 않습니다. 슬롯이 원래 값으로 돌아올 때 환불하려면 호출 프레임 상태와 함께 저널링해야 합니다. 되돌리는 쓰기가 나중에 revert되면 이전 값 변경이 BAL에 다시 나타나는데 바이트는 환불된 채로 남기 때문입니다. 단조 증가하는 metered_storage_values 집합은 슬롯당 한 번만 물려 롤백 장치 없이 상한을 지킵니다. 집합이 없으면 원래 값 O를 떠났다 돌아오는 순환마다 2,048가스가 더 붙지만 EIP-7928은 슬롯당 사후 값을 최대 하나만 기록합니다. 테스트 케이스로 보면 O를 X로 바꿨다가 O로 되돌리는 왕복은 키 32 + 값 32 = 64바이트를 계측해 BAL보다 32바이트 과대 계산입니다. O에서 A, B, C로 연속으로 바꾸는 경우와 A로 갔다가 O로 돌아온 뒤 B로 가는 경우는 모두 64바이트로, BAL이 기록하는 단일 사후 값과 일치합니다. 값이 있는 CALL이 revert되면 64바이트가 과대 계산됩니다. 콜드 SSTORE(0에서 0 아닌 값)는 64바이트로 4,096가스지만 실행 요금 22,100이 더 커서 실행 쪽이 지배합니다. 과대 계산은 있어도 과소 계산은 없으므로 상한은 유지됩니다.

호환성, 메인넷 표본, 가스 추정

하드포크 변경입니다. 위임 서명당 합산 하한은 (108 + 51) × 64 = 10,176가스로 서명당 고유 가스 PER_EMPTY_ACCOUNT_COST = 25,000보다 여전히 낮습니다. 정적 거래 검증은 이 합산 고정 하한이 지배할 때만 달라집니다. 실행 중에는 BAL 확장이 gasUsed를 올리거나, 새 하한이 실행 예산을 넘으면 OutOfGasError를 낼 수 있고 미리 데워진 첫 접촉도 포함됩니다. 단순 ETH 송금은 21,000 그대로입니다. 2026년 5월 메인넷 표본(무작위 1,500블록, 거래 441,271건, 그중 20,000건 BAL 바이트 추적)에서 EIP-8131 단독으로는 거래의 3.24%가 더 내고 가스는 +3.29%였습니다. EIP-8279는 여기에 0.54%p와 +0.77%p를 더해 합계 3.79% / +4.06%입니다. 표본에서 BAL 몫이 단독으로 구속한 경우는 없었습니다. TX_BASE 흡수 후 거래당 BAL 바이트는 평균 120~200바이트, 하한 가스로 13k 미만이라 보통의 실행 가스보다 훨씬 낮습니다. 이 EIP의 주된 역할은 EIP-8131과 짝을 이뤄 호출 데이터 + SLOAD 우회를 막는 것이지 널리 구속하는 독립 하한을 더하는 것이 아닙니다. 지갑과 eth_estimateGas는 서명당 항을 포함한 새 고정 하한을 계산하고 실행을 추적할 때 첫 접촉, 값 전송 호출, 배포의 BAL 바이트를 고유 가스와 함께 세어야 합니다. 빠뜨리면 하한에 걸리는 거래의 추정이 낮아져 정적 검증은 통과하고도 실행 중 OutOfGasError로 멈출 수 있습니다.

상태와 코어 개발자 콜 결정

원문 상태는 Draft입니다. 상수, 계측 트리거, 표본 수치 모두 아직 바뀔 수 있습니다. 코어 개발자 콜에서는 09.24 ACDE #246에서 EIP-8131과 묶어 이 BAL 바이트 플로어 EIP를 헤고타(Hegota) 포함 검토(CFI)로 올렸습니다. 평가가 가장 높던 후보들이 한꺼번에 다음 단계로 넘어간 자리였습니다. 10.12 ACDT #100에서도 논의됐지만 결정은 없었습니다. 원문도 두 EIP가 서로를 필요로 한다고 씁니다. EIP-8131은 BAL 바이트에 값을 매기지 않고 EIP-8279는 EIP-8131의 하한을 재사용하므로, 어느 하나만으로는 우회가 닫히지 않습니다.

EIP 원문 · ← EIPs