[블록체인 개발공부] Mastering Bitcoin 따라가기 - 들어가며, Ch 3

in #kr7 years ago (edited)

들어가며

안녕하세요. ICO Report의 @wklee 입니다. 하루가 다르게 블록체인에 대한 관심이 늘고 있습니다. 높아지는 관심처럼 비트코인은 전고점(ATH)을 돌파하고 고공행진을 하고 있습니다. ICO Report를 운영하면서 블록체인에 대해 많은 것을 알게되었지만 아직도 배울 것은 많아보이기만 합니다. 그래서 블록체인이라는 기술을 처음 소개시켜준 비트코인 에 대한 공부를 시작해보려고 합니다.

이 시리즈를 통해 블록체인을 공부하는 개인의 입장에서 학습한 내용을 공유하고자 합니다. 이 시리즈는 '공룡책' 과 같은 컴퓨터 프로그래밍의 바이블을 만들어온 O'Reilly Media 사가 출판한 Mastering Bitcoin(2017, Antonopoulos, A) 를 따르고 있습니다. 이 포스팅에서 다뤄지는 예제나 코드는 모두 Mastering Bitcoin(2017, Antonopoulos, A) 를 참조했습니다. 원문은 여기 에서 읽어볼 수 있습니다. 이 시리즈는 독자가 Cli (Command Line Interface), Python, C++ 에 대한 기본적인 이해가 있다고 가정하고 쓰여졌습니다.


이 책의 Chapter 1 과 Chapter 2 는 블록체인이 동작하는 방식에 대한 개요를 담고 있습니다. 이에 대한 설명은 @hanmomhanda 님이 작성해주신 BlockChain 기초 개념 글에 자세히 다뤄져 있으므로 이 시리즈에서는 다루지 않겠습니다. 이 글을 통해 블록체인의 기본동작을 이해하고 이 시리즈를 따라오시기를 강력하게 권합니다.


Chapter 3

Chapter 3에서는 Command Line 비트코인 클라이언트 bgitcoind 를 만드는 과정을 다루고 있습니다. (아래는 제 개발환경인 Mac OSX 를 대상으로 쓰여진 글입니다.)

Bitcoin Core 는 비트코인 시스템의 Reference implementation 입니다. 즉, 비트코인 어플리케이션이 어떤 형태를 갖고 만들어져야 하는지를 담은 Reference라고 볼 수 있습니다. 그 구조는 위와 같습니다.

Bitcoind

Chapter 3 에서 우리는 커맨드라인 비트코인 클라이언트인 bitcoind 를 만들어보도록 하겠습니다.

주의 : 앞으로의 과정에서 bitcoind 는 bitcoin core 전체를 다운로드 받습니다. 즉 13 GB 이상의 용량이 필요합니다.

먼저, 아래와 같이 비트코인의 소스코드를 다운받습니다.

$ git clone https://github.com/bitcoin/bitcoin.git

다운로드가 완료되었으나, 현재 Master Branch 가 릴리즈 가능한 안정된 버전인지 알 수 없습니다. 아래 명령어를 시행하여 최신 버전을 선택합니다. 버전 뒤에 붙은 rc 는 Release Candidate을 의미하며 릴리즈 되지 않은 버전입니다. rc 가 붙지 않은 최신 버전을 선택하도록 합니다. 아래와 같이 Checkout 과 Status 커맨드로 해당 버전을 사용하도록 설정합니다.

$ git tag
$ git checkout v0.14.2
$ git status

준비 (Prerequisite)

bitcoind를 만들기 위해 README.mddoc/build-osx.md 를 읽어야 합니다. doc/build-osx.md 에는 bitcoind를 만들기 위한 dependencies 가 있으므로 꼭 읽고 순서를 따라 진행해야 합니다.

먼저, Xcode의 Command Line tool 이 설치되어 있어야 합니다. ( Xcode를 실행하면 필요한 컴포넌트들이 나오는데 다 설치하면 되었던 것 같습니다. ) 또한 Homebrew 가 설치되어 있어야 합니다. 이후 아래 코드를 입력합니다.

$ brew install autoconf automake libtool boost miniupnpc openssl pkg-config protobuf qt libevent
## 모든 Dependencies 를 설치합니다.

$ openssl version
## openssl 이 정상적으로 설치되었는지 확인

$ brew install berkeley-db4.rb
## db 설치, 책에 현재는 사용할 수 없는 링크가 나와있습니다. 지금은 이와 같이 설치할 수 있습니다.

Build

bitcoin 디렉토리로 이동하여 ./autogen.sh 를 입력하면 자동으로 필요한 과정들을 진행됩니다.

$ cd bitcoin
$ ./autogen.sh

다음으로 Configure입니다. ./configure —help 를 하면 configure 옵션을 볼 수 있습니다. ./configure 로 configure를 마칩니다. 이때 에러가 발생하면 Dependencies 설치가 완료되지 않은 것 입니다. 에러메시지를 구글링하면 어렵지 않게 설치할 패키지를 찾을 수 있습니다.

$ make
## Make로 소스코드를 컴파일합니다.
$ sudo make install

설치가 완료되면 다음 명령어를 칠 때, 설치된 디렉토리가 표시됩니다.

$ which bitcoind
$ which bitcoin-cli

Running a Bitcoin Core Node

bitcoind 를 처음 실행하려면 bitcoin.confrpcpasswordrpcuser 를 설정해야합니다.

$ echo -e "rpcuser=bitcoinrpc\nrpcpassword=$(xxd -l 16 -p /dev/urandom)" > "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"

## 접근 권한 변경
$ chmod 600 "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"

완료되었다면, 해당 파일에 rpcuserrpcpassword 가 잘 설정되었는지 확인해주세요.

Configuration

bitcoind —help 를 이용하면 여러 configuration 옵션을 볼 수 있습니다. 중요한 옵션들은 다음과 같습니다. (앞으로 Transaction은 'Tx' 로 표기합니다. )

  • prune 옵션은 이전 오래된 block을 삭제할 수 있는 옵션입니다.
  • txindex 는 모든 거래에 순서를 부여하는 옵션입니다. 이 옵션 이용하면 getrawtransaction 으로 모든 Tx에 접근할 수 있습니다. 이를 full-index node라고 합니다.
  • maxconnection 은 인터넷 사용량이 제한된 상황에 연결된 node를 제한하는 옵션입니다.

위 예는 리소스가 제한된 컴퓨터에서 bitcoind 를 사용가능하도록 설정한 모습입니다. prune 이 5000 개로 지정되어 그 이전 기록들은 삭제하도록 설정되었고, maxmempool 로 메모리를, maxconnections 로 연결되는 노드를 제한했습니다.


bitcoin-cli getinfo 를 하면 현재 노드가 돌아가는 상태를 확인할 수 있습니다. bitcoind 를 컴퓨터 시작시 실행하려면 contrib/initReadme.md 를 읽어보시기 바랍니다.

Execute

커맨드 라인에 bitcoind -txindex 를 입력합니다. 그리고 다른 창을 하나 더 띄워서

tail -f $HOME/Library/Application\ Support/Bitcoin/debug.log

를 입력합니다. 이전의 Tx를 다운로드 받고 있는 것을 볼 수 있습니다.

참조

아래에 나올 RPC 를 이용하지 않고 getrawtransaction 으로 Tx 를 조회하려면 bitcoind -txindex커맨드를 이용해 Full index node 를 돌려야 합니다. 120 GB 가 넘는 용량을 필요로 합니다. 제 맥북으로는 이를 감당하지 못하기때문에 -Prune=5000 옵션을 썼습니다. 용량이 충분치 않으면 마지막 옵션으로 prune 을 고려해보시기 바랍니다. 책에서는 Full index node 를 돌리는 것을 권장하고 있습니다.


Bitcoin Core Application Programming Interface (API)

Exploring and Decoding Transaction

Bitcoin Core client 는 bitcoin-cli 커맨드로 엑세스할 수 있습니다. bitcoin-cli getinfo 커맨드로 동작하고 있는 bitcoin Core client 에 대한 정보를 확인할 수 있습니다.

{
 "version" : 110200,
 "protocolversion" : 70002,
 "blocks" : 396367,
 "timeoffset" : 0,
 "connections" : 15,
 "proxy" : "",
 "difficulty" : 120033340651.23696899,
 "testnet" : false,
 "relayfee" : 0.00010000,
 "errors" : ""
}

bitcoin-cli getblockhash 1000 를 입력하면 아래와 같은 결과가 나옵니다. 이 커맨드는 1000번 째 block의 해시값(아래)을 보여줍니다. 이에 대한 내용은 뒤에서 더 다뤄집니다.

00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09

Commands: getrawtransaction , decoderawtransaction

위 커맨드로 Tx에 대한 정보를 확인할 수 있습니다. 예를 들어 Alice가 Bob 의 카페에서 커피를 사고 커피값을 비트코인으로 지불 했고 이 거래의 txid는 아래와 같습니다. '0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2'

getrawtransaction

 bitcoin-cli getrawtransaction 0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2

위 명령어는 전체 Tx가 Hash화된 값인 txid 를, Raw 값인 Hex string 으로 바꾸어줍니다. 즉, 이 명령어는 해당 txid 에 담긴 전체 거래정보를 반환합니다. 결과는 웹 기반 Bitcoin API 툴인 ChainQuery에서도 확인할 수 있습니다 ( 결과 )

decoderawtransaction

bitcoin-cli  decoderawtransaction  ...

위에서 나온 결과를 decoderawtransaction 의 Parameter (... 부분) 로 입력하면 해당 Txid 가 담고 있는 거래정보가 자세히 표시됩니다. 마찬가지로 결과는 웹 기반 Bitcoin API 툴인 ChainQuery 에서도 확인할 수 있습니다

거래를 BlockChain Info 에서 확인하면 아래와 같습니다.

위에서 Tx에서 볼 수 있듯, Alice (1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK)는 0.1 btc를 BoB의 주소(1GdK9UzpHBzqzX2A9JFP3Di4weBwqgmoQA)로 전송(커피값 지불)했고, Alice는 BoB으로 부터 자신의 주소(1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK)로 거스름돈 0.0845BTC 를 돌려받았습니다.

참고(Tip)

Txid 는 TX가 끝날 때까지 완전히 유효(authoritative) 하지 않습니다. 또한, Tx hash가 표시되지 않았다고 거래가 진행되지 않은 것은 아닙니다. 이는 '거래 가변성(Transaction Malleability)'이라는 블럭체인의 속성 때문입니다. 거래 가변성이란 Tx의 Hash는 거래가 완료되고 블럭에 포함되기전에 변경될 수 있음을 의미합니다. 거래가 완료(Confirmed)되고 나서 txid 는 비가역적, 유효(immutable, authoritative) 합니다. (참고 :비트코인 버그, Transaction Malleability?, "비트코인 버그?" - 코빗블로그](http://blog.naver.com/PostView.nhn?blogId=allthatbtc&logNo=20205397111))

Exploring Blocks

Commands: getblock , getblockhash

 bitcoin-cli getrawtransaction 0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f

예제로 제시된 위 Tx(커피 구매) 는 277316 블럭에 포함되어 있습니다.

 bitcoin-cli getblockhash 277316

이 명령어는 Block Hash를 돌려줍니다.

0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4

이제 이 블럭을 찾아보겠습니다.

bitcoin-cli getblock `0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4`

이 명령어를 통해 해당 블럭에 들어있는 tx와 사이즈, 머클hash(merkleroot), 난이도 등 블럭의 모든 정보를 알 수 있습니다.

Using Bitcoin Core's Programmatic Interface

Bitcoin-cli 는 Bitcoin Core API 를 탐색할 수 있는 툴입니다. Bitcoin Core API 는 JSON-RPC 로 이뤄져있습니다. RPC 는 Remote Procedure Call의 약자로 Bitcoin Core node 의 Procedure( function ) 을 호출한다는 의미입니다. Bitcoin-cli 가 예제로 제공하는 커맨드는 아래와 같이 cURL 커맨드로 이뤄져있습니다.

$ curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getinfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/

위 명령어는, jsonrpc 형태의 HTTP request, getinfo method 를 Localhost(127.0.0.1), Default Bitcoin Port(8332)로 text/plain 인코딩으로 보내는 것입니다.

  • jsonrpc
  • Http request
  • address : 127.0.0.1
  • port : 8332
  • method : getinfo
  • type : text/plain

이런 요청을 Python-bitcoinlib 라이브러리를 이용해 간편화할 수 있습니다. 이를 사용하기 위해서는 BItcoin Core instance 가 동작하고 있어야 합니다 .

Python-bitcoinlib 과 JSON-RPC 를 이용한 Getinfo 호출.

# rpc_example.py

from bitcoin.rpc import RawProxy

# Create a connection to local Bitcoin Core node
p = RawProxy()

# Run the getinfo command, store the resulting data in info
info = p.getinfo()

# Retrieve the 'blocks' element from the info
print(info['blocks'])

Bitcoin Core의 Root 디렉토리에 다음 코드를 실행해주세요.

# 라이브러리 설치
$ pip install python-bitcoinlib

# 실행
$ python rpc_example.py

실행하면 Return되는 숫자가 바로 Local Bitcoin Core 갖고 있는 블럭의 수입니다


위에서 사용한 getrawtransaction , decoderawtransaction 을 이용해 커피를 구매한 tx의 정보를 불러오도록 하겠습니다.

from bitcoin.rpc import RawProxy

p = RawProxy()

# Alice's transaction ID
txid = "0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2"

# First, retrieve the raw transaction in hex
raw_tx = p.getrawtransaction(txid)

# Decode the transaction hex into a JSON object
decoded_tx = p.decoderawtransaction(raw_tx)

# Retrieve each of the outputs from the transaction
for output in decoded_tx['vout']:
 print(output['scriptPubKey']['addresses'], output['value'])

∆ 해당 Tx를 다운로드 받지 못했거나 Full index node 가 아니라면 에러가 발생합니다.

$ python rpc_transaction.py
([u'1GdK9UzpHBzqzX2A9JFP3Di4weBwqgmoQA'], Decimal('0.01500000'))
([u'1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK'], Decimal('0.08450000'))

위 명령어를 시행하면, 이와 같은 Response가 나옵니다. 이전에 다뤄졌던 것처럼 커피값 지불과 거스름돈을 돌려받는 거래가 담겨있는 것을 볼 수 있습니다.

다음 예제는 거래가 진행된 블럭의 모든 Output 을 함께 볼 수있는 코드입니다.

from bitcoin.rpc import RawProxy

p = RawProxy()

# The block height where Alice's transaction was recorded
blockheight = 277316

# Get the block hash of block with height 277316
blockhash = p.getblockhash(blockheight)

# Retrieve the block by its hash
block = p.getblock(blockhash)

# Element tx contains the list of all transaction IDs in the block
transactions = block['tx']

block_value = 0

# Iterate through each transaction ID in the block
for txid in transactions:
 tx_value = 0
 # Retrieve the raw transaction by ID
 raw_tx = p.getrawtransaction(txid)
 # Decode the transaction
 decoded_tx = p.decoderawtransaction(raw_tx)
 # Iterate through each output in the transaction
 for output in decoded_tx['vout']:
 # Add up the value of each output
 tx_value = tx_value + output['value']

 # Add the value of this transaction to the total
 block_value = block_value + tx_value

print("Total value in block: ", block_value)

실행시 아래와 같은 값이 나옵니다.

$ python rpc_transaction.py
('Total value in block: ', Decimal('10322.07722534'))

위 값은 Alice와 Bob 의 거래가 담긴 블럭에서 거래된 총액은 10322.07722534 BTC 임을 의미합니다. 여기에는 25BTC 블럭 발행 보상과 수수료를 포함합니다.

정리

Chapter 3 에서는 아래 내용을 다뤘습니다.

  • CLI 비트코인 클라이언트 Bitcoind를 만들었습니다.
  • bitcoind 를 만들때 어떤 configuration이 가능한지 다뤘습니다.
  • RPC 와 Bitcoin API 에 대해 공부했습니다.
  • getrawtransaction 을 이용해 txid 를 Hex string으로 바꾸었습니다.
  • decoderawtransaction 을 이용해 Hex String으로 바뀐 txid를 이용해 해당 txid 에 담긴 거래정보를 확인했습니다.
  • getblockgetblockhash 를 이용해 특정 거래가 담긴 블럭과 그 블럭에 담긴 모든 거래를 알 수 있었습니다.
  • python 비트코인 라이브러리인 python-bitcoinlib 을 이용해 위 Method를 이용한 스크립트를 만들어 봤습니다.
  • 특정 txid 를 조회해 안에 담긴 거래를 확인하는 python 스크립트를 만들었습니다.
  • 특정 블럭의 모든 Output을 확인하는 python 스크립트를 만들었습니다.

Chapter 3 는 여기까지 입니다. 중요한 내용은 모두 담도록 노력했으나 원문 을 읽어보실 것을 권해드립니다.


References

Antonopoulos, A. (2017). Mastering Bitcoin : programming the open Blockchain. Sebastopol, CA: O'Reilly Media.

Sort:  

잘 읽고 갑니다. 마스터링 이더리움 나올때까지 공부해봐야겠네요.


Good Job. I think you are better than me .

연재 잘보겠습니다~

잘읽고갑니다