EIP-7549 위원회 인덱스를 서명 밖으로 (Move committee index outside Attestation)

최종 확정 · 합의·스테이킹 · 원문 상태 Final · 2023-11-01 작성

서명되는 투표 메시지에서 위원회 번호(index)를 빼서 내용이 같은 합의 투표를 위원회와 무관하게 하나로 합칠 수 있게 합니다. 합의 확인에 필요한 서명 검증 수가 크게 줄고 블록에 더 많은 투표가 들어갑니다.

왜 필요한가

이더리움 합의에서 검증자들은 매 슬롯 여러 위원회로 나뉘어 투표(어테스테이션, Attestation)를 보냅니다. 투표에는 포크 선택용 LMD GHOST 투표와 체인 확정용 Casper FFG 투표가 함께 담기는데, 지금은 자기가 속한 위원회 번호(index)까지 서명 대상에 포함됩니다. 그래서 투표 내용이 완전히 같아도 위원회가 다르면 서명 결과가 달라져 하나로 합칠 수 없습니다. 활성 검증자 인덱스가 262144개 이상인 네트워크에서는 3분의 2 임계를 확인하려면 최소 1366개의 어테스테이션을 검증해야 합니다. 서명 검증에 드는 페어링 연산이 그만큼 많아져 모든 클라이언트에 부담이 되고 특히 Casper FFG 합의를 증명하는 ZK 회로에 비용이 가장 큽니다. 블록 하나에 담을 수 있는 투표도 약 2슬롯 분량에 그쳐, 온라인 상태인 블록 제안자가 적으면 투표를 체인에 모두 싣지 못할 수 있습니다.

무엇이 바뀌나

지금

EIP-7549 이후

누구에게 영향이 있나

심층 설명

컨테이너 구조 변경

합의 계층에서 세 가지를 바꿉니다. AttestationData의 index 필드를 고정값 0으로 설정하고 위원회 식별 정보를 바깥 Attestation 컨테이너의 committee_bits로 옮기며 aggregation_bits 용량을 한 슬롯의 모든 위원회를 담을 수 있게 늘립니다. 실행 계층에는 변경이 없습니다. 전체 명세는 consensus-specs 저장소의 /specs/electra/beacon-chain.md에 있습니다.

검증 횟수가 62분의 1로 주는 원리

Attestation 메시지는 세 요소를 담습니다. LMD GHOST 투표 (beacon_block_root, slot), FFG 투표 (source, target), 그리고 위원회 index입니다. 세 번째 요소까지 서명하면 투표 내용이 같아도 서명 루트가 달라집니다. 활성 인덱스 262144개 이상인 네트워크에서 3분의 2 임계를 확인하려면 최소 ceil(32*64 * 2/3) = 1366개의 어테스테이션을 검증해야 하는데, index를 서명 밖으로 빼면 ceil(32 * 2/3) = 22개로 줄어듭니다. 62배 차이입니다. 모든 클라이언트가 이득을 보지만 Casper FFG 합의를 증명하는 ZK 회로의 효과가 가장 클 것으로 원문은 설명합니다.

index를 지우지 않고 0으로 두는 이유

index 필드를 없애는 방법은 세 가지가 검토되었습니다. 필드를 제거하는 것, 필드를 남기고 0으로 설정하는 것, EIP-7495의 StableContainer를 써서 Optional 타입으로 바꾸는 것입니다. 이 EIP는 두 번째를 택했습니다. AttesterSlashing 객체의 포함을 복잡하게 만들지 않기 위해서입니다. Attestation 컨테이너는 바뀌지만 AttesterSlashing은 위원회 데이터가 없는 indexed attestation을 담기 때문입니다.

MAX_ATTESTATIONS 8, MAX_ATTESTER_SLASHINGS 1로 조정

어테스테이션 하나의 최대 크기가 커집니다. 위원회가 최대로 찬 네트워크에서는 비트필드가 64배 커집니다. 그래서 MAX_ATTESTATIONS를 8로 줄여 블록 크기를 제한하면서도 전체 투표 용량은 늘립니다. 값 8은 활성 인덱스 120만 개 네트워크 기준으로 어테스테이션이 차지하는 공간은 같게 유지하면서 투표 용량을 4배로 만듭니다. AttesterSlashing은 참여자 인덱스 목록을 담는데 최악의 경우 크기가 64배 늘어, 검증자 100만 네트워크에서 비압축 488 KB, Snappy 압축 후에도 320 KB에 이릅니다. 블록 최대 크기를 묶기 위해 MAX_ATTESTER_SLASHINGS를 2에서 최솟값 1로 줄입니다.

committee_bits에 Bitvector를 쓰는 이유

committee_bits는 최대 MAX_COMMITTEES_PER_SLOT = 64 길이의 가변 시퀀스입니다. Bitlist 타입은 실제 길이를 인코딩에 포함해서 Bitvector보다 크기가 2배가 됩니다. 그래서 고정 길이 Bitvector를 씁니다. 슬롯의 실제 위원회 수가 최댓값보다 적을 때 committee_bits가 올바른지는 비컨 체인 상태 전이가 보장합니다.

포크 직후 첫 블록의 투표 공백

온체인 Attestation 컨테이너가 바뀌므로 이전 포크의 어테스테이션은 일렉트라 이후 블록에 넣을 수 없습니다. 그래서 포크 후 첫 블록에는 어테스테이션이 0개일 수 있습니다. LMD 투표는 on_attestation 핸들러로 포크 선택에 계속 반영되므로 손실은 FFG 투표의 32분의 1에 그칩니다. 포크 직전 마지막 슬롯에 배정된 증명자는 한 에포크 분량의 오프라인 페널티를 받습니다. 두 포크의 어테스테이션을 모두 허용하도록 블록 바디를 바꾸는 완화책도 있지만 얻는 것에 비해 복잡도가 커서 이 제안은 채택하지 않았습니다.

가십에서의 변조 가능성과 방어

index가 서명 밖으로 나오면 악의적 변조는 p2p 가십 토픽 beacon_attestation_${subnet_id}에서만 가능합니다. 그 밖의 모든 곳에서는 Attestation이 바깥 서명으로 감싸져 변조가 막힙니다. 이 가십 토픽의 검증 규칙에는 증명자가 해당 위원회의 구성원인지, 즉 attestation.attester_index가 get_beacon_committee(state, attestation.data.slot, index)에 있는지 확인하는 REJECT 규칙이 있습니다. 공격자가 index를 바꾸면 이 검사에 실패해 메시지가 버려집니다. 구현이 이 검사를 first-seen 캐시 등록 전에 수행하면 캐시 오염 위험도 없습니다.

하드포크가 필요한 Final 제안

이 EIP는 합의 계층의 블록 검증 규칙을 하위 호환되지 않게 바꾸므로 반드시 하드포크와 함께 적용해야 합니다. 원문 상태는 Final이며 명세는 일렉트라(Electra) 비컨 체인 스펙에 통합되어 있습니다.

EIP 원문 · ← EIPs