BitcoinプロトコルをGo言語で少し書いてみた
前回、ビットコインピアと直接通信してみたいという話をしました。
今回はdnsseed-rubyの一部をGo言語に移植して、通信するところまで作成してみました。 プロトコルは下記サイトを参照。エンディアンが入り乱れていて、コーディングしにくかったです。
Protocol documentation - Bitcoin Wiki
以下のgistがソースコード。 ライブラリとかすでにありそうだけど、何も見ずに作りました。(dnsseed-rubyは見てます。) ライセンスはdnsseedと同じにしようと思います。
以下、実行例。あ、ちなみにビットコインじゃなくてモナーコインで試しています。
$ go run fake-coind.go xx.xx.xx.xx version 104 more data 1 [1] /Satoshi:0.10.2.2/ 70003 692751 verack 0 alert 165 ping 8 inv 37 1 1 inv 37 1 1 inv 37 1 2 62804b60c5242c9882db6d28a83e0bb87be220d38dee863361edb6ffe890f09f
こんな感じでブロックのハッシュが届きます。
Insight でちゃんとあるかどうか確認するとよいと思います。
Go言語なのでコンパイルすればWindowsでも動くと思います。 試していませんが。
次は実際にブロックをダウンロードできるようにして、さらに並列ダウンロードに対応して bootstrap.dat の高速生成なんかができたらいいなぁと妄想しています。
最終的には electrum-server のお供にできるようにしたいです。
ビットコインピアと直接通信してみたい
タイトルでビットコインピアと直接通信してみたいと書いてみましたが、実はすでにアルトコインとはDNS Seedというサービスで通信しております。
ソースはこれ。
https://github.com/ohac/dnsseed-ruby
これはdnsseedというPHPで書かれているコードをRubyに移植したものです。
ただ、これで通信しているのは以下のような流れで、ほんの少ししかコマンドを使っていないのです。
- version, verack でバージョンと最大ブロック高を送受信
- getaddr で既知のピアの情報をもらう
一方、bootstrap.datを作成するためのblockchain2torrentというのがあります。
https://github.com/ohac/blockchain2torrent
これはRPCで通信しているので、自分で立ち上げたノードとしか普通は通信できません。
これは以下のRPCコマンドを使っています。
これら3つのコマンドをRPCなしで得られれば、自分でノードを立ち上げる必要がなくなります。
ノードが信頼できるかどうか分かりませんので、なんらかの基準を設けて選定し、さらに複数ノードでベリファイするような処理が必要ですが、実験やbootstrap.datを得るためだけであればあまり慎重にならなくてもよいかもしれません。
さらにbitcoin-abeやelectrum-serverを動かすには下記RPCコマンドも必要となります。
- bitcoin-abe, electrum-serverに必要
- electrum-serverに必要
- sendrawtransaction - 送金などのbroadcastで必要
- estimatefee - feeの計算で必要
- getinfo - relayfeeも見る必要がある
ここまでサポートできたらSPVが各種コアデーモンを立ち上げずに実現できるのでうれしいかもしれません。
Ringoが使えるようになるまでにかかった時間
ようやくRingoの移行が完了しました。
Ringo等を自宅サーバに移す準備をしているのですが、ブロックが500毎に長時間一時停止してしまい、なかなかダウンロードが終わりません。
このあと本日昼ぐらいにようやくキャッチアップが完了しました。
これらは以下の2つのサービスで使っています。
Ringoはブロックの生成が早いため、すでに90万ブロックに達しております。 500ブロックを5分で処理できたとすると1週間ぐらいかかってしまいます。
Monacoinの方はLitecoinの先端を移植済みでダウンロードは早いし、詰まることもなく問題はありませんでした。
定期的に更新されるbootstrap.datがあればまだましですが、あったとしても手順が増えるので使い勝手はあまりよくないです。 このようなSPVのないアルトコインは初めて使う人には難易度が高すぎるのではないかと思います。
ブロックチェインのダウンロードが500毎に一時停止してしまう問題
さくらのクラウドの無料枠が終わってしまったためRingo等を自宅サーバに移す準備をしているのですが、ブロックが500毎に長時間一時停止してしまい、なかなかダウンロードが終わりません。
あと、なぜかdnsseedを使っているとルータ内蔵のDNSサーバがハングアップしてしまうようです。
後者はringo.confにdnsseed=0を入れることで対策できました。 rinseed.sighash.infoで提供しているIPの数を減らした方がよいのかもしれません。 それにしても脆弱なルータです。
で、前者ですが、grep -w 500でソースを検索してみると main.cpp と main.h に関係してそうなコードがありました。 両方とも変えて試しましたが、状況は変わらず。おそらく送信側に制限がついているのではないかという気がしてきた。
とりあえず定期的にストップ、再開するようにしてお茶を濁した。
$ while [ 1 ]; do ringod stop; sleep 30; ringod; sleep 600; done
Electrumでコールドウォレットを試してみた
まだBitcoin Coreが比較的軽かった頃、いくつかウォレットを作っていましたが、もう最近ではリソースを食いすぎて、全く使わなくなってしまいました。
しかし、ちゃんと取り出せるようにしておきたいので、紙に書き出しておいたプライベートキーからElectrumのコールドウォレットに取り込んで、送信トランザクションの作成と署名ができるかどうか試してみました。
ただ、完全にネットから切り離されたPCを準備するのは大変なので、Dockerでネットアクセスできないコンテナを作成して実験することにしました。
まずはDockerでElectrumをビルドして、イメージを作成。次に実行するのですが、このときに --net=none を付けてネットワークが使えないようにしたいところですが、どうもElectrumはネットワークへの接続を前提にしているようですのでこのオプションは付けないで実行します。
(追記: restoreのときに-o(オフライン)オプションを付けるとよいみたいです。ただし、この場合はその後のpaytoでエラーとなるため、公式ドキュメントに書かれているようにウォッチオンリーなホットウォレットから署名なしのtxを作成し、それをオフラインウォレット側で署名するという手順が必要となるようです。)
$ docker build -t electrum . $ docker run -it --rm electrum
Electrumの最新をビルドするようになっていますが、本当はちゃんとタグの付いたやつをビルドすべきです。 今はテストなのでこのまま進みます。
最初はネットワークにつないでヘッダを取っておきます。
root@xxx:~/electrum# electrum daemon start
同期するまで少し時間がかかります。 ~/blockchain_headers のサイズでも監視しながら待ちましょう。
root@xxx:~/electrum# ls -l ~/.electrum/ total 2284 -rw-r--r-- 1 root root 2326528 Jun 4 13:37 blockchain_headers
2016/06/04の時点で32MBぐらいでした。結構でかいです。
同期が完了したら、daemonを停止しておきます。
(追記: 停止してもrestore時に開始してしまうので意味がないようです。)
root@xxx:~/electrum# electrum daemon status { "auto_connect": true, "blockchain_height": 400043, "connected": true, ... "server_height": 414752,
ここで5で始まるプライベートキーを取り込みます。
root@xxx:~/electrum# ./electrum restore -w coldwallet : Enter argument (will not echo): Password (hit return if you do not wish to encrypt your wallet): Recovering wallet... Recovery successful Wallet saved in '/root/electrum/coldwallet'
プライベートキーはタイピングかコピペになると思いますが、キーロガーやクリップボードを盗むようなソフトが入っているとまずいので多少フェイクを入れながら入力するとよいかもしれません。まあ、そもそもそういうコンピュータを使っている時点でやばそうですが。
マルウェアじゃなくてもクリップボードをいろいろと監視するソフトなどが入っているとそこからセキュリティホールができちゃうかもしれませんので、切っておいた方がよいです。Ubuntuの場合はfcitxのデフォルトでそういうのが入っているので注意しましょう。
完了したら、パブリックアドレスと残高を確認してみましょう。
root@xxx:~/electrum# electrum listaddresses -w coldwallet -b [ "1xxxx, 1.2345..." ]
送信リクエストの発行と署名を行います。
root@xxx:~/electrum# electrum payto -w coldwallet -f 0.00002 1xxxx... 0.0001 { "complete": true, "final": false, "hex": "010...
最後にhexの右のクォートの中をオンラインウォレットでbroadcastすればよいようです。
送信は過去にLitecoinで試したので、これでいけるはずですが、まだ試していません。
まあ、なんにせよプライベートキーからパブリックキーと残高がちゃんと確認できたら一安心ですね。
a-ads.comの成果
最近、なかなかやる気が出なくて全然記事を書いてませんでした。
3箇所に貼り付けているa-ads.comの成果ですが、トータルで0.00083950Ƀの入金がありました。
50円ぐらいですね。まあ、ないよりはましですね。
JACKで自動的に接続するツールをGo言語で作ってみた
JACKは色々なことができて便利なのですが、PulseAudioと比べると準備に色々と手間がかかって面倒なことがあります。
面倒なことをできるだけ減らしたいので、まずは新たなポートが見つかるとjack_mixerへ自動的に接続してくれるツールを作ってみました。
audio-tools/main.go at master · ohac/audio-tools · GitHub
まだ、マッチングの処理が賢くないので、改善していく必要がありますが、とりあえずはメトロノームのjack_metro --bpm 90を立ち上げると自動でjack_mixer:metro(モノラルチャンネル)につながるところまではできました。
WindowsでJACKを使っている人はあまりいないと思いますが、これはLinuxでしか動作確認していません。
ハマったところはコールバック内でconnectはできないことと、chanがうまく使えなかったところです。 とりあえず1秒間隔のポーリングにしていますが、シングルタスク用のキューみたいなやつに置き換えたいです。