비트코인 코어
블록체인을 본격적으로 공부하면서 빼먹을 수 없는 것이 비트코인인지라 비트코인의 참조구현인 Bitcoin Core 를 나름 반나절이 걸려 드디어 빌드에 성공하여 블로그에 남겨보기로 했다. WSL(Windows Subsystem Linux)를 써서 할까 했었다가 Microsoft Visual Studio 를 통해서도 빌드가 가능한 듯하여 시도해보았다.
bitcoin/bitcoin
Bitcoin Core integration/staging tree. Contribute to bitcoin/bitcoin development by creating an account on GitHub.
github.com
비트코인 소스를 git clone 으로 다운받고나면 build_msvc 라는 폴더가 있는데, 그곳에 Bitcoin Visual Studio Solution 파일이 존재하여 이것을 통해 빌드할 수 있다. 빌드방법은 상위에 있는 디렉토리에서 doc 폴더에 들어가보면 플랫폼별로 분리되어 있는데, 다음과 같이 나타난다.
나는 Windows 에서 빌드할 것이므로 build-windows.md 문서를 볼 것인데, 아래와 같은 문장이 있다.
* On Windows, using a native compiler tool chain such as [Visual Studio](https://www.visualstudio.com). See [README.md](/build_msvc/README.md).
지시하는 대로 build_msvc/README.md 를 찾아가보면 종속성(Dependencies)이 있는 것을 볼 수 있는데, 빌드하기 전에 꼭 필요한 것들이니 설치가 필요하다.
- Use Microsoft's [vcpkg](https://docs.microsoft.com/en-us/cpp/vcpkg) to download the source packages and build locally. This is the recommended approach.
- Use [nuget](https://www.nuget.org/) packages with the understanding that any binary files have been compiled by an untrusted third party.
vcpkg 는 Visual Studio Package 를 관리하는 애플리케이션이다. 설치를 위해서는 다음을 참고하자. 다른 것보다도 Visual Studio English Language Pack 은 설치를 까먹어서 에러가 나버렸었다.
github.com/microsoft/vcpkg/blob/master/README_ko_KR.md
microsoft/vcpkg
C++ Library Manager for Windows, Linux, and MacOS. Contribute to microsoft/vcpkg development by creating an account on GitHub.
github.com
nuget 의 경우 Visual Studio 2019 에서는 이미 포함이 되어있는 상태여서 패스했다. 설치가 안 되어있다면 따로 설치를 해야한다. VS 2017 이상부터는 이미 포함되어 있을 것이다.
솔루션 빌드하기
build_msvc/READM.md 에 보면 빌드 스탭이 나와있다. 아래와 같이 따라해보자. 여기서 msbuild 명령어를 찾지 못하는 경우 Visual Studio Installer 에서 MSBuild(Microsoft Build Engine)와 관련된 것을 설치하여 PATH 환경변수에 추가해야 한다.
$ cd build_msvc
$ py -3 msvc-autogen.py
$ msbuild /m bitcoin.sln /p:Platform=x64 /p:Configuration=Release /t:build
msbuild 는 bitcoin.sln 파일을 열고 GUI 상에서 빌드하는 것과 같다.
Qt 에 대한 빌드 설정은 생략했으나 꼭 필요한 것은 아니고 옵션이기 때문에 그것과 관련된 오류가 나더라도 무시하면 된다. bitcoin-qt, test_bitcoin-qt, libbitcoin_qt 가 그것에 해당한다.
비트코인 노드 실행하기
빌드가 끝나면 build_msvc/x64/Release 에 관련 바이너리들이 생성되는데, bitcoind 가 비트코인 네트워크에 접속하는 클라이언트다. 해당 클라이언트를 실행하면 현재의 블록 height 를 따라잡기 위해 블록을 다운받아오기 시작한다. 비트코인의 제네시스 블록부터 시작할 것이기 때문에 동기화에는 상당한 시간이 걸린다.
$ cd build_msvc/x64/Release
$ ./bitcoind
JSON-RPC 서버
비트코인 노드에서 JSON-RPC 서버를 켜려면 bitcoind 를 실행할 때 -server 옵션을 주면 되는데, 비트코인 클라이언트 설정에 rpcuser, rpcpassword
값이 있어야 한다. 윈도우 기준으로 아래와 같은 경로에 위치한다. __USER__
에는 현재 자신의 유저 이름이 위치할 것이다.
C:\Users\__USER__\AppData\Roaming\Bitcoin\bitcoin.conf
나의 경우에는 다음과 같이 설정했다. 비트코인 클라이언트의 JSON-RPC 서버는 HTTP 를 사용하기 때문에 이부분은 HTTP Basic 인증이라고 생각하면 된다.
rpcuser=bitcoinrpc
rpcpassword=bitcoinrpc
bitcoin-cli
기본적으로 http://127.0.0.1:8223 으로 서버가 켜져있기 때문에 관련 경로로 요청을 보내면 통신이 가능하다. 가장 먼저 bitcoin-cli 를 사용해보자. bitcoin-cli 를 사용하면 JSON-RPC 서버와 통신이 가능하다. 먼저 bitcoind -server 로 서버가 켜져있어야 한다.
$ ./bitcoin-cli getblockchaininfo
{
"chain": "main",
"blocks": 227653,
"headers": 677070,
"bestblockhash": "00000000000001550da2ce04d8b4b1819393d01d31ed316ebfd075de73037cd1",
"difficulty": 4847647.152065606,
"mediantime": 1364067242,
"verificationprogress": 0.02364968551503,
"initialblockdownload": true,
"chainwork": "000000000000000000000000000000000000000000000030be3bfbad43edc816",
"size_on_disk": 7548762884,
"pruned": false,
"softforks": {
"bip34": {
"type": "buried",
"active": false,
"height": 227931
},
"bip66": {
"type": "buried",
"active": false,
"height": 363725
},
"bip65": {
"type": "buried",
"active": false,
"height": 388381
},
"csv": {
"type": "buried",
"active": false,
"height": 419328
},
"segwit": {
"type": "buried",
"active": false,
"height": 481824
}
},
"warnings": ""
}
curl
curl 을 사용해서도 통신할 수 있다. 다음과 같이 해보면 똑같은 결과가 나온다.
$ curl --user bitcoinrpc --data-binary '{"jsonrpc":"1.0", "id":"curltest", "method":"getblockchaininfo", "params":[] }' -H 'content-type: text/plain;' http://127.0.0.1:8332
Enter host password for user 'bitcoinrpc':
{"result":{"chain":"main","blocks":229352,"headers":677071,"bestblockhash":"0000000000000155df35dff209dd7c2a8405861cb9cf05eaa9f26b44bef1a91e","difficulty":6695826.282596251,"mediantime":1364927393,"verificationprogress":0.02450738708891016,"initialblockdownload":true,"chainwork":"000000000000000000000000000000000000000000000033535ac96019218688","size_on_disk":7927469372,"pruned":false,"softforks":{"bip34":{"type":"buried","active":true,"height":227931},"bip66":{"type":"buried","active":false,"height":363725},"bip65":{"type":"buried","active":false,"height":388381},"csv":{"type":"buried","active":false,"height":419328},"segwit":{"type":"buried","active":false,"height":481824}},"warnings":""},"error":null,"id":"curltest"}
간단한 라이브러리 만들어보기
curl 로 통신이 가능하다는 것은, 프로그래밍을 통해 Http Request 를 보내서 결과를 얻어올 수 있음을 의미한다. 단순하게나마 다음과 같이 간단하게 코드를 짜보았더니 잘 나오는 것을 볼 수 있다.
RequestContext
먼저 요청을 위한 RequestContext
타입을 만든다. 이 타입은 이후에 JSON 으로 변환하기 위해 사용 될 것이다.
const URL = "http://bitcoinrpc:bitcoinrpc@127.0.0.1:8332"
type RequestContext struct {
JsonRpc string `json:"jsonrpc"`
ID string `json:"id"`
Method string `json:"method"`
Params []interface{} `json:"params"`
}
.ToBitcoindJsonRpc() []byte
실제로 JSON-RPC 서버에 요청을 보내기 위한 메서드다. RequestContext
를 JSON 으로 인코드하고 HTTP Post Body 에 첨부하여 보낸다.
func (req *RequestContext) ToBitcoindJsonRpc() ([]byte, error) {
b, err := json.Marshal(req)
if err != nil {
return nil, err
}
res, err := http.Post(URL, "text/plain", bytes.NewReader(b))
if err != nil {
return nil, err
}
resText, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
return resText, nil
}
main
이제 아래와 같이 호출하면 curl 에서 호출한 것과 똑같이 나오는 것을 볼 수 있을 것이다!
func main() {
req := RequestContext{"1.0", "curltest", "getblockchaininfo", []interface{}{}}
resText, err := req.ToBitcoindJsonRpc()
if err != nil {
log.Panic(err)
}
fmt.Printf("%s", resText)
}