Bitcoin JSON-RPCを叩く
Bitcoin JSON-RPCを叩く:
JavaScriptで bitcoin/bitcoin (Bitcoin core)の API を叩こうとしたとき、検索すると、いくつかの定番っぽい npm がヒットしますが、どれも古すぎてメンテナンスもされていません。
現在の Bitcoin core のバージョンは0.17ですが、0.16以前とは API 仕様に違いがあります。ウォレット関連で、いくつものAPIが deprecated になって、新しい API も新設されています。
というか、Bitcoin core の API を JSON-RPC で叩くのはアホみたいに簡単なのでわざわざライブラリ、それも古代に書かれたものを使う必要性はありません。
bitcoindのrpc用のポートにHTTP POSTを投げるだけです。
筆者の好みでrequest-promiseで書くと以下のようなコードになります。
たとえば
毎回、hostだのを書くのは大変なのでクライアントというものを作ってみます。
これだと
既存のライブラリだとクライアントのメソッドとして、
まずは、Client型の定義をします。もっともこれはTypeScriptの話なので、JavaScriptだけで生きていく決意をしている方には不要です。
ECMAScriptで定義されているProxyを使っています。Proxyオブジェクトは、メンバーへのアクセスを乗っとることができます。
あと、既存のライブラリは、キャメルケースの区切りがいまいちよくわからない感じがあってクソダルいのと、もともとBitcoin coreのJSON-RPCのmethod名は、全部小文字と決まっているので、
ちなみに
みたいなコードを書いた時に、なるようです。おそらく、resolveする時だかthenを実際に呼び出すときだかに、resolveする変数がthenableかどうかチェックしているためでしょう。きっと。
既存のライブラリのように変換テーブルを持っておくのは手ですが、それだとAPIが追加されたときにいちいちテーブルに追加する必要があります。
JavaScriptで bitcoin/bitcoin (Bitcoin core)の API を叩こうとしたとき、検索すると、いくつかの定番っぽい npm がヒットしますが、どれも古すぎてメンテナンスもされていません。
現在の Bitcoin core のバージョンは0.17ですが、0.16以前とは API 仕様に違いがあります。ウォレット関連で、いくつものAPIが deprecated になって、新しい API も新設されています。
というか、Bitcoin core の API を JSON-RPC で叩くのはアホみたいに簡単なのでわざわざライブラリ、それも古代に書かれたものを使う必要性はありません。
Bitcoin core JSON-RPC
bitcoindのrpc用のポートにHTTP POSTを投げるだけです。筆者の好みでrequest-promiseで書くと以下のようなコードになります。
const dispatch = async (host, rpcport, user, pass, method, ...params) => { const { result, error } = JSON.parse( await rp(`http://${host}:${rpcport}`, { method: 'POST', body: JSON.stringify({ method, params }), auth: { user, pass }, }).catch(e => { if (e.statusCode) { return JSON.stringify({ error: JSON.parse(e.error).error }) } else { return JSON.stringify({ error: e.error }) } }) ) }
const { result } = await dispatch('localhost', 18332, 'u', 'p', 'help')
みたいに叩くだけです。いとも簡単ですね。
接続情報を毎回返さなくてもいいようにする
毎回、hostだのを書くのは大変なのでクライアントというものを作ってみます。export const createClient = ({ host, rpcport, user, pass }) => { return async (method, ...params) => { ... } } const client = createClient(.....) client('help')
const client = createClient({host: 'localhost', ...})
でクライアントを作成し、クライアントの引数にメソッドとパラメータを渡すだけです。
メソッドを引数ではなくてメソッドとして叩けるようにする
既存のライブラリだとクライアントのメソッドとして、client.help()
とか client.getBlockchainInfo()
のようなたたき方ができるので、それを実現します。export interface Client { [method: string]: (...args) => Promise<any> }
export const createClient = ({ host, rpcport, user, pass }) => { const client: Client = new Proxy({}, { get: (target: any, method: string) => { if (method === 'then' || method === 'catch') { return target[method] // 実質 undefined } method = method.toLowerCase() return async (...params) => { // 省略 } } }) return client }
get
ハンドラを書くと、メンバー変数の読み出し、メソッドの呼び出しを制御ます。あと、既存のライブラリは、キャメルケースの区切りがいまいちよくわからない感じがあってクソダルいのと、もともとBitcoin coreのJSON-RPCのmethod名は、全部小文字と決まっているので、
.toLowerCase()
をしています。ちなみに
then
catch
を特別扱いしているのは、特定のケースでなぜかクライアント自体のthenが叩かれることがあるっぽいからです。return new Promise(resolve => { ... resolve(client) })
既存のライブラリのように変換テーブルを持っておくのは手ですが、それだとAPIが追加されたときにいちいちテーブルに追加する必要があります。
まとめ
- Bitcoin coreのJSON-RPCを叩くのにライブラリはいらん
- むしろ古すぎて弊害が大きい
- どうせ簡単
- 関数を返す関数で関数型プログラミング気分
- Proxy 便利
コメント
コメントを投稿