EIP-8411 실행 페이로드 빠른 전파 (Fast Execution Payload Broadcast)
Hegota 포함 검토 (CFI) · 네트워크·노드 · 원문 상태 Draft · 2026-09-05 작성
EIP-7732가 실행 페이로드를 한 덩어리 메시지로 보내던 방식을 64조각으로 나눠 보내는 방식으로 바꿉니다. 빌더가 입찰에 조각 묶음의 머클 루트를 넣어 각 조각을 따로 검증할 수 있게 합니다.
왜 필요한가
EIP-7732가 가능하게 하는 가스 한도 증가는 실행 페이로드가 커진다는 뜻입니다. 페이로드가 커지면 네트워크에 퍼지는 시간이 길어집니다. 페이로드 적시성 위원회(Payload Timeliness Committee, PTC) 멤버가 증명 마감 안에 페이로드를 받지 못하면 멀쩡한 페이로드도 누락된 것으로 처리됩니다. 지금의 execution_payload 가십 토픽은 페이로드가 커질수록 두 가지 문제가 두드러집니다. 첫째, 큰 메시지를 이미 받은 노드가 다른 경로로 들어오는 중복 전송을 중간에 끊기 어려워 같은 바이트가 여러 번 도착하고 새 데이터를 나를 수 있는 대역폭을 잡아먹습니다. 둘째, 노드는 메시지를 전부 받은 뒤에야 다음 노드로 넘길 수 있어 홉(hop, 노드 사이의 한 단계 전달)마다 전체 전송이 한 번씩 더해지고 지연이 메시지 크기와 홉 수의 곱에 비례해 늘어납니다. 메시지를 조각으로 나누면 두 문제가 모두 줄어듭니다. 조각 단위에서는 큰 중복이 생길 수 없고 노드가 조각을 받는 즉시 전달할 수 있어 홉들이 차례로 줄 서는 대신 겹쳐서 진행됩니다.
무엇이 바뀌나
지금
- 빌더가 실행 페이로드 봉투를 execution_payload 토픽에 한 덩어리 메시지로 보냅니다.
- 노드는 메시지를 끝까지 받은 뒤에야 다음 노드로 넘길 수 있어 홉마다 전체 전송 시간이 더해집니다.
- 큰 메시지가 여러 경로로 겹쳐 들어와도 중간에 끊기 어려워 같은 바이트를 여러 번 받습니다.
- 봉투 안에 비콘 블록 루트(beacon_block_root)가 들어 있습니다.
EIP-8411 이후
- 봉투를 64조각으로 나눠 execution_payload_chunks 토픽으로 보내고 기존 토픽은 없앱니다.
- 조각 하나가 도착하면 입찰에 담긴 머클 루트로 바로 검증하고 나머지를 기다리지 않고 바로 전달합니다.
- 중복이 생겨도 조각 크기만큼이라 낭비되는 대역폭이 작습니다.
- 비콘 블록 루트는 봉투에서 빠지고 각 조각 메시지에 힌트로 실립니다.
누구에게 영향이 있나
- 합의 클라이언트 팀: 새 가십 토픽, Seen 캐시 확장, 조각 검증 규칙, 봉투 재조립을 구현해야 합니다. 기존 토픽이 제거되므로 포크가 필요합니다.
- 빌더: 입찰을 만들 때 봉투를 미리 조각 내 payload_chunks_root를 계산해 넣고 자기 입찰이 담긴 블록을 본 뒤 64개 조각 메시지를 발행합니다.
- 검증자와 PTC: 조각이 도착하는 대로 전달되므로 페이로드를 증명 마감 안에 받을 가능성이 커집니다.
- 일반 사용자와 앱 개발자: 지갑이나 앱의 사용 방식은 바뀌지 않습니다. 노드 사이의 전파 방식만 바뀌며 더 큰 페이로드를 받칠 수 있는 기반이 됩니다.
심층 설명
상수, 타입, 입찰에 들어가는 커밋
조각 수 TOTAL_EXECUTION_PAYLOAD_CHUNKS는 64, 포함 증명 깊이 CHUNK_INCLUSION_PROOF_DEPTH는 6입니다. 조각 하나의 최대 크기 MAX_PAYLOAD_CHUNK_SIZE는 MAX_PAYLOAD_SIZE // TOTAL_EXECUTION_PAYLOAD_CHUNKS로 163,840바이트입니다. 새 타입 ChunkIndex는 uint64로 0부터 TOTAL_EXECUTION_PAYLOAD_CHUNKS - 1까지의 조각 번호이고 Chunk는 ByteList[MAX_PAYLOAD_CHUNK_SIZE]로 직렬화된 ExecutionPayloadEnvelope의 연속된 한 구간입니다. 커밋은 입찰에 실립니다. ExecutionPayloadBid에 payload_chunks_root: Root 필드가 추가되는데, 직렬화된 봉투의 조각들을 각각 SHA-256으로 해시해 Vector[Bytes32, TOTAL_EXECUTION_PAYLOAD_CHUNKS]에 담고 SSZ hash_tree_root를 구한 값입니다. 수신자는 입찰 서명을 한 번만 확인하고 조각마다 머클 포함 증명을 한 번씩 확인하면 됩니다. 봉투를 다시 조립한 뒤에는 비콘 블록에 약속된 페이로드 해시와 반드시 대조해야 합니다(MUST).
봉투에서 빠지는 블록 루트와 PayloadChunk 메시지
ExecutionPayloadEnvelope는 payload, execution_requests, parent_beacon_block_root, builder_index를 담고 기존의 beacon_block_root는 빠집니다. 빌더가 입찰을 만드는 시점에는 블록이 아직 없어 블록 루트를 알 수 없기 때문입니다. EIP-7732에서는 입찰이 블록에 들어간 것을 본 뒤 봉투를 만들어 루트를 넣을 수 있었습니다. 블록 루트는 대신 조각 메시지에 실립니다. PayloadChunk는 payload_chunks_root, index, chunk, chunk_inclusion_proof(Vector[Bytes32, CHUNK_INCLUSION_PROOF_DEPTH]), slot, beacon_block_root로 구성됩니다. payload_chunks_root는 입찰의 커밋과 같은 값이며 조각 묶음을 식별합니다. 입찰은 자체 가십 토픽으로 블록보다 먼저 퍼지므로, 그 루트를 커밋한 유효한 입찰을 본 수신자는 블록을 기다리지 않고 조각을 바로 검증할 수 있습니다. slot과 beacon_block_root는 포함 증명 밖에 있는 인증되지 않은 힌트입니다. slot은 조각을 슬롯 창으로 싸게 거르는 용도이고 그 루트를 커밋한 입찰의 슬롯과 같아야 합니다(MUST). beacon_block_root는 해당 블록을 찾거나 요청하는 용도이고 그 입찰을 담은 블록의 루트와 같아야 합니다(MUST). 수신자는 두 필드를 인증된 값으로 취급하면 안 되고(MUST NOT) 조회 경로를 정하는 데만 씁니다. 조각과 입찰을 묶는 것은 오직 payload_chunks_root입니다.
조각 나누기 규칙과 포함 증명
빌더는 반드시(MUST) 다음 방식으로 조각과 payload_chunks_root를 만들어야 합니다. compute_payload_chunks는 봉투를 serialize한 바이트열 data에 대해 chunk_size = (len(data) + TOTAL_EXECUTION_PAYLOAD_CHUNKS - 1) // TOTAL_EXECUTION_PAYLOAD_CHUNKS를 구하고, start = i * chunk_size일 때 i번째 조각을 data[start:start + chunk_size]로 잘라 TOTAL_EXECUTION_PAYLOAD_CHUNKS개를 만듭니다. 패딩은 넣지 않습니다. 내용이 있는 마지막 조각은 더 짧을 수 있고 그 뒤 조각들은 비어 있을 수 있습니다. compute_payload_chunks_root는 각 조각의 SHA-256 해시 hash(chunk)를 Vector[Bytes32, TOTAL_EXECUTION_PAYLOAD_CHUNKS]의 리프로 놓고 hash_tree_root를 구합니다. chunk_inclusion_proof는 그 리프에 대응하는 머클 가지입니다. verify_payload_chunk_inclusion_proof는 is_valid_merkle_branch에 leaf=hash(chunk), branch=chunk_inclusion_proof, depth=CHUNK_INCLUSION_PROOF_DEPTH, index=index, root=payload_chunks_root를 넣어 확인합니다. 수신자는 조각 0부터 TOTAL_EXECUTION_PAYLOAD_CHUNKS - 1까지 이어 붙여 역직렬화합니다. 각 리프가 조각의 정확한 바이트를 해시하므로 떼어낼 것은 없습니다.
새 가십 토픽과 Seen 캐시 확장
execution_payload_chunks 토픽이 새로 생기고 execution_payload 토픽은 폐기됩니다. 새 토픽은 PayloadChunk 메시지를 나릅니다. 빌더는 자기 입찰이 담긴 비콘 블록을 관측한 뒤 TOTAL_EXECUTION_PAYLOAD_CHUNKS개의 PayloadChunk를 만들어 토픽에 발행합니다. 가십 검증 함수가 쓰는 Seen 캐시에는 두 집합이 추가됩니다. payload_chunks_roots는 Set[Tuple[Slot, Root]]로, 입찰 토픽에서 수락된 SignedExecutionPayloadBid마다, 그리고 유효한 비콘 블록에 든 입찰마다 (bid.slot, bid.payload_chunks_root)를 넣습니다. 항목은 해당 슬롯이 끝날 때까지(MAXIMUM_GOSSIP_CLOCK_DISPARITY 범위 안에서) 반드시 유지하고(MUST) 그 뒤에는 지워도 됩니다(MAY). 입찰 토픽의 검증 규칙이 슬롯당 들어오는 입찰 수를 제한하므로 이 집합은 작게 유지됩니다. payload_chunk_tuples는 Set[Tuple[Root, ChunkIndex]]로, 수락된 조각마다 (payload_chunks_root, index)를 기록합니다. 컬럼 사이드카의 data_column_sidecar_tuples와 같은 역할이며 처음 본 조각인지 가리는 검사의 근거가 됩니다.
조각을 전달하기 전 거치는 가십 검증
노드는 다음 검증을 모두 통과한 PayloadChunk만 토픽에 전달해야 합니다(MUST). [IGNORE] chunk.slot이 현재 슬롯과 같아야 하며 MAXIMUM_GOSSIP_CLOCK_DISPARITY만큼의 오차를 허용합니다. [REJECT] chunk.index가 TOTAL_EXECUTION_PAYLOAD_CHUNKS보다 작아야 합니다. [IGNORE] (chunk.slot, chunk.payload_chunks_root)가 seen.payload_chunks_roots에 있어야 합니다. 클라이언트는 모르는 루트를 가리키는 조각을 잠시 큐에 두었다가 입찰이 도착하면 다시 검증해도 됩니다(MAY). [REJECT] verify_payload_chunk_inclusion_proof(chunk)가 참이어야 합니다. [REJECT] 노드가 chunk.payload_chunks_root를 커밋한 입찰이 든 유효한 비콘 블록을 이미 봤다면 chunk.beacon_block_root가 그 블록의 hash tree root와 같아야 합니다. [IGNORE] (chunk.payload_chunks_root, chunk.index)가 seen.payload_chunk_tuples에 없어야 하며 수락하면 그 쌍을 추가합니다. 검증을 통과한 조각은 나머지 조각이나 비콘 블록을 기다리지 않고 즉시 전달해야 하고(MUST) 봉투를 재구성할 수 있을 때까지 버퍼에 보관합니다.
설계 근거와 열린 질문
머클 커밋을 고른 이유는 KZG 같은 대안이 증명 생성을 빌더의 임계 경로에 올려놓기 때문입니다. 조각 위에 머클 트리를 세우는 일은 입찰 시점에 해도 될 만큼 싸고 입찰에 루트 하나만 넣으면 이미 검증된 서명 하나에 기대어 각 조각이 스스로 검증됩니다. TOTAL_EXECUTION_PAYLOAD_CHUNKS = 64는 측정에서 나온 값이 아닙니다. 더 적은 조각 수로도 큰 메시지 하나보다 이점이 나타납니다. 64를 고른 것은 앞으로 c-kzg로 소거 부호화(erasure coding)를 프로토콜에 넣을 경우를 대비한 호환성 때문입니다. c-kzg는 데이터를 64조각으로 나눠 128조각으로 확장합니다. 조각을 패딩 없는 ByteList로 둔 이유는 SSZ에 바깥 길이 접두사가 없어서입니다. 패딩 바이트를 넣으면 봉투 데이터로 역직렬화되지만 조각의 정확한 바이트를 해시하면 실제 길이까지 커밋됩니다. 분할과 머클화를 SSZ에 고정하면 두 클라이언트가 기존 코드로 같은 루트를 얻습니다. 열린 질문은 두 가지입니다. 조각에 소거 부호화를 적용하면 일부 조각만으로 봉투를 복원할 수 있습니다. 복잡도와 대역폭이 늘 수 있지만 몇 조각을 못 받은 수신자가 오래 기다리는 쿠폰 수집가 문제를 완화할 수 있습니다. 또 지금은 실행 페이로드 안에 들어 있는 블록 접근 목록(BAL, EIP-7928)을 같은 방식의 bal_chunks 토픽으로 따로 보내 나머지 페이로드보다 먼저 전파를 시작하게 하는 안도 언급됩니다.
보안 고려 사항
조각에는 개별 서명이 없습니다. 진위는 전적으로 입찰 서명에서 payload_chunks_root를 거쳐 나옵니다. 조각에 실린 루트 자체는 인증되지 않지만 서명 검증을 통과한 입찰이 그 루트를 커밋한 경우에만 조각이 수락됩니다. 모르는 루트를 가리키는 조각은 전달되지 않으므로 서명 없는 조각 스팸은 첫 홉에서 걸러집니다. slot과 beacon_block_root는 입찰 서명에도 포함 증명에도 들어가지 않으므로 조회 용도로만 쓰도록 제한됩니다. slot을 바꿔 재전송한 조각은 (slot, payload_chunks_root) 멤버십 검사에서 떨어지고 beacon_block_root를 바꾼 조각은 입찰이 든 블록이 알려지면 거부됩니다. 조각 바이트는 증명에 묶여 있으므로 힌트 필드만 다른 메시지로는 재조립된 봉투를 바꿀 수 없습니다. 같은 (payload_chunks_root, index)에서 서로 다른 두 조각이 모두 검증되려면 머클 트리 충돌이 필요하므로 인덱스별 이중 조각(equivocation)은 불가능합니다. chunk.index 상한은 핵심 장치입니다. is_valid_merkle_branch는 하위 CHUNK_INCLUSION_PROOF_DEPTH비트만 읽으므로 상한이 없으면 같은 조각이 index + k * TOTAL_EXECUTION_PAYLOAD_CHUNKS로 다시 퍼질 수 있습니다. 블록 전 버퍼링도 한정됩니다. 노드는 payload_chunks_roots 항목당 최대 TOTAL_EXECUTION_PAYLOAD_CHUNKS개 조각만 저장하고 그 집합의 크기는 입찰 가십 검증(빌더 서명과 슬롯 창)이 제한합니다. 조각이 가십 검증을 통과했다고 재조립된 봉투가 유효한 것은 아니며 봉투 전체 검증은 EIP-7732에서처럼 재조립 뒤에 이뤄집니다.
호환성, 상태, 포크 결정
execution_payload 토픽이 제거되므로 이 변경은 이전 버전과 호환되지 않으며 포크가 필요합니다. 참조 구현은 아직 정해지지 않았습니다(TBD). 원문 상태는 Draft이므로 상수, 메시지 구조, 검증 규칙은 아직 바뀔 수 있습니다. 코어 개발자 콜에서 다뤄진 경과는 이렇습니다. 09.10 ACDE #245에서 논의됐고 결정은 없었습니다. 09.17 ACDC #187에서 헤고타(Hegota) 후보로 접수(PFI)됐고 포함 검토(CFI) 여부는 다른 EIP들의 범위 결정이 끝난 뒤로 미뤄졌습니다. 09.21 ACDT #97에서는 EIP-8142(BiB)를 챔피언이 철회하고 대체안으로 이 EIP를 제안했다는 공지가 있었습니다. 이 콜에서 결정은 없었고 CL 팀들은 다음 ACDC 전에 평점을 매겨 달라는 요청을 받았습니다. 10.29 ACDC #190에서 헤고타 CFI로 결정됐습니다.