> THE-ARSENAL
> _

자바스크립트 제국과 솔리디티 연방의 언어 장벽

자, 상상을 좀 해보자. 여기 거대한 두 개의 세계가 있다. 한쪽은 우리가 매일 보는 웹사이트와 앱들이 화려하게 돌아가는 '자바스크립트(JavaScript) 제국'이다. 이 친구들은 유연하고, 빠르고, 무엇보다 사용자 친화적이지. 버튼을 누르면 반응하고, 화면을 예쁘게 꾸미는 데 도가 텄다.

반대편에는 '솔리디티(Solidity) 연방'이 있다. 블록체인이라는 차가운 금속성 대지 위에 세워진 이 나라는 엄격하다. 한번 뱉은 말(코드)은 절대 주워 담을 수 없고, 돈과 자산이 오가는 곳이라 융통성이라곤 눈곱만큼도 없다. 게다가 이더리움 가상 머신(EVM)이라는 아주 독특한 기계 안에서만 숨을 쉴 수 있지.

문제는 이 두 세계가 서로 대화를 해야 한다는 거다. 네가 웹사이트(DApp)에서 "내 토큰을 교환해줘"라고 버튼을 누르는 순간, 자바스크립트 제국의 전령은 솔리디티 연방의 금고지기에게 이 명령을 전달해야 한다. 그런데 어쩌나? 둘은 언어가 완전히 다르다. 자바스크립트가 "Hey, swap this!"라고 외쳐봐야, 솔리디티는 그게 무슨 귀신 씻나락 까먹는 소리냐며 무시할 뿐이다. 심지어 이 판에는 '러스트(Rust)'나 'WASM' 같은 제3세계 언어들까지 끼어들어 스냅(Snap)이라는 이름으로 활동하고 있다.

이 난장판 속에서 어떻게 오해 없이, 단 하나의 토씨도 틀리지 않고 수백억 원짜리 거래 명령을 전달할 수 있을까? 바로 여기서 '통역사'가 등장한다. 아주 깐깐하고, 절대 농담을 하지 않는 기계적인 통역사. 우리는 그걸 JSON-RPC라고 부른다.

가장 쉬운 공용어, 텍스트(Text)로 대화하자

개발자들이 바보는 아니다. 서로 다른 시스템끼리 통신하는 게 얼마나 골치 아픈 일인지 진작에 알았다. 그래서 그들은 합의했다. "복잡한 거 다 집어치우고, 그냥 텍스트(Text)로 주고받자."

생각해 봐. 0과 1로 이루어진 이진 데이터(Binary)는 기계에겐 좋지만, 보내는 놈이나 받는 놈이나 해석하기 까다롭다. 하지만 텍스트는 만국 공통이다. 알파벳과 숫자, 그리고 몇 가지 기호만 있으면 된다. 이게 바로 JSON(JavaScript Object Notation)의 핵심이다. 이름은 자바스크립트에서 따왔지만, 이제는 C언어든, 파이썬이든, 솔리디티든 누구나 읽고 쓸 수 있는 '지구어'가 됐다.

JSON-RPC는 이 JSON이라는 편지지에 "나, 너한테 이거 요청할게(Remote Procedure Call)"라고 적어 보내는 규약이다. 아주 단순하고 무식해 보이지만, 이 단순함 덕분에 웹사이트(JS)가 보낸 메시지를 메타마스크(Extension)가 받고, 그걸 다시 스냅(SES/JS)이나 블록체인 노드(Go/Rust)로 전달하는 기적 같은 일이 벌어진다.

스냅 개발 문서를 뒤적이다 보면 parseJson이나 getJsonSizeUnsafe 같은 함수들이 툭툭 튀어나오는 걸 볼 수 있다. 이건 그냥 데이터를 쪼물딱거리는 게 아니다. 서로 다른 차원의 존재들이 대화하기 위해, 가장 기초적인 형태인 '문자열'로 정보를 변환하고(Serialize) 다시 해석하는(Deserialize/Parse) 성스러운 의식인 셈이다.

문법은 딱 4가지: jsonrpc, method, params, id

이 통역사는 말이 많지 않다. 딱 네 마디만 알아들으니까. 네가 DApp 개발자든 스냅 개발자든, 메타마스크에게 뭔가를 부탁하려면 이 네 가지 규칙을 목에 칼이 들어와도 지켜야 한다.

  1. jsonrpc: "나 지금 2.0 버전 문법 쓰고 있어."라고 버전을 명시하는 거다. 보통 "2.0"이라고 박아넣는다. 이걸 안 쓰면? 옛날 사람 취급받거나 아예 무시당한다.
  2. method: "그래서 뭘 하고 싶은데?"에 대한 답이다. wallet_invokeSnap처럼 "스냅 좀 깨워줘"라거나, eth_sendTransaction처럼 "송금해줘" 같은 구체적인 동사를 적는다.
  3. params: "구체적인 내용은 뭔데?"다. 누구한테, 얼마를, 어떤 데이터와 함께 보낼지 세부 정보를 담는 보따리다.
  4. id: "이건 101번 요청이야."라고 번호표를 붙이는 거다. 비동기 세상에서는 요청과 응답이 뒤죽박죽 섞일 수 있기 때문에, 내가 보낸 요청에 대한 답이 맞는지 확인하려면 이 번호표가 필수다.

이 4가지가 딱 맞아떨어져야 비로소 JsonRpcSuccess라는 도장이 찍힌 응답이 돌아온다. 만약 하나라도 틀리면? 가차 없이 JsonRpcFailure 딱지가 붙은 에러 메시지만 덩그러니 받게 될 거다. 메타마스크 지갑에서는 assertIsJsonRpcSuccess라는 함수가 문지기처럼 서 있다. 성공이냐 실패냐, 그 냉혹한 판정이 여기서 갈린다.

통역사가 실수를 걸러내는 법 (Schema Validation)

그러나 통역사가 단순히 말만 옮기는 앵무새라고 생각하면 오산이다. 훌륭한 통역사는 말도 안 되는 소리는 애초에 차단한다. 메타마스크 스냅 시스템에는 '스키마(Schema)'라는 엄격한 필터가 있다.

예를 들어보자. 어떤 DApp이 스냅을 호출하려고 한다. 그런데 이 DApp이 믿을만한 놈인지, 아니면 피싱 사이트인지 어떻게 알지? 여기서 RpcOriginsStruct라는 구조체가 등장한다. 이건 일종의 입국 심사관이다.

// 깐깐한 심사관의 기준표
export const RpcOriginsStruct = refine(
  object({
    dapps: optional(boolean()), // DApp 접근 허용할까?
    snaps: optional(boolean()), // 다른 스냅 접근 허용할까?
    allowedOrigins: optional(AllowedOriginsStruct), // 특정 주소만 허용할까?
  }),
  // ...
);

이 심사관은 isOriginAllowed 함수를 통해 요청 보낸 놈의 신분을 확인한다. "너, 우리 목록에 있어?"라고 묻는 거지. 만약 https://evil-site.com이 접근하려고 하는데 허용 목록(AllowedOrigins)에 없다? 바로 컷이다. 재미있는 건 와일드카드(*) 규칙이다. https://*.metamask.io처럼 "메타마스크 가문 사람들은 다 통과"라고 할 수도 있지만, 와일드카드가 2개를 넘어가면 "너 신분이 너무 모호해"라며 에러를 뱉는다. 보안은 모호함을 제일 싫어하니까.

사투리는 허용되지 않는다 (Strict Typing)

프로그래밍 언어마다 데이터의 생김새가 조금씩 다르다. 자바스크립트에는 undefined라는 게 있지만, JSON에는 없다. 어떤 언어는 정수와 실수를 구분하지만, 어떤 언어는 퉁쳐서 숫자라고 부른다. 이런 '사투리'를 그대로 통역하면 사고가 난다.

그래서 스냅 시스템은 'Strict Typing(엄격한 타입 지정)'을 고수한다. 들어오는 데이터가 JSON 표준을 완벽하게 따르는지, 그리고 우리가 약속한 구조(Struct)와 정확히 일치하는지 현미경으로 들여다본다.

"대충 알아들으면 되지"는 인간 세상에서나 통하는 말이다. 금융 자산을 다루는 이곳에서는 "사과"를 "능금"이라고만 해도 거래가 취소되거나, 최악의 경우 해킹의 빌미가 된다. 그래서 이 통역사는 표준어가 아니면 아예 입도 뻥긋 못하게 입을 막아버린다.

메타마스크라는 거대한 통역 센터

이제 전체 그림을 보자. 메타마스크는 단순한 지갑이 아니다. 온갖 언어와 프로토콜이 뒤섞인 웹3 세상의 '거대한 통역 센터'다.

사용자가 화면을 클릭한다. (이벤트 발생)
→ 웹사이트(JS)가 wallet_invokeSnap이라는 JSON-RPC 메시지를 작성한다.
→ 브라우저를 타고 메타마스크 확장 프로그램(Controller)에 도착한다.
→ 메타마스크는 봉투를 뜯어 snapId를 확인하고, 권한(isOriginAllowed)을 체크한다.
→ 문제가 없으면 격리된 방(SES 샌드박스)에서 자고 있던 스냅을 깨운다.
→ 스냅(Executor)은 메시지를 받아 처리하고, 다시 JSON 결과를 돌려준다.

이 모든 과정이 눈 깜짝할 새에 일어난다. 우리는 그저 화면에 뜨는 "승인하시겠습니까?" 팝업만 볼 뿐이지만, 그 뒤에서는 수많은 assert 함수와 검증 로직들이 미친 듯이 돌아가며 "이 메시지 안전해?", "이 문법 맞아?", "이 출처 확실해?"를 따지고 있는 거다.

결론: 시스템은 달라도 데이터는 하나로 통한다

결국 JSON-RPC는 외계인과 대화하기 위해 인류가 찾아낸 가장 효율적인 타협점이다. 서로의 내부 사정(어떤 언어를 쓰는지, 메모리는 어떻게 관리하는지)은 알 필요도 없고 알 수도 없다. 그저 약속된 텍스트 메시지만 정확하게 주고받으면 된다.

이것이 웹3가 탈중앙화될 수 있는 기술적 기반이다. 누구든 이 문법만 지키면 메타마스크와 대화할 수 있고, 이더리움과 소통할 수 있다. 거대한 성벽 같은 플랫폼 기업의 허락을 받을 필요 없이, 규약(Protocol)만 지키면 연결되는 세상. 그 자유를 가능케 하는 건, 아이러니하게도 아주 엄격하고 깐깐한 텍스트 통역사들 덕분이다.

그러니 다음에 메타마스크가 툭 튀어나오면, 그 뒤에서 땀 흘리며 통역하고 있을 JSON-RPC에게 마음속으로라도 감사 인사를 전하자. 걔네 없었으면 우린 아직도 16진수 바이너리 코드랑 씨름하고 있었을 테니까.

3줄 요약

  1. DApp(웹)과 스냅(로컬), 블록체인(온체인)은 서로 다른 언어를 쓰기 때문에, JSON-RPC라는 텍스트 기반 공용어로만 소통할 수 있다.
  2. 이 통역 과정은 단순히 말을 옮기는 게 아니라, 출처(isOriginAllowed)와 문법(assertStruct)을 깐깐하게 검증하여 보안 사고를 막는 핵심 관문이다.
  3. 메타마스크는 이 모든 메시지가 오가는 거대한 허브이며, 엄격한 데이터 표준 준수 덕분에 누구나 연결 가능한 탈중앙화 생태계가 유지된다.