블록체인

비트코인: 비트코인 코어 빌드 및 JSON-RPC 사용해보기(feat. 윈도우)

비트코인 코어

블록체인을 본격적으로 공부하면서 빼먹을 수 없는 것이 비트코인인지라 비트코인의 참조구현인 Bitcoin Core 를 나름 반나절이 걸려 드디어 빌드에 성공하여 블로그에 남겨보기로 했다. WSL(Windows Subsystem Linux)를 써서 할까 했었다가 Microsoft Visual Studio 를 통해서도 빌드가 가능한 듯하여 시도해보았다.

 

github.com/bitcoin/bitcoin

 

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.

vcpkgVisual 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)
}

더 읽을거리

비트코인: 개인간 전자화폐 시스템