블록체인 기술을 공부하는 가장 기본적인 목표인 Transaction 발생을 해보도록 하겠다.
이 Transaction 발생은 어떤 블록체인이건 개념이해 후 가장 첫 걸음을 떼는 단계이므로 잘 따라해보도록 하자.

Transaction 을 발생하는것을 포함하여 Ethereum 과 Interaction 을 할 수 있는 방법에 대한 설명과 실제 간단한 Transaction 을 JSON-RPC 를 통해 발생시키는 방법을 알아보겠다.

이후 모든 Ethereum 과 관련한 내용은 Geth 를 기준으로 하겠다.
Eth 만 있는 기능인 경우 Eth 를 언급하겠으나 별도 언급이 없으면 모두 Geth 환경이다.

▌Ethereum 에서 개발하는 방법
이더리움을 블록체인 플랫폼의 코어 엔진으로 생각했을 때, 이 코어 엔진을 활용하여 응용을 개발할 수 있는 방법에는 아래 세가지가 있다.

  1. HTTP 기반 JSON RPC API 사용
    REST API Test 프로그램이나 Curl 등으로 즉시 테스트해볼 수 있으며, 원격 응용 프로그램과 통신하기에 적합한 인터페이스.
  2. JavaScript 기반의 web3.js API 를 사용
    Ethereum 이 Dapp 개발을 위해 기본으로 제공하는 JavaScript API 로, Browser, Node.JS, Mist 등으로 실행할 수 있는 인터페이스 이다. 내부적으로는 JSON RPC 를 사용한다.
  3. 응용에 엔진을 라이브러리 형태로 활용하는 방법
    소스코드 형태로 Ethereum 을 사용하며, 가장 응용과 Tight 하게 동작할 수 있다. 그러나 그래야 할 확실한 이유가 있지않는 한 추천하고싶지 않은 방법이다.

위 세가지 방법 중 1,2 번은 비교적 쉬운 방법이나, 3번의 경우 Ethereum 의 코드 분석 없이는 활용이 거의 불가능하다고 봐야하며, 이 코드를 분석하는 데만도 수개월 이상의 노력이 필요하다.
나도 C++ Ethereum 을 3번 형태로 응용하는것을 목표로 한적이 있으나, 200,000 라인에 육박하는 코드에, 난무하는 Template Class 와 상호 Dependency 가 높고 boost 로 발라놓은 C++ 11 스펙의 코드를 해석하기에는 시간이 매우 부족하였다.

따라서, 1,2번 방법이 Ethereum 을 "활용"하기 가장 적합한 방법이라고 생각되며, Transaction 발생과 같은 매우 간단한 API 사용부터 시작하는게 응용을 위한 이해의 첫걸음이라 하겠다.

▌JSON RPC 인터페이스 기본 이해
ETH 와 GETH 모두 HTTP 기반의 JSON RPC 2.0 스펙을 지원한다. JSON RPC API 는 여기 에서 확인할 수 있으며 사용법은 매우 간단한 편이다.

Listen Port : JSON RPC 의 기본 Listen Port 는 8545 번이다. (Geth, Eth 공통)
실행 옵션
     --rpc : rpc 를 사용함
     --rpcaddr : RPC 를 Listen 하는 IP Address Bining (기본: 127.0.0.1)
     --rpcport : RPC Listen Port (기본:8545)
     --rpcapi : RPC 를 통해 사용 가능한 API 셋 (기본: db, eth, net, web3) (이외에 admin, debug, miner, shh, txpool, personal 을 , 로 구분하여 추가 가능)
     --rpccorsdomain : Browser 에서 web3.js 사용 시 Cross Domain 문제가 생기지 않도록 Accept 할 Document 의 Origin Domain.

테스트 환경을 위해 두개의 Node Instance 를 아래와 같이 구성하였다
[Node 1]
  1. Miner 동작
  2. RPC Listen Address Binding : ALL
  3. RPC Listen Port : 8541
  4. RPC API : admin, db, eth, debug, miner, net, shh, txpool, personal, web3
  5. Geth Listen Port : 3031
  6. JavaScript Console 켜기

일단, 아래 커맨드로 Account 를 하나 생성한다
$ geth --datadir $ETH_HOME/db/p1_net_node1 account new

그리고 나서 Miner 인 Node 1을 실행시킨다
$ geth --datadir $ETH_HOME/db/p1_net_node1 --genesis $ETH_HOME/res/p1_net/genesis.json --rpc --rpcaddr "0.0.0.0" --rpcport "8541" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 3031 --nodiscover --mine console


[Node 2]
  1. Miner 동작 안함
  2. RPC Listen Address Binding : ALL
  3. RPC Listen Port : 8542
  4. RPC API : Node 1 과 동일
  5. Geth Listen Port : 3032
  6. JavaScript Console 켜기

Node 2 용 Account 도 하나 생성한다
$ geth --datadir $ETH_HOME/db/p1_net_node2 account new

$ geth --datadir $ETH_HOME/db/p1_net_node2 --genesis $ETH_HOME/res/p1_net/genesis.json --rpc --rpcaddr "0.0.0.0" --rpcport "8542" --rpcapi "admin,db,eth,debug,miner,net,shh,txpool,personal,web3" --port 3032 --nodiscover $@

[genesis.json]
 {
 "alloc": {
    "d1c8b6e81af8ef16a7dbcd410234f12e10f1579d": {
      "balance""5000000000000000000000000000"
    },

    "2c6191a4792a3a33cbd2f8b7b7e583a61fb33b23": {
      "balance""5000000000000000000000000000"
    }
  },

  "nonce""0x0000000000000000",
  "difficulty""0x010000",
  "mixhash""0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase""0x0000000000000000000000000000000000000000",
  "timestamp""0x00",
  "parentHash""0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData""0x",
  "gasLimit""0x1000000000"
}

위 alloc 의 Account Address 는 각 Node 1, 2 를 위해 생성한 Account 들이다

[static-nodes.json]
위 CLI 옵션에서 보이듯 --nodiscover 옵션을 주었으므로 자동으로 Peer 를 찾지 않을것이다. Node 2 의 <datadir>/static-nodes.json 파일에 static node 로 Node 1 을 추가해준다.
[
    "enode://258a9b4558c163fdaa48f4f7111b8479d87360bc61c77680269b34204dadc293fccdf2c915acb446953712c12ab8a040d2f7b79ef1e066da60b65a88a7bb382d@[::]:3031"
]

두 Peer 를 실행시키면 Node 1 은 DAG 파일을 생성한 후 Mining 을 시작하고, Node 2 를 띄우면 Node 1 에 접속하여 Block 을 sync 하기 시작한다.
이제 테스트할 환경이 만들어졌다.

▌JSON RPC 테스트환경 만들기
JSON RPC API 를 테스트하기 전에 curl 대신 좀더 쉽게 테스트할 수 있는 환경을 만들어보자. 
Chrome 을 사용하고있다면, Post Man 이라는 REST 테스트 도구를 사용할 수 있다. Plugin 을 설치하고 실행하면 아래와 같은 화면이 보인다.

JSON RPC 로 테스트 하여 성공한다면, 이후 어떠한 언어로든 Ethereum Blockchain 을 사용하는 응용을 만들 수 있게 되는것이다.


위 화면에서, Collection 을 하나 만들어두자


이름은 Geth 로 해 두고, 이제 화면 우측 상단의 "Manage Environment" 를 클릭한다.


Add 버튼을 눌러 Environment 이름을 적당히 준다.


key 에 "url" 이라고 입력하고, value 에 Geth 의 JSON RPC Listen IP 주소와 Port 를 입력한다
나는 node 2 (Miner 아닌 Node) 를 대상으로 해보겠다.

이렇게 등록한 Environment Variable 은 향후에 {{url}} 과 같이 사용할 수 있다.



▌Client Version 가져오기

위 모든 과정들을 마쳤다면 이제 JSON RPC 테스트 환경이 끝난것이다. 아주 간단한 Client Version 을 요청하는 API 부터 사용해본다.
Client 의 Version 을 가져오는 API 이름은 web3_clientVersion 이다.

Spec 상, Parameter 는 없고, Return 은 현재 Client 의 버전을 담은 정보가 들어오게 되어있다.


위 처럼 새로운 요청을 만들고, Request Type 은 "raw" 로 하고, 데이터 포맷은 "JSON (application/json)" 으로 한다.
Send 를 누르면, 아래와 같은 응답이 온다.
{
  "id"100,
  "jsonrpc""2.0",
  "result""Geth/v1.3.5-cab802b4/linux/go1.6"
}

성공이다. 이제 원하는 API 를 무엇이든 응용하여 사용할 수 있다.

▌JSON RPC 를 통한 Block 정보 가져오기

하나만 더 해보자. Node 1 에서 Miner 가 돌고 있으므로, Block 이 계속 생성되고 있을 것이다. Difficulty 가 매우 낮으므로 빠른 속도로 생성되고 있을 것이다.
Node 2 가 Import 한 최신 Block 의 정보를 가져와보도록 하겠다.

[Request]
{
    "jsonrpc":"2.0",
    "method":"eth_getBlockByNumber",
    "params":["latest",true],
    "id":100
}

params 의 첫번째 파라미터는 "최신 블록"을 가져오란 이야기 이고,
params 의 두번째 파라미터 true 는, Transaction 데이터 전체를 가져오겠다는 이야기이다. (그러나 Transaction 을 발생시키지 않았으므로, 이 배열값은 비어있다)

[Response]
{
  "id"100,
  "jsonrpc""2.0",
  "result": {
    "number""0x1ff",
    "hash""0x1c9dd4d3191be60a30a01cd8423f05ee203617a03c60d330f76805be2d8df0de",
    "parentHash""0x267128da87431da30d30bf280efa1ef41f5c5e7a2dee846f3d2c94b89947adfd",
    "nonce""0x7652646a68725a33",
    "sha3Uncles""0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "logsBloom""0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "transactionsRoot""0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
    "stateRoot""0x9ad2a3c192a39ec9653915f6935c3502fd46d9e6e2805309d80408ea3227e1b4",
    "receiptRoot""0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
    "miner""0xd1c8b6e81af8ef16a7dbcd410234f12e10f1579d",
    "difficulty""0x27be0",
    "totalDifficulty""0x4788d6e",
    "size""0x219",
    "extraData""0xd583010305844765746885676f312e36856c696e7578",
    "gasLimit""0x9b62bb0db",
    "gasUsed""0x0",
    "timestamp""0x56ed6d1b",
    "transactions": [],
    "uncles": []
  }
}

Block Number 는 0x1ff (511) 이다.
sha3Uncles, logsBloom, stateRoot, receiptRoot, totalDifficulty, extraData, gasLimit, gasUsed, uncles 등이 기존 Bitcoin 을 했던 사람들은 생소하게 보일것이다. 이건 차츰 알아가보도록 하고, 일단 정보가 잘 왔다면 가장 기본적인 API 를 성공적으로 실행 한 것이니 박수를 치자.

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,