블록체인 도메인 개발자가 JSON-RPC를 꼭 알아야 하는 이유
2026. 1. 26. 20:51

블록체인 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

제 경험상 실무에서 가장 많이 사용하는 메서드들입니다:

  1. eth_blockNumber: 최신 블록 번호 조회
  2. eth_getBalance: 계정 잔액 조회
  3. eth_call: 스마트 컨트랙트 읽기 전용 함수 호출
  4. eth_sendRawTransaction: 서명된 트랜잭션 전송
  5. eth_estimateGas: 가스 사용량 추정
  6. eth_gasPrice: 현재 가스 가격 조회
  7. eth_getTransactionByHash: 트랜잭션 정보 조회
  8. eth_getTransactionReceipt: 트랜잭션 영수증 조회
  9. eth_getBlockByNumber: 블록 정보 조회
  10. 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 없이도 구현 가능합니다

추가 학습 리소스

더 깊이 공부하고 싶으시다면:

처음에는 Web3.js만 사용했는데, JSON-RPC를 직접 다뤄보니 블록체인 통신의 본질을 이해하게 되었습니다. 여러분도 한 번쯤은 curl이나 fetch로 직접 JSON-RPC를 호출해보시길 추천드립니다. 생각보다 간단하면서도, 많은 걸 배울 수 있을 겁니다!