EIP-7745 신뢰 없는 로그·트랜잭션 인덱스 (Trustless log and transaction index)
콜 결정 없음 · 확장성·데이터 · 원문 상태 Draft · 2024-07-17 작성
블록 헤더의 2048비트 블룸 필터를 없애고 모든 로그·트랜잭션·블록을 하나의 선형 인덱스 공간에 올려 머클 증명으로 검증하며 검색할 수 있는 새 인덱스 구조로 바꿉니다.
왜 필요한가
지금 블록 헤더에는 2048비트짜리 블룸 필터가 들어 있어 그 블록에 어떤 로그가 있는지 대략 알려 줍니다. 그런데 이 필터는 충분히 비어 있을 때만 쓸모가 있습니다. 블록 가스 한도가 커지면서 요즘 메인넷 블록 하나가 평균 1000개가 넘는 로그 주소와 토픽을 담게 되었고 필터가 가득 차 '있다'고 잘못 답하는 비율(거짓 양성)이 치솟아 사실상 무용지물이 되었습니다. 쓸 만한 수준으로 되돌리려면 필터 크기를 10배쯤 키워야 하는데 그러면 헤더가 약 3킬로바이트로 커지고 그래도 최근 1년치 로그를 찾으려면 6기가바이트가 넘는 헤더 데이터를 내려받아야 합니다. 트랜잭션이 어느 블록에 들어갔는지 확인하는 일도 검색 구간의 모든 블록 본문이 필요합니다. 풀 노드나 RPC 서버가 자체 인덱스를 만들어 쓰고 있지만 이 인덱스는 원격에서 검증할 수 없어 결국 사용자가 서버를 믿어야 합니다. 트랜잭션 처리량을 아무리 늘려도 그 결과를 신뢰 없이 확인할 방법이 없다면 이더리움의 취지에 어긋난다는 것이 이 제안의 출발점입니다.
무엇이 바뀌나
지금
- 블록마다 고정 2048비트 블룸 필터가 헤더에 들어가지만 거짓 양성이 너무 많아 사실상 쓸모가 없습니다
- 긴 구간에서 로그를 찾으려면 헤더 전체와 영수증 상당 부분을 내려받아야 합니다
- 트랜잭션 포함 여부 확인에 검색 구간의 모든 블록 본문이 필요합니다
- 풀 노드가 만드는 자체 검색 인덱스는 원격에서 검증할 수 없어 서버를 믿어야 합니다
EIP-7745 이후
- 헤더의 logs_bloom 자리에 전체 인덱스의 루트 해시인 log_index_root가 들어갑니다
- 원하는 이벤트와 관련된 작은 조각만 머클 증명으로 받아 검증하며 검색할 수 있습니다
- 로그뿐 아니라 트랜잭션 해시 조회, 블록 해시와 블록 번호 조회도 같은 구조로 증명됩니다
- 맵 하나에 담기는 값의 수가 고정되어 거짓 양성 비율이 일정하게 낮게 유지됩니다
누구에게 영향이 있나
- 지갑·앱 개발자: eth_getLogs 등 기존 로그 필터 API를 그대로 쓰면서 검색 성능 향상을 누립니다. 애플리케이션 코드 변경은 필요 없습니다.
- 라이트 클라이언트 사용자: 신뢰할 수 있는 서버 없이도 원격 증명자에게 받은 머클 증명만으로 로그 검색 결과가 빠짐없고 정확한지 검증할 수 있습니다.
- 클라이언트 팀: 헤더 스키마 변경, 새 인덱스 자료구조, 초기화용 와이어 프로토콜 확장을 구현해야 합니다. 추가 저장 공간은 실제 로그 크기의 15~20% 수준입니다.
- 검증자: 로그 검색이나 증명에 관심이 없어도, 크기가 하드 캡으로 제한된 최소 인덱스 상태만 유지하면 루트 해시를 만들 수 있습니다.
심층 설명
헤더 변경: logs_bloom을 log_index_root로 교체
FORK_TIMESTAMP 이후 실행 클라이언트는 헤더의 logs_bloom 필드를 log_index_root로 교체해야 합니다. 이 값은 해당 블록에서 발생한 로그까지 추가한 뒤의 LogIndex 구조 루트 해시입니다. 블록별로 독립적이던 블룸 필터와 달리, 체인 전체의 이벤트를 누적한 하나의 전역 인덱스를 매 블록 헤더가 커밋하는 방식입니다. 덕분에 검색자는 최신 헤더 하나만 신뢰하면 과거 전체 구간의 로그 검색 결과를 증명받을 수 있습니다.
선형 인덱스 공간과 세 가지 인덱스 엔트리
로그, 트랜잭션, 블록 세 종류의 인덱스 엔트리가 전역 선형 인덱스 공간에 순서대로 배치됩니다. 각 엔트리는 하나 이상의 맵 값을 만드는데, 로그 엔트리는 주소 값 1개와 토픽 값 0~4개, 트랜잭션 엔트리와 블록 엔트리는 각각 1개를 만듭니다. 맵 값 해시는 sha2(address), sha2(topic), sha2(tx_hash + b"\x01"), sha2(block_hash + b"\x02")로 계산합니다. 트랜잭션마다 트랜잭션 엔트리가 먼저, 그다음 로그 엔트리가 EVM 실행 순서대로 추가됩니다. 블록 N의 블록 엔트리는 블록 해시가 확정된 뒤에야 넣을 수 있으므로 블록 N+1의 인덱스 상태에 첫 엔트리로 나타납니다. 엔트리마다 LogMeta, TransactionMeta, BlockMeta 메타데이터가 붙어 영수증과 블록 해시 조회까지 증명 가능하게 합니다.
필터 맵 구조와 제안 상수
인덱스 공간은 VALUES_PER_MAP(2**16) 길이 구간마다 하나의 필터 맵을 가집니다. 필터 맵은 MAP_WIDTH(2**24) x MAP_HEIGHT(2**16) 크기의 희소 비트맵이고 맵 값 하나당 비트 하나가 찍힙니다. 맵마다 값의 수가 VALUES_PER_MAP으로 고정되므로 거짓 양성 확률이 일정하게 유지됩니다. 맵은 MAPS_PER_EPOCH(2**10)개씩 인덱스 에포크로 묶이고 에포크 안에서 같은 행 번호의 행들이 해시 트리에서 서로 가깝게 배치되어 하나의 머클 멀티프루프로 싸게 가져올 수 있습니다. 행은 ProgressiveList[uint32]로, 열 인덱스를 오름차순으로 나열해 인코딩합니다. 전체 히스토리는 MAX_EPOCH_HISTORY(2**24) 에포크까지 담습니다.
매핑 레이어: 인기 값의 행 포화 문제 해결
특정 주소나 토픽이 매우 자주 나오면 그 값이 배정된 행이 길어져 검색 효율이 떨어집니다. 이를 막기 위해 행 길이가 MAX_ROW_LENGTH[0](8)에 도달하면 이후 값들은 레이어 1의 다른 행으로 옮겨 가고 한도도 MAX_ROW_LENGTH[1](168)로 커집니다. 이런 식으로 2728, 10920까지 올라갑니다. 레이어 0의 행 배정은 에포크마다(MAPPING_FREQUENCY[0]=2**10 맵) 바뀌지만 높은 레이어일수록 더 자주(2**6, 2**2, 1 맵) 바뀌어 인기 값과 우연히 충돌한 희귀 값이 오래 피해를 보지 않게 합니다. 검색자는 행이 해당 레이어 한도만큼 차 있으면 다음 레이어의 행도 확인하고 한도를 넘는 데이터는 상위 레이어 몫으로 보고 무시해도 안전합니다.
열 매핑과 거짓 양성률
열 인덱스는 맵 값 인덱스와 맵 값 해시를 fnv1a_64로 섞어 계산하며 각 인덱스 위치마다 MAP_WIDTH // VALUES_PER_MAP 너비의 전용 구간에 정확히 한 비트가 찍힙니다. 그래서 열 인덱스에서 원래 위치를 복원할 수 있고 다시 계산한 열 인덱스가 일치하는지 보는 것으로 후보를 거릅니다. 맵 하나당 평균 거짓 양성은 약 VALUES_PER_MAP ** 2 / MAP_WIDTH / MAP_HEIGHT에 레이어 추가 확인 비용을 더해 약 0.0044건입니다. 2025년 3월 기준 블록당 맵 값이 1000개 남짓이므로 대략 14000블록당 1건, 체인 전체 히스토리로는 약 1200건 수준입니다. 주소와 토픽을 함께 거는 패턴 검색은 여러 위치가 동시에 맞아야 하므로 거짓 양성률이 지수적으로 더 낮아집니다.
최소 상태와 초기화, 와이어 프로토콜 확장
트리에서 확정된 서브트리는 노드 하나로 접을 수 있어 검증만 하는 클라이언트는 크기가 하드 캡으로 제한된 최소 상태만 들고도 루트 해시를 갱신할 수 있습니다. 효율적으로 직렬화하면 최소 상태는 21300808바이트(약 21메가바이트)로, 어느 시점에서든 이 정도 데이터면 인덱스를 초기화할 수 있습니다. 에포크 경계에서 초기화하면 더 싸지만 경계 이후의 블록과 영수증으로 마지막 미완성 에포크를 직접 만들어야 합니다. 두 방식 모두 최근 확정 블록을 기준으로 머클 멀티프루프를 요청하는 이더리움 와이어 프로토콜 확장이 필요하며 데이터가 커서 여러 개의 독립 검증 가능한 증명으로 나눠 받습니다.
호환성과 비용
eth_getLogs, eth_newFilter, eth_getFilterLogs, eth_getFilterChanges 등 기존 로그 필터 API는 새 구조 위에서 그대로 구현할 수 있어 기존 애플리케이션은 변경 없이 더 빠른 검색을 누립니다. EVM은 로그를 내보내기만 하고 직접 읽지 않으므로 영향이 없습니다. 추가 처리 비용은 크지 않지만 저장 비용이 약 15% 늘어나므로, 벤치마크 후 LOG 옵코드 가격 조정을 검토할 수 있다고 원문은 적습니다. 보안 측면에서는 특정 값의 거짓 양성을 일부러 키우는 충돌 공격이 이론상 가능하지만 열 인덱스가 값과 정확한 위치 모두에 의존하므로 블록 빌더만 시도할 수 있고 실익이 적다고 분석합니다.
진행 상황: Draft 단계
이 EIP는 Draft 상태로, 상수와 자료구조를 포함한 내용이 앞으로 바뀔 수 있습니다. SSZ 타입인 ProgressiveList와 ProgressiveByteList를 정의하는 EIP-7916을 전제로 합니다. 콜 기록으로는 08.29 AMA #14에서 논의되었고 포크 포함 등 결정은 없었습니다.