이더리움 eth_getProof 가이드: 계정·스토리지 상태 검증하기
eth_getProof 응답의 계정·스토리지 증명을 블록 상태 루트와 연결해 검증하는 원리, 절차, 신뢰 경계와 한계를 설명합니다.

RPC 서버에 이더리움 잔액이나 컨트랙트 값을 물으면 답은 금방 돌아옵니다. 그런데 그 답을 서버의 데이터베이스만 믿지 않고 특정 블록과 대조할 수 있을까요? 이 블록체인 기초 가이드에서는 계정 증명(Account Proof)과 선택한 컨트랙트 스토리지 증명(Storage Proof)을 돌려주는 JSON-RPC 메서드 eth_getProof를 설명합니다.
이 메서드가 모든 신뢰를 자동으로 없애 주는 것은 아니에요. 증명은 특정 상태 루트(State Root)에 대한 값의 관계만 확인합니다. 진짜 블록 헤더, 정확한 블록 기준, 올바른 트라이 검증, 반환된 바이트의 정확한 해석이 모두 필요해요.
eth_getProof는 무엇을 하나요?
이더리움 상태를 문 하나에 위변조 방지 봉인이 붙은 거대한 창고라고 생각해 보세요. 일반 RPC 조회는 창고 관리인에게 선반 하나의 내용물을 물어봅니다. eth_getProof는 내용물과 함께 그 선반에서 문 봉인까지 이어지는 봉인된 상자 경로를 요청해요. 로컬에서 해시를 다시 계산해 예상한 봉인으로 끝나지 않는 경로를 거부할 수 있습니다.
그 문 봉인이 블록의 stateRoot예요. 현재 이더리움 실행 API 명세는 eth_getProof가 계정과 선택적 스토리지 키의 머클 증명(Merkle Proof)을 반환한다고 정의합니다. EIP-1186 제안서는 도입 동기와 증명 구조를 상세히 설명해요.
상태는 정확히 구분해야 합니다. EIP-1186 문서는 Stagnant로 표시되어 있으므로 이 제안 자체를 새로 확정된 EIP라고 부르면 안 됩니다. 다만 메서드는 현재 실행 API에 실려 있고 Geth 같은 클라이언트에도 구현되어 있어요. 제안서 상태만으로 지원 여부를 추정하지 말고 실제 클라이언트와 RPC 제공자를 확인하세요.
두 단계 증명 구조
이더리움 실행 상태는 두 겹으로 중첩됩니다. 이 구조를 알면 검증에서 흔히 생기는 실수를 피할 수 있어요.
- 전역 상태 트라이(State Trie)는 해시된 계정 주소를 계정 레코드에 연결합니다.
- 계정 레코드에는
nonce,balance,storageRoot,codeHash가 들어 있어요. - 컨트랙트별 스토리지 트라이(Storage Trie)는 해시된 32바이트 스토리지 위치를 값에 연결합니다.
전체 자료 구조는 이더리움 머클 패트리샤 트라이 가이드에서 다룹니다. eth_getProof 관점에서는 이렇게 정리할 수 있어요. accountProof는 계정 레코드를 블록 stateRoot에 연결하고, 각 storageProof는 선택한 스토리지 키와 값을 API가 반환한 storageHash, 즉 그 계정의 스토리지 루트에 연결합니다.
따라서 스토리지 검증은 두 단계예요. 먼저 신뢰할 수 있는 블록 루트를 기준으로 계정 증명을 확인합니다. 그다음 인증된 계정 안의 스토리지 루트를 이용해 슬롯을 검증해요. 첫 단계를 건너뛰면 RPC 서버가 임의로 준 스토리지 루트를 그대로 믿는 셈입니다.
계정·스토리지 증명 요청 방법
요청에는 위치가 정해진 매개변수 세 개가 들어갑니다.
- 20바이트 계정 주소
- 스토리지 키 배열. 계정 증명만 필요하면 빈 배열을 사용해요.
- 블록 번호 또는 지원되는 블록 태그
다음 예시는 현재 실행 API의 매개변수 형식을 따릅니다.
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_getProof",
"params": [
"0xe5cB067E90D5Cd1F8052B83562Ae670bA4A211a8",
[
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
],
"finalized"
]
}예시 키를 관계없는 컨트랙트에 그대로 넣고 의미 있는 변숫값을 기대하면 안 돼요. Solidity 매핑(Mapping), 배열, 패킹 필드, 프록시, 네임스페이스 스토리지는 필요한 위치를 바꿉니다. 먼저 검증된 소스와 컴파일러 메타데이터로 위치를 계산하세요. 이더리움 컨트랙트 스토리지 슬롯 가이드에서 그 절차를 설명합니다.
재현 가능한 감사 기록이 필요하다면 움직이는 태그보다 명시적인 블록 번호와 해시를 함께 보관하는 편이 좋아요. 실행 API는 latest를 클라이언트가 관찰한 최신 정규 블록으로 설명하고, safe와 finalized에는 더 강한 합의 의미를 부여합니다. eth_getProof와 eth_getBlockByNumber가 같은 블록을 가리키도록 먼저 기준을 확정하세요.
응답 필드 읽는 법
응답에는 서로 연결된 필드가 들어 있습니다.
| 필드 | 의미 | 검증 역할 |
|---|---|---|
address | 요청한 계정 | 응답 대상 확인 |
balance | 16진수 수량으로 표현한 ETH 잔액 | 계정 레코드 구성 요소 |
nonce | 16진수 수량으로 표현한 계정 논스 | 계정 레코드 구성 요소 |
codeHash | 계정 바이트코드의 해시 | 계정 레코드 구성 요소 |
storageHash | 계정 스토리지 트라이의 루트 | 스토리지 증명의 기준점 |
accountProof | 계정 경로의 인코딩된 트라이 노드 | stateRoot에 대한 계정 검증 |
storageProof | 요청한 키별 키·값·트라이 노드 경로 | storageHash에 대한 슬롯 검증 |
증명 배열은 단순한 이진 머클 트리의 형제 해시 목록과 달라요. 현재 이더리움 실행 상태는 수정된 머클 패트리샤 트라이(Modified Merkle Patricia Trie)를 사용합니다. 노드는 재귀 길이 접두부(RLP)로 인코딩되고, 경로에는 니블(Nibble) 단위 압축 인코딩이 적용되며, 짧은 노드는 해시 대신 상위 노드 안에 직접 들어갈 수도 있어요. 운영 환경에서는 블로그 예시로 디코더를 새로 만들기보다 충분히 검증된 라이브러리를 사용하세요.
eth_getProof는 값이 없다는 사실도 증명할 수 있습니다. 경로가 빈 분기에서 끝나거나 다른 잎의 남은 경로와 어긋난다면 요청한 계정 또는 슬롯이 해당 루트에 존재하지 않음을 보일 수 있어요. 부재 증명(Absence Proof)은 단순한 RPC 오류와 다르므로 검증기가 트라이 규칙을 정확히 적용해야 합니다.
안전한 검증 순서
결과가 중요한 시스템이라면 다음 순서를 지켜 보세요.
- 블록 하나를 정합니다. 움직이는 화면 표기만 믿지 말고 번호와 해시를 확정해요.
- 헤더를 인증합니다. 합의를 검증하는 라이트 클라이언트, 직접 검증한 노드 또는 문서화한 다른 신뢰 모델로 블록 헤더를 얻습니다.
stateRoot를 읽습니다. 계정 증명이 최종적으로 재현해야 할 루트예요.- 같은 블록으로
eth_getProof를 요청합니다. 실제 필요한 스토리지 키만 포함하세요. - 계정 경로를 검증합니다. 주소에서 계정 트라이 키를 만들고 모든 인코딩 노드를 검사한 뒤 계산한 루트를 헤더의
stateRoot와 비교해요. - 계정 레코드를 해석합니다. 논스, 잔액, 스토리지 루트, 코드 해시가 응답 필드와 일치하는지 확인합니다.
- 각 스토리지 경로를 검증합니다. 외부에서 따로 받은 루트가 아니라 계정 증명으로 인증한 스토리지 루트를 사용해요.
- 애플리케이션 의미를 별도로 해석합니다. 증명된 32바이트 워드라도 올바른 컨트랙트·프록시 맥락·레이아웃·자료형·바이트 오프셋이 필요합니다.
이 구분이 핵심이에요. 암호학은 “이 루트 아래 이 경로에 해당 바이트가 있었다”를 증명할 수 있습니다. “변수 이름이 맞다”, “컨트랙트가 안전하다”, “이 자산을 사야 한다”까지 증명하지는 않아요.
리스크와 한계
상태 루트의 출처가 믿을 만해야 해요
같은 불신 RPC 서버가 가짜 헤더와 그 가짜 헤더에 맞춘 증명을 함께 제공한다면 두 값의 해시는 서로 일치할 수 있어요. 별도의 검증 경계가 진짜 헤더를 제공할 때 증명이 의미를 가집니다. 그래서 eth_getProof는 라이트 클라이언트와 트러스트리스 RPC를 대체하지 않고 보완해요.
과거 상태를 바로 제공하지 못할 수 있어요
노드는 모든 오래된 상태를 즉시 무작위 조회할 수 있게 저장하지 않아도 체인을 검증할 수 있습니다. 이더리움의 아카이브 노드 문서는 아카이브 설정이 역사적 상태를 보존하고, 다른 노드는 오래된 상태를 정리하거나 추가 비용을 들여 재구성할 수 있다고 설명해요. RPC 제공자가 메서드, 블록 범위, 호출 빈도를 더 제한할 수도 있습니다. 실제 엔드포인트를 테스트하고 명시적인 실패를 처리하세요.
증명된 바이트도 잘못 해석할 수 있어요
스토리지 증명에는 Solidity 변수 이름이나 검증된 ABI가 들어 있지 않습니다. 프록시 대신 구현 주소를 읽거나, 매핑 키를 잘못 인코딩하거나, 패킹 필드의 오프셋을 틀리면 유효한 증명에서 잘못된 애플리케이션 결론을 만들 수 있어요.
모든 네트워크의 지원이 같지 않아요
이더리움 JSON-RPC 문서는 최신 API 지원 여부를 각 클라이언트 문서에서 확인하라고 안내합니다. EVM 호환 네트워크가 다른 상태 커밋 구조를 쓰거나, 비슷한 메서드에 다른 제한을 두거나, 메서드를 제공하지 않을 수 있어요. 이더리움 동작을 다른 체인에 그대로 가정하지 마세요.
운영 코드 자체에도 위험이 있어요
검증 코드에는 파싱 버그, 서비스 거부 취약점, 안전하지 않은 기본값이 있을 수 있습니다. 라이브러리 버전을 고정하고, 가능한 경우 공식 테스트 벡터를 사용하며, 응답 크기를 제한하고, 손상된 노드를 시험하세요. 블록·루트·주소·키 중 하나라도 정확히 맞지 않으면 실패 처리해야 합니다.
실무 체크리스트
- 체인 ID, 블록 번호, 블록 해시를 기록했나요?
- 증명 제공자와 독립적인 방식으로 헤더를 인증했나요?
- 계정 증명이 헤더의
stateRoot를 재현했나요? - 계정 증명으로 인증한 루트를 기준으로 스토리지 증명을 확인했나요?
- 주소와 스토리지 키를 트라이 규칙에 맞게 정확히 인코딩했나요?
- 검증된 소스와 컴파일러 메타데이터가 슬롯 해석을 뒷받침하나요?
- 프록시, 패킹 필드, 매핑, 사용자 지정 레이아웃을 고려했나요?
- 선택한 클라이언트 또는 제공자가 해당 과거 블록을 지원하나요?
- 손상·누락·불일치 증명을 검증기가 거부하나요?
자주 묻는 질문
eth_getProof와 eth_getStorageAt은 같은가요?
아니요. eth_getStorageAt은 주소, 위치, 블록을 기준으로 스토리지 워드를 반환합니다. eth_getProof는 그 값과 함께 계정의 스토리지 루트에 대조할 트라이 노드, 그리고 블록 상태 루트까지 연결하는 계정 증명을 반환할 수 있어요.
스토리지 키 없이 ETH 잔액을 검증할 수 있나요?
가능합니다. 스토리지 키에 빈 배열을 전달하고 계정 레코드를 검증하세요. 잔액은 논스, 스토리지 루트, 코드 해시와 함께 계정 레코드에 들어 있습니다.
유효한 증명이 있으면 블록도 최종 확정된 건가요?
아니요. 증명 유효성과 합의 최종성(Finality)은 다른 질문입니다. 증명은 데이터를 루트에 묶고, 어떤 체인 상태를 받아들일지는 인증한 헤더와 블록 선택 정책이 결정해요.
eth_getProof로 컨트랙트의 모든 슬롯을 찾을 수 있나요?
아니요. 이미 알고 있는 스토리지 키를 요청하는 메서드입니다. 키 공간이 매우 크고 매핑 위치는 해시되기 때문에 범용 슬롯 열거 도구로 사용할 수 없어요.
EIP-1186은 확정된 표준인가요?
아니요. EIP 페이지에는 Stagnant로 표시됩니다. 현재 메서드 문법과 응답 검증은 최신 이더리움 실행 API 명세를 기준으로 하고, 사용하는 클라이언트에서 실제 동작을 확인하세요.
핵심 정리
eth_getProof는 RPC 서버의 주장을 인증된 이더리움 상태 루트와 대조할 수 있는 자료로 바꿉니다. 신뢰 사슬 전체를 봐야 해요. 헤더에서 상태 루트로, 상태 루트에서 계정으로, 계정 스토리지 루트에서 슬롯으로, 슬롯 바이트에서 신중하게 검증한 애플리케이션 의미로 이어집니다.
각 단계를 분리하고 하나라도 어긋나면 실패 처리하세요. 최신 클라이언트 동작은 1차 문서로 직접 확인해야 합니다. 이 글은 교육 목적이며 투자 조언이 아닙니다(NFA). 크립토 자산과 애플리케이션에는 기술·상대방·시장 위험이 있으므로 독립적으로 검증하고 DYOR하세요.
1차 자료
함께 읽으면 좋은 글

이더리움 머클 패트리샤 트라이: 상태 루트가 네트워크를 증명하는 법
이더리움 머클 패트리샤 트라이는 계정·컨트랙트 저장소·트랜잭션·영수증을 작은 루트에 연결해요. 구조와 증명 원리를 알아봅니다.

이더리움 컨트랙트 스토리지 슬롯: 패킹·매핑·eth_getStorageAt 읽는 법
Solidity가 이더리움 컨트랙트 스토리지 슬롯을 배치하는 원리와 매핑·배열 위치 계산, eth_getStorageAt 검증 방법을 설명합니다.
이더리움 라이트 클라이언트와 트러스트리스 RPC: 풀 노드 없이 검증하기
이더리움 라이트 클라이언트가 헤더와 RPC 데이터를 검증하는 원리, 트러스트리스 RPC의 범위와 보안·프라이버시 한계를 정리합니다.
관련 주제 살펴보기

이더리움 글램스테르담 업그레이드: ePBS·BAL과 확정된 사실
글램스테르담은 2026년 4분기 예정이에요. 확정된 범위, 세폴리아 일정, ePBS, 블록 레벨 접근 리스트와 남은 변수를 설명합니다.
크립토 주소 포이즈닝: 송금 전 지갑 주소를 검증하는 방법
주소 포이즈닝은 거래 내역에 닮은 지갑 주소를 심는 사기예요. 작동 원리와 안전한 전체 주소 검증 체크리스트를 알아보세요.