이전의 JSON RPC API 기본의 연장이다.
이번에는 JSON RPC 를 통해 실제 Ether 를 이체시키는 Transaction 을 발생시켜보자.

▌Unlock Account
Geth 와 Eth 모두 Account 로 부터 Transaction 을 발생시키기 위해서는 From 이 되는 Account 를 unlock 해야 한다. 
Account 를 Unlock 하기 위해서는 Account 를 생성했을 당시 입력한 패스워드를 반드시 알고 있어야 한다.

일단, 아래와 같이 Request 를 한다.
{
    "jsonrpc":"2.0",
    "method":"personal_unlockAccount",
    "params": [
        "0x2c6191a4792a3a33cbd2f8b7b7e583a61fb33b23",
        "1111",
        0
        ],   
    "id":100
}
"params" Object 의
1번째 파라미터는 "Unlock 을 하고자 하는 자기 Account 의 주소"이다
  Wallet 안에 해당 Account 가 존재해야 하며, Wallet 의 위치는 datadir 에 따라 다르므로, geth account list 나 JSConsole 또는 RPC 로 현재 자신의 Wallet 내의 account 를 확인한 후 입력하자
2번째 파라미터는 "Account 의 Password" 이다
3번째 0 은 Unlock 의 Timout 을 "초" 단위로 입력한다.
  0 으로 지정하면, 이번 Session (Geth 의 Instance 가 살아있는) 동안은 계속 unlock 하게 된다.

성공 했다면 아래와 같은 response 가 온다
{
  "id"100,
  "jsonrpc""2.0",
  "result"true
}


▌Ether 보내기
일단 다른 Node 에 Account 를 하나 추가하였다. Address 는 "0xd33cbaced7b3990554667391708350cbbe3083a6" 로 EOA 를 생성했고, 아직 balance 는 0 이다.
2c6191a4792a3a33cbd2f8b7b7e583a61fb33b23 계좌에서 위 계좌로 150 ether 를 이체 해보겠다. 
Transaction 을 보낼때는 Wei 단위를 쓰며, 150 이더는 150,000,000,000,000,000,000 Wei 이다. 이걸 HEX 값으로 바꾸면 0x821ab0d4414980000 이 된다.

{
    "jsonrpc":"2.0",
    "method":"eth_sendTransaction",
    "params": [{
      "from""0x2c6191a4792a3a33cbd2f8b7b7e583a61fb33b23",
      "to""0xd33cbaced7b3990554667391708350cbbe3083a6",
      "value""0x821ab0d4414980000"
    }],   
    "id":100
}

위 처럼 Request 를 보내면, 정상적인 Transaction 이 발생 되었다면 아래와 같은 응답이 온다.

{
  "id"100,
  "jsonrpc""2.0",
  "result""0x265be2659d440ccd894370a9354bb189123f71ad17fea55f3b7dc2f8900d1664"
}

Result 로 보내준 값은 Transaction 의 Hash 이다.

▌Receipt 조사하기
Ethereum 은 Miner 가 생성한 Block 을 Import할 때 Transaction 을 처리하였다면, Receipt 를 만들어서 저장한다. 그래서, Transaction 이 정상적으로 Block 으로 묶여서 처리되었다면 Receipt 가 생기게 되어있다. Receipt 에는 해당 Transaction 처리에 소모된 Gas 와 Transaction 이 묶인 Block 의 번호 등이 포함되며, Smart Contract 를 Create 한 경우, Contract Account 의 Address 도 들어가게 된다.

Receipt 요청
{
    "jsonrpc":"2.0",
    "method":"eth_getTransactionReceipt",
    "params":[
        "0x265be2659d440ccd894370a9354bb189123f71ad17fea55f3b7dc2f8900d1664"
        ],
    "id":100
}

Receipt 결과
{
  "id"100,
  "jsonrpc""2.0",
  "result": {
    "transactionHash""0x265be2659d440ccd894370a9354bb189123f71ad17fea55f3b7dc2f8900d1664",
    "transactionIndex""0x0",
    "blockNumber""0x7a7",
    "blockHash""0xb760b2d919227cf557f7289c3a5181f09fb0deda669df35b50c510af189cdc5a",
    "cumulativeGasUsed""0x5208",
    "gasUsed""0x5208",
    "contractAddress"null,
    "logs": []
  }
}

해당 Transaction 이 Mining 되어 Block 들어갔고, Block Hash 도 보여준다.

이제 잔고를 확인해보면 된다.

▌잔고 확인하기
위 이체 작업이 잘 되었는지 잔고를 확인해보도록 하겠다.

Balance 확인 요청
{
    "jsonrpc":"2.0",
    "method":"eth_getBalance",
    "params": [
        "0xd33cbaced7b3990554667391708350cbbe3083a6"
        ],   
    "id":100
}

Balance 확인 응답
{
  "id"100,
  "jsonrpc""2.0",
  "result""0x0821ab0d4414980000"
}

위 처럼 150 ether 가 잘 이체되었음을 알 수 있다.


이렇게 JSON RPC API 를 사용한 방법은 아주 간결하다. 다만 Bitcoin 과 프로세스 상 다른부분들이 있어서 까다로워 보일 뿐이다.
이제 기본적인 Transaction 발생까지 해보았으니, 다음부터는 Web3 API 나 RPC 를 사용한 Smart Contract 로 들어가볼까 한다.

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
블록체인 기술을 공부하는 가장 기본적인 목표인 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

,

우리는 흔히 시스템의 처리 성능을 TPS 로 나타낸다. 말 그대로 초당 몇개의 "Transaction" 을 "처리"할 수 있느냐를 나타내는 수치이다. 

이번에 블록체인의 TPS 성능에 대해 이야기 해보고자 한다. 사람들이 많이 궁굼해 하지만 답변하는 사람들의 답변 내용을 들어봐도 딱히 맞다는 생각이 들지는 않더라.

Blockchain 이 널리 쓰이는 중요한 인프라소프트웨어 가 되려면 반드시 당면하게 될 문제 중 하나가 바로 “Transaction 처리 성능” 이다.


▌Bitcoin Blockchain PoW 방식 에서의 TPS 한계성

현재 Blockchain 은 1MB 의 블록 크기와 10분의 블록 생성을 근거로, 1 트랜잭션의 크기를 1 Input, 1 Output 만을 포함하는 최소한의 Size 로 잡더라도,
(1MB/600초)/약260바이트 = 약 7TPS
가 채 안나오게 된다.

이 7 TPS 라는 수치를 계산해내는 방법을 보았듯이, 우리가 생각하는 일반적인 TPS 와는 그 개념이 다르다. TPS 는 시스템의 "성능"을 측정하는 단위이지만, 블록체인은 그 성능 보다는 "10분 후 전파되는 블록에 담긴 Transaction 수"이다.

아래는 C/S 환경에서의 Transaction 처리를 간략히 표현해본 그림이다.

그림에서 처럼 클라이언트는 서버를 바라보며 요청을 하고, 해당 요청이 처리된 즉시 응답을 받는다. 이러한 요청은 여러 클라이언트가 동시에 할 수 있으며, 서버는 이러한 요청을 초당 몇개 처리할 수 있는지를 TPS 수치로 표현할 수 있다.

그러나, 아래와 같은 Blockchain 환경에서 보면, 이러한 TPS의 의미가 다르게 해석되어야 함을 알 수 있다.


Node 들 중에는 Miner 도 있고, Lightweight Client 들도 있다. SPV 라고 표현하던 것들이다. 이중 일반 Node 가 처리를 요청하면, 요청을 Transaction 메시지로 자신과 연결된 (1)Peer 들에게 전파된다. 모든 Node 들은 이러한 Transaction 에 대해 (2)검증 을 해야 한다. 또한 Transaction 을 검증한 Node 는, 해당 Transaction 을 자신의 Peer 들에게 (3)(4)전파 해야 한다. 그러면 그 트랜잭션은 Miner 에 의해 (5)검증 되며, Transaction Pool 에 담겨있던 Transaction 은 (6)Pow 를 통해 최소 10분 후 블록에 묶이게 된다. 이 블록은 Miner 의  Peer 들에게 (7)전파 되며 해당 Peer 는 받은 블록에 대해 (8)블록검증 을 수행하고, 검증된 블록은 다시 (9)전파 된다. 최종적으로 Transaction 처리에 대한 응답을 확인하고자 하는 Peer 는 이 블록을 받았을 때 (10)응답을 확인 할 수 있게 된다. 그리고 그 블록에는 최대 약 7*60초*10분 = 약4,200 개의 Transaction 이 포함되어있을 수 있다. 

위 시나리오는 매우 정상적인 Case 에서의 동작이며, 이론상 최대한 희망적인 상황에서의 상황이다. 실제로는
A. 여러 Input 과 Output 이 1 트랜잭션에 포함되어 Transaction 크기가 커진다
B. Miner 의 Transaction Pool 에 들어가도, 이미 Mining 중인 Block 이 있다면 트랜잭션은 가장 빨리 블록을 생성해낸 마이너의 다음 마이닝 작업에 대상이 된다. 그러므로 최대 19.9분 후에 블록을 받을 수도 있다
C. 어떤 Node 들은 6 Confirm 이상을 최종 Commit 으로 간주 하므로 약 1시간 뒤에 해당 Transaction 이 최종 “처리” 됨을 인정받을 수 있다.

이렇게 “처리”의 개념이 일반적인 C/S 아키텍쳐와 다르며, 그 이유는 “합의” 라는 과정과 “P2P” 라는 환경으로 인해 발생하는 것이다. 이 두가지 과정으로 인해 “처리 Latency" 가 높아지게 되며, 이것은 전체적인 시스템의 처리 성능이 매우 늦어지게 되는 결과를 초래한다.

아래 흐름을 보자. 우선, 설명을 위해 매우 단순한 CS 구성에서의 Transaction 처리 시나리오이다.

그림 처럼, client_1 과 client_2 는 Transaction 을 "직접 서버로" 전달한다. Client 3,4,5,6,... 모두 Server 에게 직접 Transaction 을 전달하며, 서버는 Transaction 을 처리하고 처리된 결과나 처리되었음을 알리는 Notification 을 Client 에게 전달한다. Client 에게 1 TX 처리에는 0.001초가 걸린 것이며, 서버의 입장에서는 1초에 1,000 TPS 를 처리한 것이 된다.

다음은 Blockchain 의 경우이다. 설명을 위해 node2 가 Miner 역할을 하며, node1,3,4 등은 SPV 로 간주하면 되겠다.

node 들은 P2P 환경으로 구성되어있다. node1 이 운 좋게 miner 인 node_2 를 peer 로 직접 추가하고 있거나, node1 자체가 miner 인 경우에도 최소 1 Transaction 이 처리되어 처리된 결과를 자신의 State 에 반영할 수 있는데 까지는 최소 10분 이상이 소요된다. node4 의 경우, node3 의 peer 인 경우로, 이 경우 node3 으로의 TX 전파와 node3 의 TX 검증 단계를 거친 후 miner 에게 전달될 수 있다. 만약 node1 이 Miner 라고 하더라도 Block 이 나오는데 까지는 10분이 소요되므로 사실상 "의미있는" Transaction 의 완전한 처리는 최소 10분이 되는 것이다.
이 경우, Miner 는 최대 7 TPS 로 10분 만에 Transaction 을 Commit 을 하게 된 것이며, Client 의 입장에서는 1 TX 를 처리하는데 10분이 걸린 것이다.

“처리”를 어디까지 볼것인가. 1:1 상황에서의 “전달” 과 "Transaction 검증", “(블록없이 Transaction 만만으로의)State 전이 완료 (Pre-Mined State)” 까지를 Transaction 처리 완료 시점이라고 정한다면 상당히 높은 성능의 시스템 구현이 가능하겠지만, 다수가 참여해야 하는 P2P 환경에서는 이러한 기준은 무의미 하다시피 하다. 

위 그림의 Pending TX 범위안에 있는 Transaction 들로 Miner 는 Block 을 만들게 되는데, 만약 Transaction 의 합이 Block Header 를 포함하여 총 1MB 를 넘게 되면, 1MB 내에서 Pending TX 를 잘라내고 잘라낸 만큼만을 Block 으로 만들게 된다. Mike Hearn 이 이야기 했던 1MB 의 블록 용량의 한계는 바로 이때문이다. 만약 비트코인 거래가 더 활발해져서 Transaction 수가 더 많아진다면, 저 Pending TX 의 용량은 조만간 1MB 를 넘을 것이다. 아래 그림을 보자.


노란색 그래프가 Block 의 평균 크기 이며, 이미 700KB 선이다. 7 TPS 의 트랜잭션도 안되며, 만약 700KB 로 계산해보면, 4~5 TPS 정도의 트랜잭션 발생에 블럭의 크기가 저렇게 된 것이다.

C/S 환경에서는 서버의 DB 에 최종 Commit 만 되었다면 이 즉시 모든 클라이언트가 전이된 State 를 기반으로 다음 작업을 할 수 있다. 그러나 Blockchain 의 경우, Block 이 적어도 다음 Transaction 을 발생시켜야 하는 Client 에게는 전달되었고 그 Block 에 의해 변이된 State 가 “옳다” 라는 “합의”가 되어지지 않는다면 다른 Peer 들은 내 Transaction 을 무시하게 될 것이다.

Pending Transaction 을 기반으로 작업을 한다면 Double Spending 을 막을 수 없다. 내가 매우 빠른속도로 어떤 네트워크에서 잔고 1,000 원에서 100원을 이체시키고, 다른 네트워크(또는 다른 멀리 있는 피어)로 이체 이전 상태인 1,000 원 상태에서 다시 500원을 이체하도록 한다면, 10분 뒤 블록이 나오기 이전에 Pending Transaction 을 기반으로 거래를 확정한 상대 시스템은 10분 후에나 문제가 있었음을 알 수 있으며, 어쩌면 그 다음 블럭인 20분 후에 이 사실을 알게된다.

Bitcoin 에서 최종 거래확정에 6 Confirm 을 권고하는 이유도, 1 Confirm 으로 들어온 블록이 Best Blockchain 이라고 말하기 어렵기 때문이며, 이후 들어온 블록을 기반으로 뒤따라 마이너들이 지속적으로 블록을 연결했다면, 결국 이전에 받은 1 Confirm 블록 내에 Double Spending 중 하나가 섞여있었을 수도 있기 때문이다.

"만약, Bitcoin 으로 한사람이 편의점에서 담배를 결재한 후 10분 이내에 라이터를 추가결재 하려 한다면, 이 거래는 현재 Bitcoin 내에서는 불가해야 한다" 왜냐하면, 아직 1 Confirm 도 떨어지지 않았을 것이기 때문이다. 물론 작은 금액의 거래에 대해서는 1 Confirm, 심지어 Pending Transaction 에 있어도 인정하는 추세이기는 하지만 어디까지나 이건 위험하다.

▌블럭을 크게, 생성 주기를 빠르게 하면? 

블럭 생성을 빠르게 한다면 Bitcoin 보다 더 빠른 응답속도가 가능해지며, Block 의 사이즈가 커진다면 블록에 더 많은 Transaction 을 담을 수 있게된다. Ethereum 의 경우, 0x0D (13초)를 블록 생성주기로 맞추어 놓고 있으며, 아직까지는 Block 의 사이즈를 제한하지는 않고, 대신 Block 의 Gas Limit 을 두어 Gas Limit 내에서 Transaction 을 담을 수 있게 하였다.

이러한 방식은 Bitcoin Blockchain (이제 Blockchain 1.0 이라고 하겠다) 에 적용했을 때 문제가 발생하게 되는데, 바로 다수의 Miner 가 동시에 생성해내는 Block 이 많아지는 문제가 생기는 것이다. Stale Block, Ethereum 에서는 Uncle 이라고 불리우는 Fork 들인데, 이러한 Fork 가 많아지게 되면 발생하는 문제는 State 의 불안정성이다.

Fork 를 인정하지 않는 Blockchain 1.0 방식으로 가게되면, Best Block Chain 이 바뀌는 순간 State 가 출렁일 수 있다. 특정 Account 의 Nonce 가 100 까지 올라간 Block을 받아서 State 가 올라갔는데, 새로 들어온 같은 Block Number의 Block 에는 이 State 변이를 실행했던 Transaction 이 제외되어 있으나 새로들어온 Block 의 Chain Total Difficulty 가 이전의 Difficulty 보다 높았다면 Best Blockchain 이 버뀌면서 State 가 Nonce 100 에서 99로 다시 바뀔 수 있다.

Ethereum 은 이러한 상황을 예상하여 GHOST(Greedy Heaviest Observed Subtree) 라는 프로토콜을 응용하여 자신들의 State Tree 인 Patricia Tree 를 구성할 때 Uncle Block 을 포함하도록 하였으며, 새로운 Block 이 생성될 때 자신이 참고하는 Uncle Block 을 포함시키도록 하였다. Uncle Block 에 대해서도 93.75% 의 Reward 를 주며, 이를 포함하는 Block 이 Best Block 이 되었을 때에는 각 Uncle Block 의 Reward 의 3.125% 를 Best Block 의 Coinbase 에 추가하도록 하였다.

이외에도 많은 부분을 생각해야 한다. 사이즈가 큰 블록은 네트워크 전파 속도가 느려지게되어 결국 더 많은 Uncle Block 들이 생기게 되고, 너무 작은 블록도 오버헤드를 높여 전체적인 성능을 저하시킨다. 특히나 시간이 짧아질수록 평균 Hashrate 를 기반으로한 블록 생성속도의 오차율은 커지게 되는데, 아래 그림(블록생성시간)처럼 블록생성시간의 오차범위는 매우 커지게 된다.


Ethereum 의 지금 시각 평균 Hashrate 는 etherstat 리포팅을 하고있는 node 들 기준으로 1.4TH/s 정도 되며, Difficulty 는 14~15초 정도 되는 20.34 TH 정도로 맞추어져있다.


빨라지는 주기를 PoW 로 때우기 위해서는 Block 생성 시간이 안정적이어야 하고 ASIC 같은 돈버러지를 떼어내야 하는데, 이때문에 Ethereum 은 DAG (Dagger Hashimoto)와 같은 방법을 썼고, 현재는 ethash 알고리즘으로 약1GB 정도의 Hash Cache 를 위한 Seed Table 을 생성하게 해놨으며, 100시간 정도 되는 30,000 블럭 주기로 이 DAG 를 전체 재생성 하도록 해놓았다. 이게 생성되는 것만도 십수분은 걸린다.

▌Authority 기반 블록 생성은?

권한 기반의 블록체인은 이미 작년 부터 Private Blockchain 과 Consorthium Blockchain의 필요성이 나오면서 구현체들이 나왔고, Ethereum 조차도 C++ eth 에서 이 PoA 를 flu 라는 CLI 를 통해 제공했었다. 현재는 Homestead 런칭으로 기능을 삭제한 상태이며 이전에 구현했던 방식도 그다지 세련되지 않은 방식이었다.

Authority 기반의 블록체인의 기본적인 핵심은 "블록을 생성할 수 있는 권한을 부여"하는 것부터 출발하는 것이다. PoW 를 하건, PoS 를 하건 최종 블록을 만들어내는건 "권한"을 가진 Node 가 만들어내게 하는 것이다. 

권한이 있고 이 권한을 신뢰하여 Blockchain 을 구성한다면 궂이 Nonce 를 찾을 이유도 없다. 전제조건은 경제관념이 없어야 제대로 돌아갈 수 있으며 권한이 있는 모든 노드들은 모두 신뢰된 관계여야 한다는 것이다. 경제관념이 생긴다면 그중 어떤 Node 는 더 많은 Token 을 얻으려 할 것이며, 이러다 보면 다시 권한이 있는 노드들 간에 합의가 필요하게 된다.

신뢰된 관계 또한 매우 중요하다. 권한이 있는 Node 이더라도 악의적 행위를 할 수 있다라고 판단되는 경우 이는 다시 합의가 필요한 상황으로 치닫게 된다. 또한 이러한 신뢰관계를 어떻게 시스템 간에 구현 할 것이냐는 것에 대해서도 충분히 고민하여야 한다. 

아무생각 없이 Genesis 에 Key 박아두거나 권한 Key 를 누군가 관리하며 추가 발급한 후에 "응용 업데이트 됐습니다. 다운받으세요." 하는거나 "신뢰는 별도의 보안솔루션이 있쟎아" 라고 하는거면 고개를 몇번 갸우뚱~ 해봐야 하지 않겠나 싶다.

▌Proof of Stake 에서는?

Proof of Stake 는 자신의 지분이 곧 블록생성권 지분율이 되는 형태이다. Public Blockchain 에서는 자신의 Balance 가 크면 블록을 생성할 수 있는 권한이 생기게 되며 블록을 Accept 할 때에도 Miner 의 지분율을 보아야 한다. PoW 대비 블록 생성 주기가 매우 짧아질 수 있으나 가장 지분이 큰 Miner 가 꺼져있거나 하는 상황에서는 전체 네트워크의 Node 상태를 알지 못하는 이상 어떤 블록이 Best Block 인지 판단하기 쉽지 않다는 단점와 빈익빈 부익부 현상이 나타날 수 있다는 부작용이 있다.
이러한 부분을 개선하는 노력들을 많이 해왔으며 Coin Ages Selection 방식이나 Random 방식, PoSV (Velocity) 방식, Voting 방식 등이 블록 채택을 위한 PoS 알고리즘으로 나와있다.

대량의 Transaction이 빠르게 처리되어야 한다면 고려해야하는 모델이며, 특히나 Consortium Blockchain 의 경우 고려할 필요가 있는 방식이 아닐까 생각한다. 

Eris 의 경우, PoS 의 Voting 방식을 채택하고있는데, 모든 권한있는 Node 가 Voting 을 하게 되어있다. Voting Message 를 통해서 Block Proposal 에 대해서 투표하고, 최종 Confirm 은 2/3 의 Token (Voting Power)이 확인되고 Signature 로 Voter 가 확인하면 최종 Step 에서는 Precommit 후 Commit 하여 해당 Transaction List 를 승인하도록 되어있다.

이러한 방식은 블록 생성과 전파 대비 효율적이긴 하나 Public 에서 사용하기에는 효율성이 떨어질 수 있으며, Voting Power 에 해당하는 Token 을 무엇에 맵핑할것인지 생각해야 한다. Eris 는 이러한 Token 을 Genesis 에 Key 와 함께 부여할 수 있도록 하였다. 좀 문제이긴 하다.

그러나 PoW 대비 Transaction 처리의 Confirm 속도는 확연히 차이가 나며 Eris 를 실제 구동해보면 1~3초 이내에 Commit 이 되는것을 볼 수 있다. (Node 3대로 테스트라 좀 그렇긴 하다).


▌그래서 ?

그래서 결론은,
  1. Blockchain 에서의 TPS 를 이야기 할 때에는 부디 C/S 아키텍쳐에서의 TPS 잣대를 들이대지 말자.
  2. 합의 방식에 따라 Transaction 처리 방법과 시스템 전체 성능은 달라진다.
  3. 합의 필요 없고 완전 믿을 수 있는 네트워크라면 그냥 합의하지 말아라. (블록체인 불필요)
  4. 높은 TPS 성능만 필요한거라면, 차라리 성능 좋은 분산 DB 와 Messaging M/W 를 쓰고 참여자 간 인터페이스 통일해라. 

Blockchain 이 풀어낸 가장 큰 문제는 "신뢰" 를 증명하는 방법이다. 
스티븐 코비의 "신뢰의 속도" 라는 책이 떠오른다. 어떠한 일이든 가장 빠른 방법은 "신뢰"를 바탕으로 했을 때이지, 신뢰할 수 없는 환경에서가 아니다.
보안, 위변조, 합의, 정합성, ... 믿을 수 있다면 무엇이든 빠르고 좋은걸 해라. 그리고 다른것에 더 힘을 쏟아라.

(이상 책상에 앉아서 계획없이 생각나는대로 함 써봤다.. 훑어보니 내용이 좀 산으로 갔네요.. 졸려서 이만..^^)


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Smart Contract 는 1994년 암호학, 법학에 일가견이 있는 컴퓨터 과학자인 Nick Szabo 에 의해 소개된 개념이다. 신뢰할 수 없는 컴퓨터 인터넷 환경에서 "고도로 발달된" 계약을 준수하도록 하는 프로토콜이다.

혹 처음 "스마트 계약" 이라는 말을 처음 듣는 사람들은, 블록체인에 "계약" 이라 불리울만한 "문서"를 업로드 하고 이를 준수하도록 "약속"하는 것이라는 막연한 상상을 하고는 한다(실제로 있었다). Contract 라는 용어가 그러한 오해를 살 수도 있는게 사실이긴 하다.

말을 약간 바꿔보자. "스마트 계약"은 블록체인에 모든 Node가 접근할 수 있는 "코드" 를 업로드 하고, 이를 "실행" 하도록 하는 "프로토콜" 이라고 한다면 좀더 이해하기 편할 수 있을 것이다.


▌사전 이해 필요항목
일단 이 Smart Contract 에 대하여 기술적으로 이해하기 전에 Ethereum 의 기본적인 아래 사항에 대해 이해하고 있는게 좋다.

  1. EOA/Contract Account
  2. Account / Global State
  3. Create/Message/Transfer Transaction, Call
  4. Transaction Receipt
  5. Gas, GasPrice
  6. Ethereum Virtual Machine
  7. Turing Complete

(위 개념들은 시간나는대로 정리하여 블로그로 올리기로 한다)

▌Bitcoin 의 Contract Code

Contract 는 마치 Assembly 코드를 연상시키는 듯한 Byte Code 형태의 코드로 구성해왔다. OP_CODE 로 불리우는 1바이트 크기의 명령인 Operation Code 들은 Stack 에 쌓이며 실행된다. 

Bitcoin 의 경우, Script 라고 부르고 있으며 기본적인 Balance Transfer Transaction 의 경우 Client 가 Transaction 의 Script 파트에 Pubkey, PubKeyHash, Private Key Signature 를 연산하여 UTXO 를 소비하려는 현재 Transaction 이 정당한지를 검증하는 Script 를 자동으로 추가하도록 되어있다.

좀더 자세히는, UTXO 의 Public Key Hash 가  Transaction 의 INPUT 파트에 있는 Unlocking Script 내의 Public Key 의 HASH160 OPCODE 연산 결과와 같은지를 비교하며 최종 CHECKSIG OPCODE 를 통해 Private Key 의 Signature 를 Public Key 로 검증하여 TRUE 를 리턴하는지를 검사한다.

이러한 Script 파트에는 원하는 OPCODE 들을 구성하여 Transaction 을 만들어낼 수 있는데, 쌍방 혹은 여러 “신뢰되지 않은” Peer 들 간에 특정한 OPCODE Script를 실행시켰을 때 값이 정상이라면 그 Transaction 을 "정상으로 인정한다”라는 “계약적인 조건”을 명시하고 실행 가능하므로, 이러한 개념으로  Contract Code 라고 표현하고 있다.

Bitcoin 의 OPCODE 는 Constants, Flow Control, Stack, String 의 Splice, Bitwise, Arithmetic, Crypto, Locktime, Pseudo-Words 의 카테고리에 해당하는 85개 정도의 명령어를 제공하고있다.

▌Ethereum 의 Smart Contract 차이점 

Bitcoin 이 선보인 이 Contract Script 는 매우 획기적인 방식이며 신뢰할 수 없는 환경에서 신뢰를 기반으로 해야하는 중요한 거래가 가능하도록 하는 핵심적인 요소로서 동작한다. Ethereum 의 Vitalik Buterin 은 어린나이에 이러한 Bitcoin Blockchain 에 대해 이해하고 Contract Code 를 더 확장하면 무한한 확장성을 가진 탈 중앙화 된 컴퓨팅 환경, 더 나아가서는 Global/World Computer 를 실현시킬 수 있다고 믿고 Gavin Wood 박사는 그의 사상을 구현하기위해 함께하며 개발언어에 독립적인 Yellow Paper 를 만든다.

Ethereum 은 Bitcoin 의 Contract 에 비해 매우 고도로 발전된 형태의 Contract Code 라고 말할 수 있으며, 단순한 “검증” 과 “연산” 을 뛰어넘는 ”상태”와 “함수”를 정의하고 “상태변이”와 “데이터 저장”이 가능한  Turing Complete 코드 개발을 가능하도록 하였다.

APPLY(S)=S’
(APPLY: 상태변이 함수, S:현재상태, S’: 변이된 상태)
 
라는 상태변이 함수과계에서,
Bitcoin 의 S와 S' 는 UTXO 의 Balance 만이 가능하지만,
Ethereum 의 S 는 EOA(Externally Owned Account)의 Balance 는 물론, Account의 Nonce, Contract Account 의 Storage 에 저장된 데이터의 값들도 포함된다.

즉, “잔고” 뿐만이 아니라 “데이터” 또한 상태변이 함수로 변이 가능한 상태의 대상이 된다는 것이다.
또한 이러한 상태변이 함수를 Smart Contract 라고 부르며, Smart Contract 는 EVM(Ethereum Virtual Machine) 이 실행시키고, 여기에서 실행되는 이러한 Smart Contract 함수를 정의한 Code 를 EVM Code 또는 Smart Contract Code (줄여서 Contract Code) 라고 부른다.

Loop 지원, Contract Account, (Contract 의) Block 과 Transaction 정보에의 접근, Statefull, Gas 개념 등은 Ethereum Smart Contract 의 큰 특징이다.

Bitcoin 대비 별것 아닌 변화일것이라 생각될 수 있지만 이것은 Blockchain 기술의 적용 가능 분야를 무한히 확장할 수 있는 큰 변화이다. 복잡한 금융 파생상품에서 부터 지능형 머신/IoT 디바이스의 자율적 협업,  슈퍼컴퓨터를 초월하는 강력한 컴퓨팅 까지 가능하게 하는 중요한 열쇠가 바로 이 Smart Contract 라고 할 수 있다.

Ethereum 은 Dapp (Decentralized Application) 이라는 개념을 Smart Contract 를 중심으로 하여 실현하고 있으며, 이는 기존의 중앙 집중식의 시스템의 단점(DoS 취약, 보안 취약, Single Point of Failure, Scalability 한계성, Privacy 침해, 외부 인터페이스 표준화 문제 등)으로 부터 자유로워질 수 있는 탈중앙화된 Appication 아키텍쳐가 가능해지는 기술이라고 할 수 있으며, 전통적인 P2P 로는 풀 수 없었던 “신뢰할 수 없는 환경에서의 신뢰성 있는 서비스 운영”이 가능하게 하는 핵심적인 기술이 아닐까 생각한다.

▌EVM

Ethereum 은 Smart Contract Code 구현을 위해 4가지의 언어를 구현한다. 

Mutan, LLL, Serpent, Solidity 가 현재 Ethereum 의 Smart Contract 를 구현할 수 있는 Code 이다. 이중 Mutan 은 C 언어와 유사한 구조를, LLL 은 Low-Level 의 OPCODE 형태를 가지며, Serpent 는 Python 과 유사하다고 할 수 있고, Solidity 는 JavaScript 와 매우 닮았다.

Mutan 은 Deprecated 되었으며, LLL 은 더이상 Develop 하지 않으나 여전히 지원하고는 있으며 Serpent 와 Solidity 가 주요 언어라고 볼 수 있으며 그 중 Ethereum 은 Solidity 를 Main 언어로 주력하고있다.

EVM(Ethereum Virtual Machine) 은 이러한 상위레벨 언어로 만들어진 코드가 컴파일되어 생성되는 Byte  Code 를 실행하기 위한 Runtime 으로, OPCODE, Stack 외에 Ethereum 에서 추가된 Memory, Storage 를 사용하는 주체이기도 하다.

Smart Contract 실행 (Create, Message Transaction)은 모든 Block 검증을 수행하는 Node 에서 동일하게 일어난다. 또한 Contract 를 실행하는데에는 현재 Homestead 에서도 아래와 같은 Gas 를 소모해야 한다.

Operation Name Gas Cost Remark
step 1 default amount per an execution cycle
stop 0 free
suicide 0 free
sha3 20  
sload 20 get from permanent storage
sstore 100 put into permanent storage
balance 20  
create 100 contract creation
call 20 initiating a read only call
memory 1 every additional word when expanding memory
txdata 5 every byte of data or code for a transaction
transaction 500 base fee transaction
contract creation 53000
changed in homestead from 21000

Gas 는 Gas * GasPrice 만큼의 Wei 비용으로 지불되며, 이는 Turing Complete Machine 인 이더리움이 무한루프와 같은 Attack 으로 부터 자유롭기 위함과 Contract 실행과 Storage 사용에 대한 자원비용 보상을 지불하는 목적이다.

Gas 가 생각보다 많이 나올 수 있는데, Code 실행과  sstore 등 뿐만 아니라, Transaction 의 size 에도 비용이 비례하여 증가하게 되기 때문이며, 최소 Gas Price 보다 크지 않으면 아예 Transaction 이 발생하지 못하는 비극이 발생한다. 결론적으로 돈이 있어야 한다.

▌Storage, Memory, Stack

모든 Contract Account 는 Storage 라고 불리는 Persistent 저장소를 갖고있다. Key-Value 맵 구조로 32바이트 키를 32바이트 값으로 맵핑하도록 되어있다. Contract 는 자기 자신 이외의 Contract 의 Storage 를 읽거나 쓸 수 없다.

Memory 는 Contract 가 Message Call 이 있을 때 마다 최신의 Instance 를 얻을 수 있는 공간으로, Byte 레벨로 읽고 쓸 수 있으나 32바이트 단위 Chunk로 저장된다. 즉, 1 이라는 값을 저장하면 32바이트 (256비트) 공간에 저장된다.

EVM 은 총 1024개의 Instruction Set (OPCODE) 를 담을 수 있는 Stack 을 갖으며, 256비트의 word (값) 을 갖는다. 

이러한 특성으로 Message Call 시에도 몇가지 제약사항들이 있는데, 그중 하나는 32바이트를 넘는 문자열을 하나의 파라미터로 보낼 수는 없다는 것이다. 

▌Message Call

Contract 는 다른 Contract 를 Call 하거나 EOA 로 Ether 를 보낼 수 있으며, 이때 Message Call 을 사용하게된다. 일반 이체 Transaction 과 매우 유사하지만 호출할 Contract 의 주소, Method 의 주소, 함수  파라미터(옵션)를 넣는것이 다르다.

Sub Contract Call 이 실행되어야 하는 경우, 연쇄적인 Message Call 이 Contract 에 의해 일어나게 되며, 이러한 연속된 Contract 실행을 위한 충분한 Gas 를 포함시켜야만 나중에 Contract 실행이 끝까지 될 수 있다. Call 은 최대 1024 Depth 까지 호출될 수 있다.

Message Call 의 결과는 Block 내의 Transaction Receipt 를 참고하여 조회할 수 있다.

Contract 실행 전, EVM 은 Transaction Sender 의 잔고가 충분한지 검토하고 실행하며, 실행 중 Gas 가 모두 소진되었으나 실행이 완료되지 않은 경우에는 그때까지의 Gas 는 지출되고 모든 State 는 Contract 실행 이전 단계로 돌아간다.

▌Delegate Call, Callcode, 라이브러리

Message Call 중에, Delegatecall 이라는 방식이 있는데, 이건 Contract 가 실행될 때 Contract 를 실행시킨 Contract 의 Context 를 사용한다는 것이다. 그리고, Message Sender 와 Value 가 변경되지 않고 Caller Contract 의 것을 그대로 사용한다.

이러한 특성을 활용하여 Library 형태의 Contract 를 만들 수 있다.

▌Create Contract Transaction

Contract 를 Byte Code 로 컴파일 하여 Blockchain 에 Upload 하여야 Contract 를 실행할 수 있다. Contract Create 는 EOA 가 Create 하는것이 일반적이나, Contract 가 다른 Contract 를 Create 할 수도 있다. 

▌Self Destruct

Contract 를 삭제할 수 있는 유일한 방법은 Contract Address 에서 (자신이) SELFDESTRUCT 명령을 수행하는 것이다. 이때 Contract Account 의 Ether 잔고는 지정된 Account 로 이체되고 Contract 의 모든 State 는 소멸된다.

위 기본적인 개념들 말고도 설명해야 하는 것들이 많다. 앞으로 조금씩 써보도록 하고, 예제도 종종 올려보도록 하겠다. 


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Genesis 정보까지 모두 준비되었다. 이제 Node 를 실행하면 된다.
그런데 옵션으로 주어야 할게 쫌 있다. 좀 자질구레한것들이지만 Shell Script 로 만들어놓으면 편하기 때문에 MinGW 의 bash shell script 로 만들어놓는다.

▌실행 Script

내가 사용중인 Shell Script 는 다음과 같다. Wallet 의 Master Password 는 1111 이고 JSON-RPC 를 사용하기 위한 Session-Key 로는 0000 을 지정해주었다. 

그리고 연결되는 Node 간의 시간차는 +- 13분 이내 이어야 한다. 시간을 잘 맞추고 시작하자.

[Linux]
./eth --config $ETH_HOME/res/config.json --master 1111 --json-rpc
--json-admin 0000 --admin-via-http --no-bootstrap --listen 30301
--remote "192.168.0.122" --port 30301 --db-path $ETH_HOME/db_goodjoon 
--mining on --address "0047d27a61e384403d875239cbc462896044213e" 
--verbosity 99 --json-rpc-port 8545 --ipc --upnp off  $@

[Windows]
.\eth.exe --config d:\ethereum\res\config.json --master 1111 
--json-rpc --json-rpc-port 8545 --json-admin 0000 --admin-via-http 
--listen 30301 --remote "192.168.0.60" --port 30301 
--db-path d:\ethereum\db_goodjoon --verbosity 9 
--admin-via-http -o full  --upnp off  %*

--admin-via-http 옵션은 1.2.0 에서 새로생긴 옵션인데, JSON-RPC 를 통해 admin 기능을 실행할 수 있게 허용하겠단 이야기이다. 
--no-bootstrap 으로, Peer Server 에 연결하지 않도록 하였으며
--remote 옵션으로 직접 연결할 Node 를 지정해주었다.
--db-path 로 기본 DB PATH 를 사용하지 않고 db_goodjoon 을 사용하도록 설정하였다. 
console 옵션은 어차피 1.2.1 버전의 C++ eth 는 동작하지 않는다. 나중에 process 를 하나 더 띄워서 attach 해서 사용할것이기 때문에 console 옵션은 주지 않았다.

뒤에서 언급하겠지만, 1.2.1 버전 오면서 Windows 의 버그와 Default 값의 동작이 더 심각해졌다. coinbase address 도 기본으로 안넣어주고, JSONRPC 포트도 지정해주지 않으면 -1 값이다. 그러나 아직도 --help 에는 8545 기본값으로 나온다. Geth 의 jsonrpcapi 옵션에서 볼수있었던 JSON RPC admin 기능을 위해 --admin-via-http 옵션도 생겨나고 했는데 그러면서 좀더 꼬이고있기도 하다. (새로 팀장 오고나서 팀을 "REBOOT" 하겠다고 했는데, 좀 잘 되었으면 좋겠다. Go 팀을 좀 봐라 쫌..)

▌실행 확인
(++)Ethereum 이 출력되고 이후 뭔가 좌르륵~ 나오고 있다면 일단 동작하는 것이다. 

Ubuntu에서 실행중인 모습
korean44@ubuntu-svr:~/project/blockchain/webthree-umbrella/build/webthree/eth$ ./ethGoodJoon.sh 
(++)Ethereum
...  00:36:07.628|eth  Reading /home/korean44/.web3/keys/152d7983-ac83-b2f9-159c-18ab7106fd83.json
⧎ ℹ  00:36:07.649|eth  Id: ##e808dba2…...  00:36:07.684|eth  Opened blockchain DB. Latest: #5df28093… (rebuild not needed)...  00:36:07.700|eth  Opened state DB.
⧫ ◎  00:36:07.702|eth  startedWorking()
cpp-ethereum 1.2.1
  By cpp-ethereum contributors, (c) 2013-2016.
  See the README for contributors and credits.
Transaction Signer: XE50000000000000000000000000000000 (00000000-0000-0000-0000-000000000000 - 00000000)
Mining Beneficiary: XE8916H0DGVW3SIMF6X9AWCB8J6ZV5PWE6 (152d7983-ac83-b2f9-159c-18ab7106fd83 - 0047d27a)
Foundation: XE55PXQKKK4B9BYPBGT1XCYW6R5ELFAT6EM (00000000-0000-0000-0000-000000000000 - de0b2956)
  ℹ  00:36:13.611|p2p  UPnP device: http://192.168.0.1:3274/etc/linuxigd/gatedesc.xml [st: urn:schemas-upnp-org:device:InternetGatewayDevice:1 ]
⧎ ℹ  00:36:13.684|p2p  Punched through NAT and mapped local port 30301 onto external port 15725 .
⧎ ℹ  00:36:13.684|p2p  External addr: 211.222.99.134
⧎ ℹ  00:36:13.686|p2p  p2p.started id: ##e808dba2…
 ⚡   00:36:13.695|eth  void dev::p2p::Host::start() 2091 ms
Node ID: enode://e808dba2f0d7eb464656e01be81317386af18b8a0c554c7f9fd78fcd0f1a008a584891aed201018444af50ede46faf6884750baa1f06eca9e9c706d827b931a3@211.222.99.134:15725
JSONRPC Admin Session Key: 0000
⧫ ℹ  00:36:13.738|eth  Mining Beneficiary: @0047d27a
⧫ ◎  00:36:13.739|eth  Rejigging seal engine......  00:36:13.741|eth  Generating seal on #ab31b73b… # 1
  ℹ  00:36:13.743|miner0  Loading full DAG of seedhash: #00000000…
DAG  00:36:19.606|miner0  Generating DAG file. Progress: 0 %
⧫ ◎  00:36:22.718|eth  Since 2016-03-04 15:36:07.686Z (15): 15ticks
DAG  00:36:25.842|miner0  Generating DAG file. Progress: 1 %
DAG  00:36:32.097|miner0  Generating DAG file. Progress: 2 %



아마 Windows 에서는 아예 Console 에서 JavaScript Console 기능이 동작하지 않을 것이다. 버그이다. 이건 Frontier Release 이전부터 계속되어오는 문제이다.
수정하고싶은 생각도 없는듯 하고 암튼 Windows 는 C++ Ethereum의 대상이 아닌게 날이갈수록 확신이 든다.

Miner는 DAG 파일을 만드는데에 상당한 시간이 소요된다. 처음 1회만 실행되므로 참고 기다린다.


▌Console Attach

그래도 JavaScript Console 을 띄워서 보는게 가장 빠른 방법이므로 한번 해보도록 한다.

Linux 에서는 
$ eth --session-key 0000 attach
만으로도 현재 실행중인 eth 에 attach 를 한다. Linux 에서는 console 이 잘 동작하므로 처음 실행할 때 마지막에 console 이라고 치면 되긴 하지만, 로그가 수없이 지나가므로 JavaScript API 를 실행시켜도 결과가 로그에 파묻힌다. 그래서 난 그냥 터미널 하나 더 띄워서 attach 시킨다.

Windows 는 1.2.1 버전 오더니 더 심각한 버그들이 발생한다.
$ eth --session-key 0000 attach --url "http://localhost:8545"
이렇게 url 까지 적어줘야 한다. default 가 먹히질 않는다.

암튼 Console 이 attach 되고나면 ">" 가 보인다. JavaScript Console 이다.

1.2.0 까지만 해도 안그랬던것 같은데, JavaScript API 를 Geth 와 I/F 를 맞추고있는 과정이라서 그런지 web3 만 치면 전체 object 들이 나와야 하지만 에러가 난다. 이건 Linux 나 Windows 나 모두 마찬가지이다.

그래서, web3.eth 객체를 살펴보면, 아래처럼 출력이 될 것이다.
> web3.eth
{
  _requestManager: {
    provider: {
      send: [Function],
      sendAsync: [Function]
    },
    polls: {
    },
    timeout: null,
    send: [Function],
    sendAsync: [Function],
    sendBatch: [Function],
    setProvider: [Function],
    startPolling: [Function],
    stopPolling: [Function],
    reset: [Function],
    poll: [Function]
  },
  getBalance: [Function],
  getStorageAt: [Function],
  getCode: [Function],
  getBlock: [Function],
  getUncle: [Function],
  getCompilers: [Function],
  getBlockTransactionCount: [Function],
  getBlockUncleCount: [Function],
  getTransaction: [Function],
  getTransactionFromBlock: [Function],
  getTransactionReceipt: [Function],
  getTransactionCount: [Function],
  call: [Function],
  estimateGas: [Function],
  sendRawTransaction: [Function],
  sendTransaction: [Function],
  sign: [Function],
  compile: {
    solidity: [Function],
    lll: [Function],
    serpent: [Function]
  },
  submitWork: [Function],
  getWork: [Function],
  coinbase: '0x0047d27a61e384403d875239cbc462896044213e',
  getCoinbase: [Function],
  mining: false,
  getMining: [Function],
  hashrate: 0,
  getHashrate: [Function],
  syncing: false,
  getSyncing: [Function],
  gasPrice: 50000000000',
  getGasPrice: [Function],
  accounts: ['
0x0047d27a61e384403d875239cbc462896044213e'],
  getAccounts: [Function],
  blockNumber: 0,
  getBlockNumber: [Function],
  iban: [Function],
  sendIBANTransaction: [Function],
  defaultBlock: '
latest',
  defaultAccount: undefined,
  contract: [Function],
  filter: [Function],
  namereg: [Function],
  icapNamereg: [Function],
  isSyncing: [Function]
}

▌Block Sync 확인
현재 Difficulty 도 낮춰놓고, 블록 생성 간격도 13분에서 1분으로 맞추도록 조정하였다. 


▌Windows 버전 => Linux / Mac OS X 으로 갈아타자
여태 Windows 버전을 Build 하고 소스 수정하고 해왔다. 그런데 Homestead 겨냥중인 1.2.1 버전 릴리즈 되면서 더이상 Windows 를 안쓰고싶게 만든다.
Frontier (1.0.1) 까지는 그나마 참고 쓸 수 있었으나 1.1.3 버전 부터였나 점점 되야하는 기능들이 Windows 에서 안돌더니 이제 Geth 와 I/F 맞춘다는 명목등을 이유로 작업을 하고있으면서 Windows 는 안그래도 뒷전인데 더 뒷전이 되어버렸다.

Windows 에서 못써먹겠다는 이유는 대략 이러하다.
1.0.1 => Contract 를 Create 하고 배포한 후 JSONRPC 건 JavaScript 건 call 을 2회 하면 그 다음부터는 무조건 0을 리턴한다. 재기동만이 정상화 방법이다. 그래서 Windows 에서는 Mining 시키고 Mac 이나 Linux 에 Contract call 을 해왔다.

1.1.3 => Windows 버전이 다른 Peer 와 Connect 할때 RLPx Handshake 시에 괜히 auth fail 이 난다. 그리고 이 시점 부터 다른 Platform 의 Miner 가 멈추고 아예 동작을 안한다. Windows 를 먼저 띄워놓고 다른 Platform 의 Peer 가 connect 을 하면 괜챦다. 

1.2.0/1.2.1 => Windows 가 붙으면 auth fail 은 또 계속 난다. Miner 죽는 문제는 해결한듯 하다. 그런데 Geth 와 CLI 나 JS Console 이 아직 맞춰지지도 않았고 API 가 동작하지 않는것들도 있다. 

그리고, DAG 도 버그가 있다. 어떤때는 hashrate 가 3,4 H/s 가 나온다. 계속 재실행 하다보면 언젠다 다시 정상 hashrate 가 나온다. 문제다.

위 이유로, 이후 진행은 Linux 로만 한다. Mac OS X 도 잘 지원되는 편이나 블로그 쓰는데 맥북까지 켜서 2대에서 끄적거리기가 싫다 ^^;; 그냥 VirtualBox 로 Linux 2대 켜놓고, shared folder 하나 만들어서 소스는 한군데에서 수정하고 빌드한 후 양쪽 VBox Guest (Ubuntu 15.10) 에서 실행시켜 테스트 하는 방향으로 가겠다. 뭐 필요하면 3대 4대 하거나 Instance 를 더 늘리던가 하겠다.





반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Account 까지 만들었으므로 이제 Account 의 address 에 이더가 충만한 나만의 genesis 를 만들어서 간단한 Transfer Transaction 을 실행해보겠다.

참고로, 그간 golang 강좌 초반부를 쓰느라 신경을 좀 못쓴 동안에 1.2.0 버전이 바로 어제 릴리즈 되었다 (2016.02.29 에).
git pull 하고 submodule 을 update 한 후 1.2.0 버전으로 소스를 업데이트 하고서 다시 빌드를 하였으며, 이후 설명은 eth 1.2.0 기준으로 해 가도록 하겠다.

1.1.4 버전으로 Private Network 을 구성하고 나서 좀 당황스러운 점들이 있었다. 일단, Node 간에 RLPx handshake 가 auth 를 검증하는 동안 실패하는 상황이 발생하며 Handshake가 실패하면 아예 Miner 가 Mining 을 멈추는 상황으로 가는 버그이다. 이게 수정되었는지 궁굼한데 Release Note 를 보니 Mining 쪽 버그 픽스가 되었다고 하는데 1.2.0 에서 확인해봐야 하겠다.

그리고, Geth 의 Attach 가 eth 에 가능하게 되었다. geth 에는 --session-key 옵션이 없는데 이게 어떻게 동작할라나 모르겠다. 암튼 된다고 하니 이 두녀석들을 갖고 또 테스트 해봐야 하겠다. eth 1.2.0 과 geth 1.3.4 가 거의 동시에 릴리즈 되었으니, geth 설명할 때에도 최신버전 (아예 1.3.4의 코드네임이 Homestead 이다)으로 해야 하겠다.

[goodjoon Debug]$  ./eth --version
eth version 1.2.0
eth network protocol version: 63
Client database version: 12041
Build: Windows/msvc/int/Debug
[goodjoon Debug]$

일단은 Private Network 상에서 PoW 로 Consensus 를 하는, Public 형태와 동일한 Ethereum Local Network 을 구성 해보도록 한다.

▌config.json (genesis.json) 만들기

genesis.json 이 Frontier Release 버전인 eth 1.0.0 과 달라졌다. Geth 와도 호환이 안되는 JSON 포맷으로 바뀌었다 (config.json). 그나마 좀 Simple 한 포맷이었는데, 좀더 복잡하게 바뀌었다.
create-genesis.py 스크립트로 만들어져 나오는 json 은 동작하지 않으므로, 수동으로 작업해보도록 하겠다.

1.2.0 부터는 genesis.json 으로 부르지 않고, config.json 으로 부른다. 옵션도 --config 로 바뀌었다. --genesis 옵션도 코드 내에서는 아직 살아있지만 --help 로 볼때는 나오지 않는다.

우선 내 Account 중에 억만장자를 만들고 싶은 Account 의 Address 를 결정해야 한다.
eth 가 잘 빌드되었다면

$WEBTHREE/build/libethereum/ethkey/Debug
밑에 ethkey.exe 파일이 있다

[goodjoon Debug]$  ethkey.exe list --master 1111
1a7e55b0-3eb7-05ec-248e-8d901e268d76 0096bb98… XE602H4XB00HUY08LU416SCBGO3CS63H66  Default key
6ecc980b-2f99-013d-167e-0ea9caffde4e 007386ab… XE561WBEXUY46M6G05SDKF5P9C334V3JT6  myname
31ae0923-14da-a1a9-85ba-ab9563c5da4b 005bfaf9… XE241IE5KGWVRVYD6B5H8ZHMXNMP57Q4KM  joooooon
[goodjoon Debug]$
위 처럼 Wallet 의 Key 들이 보인다면 이중에서 사용할 Key 를 선택한다. 난 "Default key" 로 자동생성되었던 Account 를 선택한다.

Genesis 에는 Account 의 Balance 를 지정해주려면 Address 가 필요한데, 위 ethkey list 명령으로 출력된 결과에는 address 가 FULL 로 표시되지 않는다. ethkey 를 다시 사용하여 Full Address 를 표시해본다.
[goodjoon Debug]$  ethkey.exe inspect "Default key" --master 1111
Default key (0096bb98…)
  ICAP: XE602H4XB00HUY08LU416SCBGO3CS63H66
  Raw hex: 0096bb9802b14f72ba4cdbd105127fe57a1dafae
[goodjoon Debug]$

옵션에 계속 --master 1111 을 넣는 이유는, 현재 MinGW/MSYS 를 사용하고있는데 eth 가 이 환경에서는 key store 의 master 패스워드 입력하라는 Prompt 가 나올 때 Exception 이 발생하므로 master 패스워드를 바로 지정해주어야 한다. (Windows Command Prompt 환경에서는 문제가 없다)

위 Raw hex : 부분이 사용할 Account 의 address 이다.

이렇게 Linux 나 Mac 버전 또는 다른 Windows 에서도 Wallet 을 만들고 (keys.info, keys.salt), Key 를 생성한다 (Wallet (keys.info) 에 key 추가, .web3/keys 디렉토리에 추가된 key 의 정보(json) 추가).
Account 의 Address 를 모두 파악했다면, 이제 Genesis 정보를 만들어준다

{
    "sealEngine""Ethash",
    "params": {
        "accountStartNonce""0x00",
        "maximumExtraDataSize""0xFF",
        "tieBreakingGas"false,
        "minGasLimit""0x1388",
        "gasLimitBoundDivisor""0x0400",
        "minimumDifficulty""0x020000",
        "difficultyBoundDivisor""0x0800",
        "durationLimit""0x0d",
        "blockReward""0x4563918244F40000",
        "registrar" : "",
        "networkID" : "0xA1"
    },
    "genesis": {
        "nonce""0x0000000000000000",
        "difficulty""0x020000",
        "mixHash""0x0000000000000000000000000000000000000000000000000000000000000000",
        "author""0x0000000000000000000000000000000000000000",
        "timestamp""0x00",
        "parentHash""0x0000000000000000000000000000000000000000000000000000000000000000",
        "extraData""0x",
        "gasLimit""0x1388"
    },
    "accounts": {
        "0096bb9802b14f72ba4cdbd105127fe57a1dafae": { "wei""10000000000000000000000000000000000"},
        "0047d27a61e384403d875239cbc462896044213e": { "wei""20000000000000000000000000000000000"}
    }
}

위 처럼 genesis 정보를 만들어 준다. 가장 아래의 "accounts" 내의 정보가 주소와 Balance 이다.

아래는 "파악된" json 파라미터 정보들이다. Ethereum 의 가장 큰 문제가 바로 "체계 없는 문서화" 라고 생각한다. 어떤것은 Github Wiki 에 있고 어떤건 Gitbook 에, 또 어떤건 readthedocs 에.. 또 어떤건 각 Repository 의 wiki 에.. 또 어떤건 Repository 내의 프로젝트에 있는 .md 파일에.. 뭐 난리다.. 그래서 더 접근하기가 쉽지 않다.

위 config.json 의 경우도 제대로 된 문서 하나를 찾지 못했다. 개념적인 부분과 소스코드를 분석했던 기억을 더듬어 다시 써보니 혹시 틀린 부분이 있다면 그저 그러려니 하자.

[SealEngine]
Block 생성을 위한 Consensus 메커니즘을 어떤걸 사용할것인지를 지정한다.
현재 SealEngineBase Class 를 상속받는 Class 들에는 Ethash, BasicAuthority, NoProof 가 있다. 

Ethash 는 DAG 나 General Hashing 을 통해 PoW 를 하는 엔진이고, BasicAuthority 는 PoA 를 위해 실험적으로 Ethereum 에서 만들어놓은 Consensus 메커니즘으로, 현재 flu core 를 통해 사용할 수도 있으며, web3 에 통합되어있다. NoProof 는 Consensus 를 위한 증명작업을 하지 않는 Sealer 이다.

[Params]
"AccountStartNonce" : Account 의 최초 시작 Nonce 값을 지정한다. 기본적으로는 당연히 0 부터 시작하면 된다.
"maximumExtraDataSize" : 블럭의 Extra Data 의 최대 크기를 지정한다. 
"tieBreakingGas" : 
"minGasLimit" : 블럭의 최소 Gas 제한량이다. Block 의 GasLimit 값은 이 minGasLimit 보다 커야한다.
"gasLimitBoundDivisor" : 현재 블럭의 GasLimit 값은 parent block 의 gaslimit 대비 +- (parent block 의 GasLimit / gasLimitBoundDivisor)이내에 있어야 한다.
"minimumDifficulty" : 블럭의 최소 Difficulty 이다. 아무리 시간이 오래걸려도 PoW 는 이 Difficulty 이상을 유지해야 한다.
"difficultyBoundDivisor" : Frontier 까지 유효하며, 이전 Block 생성시간 대비 현재 Block 생성 시간이 durationLimit 보다 작으면 parent 의 difficulty 에 parent 의 difficulty / difficultyBoundDivisor 값을 더하고, 크면 같은값을 빼서 블럭 생성 시간을 조정한다
"blockReward" : Miner 의 Codebase 에 챙겨줄 reward wei 이다
"registrar" : Olympic 부터 Frontier, Homestead 등에서 기본적으로 존재하는 registrar Smart Contract 의 Address 이다. Name Register 서비스를 해주는 Contract 로 보면 된다.
"networkID" : 피어간의 통신 시 논리적으로 네트웍을 구분짓는 ID 이다. 피어간에 통신을 위해서는 이 networkID 값이 같아야 한다. Olympic 은 0, Frontier 는 1, Morden Testnet 은 2를 쓴다.

[Genesis]
"nonce" : 블럭의 nonce 값
"difficulty" : Block 의 Difficulty
"mixhash" : Block 의 hash 값
"author" : Block Author 정보, 필요하면 넣고..
"timestamp" : 블럭 생성 시각
"parentHash" : Genesis 이므로 0
"extraData" : 넣고싶은 Extra Data
"gasLimit" : Block 의 Gas Limit

[Accounts]
"<Account Address>": {"wei":<Balance>} 와 같은 형식은 UCA/UOA Account 의 Balance 를 적는 형식이고,
"0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } } 와 같은 형식은 Precompiled Contract 를 표시하는 형식이다. Precompiled Contract 사용에 대해서는 향후에 알아보자.


이렇게 하면 일단 Private Network 에서 동작하는 Ethereum 을 위한 기본적인 Genesis 정보를 정의할 수 있다. 원래는 Genesis 만 지정하였는데, C++ Ethereum 은 좀더 유연성을 부여하기 위해 
  1. sealEngine
  2. options
  3. params
  4. genesis
  5. accounts
  6. network
로 구성된 config 정보를 입력할 수 있도록 하였다. 일단 목적은 private blockchain 을 염두에 둔것 같다.

다음은 이 Genesis 정보 기반으로 두 노드간에 실제적으로 통신을 해보자 (졸려졸려..)

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
C++ 이더리움으로 Private/Local Network 을 구성해보도록 하겠다.
Frontier 나 testnet 이 아닌, 두 개 혹은 그 이상의 peer 간에 상호 통신이 가능한 환경을 만들어 보도록 한다.

Windows 버전과 Mac OS X, Linux 버전을 사용하도록 하겠다. 
Windows 버전의 빌드는 지난번 블로그로 올렸고, Mac 과 Linux (Ubuntu) 버전은 Ethereum 의 가이드 대로 소스빌드를 하면 별 어려움 없이 빌드 가능하다.

▌Mac OS X 소스빌드 전 필요사항

  1. Mac OS X Yosemite 또는 El Capitan
  2. Home Brew
  3. git

▌Mac OS X 소스 빌드 방법

아래 커맨드 들을 순차적으로 입력하자
brew install boost --c++11
brew install cmake cryptopp miniupnpc leveldb gmp jsoncpp libmicrohttpd libjson-rpc-cpp
brew install homebrew/versions/v8-315
brew install llvm --HEAD --with-clang
brew install qt5 --with-d-bus

시간이 꽤나 걸리기때문에 인내심이 필요하다
다음으로는 소스코드를 Clone 하고 cmake 로 XCode 용 프로젝트를 생성한다
git clone --recursive https://github.com/ethereum/webthree-umbrella.git
cd webthree-umbrella

XCode 용 프로젝트를 생성한다
mkdir build_xc
cd build_xc
LLVM_DIR=/usr/local/Cellar/llvm/HEAD/lib/cmake cmake -G Xcode ..

XCode 를 띄우고 프로젝트를 Build 한다. Windows 와 다르게 매우 매끄럽게 빌드된다는 점에 놀라지 않을 수 없다

만약 빌드시에 LLVM 관련한 오류가 발생한다면, LLVM Library 의 버전을 체크하기 바란다. LLVM 라이브러리 버전은 3.7.0 이상이면 되고, 현재 Release 된 최신 LLVM Library 버전은 3.7.1 이다.
El Capitan OS X 이 내 Mac 은 이상하게 LLVM 3.9.0 이 설치되어있었다 (뭐하다가 이게 설치되어있었는지는 모른다). 그런데 3.9.0 은 Develop 버전이며, 빌드 시 오류가 생긴다. 3.7.1 버전으로 재설치 해주도록 한다.

▌Linux 소스 빌드 방법 (ubuntu 14.04 이후)

리눅스 빌드 방법도 거침 없이 진행된다. 사실 이 블로그를 쓰는 이유는 Windows 버전 때문이다. 아무리 생각해도 C++ Ethereum 은 Windows 버전은 빌드 되는지 정도만 테스트 하는것 같다. 개발은 Mac 과 Linux 로 하고있지않나 싶을정도이다. 

나는 Ubuntu 15.10 으로 apt-get 으로 upgrade 한 후 아래 가이드를 따라 소스빌드 했다.

나의 경우 오류 없이 잘 빌드되었다. 또한 console 모드로 실행해도 console 도 잘 실행된다.
(별 문제없는 과정들은 다음부터는 간단히 간단히~)

▌UPNP 코드 수정 (옵션)

eth 는 NAT 환경의 지원을 위해 upnp 기능을 제공하고있다. upnp 를 지원하는 공유기나 라우터 안에 node 가 있다면, upnp 기능으로 자동으로 포트 포워딩을 설정하도록 하는 것이다.
그러나 우리는 외부와 연결 없이 내부 node 끼리 테스트하고 싶으므로 upnp 기능까지는 필요 없다.

eth 간에 상호 peer 와 연결하기 위해 Node 간 통신 시에 자신의 IP 를 상대방에게 알려주도록 되어있는데, 이때 약간의 문제가 발생한다.
IPV4 는 Public IP 와 함께 주소 부족과 보안등의 이유로 주로 NAT 내에서 Private IP 를 사용하도록 되어있는데, 
Class A (10.*), Class B 172.(16 ~ 31).* Class C 192.168.* 는 모두 Private IP 로 분류된다.

그런데 만약 upnp 를 지원하지 않는 라우터 내에 있는 Node 간에 연결해야 하는 경우, --upnp off 옵션을 주도록 하는데, 이렇게 되면 Node 의 IP 가 public IP 를 사용하는것으로 간주한다.
하지만 public IP 가 아니므로 Exception 이 발생하고 eth 가 죽고만다.

그래서, 해당 코드를 수정해서 Private IP 를 public 으로 간주하도록 해주어야 한다.

<프로젝트 루트>\libweb3core\libp2p\common.cpp 을 열고 84 라인 부터 보면 (1.1.3 기준) 아래와 같은 코드가 있다.
bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
{
    if (_addressToCheck.is_v4())
    {
        bi::address_v4 v4Address = _addressToCheck.to_v4();
        bi::address_v4::bytes_type bytesToCheck = v4Address.to_bytes();
        if (bytesToCheck[0] == 10 || bytesToCheck[0] == 127)
            return true;
        if (bytesToCheck[0] == 172 && (bytesToCheck[1] >= 16 && bytesToCheck[1] <= 31))
            return true;
        if (bytesToCheck[0] == 192 && bytesToCheck[1] == 168)
            return true;
    }
    else if (_addressToCheck.is_v6())

위 부분에서, 자신이 속하는 class 를 체크하는 로직을 // 로 comment 처리 하거나 삭제한다.
예를들어 Class A 체크하는 부분을 삭제하면 아래와 같다.
bool p2p::isPrivateAddress(bi::address const& _addressToCheck)
{
    if (_addressToCheck.is_v4())
    {
        bi::address_v4 v4Address = _addressToCheck.to_v4();
        bi::address_v4::bytes_type bytesToCheck = v4Address.to_bytes();

        if (bytesToCheck[0] == 127)
            return true;
        if (bytesToCheck[0] == 172 && (bytesToCheck[1] >= 16 && bytesToCheck[1] <= 31))
            return true;
        if (bytesToCheck[0] == 192 && bytesToCheck[1] == 168)
            return true;
    }

위 과정은 upnp 를 지원하지 않는 라우터나 네트워크 내에 있을 때 활용할 수 있는 방법이며, 그 외의 경우는 그냥 그대로 사용하도록 한다.

이제 Account 를 만들고 나만의 genesis 를 만들어서 ether 도 충분히 넣은 후 Java Script Console, JSON-RPC 를 사용하여 Smart Contract 를 만들고 실행해보면 된다.

▌Account 만들기

Account 를 만드는 방법은 2가지가 있다. 

  1. 자동생성 방법
  2. 직접 만들기

※ 자동생성 방법
자동 생성 방법은 일단 eth 를 실행시키면 된다. eth 를 그냥 실행만 시켜도 최초 실행시에 master password 를 물어보고, master password 를 입력하면 그 즉시 Account 를 하나 생성해주고 address 를 콘솔에 출력해준다.

만약 그냥 지나갔다면, JS console 에서 web3.eth.accounts 를 쳐보면 생성된 Account 의 주소를 볼 수 있다.

※ 수동생성 방법
C++ Ethereum 팀은 Account 와 Key 를 관리하기 위한 도구를 별도로 개발했다. ethkey 가 그것이며, 프로젝트 전체를 빌드했다면 (ALL_BUILD), 
<빌드디렉토리>/libethereum/ethkey/Debug
안에 ethkey 실행파일이 있을것이다.

C++ Ethereum 과 Go-Ethereum (Geth) 는 이 키를 관리하는 디렉토리의 위치가 약간 다르다.
eth 는 Windows 의 경우 %APPDATA%\web3\keys 안에 키를 저장하도록 되어있다
geth 는 Windows 의 경우 Ethereum 의 <datadir>\keyfiles 안에 저장한다

ethkey 는 Cygwin 이나 MinGW 의 Bash 에서 실행하면 Master Password 를 물어보는 과정에서 Exception 이 발생하고 죽는다. Windows 의 Command Prompt 를 통해 실행하도록 한다.

ethkey 로 새로운 key 를 생성해본다
ethkey new <Account 이름> 을 입력하면 아래와 같은 과정이 실행된다.
> ethkey new myname
Please enter your MASTER passphrase: 
Enter a passphrase with which to secure this account (or nothing to use the master passphrase):
Please confirm the passphrase by entering it again: 
Created key 6ecc980b-2f99-013d-167e-0ea9caffde4e
  Name: myname
  Password hint:
  ICAP: XE561WBEXUY46M6G05SDKF5P9C334V3JT6
  Raw hex: 007386abec97fc9f994abafa85b1b42dd97f860a
myname 이라는 이름으로 대표할 수 있는 007386abec97fc9f994abafa85b1b42dd97f860a 주소의 Account 가 생성되었다.
처음 물어보는것은 MASTER 패스워드이며, 모든 Account 와 관련한 동작을 할 때 이 Master Password 를 입력해야 한다. eth 를 실행할때에도 마찬가지이다.
귀챦다면, --master 옵션으로 Command Line 에서 미리 주어 물어보지 않게 할 수도 있다.

ICAP (Inter-exchange Client Address Protocol)는 IBAN 의 국제 공용 계좌번호의 형식이다. 향후에 좀더 소개할 기회가 있을지 모르겠으나, Ethereum 은 향후 Ethereum과 직접적인 국제계좌 연계를 염두에 두고 이런 무리한(?) 사상을 추가도입하였다. 물론 현재 실제 ether 가 IBAN 계좌로 이체되지는 않지만 이러한 주소체계를 기본적인 20바이트 Address 외에도 추가로 표시해주고있다.

추가적으로, registrar 라는 기본 Smart Contract 를 통해 20바이트 주소 대신 Alias Name 을 통해 거래나 Smart Contract Call 도 가능하다. Frontier 이후 부터 해당 Contract 가 기본적으로 들어갔다.

말이 옆으로 샜는데, 다시 돌아와서..
위에 추가한 Account 가 잘 보이는지 확인해 본다.
>ethkey list

Please enter your MASTER passphrase: 1a7e55b0-3eb7-05ec-248e-8d901e268d76 0096bb98??XE602H4XB00HUY08LU416SCBGO3CS63H66  Default key
6ecc980b-2f99-013d-167e-0ea9caffde4e 007386ab??XE561WBEXUY46M6G05SDKF5P9C334V3JT6  myname
처음 보이는게 자동으로 만들어졌던 Account Address 이고, 두번째 것이 myname 이라는 이름으로 만든 Account Address 이다.

MASTER 패스워드라는 개념은 현재 C++ Ethereum 에서만 도입되었다. Geth 의 경우, Account 별 패스워드를 넣지만 C++ 은 Account 패스워드 외에도 MASTER 패스워드가 있다. 마치 Mac 이나 Windows 의 keystore 와 같은 개념이다. Keystore 자체에 접근하기 위한 패스워드와 서비스를 사용하기 위한 패스워드가 다르듯이 말이다.

C++ Ethereum 은 Account 별 패스워드를 지정하지 않을 수 있다. 기본으로 생성된 Account 가 그렇다. MASTER 패스워드만 사용하려면 Account 를 만들 때 그냥 Enter 만 쳐주면 된다.

-----

술먹고 들어와서 쓰려니 눈이 스르르 감긴다. 체력이 바닥나고있는 관계로 나머지는 또 다음으로..^^




반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
지난번에 빌드환경 구성이 일단 끝났고, 이번에는 실제로 Build 를 해보겠다.

Dependency 다운로드가 끝났다면 이제 본격적으로 Visual Studio 용 솔루션과 세부 프로젝트들을 CMake 를 통해 Generate 해야한다.
Command Line 에서도 빌드할 수 있지만 Visual Studio 의 Debug 를 통해 Logic 을 디버깅 해야하는 경우가 생기므로 Visual Studio 용 프로젝트를 생성해본다.

▌Visual Studio Project 생성

이제 본격적으로 Visual Studio 의 Project 를 생성한다. 
/d/ethereum/project/webthree-umbrella/build
위 디렉토리를 만들고 들어간 후
[goodjoon webthree-umbrella]$  cd build/
[goodjoon build]$  cmake -DEVMJIT=0 -G "Visual Studio 12 2013 Win64" ..
위와 같이 VS2013 용 Project 를 Generate 한다.

빌드 후 디렉토리는 아래와 같다


이제 생성 된 cpp-ethereum.sln 파일을 Visual Studio 로 열어본다.

▌EVMJIT

EVMJIT(Ethereum Virtual Machine Just In Time Compiler) 는 libethereum 의 서브모듈 이다.
위에서 cmake 시에 -DEVMJIT=0 을 해주었는데, 이렇게 해서 EVMJIT 모듈은 설치하지 않는다.

evmjit 모듈은 LLVM 라이브러리 3.7.0 이상의 Dependency 가 걸려있고, 현재 기준으로 3.7.1 이 최신버전이다.
지난번 extdep 에서 download 받은 라이브러리들 중에는 LLVM 도 포함되어있으며, Release 와 Debug 모드 모두 다운로드 받는다.

그런데 다운로드받은 이 LLVM 라이브러리 의 Debug 버전은 Visual Studio 로 Link 걸고 빌드할 때 _ITERATOR_DEBUG_LEVEL 이 0으로 정의되어있다는 오류가 발생하고, 현재 빌드하려는 프로젝트 (evmjit) 는 이 값이 2 이기 때문에 충돌이 난다고 하며 에러를 수백개 뱉어낸다.

extdeps 로 다운받은 라이브러리만 그런지는 모르겠지만, 일단 Build 환경이 다른것으로 보인다. 이러한 오류 없이 빌드하려면 LLVM 라이브러리를 소스로 가져와 Visual Studio 로 빌드하고 이 빌드된 라이브러리들을 evmjit 의 참조 프로젝트로 또는 linker 의 옵션으로 넣어주어야 할 것이다.

EVMJIT 는 Solidity 와 Serpent 의 Smart Contract Code 를 Console 이나 RPC 를 통해 Bytecode 로 런타임에 컴파일해주는 기능으로, mix 와 같은 툴이나 온라인 IDE 로도 충분히 그 기능을 대체할 수 있으므로 그냥 EVMJIT 모듈을 포함하지 않도록 하겠다.

1.0.0 Frontier Release C++ eth 의 EVMJIT 는 XCode 를 통해 Mac 에서 빌드하는데에는 문제가 없었으나 실제 동작해보면 이 또한 JIT 컴파일이 지원되지 않는 버그를 볼 수 있어서 궂이 빌드하지 않도록 하는 두번째 이유가 된다.

▌빌드 하기

솔루션 파일을 열어보면, 아래 처럼 BUILD_ALL 프로젝트가 StartUp Project 로 설정되어있다.

향후에 코드 분석에 필요하니 일단 Debug 모드를 Active 로 두고 ALL_BUILD 프로젝트를 Build 를 해본다.
(처음에는 File 들을 Parsing 하고 Indexing 하느라고 시간이 좀 걸린다. 빌드하는데에는 상관 없으므로 바로 빌드 해보자)

99개 에러와 353개 경고가 보인다.

▌에러 수정

위 에러의 이유는 모두 소스파일의 Characterset Encoding 때문에 생긴것이다. 

위 밑줄친것과 같은 UTF-8 특수캐릭터들이 PoC7 버전때 부터인가 지속 추가되어 화면에 이쁘게(?) 출력하기 위한 이상한 짓을 많해 해놓고있는데 이게 CP949 기반인 한글 Windows 와 No-BOM UTF-8 만을 자동인식하는 Visual Studio 2013 의 컴파일러가 환상적으로(?) 결합되어 빚어내는 문제이다.


에러가 발생한 소스파일을 에러를 더블클리해서 Open 한 다음

File > Advanced Save Options ... 에서 

  1. Unicode (UTF-8 with signature) - Codepage 65001 를 선택한다.
  2. OK 를 누른 후, ctrl+S 로 파일을 저장해준다

(반드시 with Signature 로 해야한다. Visual Studio 2013 은 (2015도 마찬가지) BOM 없는 UTF-8 을 자동인식하지 않으며, 이를 강제하는 옵션도 발견하지 못했다.
한글 Windows 의 경우 OS 의 기본 Characterset 인 CP949 를 기본 Characterset 으로 지정하여 파싱한다.)

BlockHeader.cpp
Block.cpp
BlockQueue.cpp
BlockChain.cpp
ClientBase.cpp
State.cpp
TransactionQueue.cpp

위 파일들을 Advanced Save Options.. 로 Encoding 을 수정해수고 저장한다.

그리고 다시 Build 를 한다.
(Warning 은 무시한다. 대부분이 Character Encoding 해석이 안된다는 경고이다.)

failed 프로젝트가 없다면 성공한 것이다.



▌동작 테스트

AlethZero 나 mix 는 좀더 수정할 것들이 있어서 향후에 해보도록 하고, 일단 가장 중요한 Ethereum 의 CLI 인 eth 가 작동하는지 확인해보자.

MinGW 로 Bash 를 열고, .bash_profile 에 
export ETH_HOME=/d/ethereum
export ETH_BUILD=/d/ethereum/project/webthree-umbrella/build
위와같이 ETH_HOME 과 ETH_BUILD 환경변수를 추가해주었다.
내가 내부적으로 사용하기 위해서 추가한것이고, 이후 블로그에서는 이 환경변수를 기반으로 설명할것이다.

$ETH_BUILD/webthree/eth
디렉토리가 eth 프로젝트 디렉토리이며, 그 밑의 Debug 디렉토리에 좀전에 빌드한 eth.exe 실행파일이 위치하고있다.

버전 확인을 해본다.
[goodjoon Debug]$  ./eth --version
eth version 1.1.3
eth network protocol version: 63
Client database version: 12041
Build: Windows/msvc/int/Debug
1.1.3 버전임을 알 수 있다. (C++ 팀 리더가 바뀌면서 요즘 바짝 긴장을 했는지, 나흘전에 또 1.1.4가 릴리즈 되었다)

보면, Network Protocol Version 이 63 인것을 볼 수 있다. Client 가 다르더라도 저 PV 는 같은 버전이어야 함을 상기해야한다.
Frontier 가 릴리즈된 1.0.0 버전은 PV61 이다. 지금은 PV61,62,63 클라이언트들이 Frontier 에도 섞여있다.

일단 Frontier 에 붙어서 동작하는걸 확인해보겠다. 이왕이면 Mining 도 ON 시켜서 동작시켜보자.
또한 CLI JS Console 로 들어가는 옵션도 함께 넣어보자.
[goodjoon Debug]$  ./eth --mining on console
(++)Ethereum
 !   21:21:18.012|main  void __cdecl dev::eth::Client::init(class dev::p2p::Host *,const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &,enum dev::WithExisting,class boost::multiprecision::number<struct boost::multiprecision::backends::cpp_int_backend<256,256,0,0,void>,0>) 18794 ms

Please enter a MASTER password to protect your key store (make it strong!): Error initializing key manager: D:\ethereum\project\webthree-umbrella\libweb3core\libdevcore\CommonIO.cpp(145): Throw in function class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl dev::getPassword(const class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > &)
Dynamic exception type: class boost::exception_detail::clone_impl<struct dev::ExternalFunctionFailure>
std::exception::what: Unknown exception

 !   21:21:19.011|main  Stop worker 962 ms
[goodjoon Debug]$
실행 하자마자 에러이다. 

일단 옵션을 설명하면,
--mining on : 마이닝 기능을 켠다는 이야기이다
console : Javascript Console 모드로 들어가라는 이야기이다

그런데 바로 뒤에 에러가 난다. Key Manager 를 초기화 하다가 에러가 나는데, 원래는 "Please enter a MASTER password to protect your key store ..." 하고나서 패스워드를 물어보게 되어있다.
그리고 이 Master Password 를 입력하고나면 그 다음단계로 진행하는데, MinGW 환경이나 CygWin 환경에서는 에러가 난다. 똑같은 커맨드를 쳐도 Windows Command Prompt 상에서는 이후에 잘 진행되는것을 확인할 수 있다. 문제는 KeyManager 모듈이 load() 될 때 발생되는데, 이건 나중에 수정되어야 할 부분이다.

이 Master Password 는 예전 PoC 8 버전에서도 도입되지 않다가 Frontier 릴리즈와 함께 도입되었는데, Wallet 의 Private Key 관리의 보안상 허점이 많이 있기 때문에 이 부분의 보안강화를 위해 생겨났다. ethkey.exe 를 통해 향후 좀더 상세한 관리를 할 수 있고, 예전처럼 무식하게 config.rlp 에 Private Key 와 Public Key 를 넣어두지 않는다는점에 주의해야 한다.

Master Password 는 까먹으면 끝장이다. Wallet 의 모든 Key 들을 관리하기 위한 Key Store 의 Master Password 이며, Private Key 를 사용하기 전에 이 Master Key 패스워드를 입력해야 한다.

현재 MinGW 에서 CLI 로 interaction 하는때에 오류가 생기므로, 옵션을 추가하여 아예 Master Password 를 지정해주면서 시작하자.
[goodjoon Debug]$  ./eth --mining on console --master 1111
(++)Ethereum
Ethereum (++) 1.1.3
  Code by Gav Wood et al, (c) 2013, 2014, 2015.
Transaction Signer: XE602H4XB00HUY08LU416SCBGO3CS63H66 (1a7e55b0-3eb7-05ec-248e-8d901e268d76 - 0096bb98)
Mining Beneficiary: XE602H4XB00HUY08LU416SCBGO3CS63H66 (1a7e55b0-3eb7-05ec-248e-8d901e268d76 - 0096bb98)
Foundation: XE55PXQKKK4B9BYPBGT1XCYW6R5ELFAT6EM (00000000-0000-0000-0000-000000000000 - de0b2956)
  i  21:41:11.885|p2p  UPnP device: http://192.168.0.1:4112/etc/linuxigd/gatedesc.xml [st: urn:schemas-upnp-org:device:InternetGatewayDevice:1 ]
 !   21:41:11.963|main  void __cdecl dev::p2p::Host::start(void) 2216 ms
Node ID: enode://2ee2a7e6a73b3af8aa737ce8bf016322828bdfdc5249d1ce4454f9e570a5b1486d988fd1119dacb18f50759de52c0728e4b4d229c01d5fdaa52fdd498ee81b57@211.222.99.182:30303
JSONRPC Admin Session Key: gsIJYPwuntU=
  i  21:41:12.450|<unknown>  Loading full DAG of seedhash: #00000000…

위와같이 --master 옵션을 주고 1111 로 패스워드를 지정해주니 잘 진행이 된다.

그리고 Mining 을 위해 DAG file 을 생성하게 된다. Dagger Hashimoto 파일이라고 불리는데, 1GB 정도 크기의 2차원 배열 데이터를 갖는 파일이다. Mining 시에 적은 ASIC 을 사용한 마이닝을 방지하고 GPU 연산을 더 효율적으로 하고, Light Client 의 Verification 성능향상 등을 위해 Hashing 시 필요한 대규모의 Cache 를 만들어놓는것이다. 자세한 이야기는 다음에 더 하도록 하고, 일단 1GB 의 용량이 최소한 필요하다는것을 상기하자.

DAG 테이블을 모두 만들어내는데에는 수십분 정도 소요되니 바람이나 좀 쐬고 와도 된다.

막간을 이용해 eth 가 사용하는 디렉토리들을 잠깐 설명해보면,

%APPDATA%/Local/ethash - DAG 파일이 위치한다
%APPDATA%/Roaming/Ethereum/config.rlp - Address 가 저장된 파일이다. eth 가 사용하며, 예전에는 Private Key, Public Key 가 들어있었으나 지금은 Key 메커니즘이 복잡해졌고, 이는 향후에 설명한다.
%APPDATA%/Roaming/Ethereum/keys.info, keys.info.salt - 실제적인 Key 가 들어있는 파일이다. AlethZero 와 eth 가 공용으로 사용한다.
%APPDATA%/Roaming/Ethereum/.web3 - Webthree 가 사용하는 Key 에 대한 정보가 들어있다.
%APPDATA%/Roaming/Ethereum/<4바이트HEX값> - state Trie, extra 데이터, block 데이터 등이 저장되는 Level DB 가 있다

이제 1GB 가량의 DAG 파일이 생성이 완료되면, Full DAG loaded 라고 뜬다.


그런데 또 문제가 있다.

console 이 안뜬다 (원래는 이쁘게 '>') 모양과 함께 web3 라고 치면 web3.js 의 JavaScript 개체들이 주욱 나와야 하나 아예 Console 자체가 동작하지 않는다.

이 또한 Windows 에서의 eth 버그이다. 사실 이후에도 eth 의 Windows 에 대한 외면은 매우 많고 다양하다. 
가장 잘 돌아가는 환경은 Mac 과 Ubuntu 이다. Windows 버전은 그냥 울며 겨자먹기로 써야하는 상황이다.
그도 그럴것이, eth 는 Front-End-User 용이 아니다. Back-End 용으로 분류하고있으며, 그래서 Linux 환경에 대해서는 매우 신경을 많이쓰는 느낌이다.


▌Console Attach 하기

Console 이 안된다고해서 실망할 필요는 없다. eth 는 attach 기능을 통해, 기존에 동작하는 eth 인스턴스에 console 을 attach 할 수 있다. 물론 2개의 Terminal 창이 필요하긴 하지만, console 을 쓸 수 있다는게 어디인가? 

일단, 현재 실행중인 Process 는 죽인다. Console 이 동작 안하니 ctrl+C 를 눌러 break 시켜버리자. ctrl+C 로 안되면 작업관리자를 열어서 강제 종료 시켜버려도 된다.

그리고, MinGW Bash Shell 을 2개 띄우고, 하나의 Shell 에서는
[goodjoon Debug]$ ./eth --json-rpc --json-admin 0000 --mode full --mining on --master 1111 --verbosity 5 console
로 실행한다. 여기서 추가된 옵션만 설명하면,

--json-rpc : JSON-RPC 인터페이스를 사용하겠다는 이야기이다. 외부 eth 를 attach 모드로 실행한 후 JavaScript Console 로 명령을 날리면, Console 이 이 JavaScript API 를 JSON-RPC 를 통해 대상 프로세스에게 요청하도록 되어있다.
--json-admin : 옵션에서 --help 를 치면 --admin 이라고 되어있는데, 이건 오타이다. 이런 옵션은 없으며, --json-admin 을 사용해야한다. (이게 언제쩍 버그인데 여태 수정을 안하고있다) JSON-RPC 를 사용하려면 Session Key 를 주어야 하는데, 원래는 eth 가 실행될 때 로그 초반에 Session Key 라는게 출력될 때 랜덤하게 생성된 그 키를 복사에서 attach 할 프로세스에 session key 로 지정해주어야 한다. 불편함을 줄이기 위해 아예 이 값을 --json-admin 옵션으로 주도록 했다.
--mode full : 기본값이긴 한데, Full Node 로 작동하게 할것인지, Peer Node (피어들의 정보만을 제공하는 노드)로 동작시킬것인지를 지정한 것이다
--verbosity 5 : Log 출력의 Verbosity 를 지정해준다. 0~99 까지 줄 수 있는데 5만 주어도 로그가 넘쳐난다.
기본값이 Frontier Network 으로 Bootstrap 하게 되어있으므로 --frontier 옵션을 쓰지는 않았다.

시간이 조금 지나면 Peer 간에 Hello 메시지를 주고받으며 PING/PONG 을 하다가 Block 을 Import 하여 Sync 하기 시작하고, Validation 작업을 수행한다.

이제 두번째 터미널을 열고, Console 을 Attach 해보자
[goodjoon Debug]$  ./eth --session-key 0000 attach
> 

--session-key 는 JSON-RPC 의 --json-admin 옵션으로 준 Key 값을 준것이고, attach 를 통해 기본적인 localhost:8545 포트의 JSON-RPC 로 연결하게 된다.

이제 잘 attach 가 되었는지 확인해보자
> web3.version
{
  api: '0.15.1',
  node: '++eth-v1.1.3-0//Debug-Windows/msvc/int',
  getNode: [Function],
  network: '',
  getNetwork: [Function],
  ethereum: '0x3f',
  getEthereum: [Function],
  whisper: Error: METHOD_NOT_FOUND: The method being requested is not available on this server,
  getWhisper: [Function]
}
>
node: 는 Client 의 Node 식별을 위한 Full Name 이며, 별도의 옵션을 주지 않았으므로 ++eth-v1.1.3-0//Debug-Windows/msvc/int 와 같이 나온다
ethereum: 은 eth 프로토콜 버전이며 10진수로 변환하면 63 이 된다

> web3.eth.coinbase
'0x0096bb9802b14f72ba4cdbd105127fe57a1dafae'> web3.eth.blockNumber
24840
> web3.eth.getBlock('latest')
{
  transactions: [],
 receiptsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
  hash'0xc88b3957581f72a2aa1f5e5bcad12898d1117ba492adc88398bdd4b2a6275b7c',
  seedHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  miner: '0x3f98e477a361f777da14611a7e419a75fd238b6b',
  uncles: [],
  extraData: '0x476574682f76312e302e302f6c696e75782f676f312e342e32',
  gasLimit: 5000, 
 transactionsRoot: '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',

  gasUsed: 0,
  size: 0,

  logsBloom: '0x000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000',
  totalDifficulty: 16505476021090676',
  number: 25657,
  parentHash: '
0xcb29677c43d3877bc401b578a64e2de7c7839a5080163b2bf3194b5fa5bdcc29',
  boundary: '
0x0000000000fa64ef32fc5b94d0c88ff91d9f142f5459c015652cd4e44bb3bc27',
  author: '
0x3f98e477a361f777da14611a7e419a75fd238b6b',
  stateRoot: '
0x429dd84e5a8e30f31a4442b7a0bc7aae79f459751ffcc57d2a2d6f699a38e532',
  difficulty: 1124127046574'
,
  nonce: '0xa8f99a70ac8ec05e',
  timestamp: 1438579639,
  mixHash: '0xf42a0dd21ec4fce0c20b21af14b661f6d43babc3c5bc215f1652a77f3fdc877b',
  sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347'
}
>

자신의 coinbase 와 가장 마지막 block 의 정보를 출력해봤다. 모두 의미있는 값이 나온다면 정상동작중인 것이다.

다음 부터는 Ethereum 의 사상에 대해서 조금씩 이야기를 정리해보기로 하겠다.
음.. 그전에 Blockchain 에 대한 기술적인 정리도 조금 할까..? 생각 중이다. 1.0  의 기술적인 개념부터 이해를 해야 Ethereum 의 개념도 이해가 갈테니 말이다.

그럼 오늘은 또 이만~


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

IBM 이 주도하고 있는 Linux Foundation 의 Collaborative Project 인 Hyperledger 프로젝트 발표 후 Github 에 업데이트가 없다가. 조금전인 2016.02.17 오전 11시 경에 README.md 의 업데이트가 있었다.

현재 시점에서 이 HyperLedger TSC(Technical Steering Commitee)는 광범위한 유스케이스와 Value Add 된 솔루션을 올릴 수 있는 블록체인 플랫폼을 지향하고있다.

이 Project 에는 4가지 종류의 Contribution Proposal 이 올라왔다. 아래 제안들은 아직 결정된것이 아니며, TSC 가 열심히 검토해서 결정하겠다고 한다. (그러나 아마도 답은 이미 나와있는상태에서 시작하는 게임 아닐까 싶기도 하다. IBM이 아니겠는가? 아니면 DAH ..? 아니면 적절한 사상들 간의 종합적인 산출물이 나올 수 있을듯 한데..)


Ripple Proposed Contribution

Rippled 는 OSS 로, C++ 로 구현된 2012년 부터 작동중인 Public Blockchain 이며, Cross-Currency 지불을 가능케 하는 플랫폼이다. 주문장(Order Books) 기반으로 이루어지는 빠른 Transaction 과 복잡한 구현을 단순화 하는데에 초점이 맞추어져있다.

분산 원장(Distributed Ledger)기술로 NuDB 라는 고성능의 Key/Value 기반의 DB 를 포함하고 있다. 수 테라바이트의 데이터셋을 최소함의 RAM 소모로 핸들링 하기에 최적화 되어있다. SSD 와 같은 고성능의 I/O 가 필요하다.

https://github.com/ripple/rippled

IBM Proposed Contribution

IBM 은 Open Blockchain (OBC) 라는 이름으로 프로젝트를 하겠다고 발표한바 있고, 2월15일에 0.1.0을 릴리즈 하였다. License 는 Apache 기반으로 진행중이며, Hyper Ledger 프로젝트에 Contribute 하기 위해 오픈소스화 하였다고 한다. 정식으로 Hyper Ledger 프로젝트로 채택되면 IBM 은 이후 Hyperledger 에 집중하고, 아래 Repository 는 IBM 내부적인 필요성에 의해 관리한다고 한다. 언어는 Go 로 개발되어있다.

Open Blockchain 은 여러 산업에서 사용할 수 있게하기위한 목적의 저수준의 Fabric Code 이다. 핵심은 Smart Contract, Digital Assets, Record Repositoroes, Decentralized Network Providing Consensus, Cryptographic Security 이다.

https://github.com/openblockchain


Digital Asset Holdings Proposed Contribution

DAH 의 후보군은 기업을 위한 Blockchain Server 형태로, Client API 를 포함한다. 이 프로젝트도 Hyper Ledger 프로젝트 채택을 위한 목적으로 공개 된 프로젝트이다. 모듈화된 아키텍쳐와 설정 가능한 네트워크 구조는 금융권에 적합한 구조를 위해 설계되었다고 한다. 데이터 백본의 컨셉을 Multi-Organization 레벨로 확장한 것이다. 라이선스는 Apache 라이선이다.

금융권용 답게 Java 기반으로 구현되어있다. 골드만삭스를 비롯 각종 금융권들로 부터 많은 긍정적인 반응과 투자를 받은 회사로 상당히 유력한 후보군이라 볼 수 있다.

https://github.com/DigitalAssetCom/hlp-candidate


Blockstream Proposed Contribution

좀 됐긴 했지만 Elements 라는 이름의 Blockchain OSS 도 있다. Bitcoin 을 확장한 개념으로, Confidential Transactions, Segregated Wirness, Relative Lock Time 등등의 확장 개념이 들어가있다. Bitcoin testnet 과의 Pegging 도 가능하다.

https://github.com/ElementsProject/elements


앞으로 이 4개 Proposal 중에 어떤게 정식으로 Hyper Ledger 의 Codebase 또는 사상으로 채택될지는 모르겠으나 내생각에는 IBM 이 가장 유력하지 않는가 싶다. 애초에 TSC 가 보고있는 관점도 "산업 전반에 걸친" 블록체인 플랫폼이므로 (왠지 IBM 이 만들어낸 기준 스러워도 보이지만) 금융권에서 신뢰받고있는 DAH 의 codebase 또한 무시못할 것으로 보인다.

Hyper Ledger 가 아니더라도, DAH 의 Blockchain 소스가(물론 일부이고 Hyper Ledger 프로젝트 채택 목적이겠지만) 공개되어 올라온것 만으로도 특히 국내 금융권에게는 희소식이 아닐까 싶다.


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
불과 며칠 전에 1.1.3 버전이 Release 되었다. 1.1.2 부터 PV62(Protocol Version 62) 와 PV63 을 지원 중이며, 1.1.2 대비 eth Console 과 AlethOne 크래쉬 버그픽스가 있었다. 이 1.1.3 Release Branch 로 빌드 해보기로 한다.

Mac OS X 에서는 그나마 빌드 및 실행이 잘되는 편인데, Windows 빌드는 예전 버전들 부터 잘 되지 않는 편이다. 빌드는 되더라도 기능에 버그가 있거나 하는 경우가 많다.

▌준비할 것

빌드하기 전에 우선 아래 준비사항이 모두 준비되었는지 확인하자.

  1. Windows 7 또는 8 64비트 (32 비트 버전과 Windows 10 은 지원하지 않음)
  2. Git for Windows 1.9.0 이상
  3. 7-Zip 
  4. CMake 3.0 이상
  5. Windows 7 또는 8 SDK 
  6. Visual Studio 2013 Community Edition (Update 5 를 별도로 받아 Build 넘버 12.0.40629.00 이 되도록 한다)
    Visual Studio 2015 는 아직 지원 안함

▌환경 설치

▪ Git 설치

Git 사이트 에서 Git for Windows 다운로드 받고, Git Bash Shell 을 설치하도록 한다.


설치하면 Git Bash 로 실행 되는지 정도는 확인하자.



▪ 7zip 설치

7zip 사이트 에서 최신 exe 버전을 다운로드 한다.


다운로드 받은 exe 파일을 실행하여 원하는 Directory 에 설치한다


그리고 반드시 설치한 디렉토리를 PATH 에 추가해 주어야 한다


위처럼 System 의 PATH 환경변수에 7zip 설치된 경로를 추가 해 주었다.

▪ CMake 설치

CMake 사이트 에서 Latest Release 에서 Installer 버전을 다운로드 받아서 설치한다.


PATH 에 CMake 를 자동 추가하도록 설치 시 옵션을 선택한다.



▪ Windows SDK 설치

Windows SDK 사이트 (7 또는 8.1) 에서 SDK 를 다운로 받아 설치한다.


▪ Visual Studio 2013 Community

Visual Studio 2013 Community 사이트 에서 Installer 를 다운로드 받고 설치한다. 시간이 꽤 걸린다.



위 처럼 Update 5 를 설치하고 있는지 확인한다.

이제 소스를 Checkout 하고 빌드를 해보도록 하자

▌소스 Clone

Git Bash 를 통해 MinGW 의 Bash Shell 로 들어간다.

우선 디렉토리를 아래와 같이 만들었고, project 밑으로 프로젝트를 clone 할 예정이다.
[goodjoon project]$  pwd
/d/ethereum/project
[goodjoon project]$

git 으로 Repository 를 Clone 한다. Submodule 들이 다수 걸려있으므로, submodule 들도 --recursive 옵션으로 모두 가져온다.
[goodjoon project]$
brella.gitproject]$  git clone --recursive https://github.com/ethereum/webthree-umbrella
Cloning into 'webthree-umbrella'...
remote: Counting objects: 71041, done.
remote: Compressing objects: 100% (2/2), done.
Receiving objects:  56% (40071/71041), 16.92 MiB | 2.96 MiB/s

webthree-umbrella 가 clone 되었고, 
[goodjoon project]$  ls -al
total 8
drwxr-xr-x 1 korean44 없음 0 Feb 14 23:16 ./
drwxr-xr-x 1 korean44 없음 0 Feb 14 23:04 ../
drwxr-xr-x 1 korean44 없음 0 Feb 14 23:16 webthree-umbrella/
[goodjoon project]$

webthree-umbrella 해서 git status 를 해보면
[goodjoon webthree-umbrella]$  git status
On branch develop
Your branch is up-to-date with 'origin/develop'.
nothing to commit, working directory clean
[goodjoon webthree-umbrella]$
확인해보면, 위 처럼 develop Branch 에 HEAD 가 있음을 알 수 있다. 그래서, Release 브랜치로 다시 checkout 을 해야한다.

[goodjoon webthree-umbrella]$  git checkout release
M       webthree-helpers
Branch release set up to track remote branch release from origin.
Switched to a new branch 'release'
[goodjoon webthree-umbrella]$  git status
On branch release
Your branch is up-to-date with 'origin/release'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   webthree-helpers (new commits)

no changes added to commit (use "git add" and/or "git commit -a")
[goodjoon webthree-umbrella]$

release Branch 로 checkout 을 하고 status 를 보면, submodule 이 실제로 update 가 안되었기 때문에 modified 된것처럼 나온다. 
Submodule 들도 Update 해주자
[goodjoon webthree-umbrella]$  git submodule update --recursive
Submodule path 'webthree-helpers': checked out '4932539374f9b9ea1030b4514c5292620d55f3c0'
[goodjoon webthree-umbrella]$  git status
On branch release
Your branch is up-to-date with 'origin/release'.
nothing to commit, working directory clean
[goodjoon webthree-umbrella]$

불과 사흘전에 Release 를 해서 그런지 Submodule 들이 대부분 최신 Branch 여서 webthree-helpers 브랜치만 Update 되었다.

▌Dependency 다운로드

Windows 에서 빌드를 하기 위해서는 llvm 및 Qt 을 비롯해 아래와 같은 라이브러리들이 필요하다
boost 1.55.0
cryptopp 5.6.2
curl 7.4.2
jsoncpp 1.6.2
json-rpc-cpp 0.5.0
leveldb 1.2
llvm 3.7.0
microhttpd 0.9.2
OpenCL_ICD 1
qt 5.4.1
miniupnpc 1.9
v8 3.15.9

apt 나 brew, port 가 없는 Windows 에서 일일이 라이브러리를 다운로드 받아 설치하기란 매우 번거로운 일이기때문에 C++DEV 팀에서 간단한 배치를 하나 제공한다.
/d/ethereum/project/webthree-umbrella/webthree-helpers/extdep
위 경로로 가보면 getstuff.bat 파일이 있는데, 이 파일을 실행시키면 모든 dependency 라이브러리들을 다운로드 받는다

[goodjoon extdep]$  ./getstuff.bat
한참동안을 뭔가 잘못된 것 처럼 가만히 있는다. 라이브러리를 하나씩 다운로드 받고 압축 풀고를 반복한다. 4.4GB 를 다운받고 압축 푸느라 수십분 정도 작업이 길어질 수 있으므로 TV나 좀 보다오자.
인터넷 연결만 잘 되어있다면 안될 이유는 없을것이다.

오늘은 너무 졸려서 이만..^^;;
다음은 본격적인 소스 빌드와 오류 해결로 넘어가보겠다.


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,