블록체인 dApp을 개발하면서 Web3.js나 ethers.js를 사용하다 보면, 내부적으로 어떤 방식으로 블록체인 노드와 통신하는지 궁금해지실 겁니다. 오늘은 그 핵심에 있는 JSON-RPC 프로토콜에 대해 알아보겠습니다.
1. JSON-RPC란 무엇인가?
정의와 역사
JSON-RPC는 JavaScript Object Notation-Remote Procedure Call의 약자로, 원격 프로시저 호출을 위한 가볍고 간단한 프로토콜입니다. 쉽게 말하면, 네트워크를 통해 다른 컴퓨터에 있는 함수를 마치 내 컴퓨터에 있는 것처럼 호출할 수 있게 해주는 규칙이라고 보시면 됩니다.
JSON-RPC는 stateless하고 light-weight한 특징을 가지고 있으며, transport에 구애받지 않아서 HTTP, WebSocket, TCP 등 다양한 프로토콜 위에서 동작할 수 있습니다. 현재 가장 널리 사용되는 버전은 2.0이며, 2013년에 공식 스펙이 확정되었습니다.
블록체인보다 먼저 존재했던 프로토콜
많은 분들이 JSON-RPC를 블록체인 전용 프로토콜로 생각하시는데, 실제로는 2005년경에 XML-RPC의 대안으로 등장했습니다. 당시 JSON이 데이터 교환 포맷으로 인기를 얻으면서, 더 가볍고 읽기 쉬운 RPC 프로토콜의 필요성이 대두되었고, 그 결과 JSON-RPC가 탄생하게 되었습니다.
그러니까 이더리움이 2015년에 출시되기 거의 10년 전부터 존재했던 프로토콜입니다. 블록체인이 나중에 이 프로토콜을 채택한 것이죠.
2. 왜 블록체인은 JSON-RPC를 선택했을까?
처음에는 "왜 하필 JSON-RPC일까?"라는 의문이 들었는데, 실제로 사용해보니 이유가 명확하더군요.
간단하고 가벼운 구조
JSON-RPC는 필수 필드가 단 4개뿐입니다. 복잡한 헤더나 메타데이터 없이도 명확한 요청-응답 구조를 만들 수 있어서, 블록체인처럼 분산 환경에서 빠르고 효율적인 통신이 필요한 경우에 이상적입니다.
HTTP 기반의 범용성
블록체인 노드는 전 세계 어디서든 접근할 수 있어야 하는데, JSON-RPC는 HTTP 위에서 동작하므로 방화벽이나 프록시 설정이 훨씬 간단합니다. 실제로 Infura나 Alchemy 같은 노드 프로바이더 서비스도 모두 HTTPS 엔드포인트를 제공하죠.
디버깅과 테스트의 용이성
개발하면서 느낀 가장 큰 장점은 디버깅이 정말 쉽다는 점입니다. curl 명령어나 Postman으로 바로 테스트할 수 있고, 요청과 응답이 모두 JSON이라 사람이 읽기에도 편합니다. 브라우저 개발자 도구의 Network 탭에서도 바로 확인할 수 있어서, 프론트엔드 개발 시 트러블슈팅이 훨씬 수월합니다.
언어 중립적 특성
JavaScript든, Python이든, Go든, Rust든 상관없이 JSON만 파싱할 수 있으면 JSON-RPC를 사용할 수 있습니다. 이는 블록체인 생태계처럼 다양한 언어로 클라이언트가 개발되는 환경에서 필수적인 특징입니다.
3. 5분만에 이해하는 JSON-RPC 구조
Request/Response 예제
JSON-RPC 요청은 놀랍도록 간단합니다. 아래는 이더리움 노드에 블록 번호를 조회하는 실제 요청입니다:
{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}
그리고 응답은 이렇게 옵니다:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x12a7b5c"
}
필수 필드 설명
- jsonrpc: 프로토콜 버전, 항상
"2.0"입니다 - method: 호출하려는 메서드 이름 (예:
eth_blockNumber,eth_getBalance) - params: 메서드에 전달할 파라미터 배열 또는 객체
- id: 요청-응답을 매칭하기 위한 식별자. 숫자, 문자열, null 가능
처음에는 id 필드가 왜 필요한지 이해가 안 갔는데, Batch Request를 사용해보니 이유를 알겠더군요. 여러 요청을 동시에 보낼 때 어떤 응답이 어떤 요청에 대한 것인지 구분하기 위해서입니다.
Error 응답 구조
요청이 실패하면 result 대신 error 필드가 반환됩니다:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params"
}
}
실제로 개발하면서 Invalid JSON RPC response 에러를 마주친 적이 있는데, 노드 연결이 끊어졌거나 잘못된 엔드포인트를 호출했을 때 발생합니다. 이럴 땐 우선 노드 URL부터 확인하는 게 좋습니다.
4. 실습: 첫 JSON-RPC 호출
이론만 보면 재미없으니, 실제로 호출해봅시다.
이더리움 블록 번호 조회하기
curl로 직접 JSON-RPC를 호출해보겠습니다:
curl https://ethereum-rpc.publicnode.com \
-X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_blockNumber",
"params": [],
"id": 1
}'
이 명령어를 터미널에 입력하면 현재 최신 블록 번호가 16진수로 반환됩니다. 저는 처음 이걸 실행했을 때 "와, Web3.js 없이도 되네?"라고 감탄했던 기억이 납니다.
계정 잔액 확인하기
이번엔 특정 주소의 ETH 잔액을 조회해보겠습니다:
curl https://ethereum-rpc.publicnode.com \
-X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": [
"0x8D97689C9818892B700e27F316cc3E41e17fBeb9",
"latest"
],
"id": 1
}'
params 배열의 첫 번째는 조회할 주소, 두 번째는 블록 태그(latest, earliest, pending 중 하나)입니다. 응답은 Wei 단위의 16진수로 오기 때문에, ETH로 변환하려면 10^18으로 나눠야 합니다.
코드 예제와 설명
JavaScript로도 똑같이 할 수 있습니다:
const fetchBalance = async () => {
const response = await fetch('https://ethereum-rpc.publicnode.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getBalance',
params: ['0x8D97689C9818892B700e27F316cc3E41e17fBeb9', 'latest'],
id: 1
})
});
const data = await response.json();
const balanceWei = parseInt(data.result, 16);
const balanceEth = balanceWei / 1e18;
console.log(`Balance: ${balanceEth} ETH`);
};
fetchBalance();
이 코드를 실행하면 해당 주소의 잔액이 ETH 단위로 출력됩니다. Web3.js 없이도 충분히 블록체인 데이터를 가져올 수 있다는 게 신기하죠?
5. Web3.js와 JSON-RPC의 관계
Web3.js는 JSON-RPC 래퍼다
사실 Web3.js, ethers.js 같은 라이브러리는 JSON-RPC를 편하게 호출하기 위한 래퍼(wrapper)에 불과합니다. 예를 들어, web3.eth.getBalance(address)를 호출하면, 내부적으로는 위에서 본 것과 똑같은 JSON-RPC 요청이 전송됩니다.
실제로 Web3.js 소스코드를 열어보면 JSON-RPC 요청을 생성하는 코드를 볼 수 있습니다. 처음 이걸 발견했을 때 "아, 그냥 편의 함수였구나" 싶더군요.
추상화 레이어 이해하기
Web3.js의 진짜 가치는 다음과 같은 부분입니다:
- 16진수 ↔ 10진수 자동 변환
- Wei ↔ ETH 단위 변환 유틸리티
- 트랜잭션 서명 및 전송 헬퍼
- ABI 인코딩/디코딩
- 이벤트 리스닝 및 필터링
하지만 코어 통신 부분은 결국 JSON-RPC입니다. 그래서 JSON-RPC를 이해하면, Web3.js가 "마법"처럼 느껴지지 않고 명확한 추상화 레이어로 보이게 됩니다.
브라우저 Network 탭으로 실제 호출 확인하기
dApp을 개발할 때 브라우저 개발자 도구(F12)를 열고 Network 탭을 보면, Web3.js가 보내는 실제 JSON-RPC 요청을 볼 수 있습니다.
실제로 MetaMask를 연결한 상태에서 계정 정보를 가져오면, eth_accounts, eth_chainId 같은 JSON-RPC 호출이 일어나는 걸 확인할 수 있습니다. 이 부분에서 주의할 점은, MetaMask가 일부 메서드는 자체적으로 캐싱하기 때문에 매번 네트워크 요청이 발생하지는 않는다는 점입니다.
6. 자주 사용하는 이더리움 JSON-RPC 메서드
필수 메서드 TOP 10
제 경험상 실무에서 가장 많이 사용하는 메서드들입니다:
- eth_blockNumber: 최신 블록 번호 조회
- eth_getBalance: 계정 잔액 조회
- eth_call: 스마트 컨트랙트 읽기 전용 함수 호출
- eth_sendRawTransaction: 서명된 트랜잭션 전송
- eth_estimateGas: 가스 사용량 추정
- eth_gasPrice: 현재 가스 가격 조회
- eth_getTransactionByHash: 트랜잭션 정보 조회
- eth_getTransactionReceipt: 트랜잭션 영수증 조회
- eth_getBlockByNumber: 블록 정보 조회
- eth_getLogs: 이벤트 로그 조회
이 10개만 알아도 대부분의 dApp 개발이 가능합니다.
메서드 찾는 법
공식 문서는 Ethereum JSON-RPC 문서에 잘 정리되어 있습니다. 하지만 저는 실무에서 다음 두 가지 방법도 많이 사용합니다:
- Web3.js 소스코드 뒤지기: GitHub에서 Web3.js 레포를 열고, 필요한 기능의 구현 코드를 보면 어떤 JSON-RPC 메서드를 호출하는지 바로 알 수 있습니다
- 브라우저 Network 탭 확인: 작동하는 dApp을 열고 Network 탭에서 실제 호출을 캡처하면, 어떤 메서드와 파라미터를 사용하는지 배울 수 있습니다
Batch Request로 여러 요청 한번에 보내기
이 부분이 JSON-RPC의 진짜 강력한 기능입니다. 여러 요청을 배열로 묶어서 한 번의 HTTP 요청으로 보낼 수 있습니다:
const batchRequest = [
{
jsonrpc: '2.0',
method: 'eth_blockNumber',
params: [],
id: 1
},
{
jsonrpc: '2.0',
method: 'eth_gasPrice',
params: [],
id: 2
},
{
jsonrpc: '2.0',
method: 'eth_getBalance',
params: ['0x8D97689C9818892B700e27F316cc3E41e17fBeb9', 'latest'],
id: 3
}
];
const response = await fetch('https://ethereum-rpc.publicnode.com', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(batchRequest)
});
const results = await response.json();
// 응답도 배열로 옵니다. id로 매칭하세요!
실제로 제가 Defi 플랫폼 개발하면서 여러 정보를 동시에 조회해야 할 때 Batch Request를 사용했는데, 네트워크 레이턴시가 1/10로 줄어들더군요. 특히 Infura 같은 유료 서비스를 사용한다면 API 호출 횟수를 줄일 수 있어서 비용 절감에도 도움이 됩니다.
이 부분에서 주의할 점은, 응답 배열의 순서가 요청 배열의 순서와 다를 수 있다는 점입니다. 그래서 반드시 id 필드로 응답을 매칭해야 합니다.
7. 마무리 및 다음 단계
JSON-RPC를 알면 좋은 점
JSON-RPC를 이해하고 나니 다음과 같은 장점이 있었습니다:
- 디버깅이 훨씬 쉬워집니다: Web3.js가 에러를 내도, 실제 JSON-RPC 요청을 확인해서 문제를 찾을 수 있습니다
- 최적화 가능: Batch Request나 캐싱 전략을 직접 구현할 수 있습니다
- 멀티체인 대응: 이더리움뿐만 아니라 Polygon, BSC, Arbitrum 등 모든 EVM 체인이 같은 JSON-RPC 인터페이스를 사용하므로, 한 번 배우면 계속 써먹을 수 있습니다
- 의존성 감소: 간단한 기능은 Web3.js 없이도 구현 가능합니다
추가 학습 리소스
더 깊이 공부하고 싶으시다면:
- JSON-RPC 2.0 공식 스펙 - 프로토콜 자체를 이해하고 싶다면 jsonrpc
- Ethereum JSON-RPC 문서 - 이더리움 메서드 전체 목록 ethereum
- Geth JSON-RPC 문서 - Geth 클라이언트의 확장 메서드까지 포함 geth.ethereum
처음에는 Web3.js만 사용했는데, JSON-RPC를 직접 다뤄보니 블록체인 통신의 본질을 이해하게 되었습니다. 여러분도 한 번쯤은 curl이나 fetch로 직접 JSON-RPC를 호출해보시길 추천드립니다. 생각보다 간단하면서도, 많은 걸 배울 수 있을 겁니다!
'Blockchain' 카테고리의 다른 글
| 암호화폐 지갑의 비밀: 12개 단어가 모든 것을 담는 이유 (0) | 2026.02.08 |
|---|---|
| ERC 토큰 표준 둘러보기 (0) | 2026.02.07 |
| EIP-6963 2편: DApp에 지갑연결 구현하기 (0) | 2026.01.27 |
| EIP-6963 1편: 지갑 연결의 새로운 표준 EIP-6963 (0) | 2026.01.27 |
| Ethers.js 없이 ERC-20 토큰 단위 변환하기 (0) | 2026.01.26 |