Ethereum Provider란 무엇인가(EIP-1193)
Provider의 정의와 EIP-1193에 대한 요약
EIP 1193
원문 : https://eips.ethereum.org/EIPS/eip-1193
배경
이더리움, 클레이튼 개발을 하다보니 web3.js나 ethers.js에서 쓰는 Provider가 정확히 무엇인지 궁금해졌습니다.
검색해보니 EIP-1193이 Provider 표준을 정의해놓은 문서라는 것을 알게 되었고, EIP 포맷에 익숙해질겸 일독을 했습니다.
이번 글은 EIP-1193을 읽고 제 임의대로 중요한 부분을 발췌해 요약 및 번역을 한 글입니다.
요약
이더리움 웹앱(dapp)생태계의 공통의 컨벤션으로 키 관리 소프트웨어(지갑)가 있다. 지갑은 웹 페이지에 자바스크립트 객체를 통해 그 지갑의 API를 노출시킨다. 이 객체를 Provider 라고 부른다.
역사상 Provider 구현체는 지갑 마다 인터페이스나 행동이 충돌해왔다. 이 EIP는 지갑의 상호운용성을 촉진시키기 위해 이더리움 Provider API를 공식화한다.
이 API는 최소한으로 이벤트 드리븐하게 디자인 되었고, 통신수단과 RPC 프로토콜 종류에 무관하다.
역사상 Provider는 웹 브라우저에 window.ethereum 으로 사용되어왔다. 허나 window.ethereum 은 이 스펙 문서에서 다루진 않는다.
정의
Provider
소비자가 사용가능한 자바스크립트 객체, 클라이언트를 사용해 이더리움에 접근하는 기능을 제공한다.
Client
Provider로부터 RPC 요청을 받고 결과를 리턴하는 엔드포인트
연결
Provider는 적어도 하나의 체인에 RPC 요청을 서비스할 수 있을 때 connected 되었다고 한다.
Provider는 어느 체인에도 RPC 요청을 서비스하지 못할 때 disconnected 되었다고 한다.
주요 API
Provider는 아래의 API들을 구현하고 선보여야 한다. 모든 API 엔티티는 타입과 인터페이스에 종속되어야 한다.
request
request 메소드는 RPC 전송과 프로토콜 표준에 독립적인 wrapper 함수로 간주된다.
Provider는 RequestArguments.method 값으로 요청받은 RPC 메소드를 확인해야 한다..
요청받은 RPC 메소드가 어느 파라미터이든 받는다면, Provider는 그 파라미터들을 RequestArguments.params 값으로 수용해야 한다.
RPC 요청은 RPC 메소드의 스펙의 값으로 resolve하는 Promise나 error로 reject하는 Promise를 리턴하는 방식으로 다뤄져야 한다.
만약 resolve 된다면, Promise는 RPC 메소드의 스펙에 대하여 결과를 resolve해야 한다. Promise는 (RPC 메소드의 리턴 타입이 정해져있지 않다면) RPC 프로토콜에 특화된 응답 객체를 resolve 하지 않아야 한다.
만약 리턴된 Promise가 reject라면 RPC Error에 정의된대로 ProviderRpcError 을 리턴해야 한다.
RPC Errors
interface ProviderRpcError extends Error {
code: number;
data?: unknown;
}
message인간이 읽을 수 있는 문자열이야 한다.
Error Standard 스펙에 종속되어야 한다.
code정수여야 한다
Error Standard 스펙에 종속되어야 한다.
data에러에 대해 쓸모있는 정보를 포함해야 한다.
Error Standards
ProviderRpcError 코드와 메세지는 아래의 컨벤션을 따라야 한다.
Provider Errors에 있는 에러
RPC 메소드 스펙으로 정한 에러들
CloseEventstatus codes
Provider Errors
| Status Code | Name | Description |
|-------------|-----------------------|-----------------------|
| 4001 | User Rejected Request | The user rejected the request. |
| 4100 | Unauthorized | The requested method and/or account has not been authorized by the user. |
| 4200 | Unsupported Method | The Provider does not support the requested method. |
| 4900 | Disconnected | The Provider is disconnected from all chains. |
| 4901 | Chain Disconnected | The Provider is not connected to the requested chain. Events
Provider는 다음과 같은 이벤트 핸들링 메소드를 구현해야 한다.
onremoveListener
이 메소드들은 Node.js EventEmitter API로 구현해야 한다.
message
메세지 이벤트는 다른 이벤트로 다루지 못하는 임의의 알림을 의미한다.
emit이 됐을 때 message 이벤트는 아래의 형태의 객체 인자로 emit 되어야 한다.
interface ProviderMessage {
readonly type: string;
readonly data: unknown;
}
connect
Provider가 connected 되었을 때 Provider는 connect 이벤트를 emit해야 한다.
emit 시기
시작 이후 Provider가 체인에 처음 연결됐을 때,
Provider가
disconnect이벤트가 emit 된 이후 체인에 연결됐을 때
이 이벤트는 아래 형태의 객체로 emit 해야 한다.
interface ProviderConnectInfo {
readonly chainId: string;
}
chainId MUST specify the integer ID of the connected chain as a hexadecimal string, per the eth_chainId Ethereum RPC method.
chainId 는 이더리움 RPC 메소드 eth_chainId 에 대해 16진수 문자열로 연결된 체인의 정수 ID를 명시해야 한다.
disconnect
Provider가 모든 체인으로부터 연결이 끊어진다면, Provider는 error: ProviderRpcError 와 함께 disconnect라는 이벤트를 emit 해야 한다.
error code 값은 status codes for CloseEvent를 따라야 한다.
chainChanged
Provider가 연결된 체인이 변경된다면, Provider는 chainId라는 문자열 값과 함께 chainChanged 라는 이벤트를 emit 해야 한다. 새로운 체인의 정수 ID는 16진수 문자열이여야 한다.
accountsChanged
Provider 변경이 가능한 계정이 있다면, Provider는 계정 주소들에 해당하는 문자열 배열인 accounts 값과 함께 accountsChanged 라는 이벤트를 emit 해야 한다.
프로바이더의 목적
Provider의 목적은 Ethereum에 대한 접근을 소비자에게 제공하는 것이다. 일반적으로, Provider는 이더리움 웹앱이 아래의 2가지를 하는 것을 가능하게 한다.
이더리움 RPC 요청
Provider의 이더리움 체인, 클라이언트, 지갑의 상태 변화에 대한 응답
Provider API 스펙은 1가지 메소드와 5가지 이벤트로 구성된다. request 메소드와 message 이벤트만으로도 온전한 Provider를 구현하기에 충분하다. 그 2가지는 각각 임의의 메세지로 통신하고 임의의 RPC 요청을 만들게 고안되었다.
나머지 4개의 이벤트는 2가지 카테고리로 분리된다.
RPC 요청을 만들기 위한 Provider의 기능에 대한 변화
connectdisconnect
중요한 앱이 다뤄야 하는 공통의 클라이언트 혹은 지갑의 상태 변화
chainChangedaccountsChanged
주의할점
Provider는 자바스크립트 객체이기 때문에, 소비자들은 일반적으로 Provider에 대해 임의의 작업을 수행할 수 있다.
그리고 객체의 프로퍼티를 읽거나 덮어쓸 수 있다. 그러므로 Provider 객체가 작업자에 의해 통제 되는 것처럼 다루는게 제일 좋다. Provider 구현자는 아래의 것들을 보장함으로써 유저, 지갑, 클라이언트를 보호한다는 것도 중요하다.
프로바이더는 private 유저 데이터를 갖고 있지않다.
프로바이더와 지갑 프로그램은 서로 분리되어있다.
프로바이더의 지갑과 클라이언트 요청은 속도 제한이 있다.
프로바이더에서 오는 모든 데이터를 지갑과 클라이언트가 검증한다.
