EIP-7862 지연 상태 루트 (Delayed State Root)
Hegota 포함 제외 (DFI) · 확장성·데이터 · 원문 상태 Draft · 2024-12-23 작성
블록 헤더에 그 블록 자신의 상태 루트 대신 직전 블록의 사후 상태 루트를 담아, 상태 루트 계산을 블록 검증에서 분리하는 제안입니다.
왜 필요한가
이더리움 블록 헤더에는 그 블록의 모든 거래를 실행한 뒤의 장부 요약값인 상태 루트(state root)가 들어갑니다. 이 값을 계산하는 일이 블록 생산의 큰 병목입니다. 블록을 만드는 빌더는 어떤 거래 조합이 가장 수익이 좋은지 겨루는 MEV 경매 동안 조합을 바꿀 때마다 상태 루트를 다시 계산해야 해서 한 슬롯에 수천 번을 계산하게 됩니다. ePBS(EIP-7732)가 도입되면 빌더의 시간 여유는 더 빠듯해집니다. 블록이 건드린 저장 공간 목록인 블록 접근 목록(Block-Level Access Lists, EIP-7928)은 상태 읽기·쓰기를 병렬화해 주지만 상태 루트는 실행이 끝나야 알 수 있어서 같은 슬롯 안에서는 도움이 되지 않습니다. 이 제안은 상태 루트를 한 블록 늦게 헤더에 담아, 검증자가 상태 루트 계산을 기다리지 않고 블록 유효성을 증명할 수 있게 합니다.
무엇이 바뀌나
지금
- 블록 n의 헤더에 블록 n 자신의 사후 상태 루트가 들어갑니다.
- 빌더는 MEV 경매 동안 상태 루트를 수천 번 계산합니다.
- 상태 루트 계산이 끝나야 검증자가 블록에 증명할 수 있습니다.
- BAL이 있어도 상태 루트 계산에는 도움이 되지 않습니다.
EIP-7862 이후
- 블록 n의 헤더에 블록 n-1의 사후 상태 루트가 들어갑니다.
- 빌더는 슬롯당 한 번(직전 블록 몫)만 상태 루트를 계산합니다.
- 상태 루트 계산이 슬롯 앞부분으로 옮겨져 증명을 막지 않습니다.
- 직전 블록의 BAL 데이터로 상태 루트 계산을 병렬화할 수 있습니다.
누구에게 영향이 있나
- 블록 빌더: MEV 경매 동안 수천 번 하던 상태 루트 계산이 슬롯당 한 번으로 줄고 BAL 상태 변경분을 적용해 직전 블록을 완전히 실행하지 않고도 다음 블록 구성을 시작할 수 있습니다.
- 클라이언트 팀: 헤더 검증, 상태 전이, 리오그 처리 로직을 바꾸는 하드포크 구현이 필요합니다. 미구현 클라이언트는 지연 상태 루트가 담긴 블록을 거부합니다.
- 검증자: 상태 루트 계산 완료를 기다리지 않고 블록 유효성에 증명할 수 있습니다.
- 라이트 클라이언트: 블록 n의 상태 증명을 받으려면 블록 n+1까지 한 슬롯을 더 기다려야 합니다. 보안 모델은 그대로입니다.
심층 설명
헤더: 필드 추가 없이 의미만 변경
Header의 state_root 필드 의미가 바뀝니다. 블록 n의 state_root는 블록 n-1의 사후 상태(post-state), 곧 블록 n의 사전 상태(pre-state)를 가리킵니다. 새 필드는 추가되지 않습니다. 명세의 Header 클래스에는 parent_hash, state_root, transactions_root, receipt_root 등 기존 필드와 함께 block_access_list_hash가 포함되어 있어 BAL(EIP-7928)을 전제로 합니다.
last_computed_state_root와 헤더 검증
BlockChain 객체에 last_computed_state_root 필드가 추가되어 마지막으로 계산한 상태 루트를 추적합니다. validate_header는 header.number가 1 미만이면 InvalidBlock을 올리고 header.state_root가 chain.last_computed_state_root와 다르면 InvalidBlock을 올립니다. 나머지 헤더 검증은 그대로입니다. 즉 블록의 상태 루트 검증이 '이 블록을 실행한 결과와 맞는가'에서 '직전 블록 실행 후 계산해 둔 값과 맞는가'로 바뀝니다.
상태 전이: 루트 계산을 실행 뒤로
state_transition은 먼저 validate_header를 수행한 뒤 apply_body로 거래와 출금을 실행합니다. 실행 결과 검증에서 state_root는 제외됩니다. 헤더 검증에서 이미 확인했기 때문입니다. block_gas_used와 header.gas_used 불일치 등 다른 검증은 유지됩니다. 실행이 끝나면 state_root(block_env.state)를 계산해 chain.last_computed_state_root에 저장하고 이 값이 다음 블록의 헤더 검증에 쓰입니다. 블록 목록은 최근 255개까지만 유지합니다.
포크 활성화와 하위 호환성
활성화 블록 F에서 apply_fork는 last_computed_state_root를 현재 상태 루트, 곧 블록 F-1의 사후 상태 루트로 초기화합니다. 블록 F는 블록 F-1의 사후 상태 루트를 담아야 하며(MUST), F+1부터는 각 블록이 부모 블록의 사후 상태 루트를 담습니다. 이 변경은 하드포크가 필요하고 구현하지 않은 클라이언트는 지연 상태 루트가 담긴 블록을 거부합니다.
ePBS 호환성과 BAL 시너지
EIP-7732(ePBS)에서 ExecutionPayloadEnvelope는 process_execution_payload 끝에 검증되는 합의 계층(CL) state_root를 담는데, 이 제안은 실행 계층(EL) 헤더의 state_root 의미만 바꾸므로 CL 쪽 검증에는 영향이 없습니다. BAL(EIP-7928)과의 시너지가 핵심입니다. 클라이언트는 블록 n을 BAL과 함께 받고 BAL로 블록 n의 상태 루트 계산을 병렬화한 뒤, 그 루트를 블록 n+1에 포함합니다. 이 제안이 없으면 상태 루트는 실행이 끝나야 알 수 있어 같은 슬롯 안에서는 BAL이 루트 계산에 도움이 되지 않습니다. 또한 빌더는 BAL의 상태 변경분을 슬롯의 사전 상태에 적용해, 직전 블록을 완전히 실행하지 않고도 블록 구성을 시작할 수 있습니다.
라이트 클라이언트 영향
블록 n에 대한 상태 증명은 블록 n+1이 나올 때까지 기다려야 합니다. 대부분의 라이트 클라이언트 프로토콜은 이미 증명 생성에 여러 블록의 지연을 허용하므로 영향은 제한적입니다. 보안 모델은 바뀌지 않고 타이밍만 한 슬롯 늦어집니다.
보안 고려: 리오그와 사전 상태 보존
체인 재구성(reorg)이 일어나면 클라이언트는 새 정규 체인의 각 블록에 대해 last_computed_state_root를 다시 계산해야 합니다(MUST). 루트가 지연된다는 특성 자체가 리오그 로직을 바꾸지는 않습니다. 또 클라이언트는 현재 블록의 상태 루트가 다음 블록에 포함될 때까지 사전 상태(부모 블록의 사후 상태)를 보존해야 하는데(MUST), 이는 리오그 대응을 위해 이미 표준적으로 하고 있는 관행입니다.
진행 상태: 헤고타 후보에서 제외
07.02 ACDE #240에서 EIP-7862가 헤고타(Hegota) 후보로 접수되었으나(PFI), 09.10 ACDE #245에서 제외되었습니다(DFI). BAL 이후 병렬 계산이 가능해 스테이트 루트가 큰 병목은 아니라는 반론이 우세했고 바이너리 트라이 작업과 함께 향후 포크에서 재검토할 수 있다는 결정이었습니다. 원문 상태도 Draft라 명세 내용은 앞으로 바뀔 수 있습니다.