コマンドラインと JSON-RPC

SVN 上のバージョン 0.2.6 はデーモンとして実行でき、コマンドラインまたは JSON-RPC で制御できるようになった。

Linux では libgtk2.0-0 がインストールされている必要があるが、GUI が実行されている必要はない。うまくいけば、ウィンドウシステムがインストールされていなくても GTK をインストールできるだろう。

デーモンとして起動するコマンド: bitcoin -daemon [スイッチ…]

または、通常通り UI を実行しつつコマンドラインや JSON-RPC からも制御可能にするには、-server スイッチを使用する。 bitcoin -server [スイッチ…]

どちらのスイッチでも、127.0.0.1:8332 でローカルソケット接続を受け付ける HTTP JSON-RPC サーバーが実行される。ポートはループバックにバインドされ、ローカルマシンからのみアクセスできるが、実行中のユーザーだけでなくどのアカウントからでもアクセスできる。

コマンドラインから制御するには、インターフェースはスイッチなしのコマンド名の後にパラメーター(ある場合)を続ける。 bitcoin <コマンド> [パラメーター…]

例: bitcoin getinfo
bitcoin getdifficulty
bitcoin setgenerate true
bitcoin stop

これはシンプルな JSON-RPC クライアントで、JSON の結果を表示する。コマンドのリストは rpc.cpp を参照してほしい。

Web アプリや自動化されたものは通常、コマンドラインではなく JSON-RPC を直接使用する。すべての主要言語に JSON-RPC ライブラリがある。PHP や Python のようなスクリプト言語では、構文はローカル関数を呼び出すのと同じくらい自然だ。

The Madhatter 2010年2月24日 02:29 UTC 原文 ·

ああ、ありがとう!

これがどれほど必要だったか、君には想像もつかないだろう。

すぐに支払いライブラリを作り上げてみせる。 😄

theymos 2010年2月24日 03:07 UTC 原文 ·
サトシ・ナカモトの投稿(2010年2月23日 13:15 UTC)

SVN上のバージョン0.2.6はデーモンとして実行でき、コマンドラインまたはJSON-RPCで制御できるようになった。

この要件はいずれ撤廃されるのか? GTK を扱うのは面倒だ。

Gtk は GUI に必要なので、同じバイナリを使いたい場合はリンクしなければなりません。別のバイナリを作る方法もありますが、どの程度のコード修正や ifdef が必要かは分かりません。

The Madhatter 2010年2月24日 05:00 UTC 原文 ·
  • madhatter2 が鋭いヘックスエディターを取り出す
マイケル・マーカートの投稿(2010年2月23日 18:07 UTC)
サトシ・ナカモトの投稿(2010年2月23日 13:15 UTC)

SVN上のバージョン0.2.6はデーモンとして実行でき、コマンドラインまたはJSON-RPCで制御できるようになった。

この要件はいつか解消されますか?GTKを扱いたくないのですが。

GTK を「扱う」のに実際どれくらいの手間がかかるのだろうか?「sudo apt-get install libgtk2.0-0」をして、いくつかの余分なライブラリが置いてあるだけの問題ではないか?GTK は何もする必要はなく、ただそこにあれば Bitcoin が起動時にリンクでき、GUI がないため gtk-init-check の呼び出しが失敗して、それで終わりだ。

GTK のリンクを避けるためだけに wxBase を使用するために、すべてを ifdef で台無しにして、別のコンパイルとバイナリを用意するよりマシだ。

The Madhatter 2010年2月24日 06:38 UTC 原文 ·

*NIX 系の人々はある種の「ピューリスト」だ。本来必要のないライブラリで OS のインストールを汚されたくないのだ。

何百万もの ifdef も答えではない。うーん…これにはもう少し考察が必要かもしれない。

サトシ・ナカモトの投稿(2010年2月24日 06:17 UTC)
マイケル・マーカートの投稿(2010年2月24日 03:07 UTC)
サトシ・ナカモトの投稿(2010年2月23日 22:15 UTC)

Linuxではlibgtk2.0-0のインストールが必要だ

この要件はいずれ取り除かれますか? GTKを相手にしたくないので。

GTKを「相手にする」のに、実際どれだけ手間がかかるのか? 「sudo apt-get install libgtk2.0-0」を実行して、ライブラリがいくつか余分に置かれるだけではないのか? GTKは何かをする必要はない、bitcoinが起動時にリンクするためにそこに在りさえすればいい。GUIがないのでgtk-init-check呼び出しが失敗する、それで終わりだ。

こうすれば、GTKのリンクを避けるためだけにifdefだらけにし、wxBaseを使う別個のコンパイルとバイナリを用意する、という形で全体を切り刻まずに済む。

theymos 2010年2月24日 06:51 UTC 原文 ·

Linux From Scratch を使っているので、GTK のような依存関係だらけのパッケージをインストールするのはかなり面倒だ。BitCoin が使わないのに、なぜ十数個のパッケージと数百メガバイトをシステムに追加しなければならないのか?

The Madhatter 2010年2月24日 07:56 UTC 原文 ·

なぜインストールするかって? 今のところそうしなければならないからだ。その気持ちは分かる。俺はミニマリストの FreeBSD サーバーを運用しているが、X ライブラリでごちゃごちゃにするのは面倒だ。

しかし、X ワークステーションにインストールするのはまったく問題ない。通常、正しい依存関係がすでに揃っているからだ。😛

これはおかしいですね…64 ビット Linux サーバーで Bitcoin をデーモンとして起動すると、残りの 250MB の RAM と 700MB のスワップをすべて食い尽くして、最終的にクラッシュします。32 ビットの Ubuntu デスクトップでは問題なく動作し、メモリー使用量は 15MB に留まります。サーバーでは 64 ビットビルドの Bitcoin を実行しています。ビルドに何か問題があるのかもしれません。

メモリー使用量はいつ、どのくらいの速さで増加したか?すぐに、長時間かけてゆっくりと、それとも何かの後のイベントから始まったか?

Ubuntu 9.10 64 ビットで -daemon を実行しており、メモリー使用量は安定している。

サーバーでの違いは 64 ビット以外に何かあるはずだ。GUI がないことによる何らかの不具合かもしれない。メモリーリークのデバッグツールが手がかりを与えてくれるかもしれない。

すぐに増加し始めました。valgrind で調べてみます。

OK、wxBase のみをリンクし GTK をリンクしないビルドターゲット bitcoind を作成した。SVN 上のバージョン 0.2.7 だ。

ui.cpp から初期化とシャットダウンの処理を init.cpp に分離したので、ui.cpp は純粋な UI のみになった。ui.h は wxUSE_GUI=0 の場合にインラインスタブを提供する。ノードから UI へのインターフェース関数は 4 つだけだ。bitcoind ビルドでは、ui.o や uibase.o はリンクしない。

マルッティ・マルミの投稿(2010年2月25日 07:32 UTC)

すぐに増加し始めました。valgrindで調べてみます。

何か UI の処理が失敗したか、正しく初期化されなかったために、wxWidgets 内で無限にリトライしているような感じがする。初期化失敗を無視して実行を続けるハックは、未知の領域に入ることを意味する。このモードでは wx をほとんど使用しないという事実に頼っている。wxGetTranslation や wxMutex など、いくつかは引き続き使用している。

別のデバッグ方法として、gdb で実行し、すべてが静かになりすべてのスレッドがアイドルになるのを待ち、ブレークして、どのスレッドが忙しく何かをしているか、何をしているかを確認する方法がある。

bitcoind はおそらく問題なく動作すると思うが、問題のデバッグをしてもらえると助かる。

theymos 2010年2月26日 09:18 UTC 原文 ·

wxBase だけでコンパイルしようとするとエラーが出る。

g++ -c -O0 -Wno-invalid-offsetof -Wformat -g -D__WXDEBUG__ -D__WXGTK__ -DNOPCH -I"/opt/tdep/include" -I"/usr/include" -DwxUSE_GUI=0 -o obj/nogui/util.o util.cpp
In file included from util.cpp:5:
headers.h:22:24: error: wx/clipbrd.h: No such file or directory
In file included from headers.h:100,
                 from util.cpp:5:
db.h: In member function 'bool CDB::Exists(const K&)':
db.h:140: error: 'class Db' has no member named 'exists'
make: *** [obj/nogui/util.o] Error 1

clipbrd.h は wxBase にはインストールされない。wxWidgets-2.9.0/include/wx/clipbrd.h を include ディレクトリに移動しても、「no such file」の 2 行が消えるだけだ。

wx/clipbrd.h は使用されていないので、#if wxUSE_GUI の中に移動してほしい。

SVN の headers.h を更新した。

すまない、wxbase にリンクしたが、コンピューターにはフルの wxWidgets があった。

db.h:140 のクラス Db にメンバー「exisits」がないというのは変だ。pdb->get、pdb->put、pdb->del はその前にコンパイルできていた。Berkeley DB のバージョン 4.7.25 を使っているか?

Db::exists() http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/CXX/frame_main.html http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/CXX/dbexists.html

おそらく最近 exists が追加されたのかもしれない。それ以前は get を使用していたのだろう。

theymos 2010年2月26日 16:58 UTC 原文 ·

Berkeley DB 4.5.20 を使っている。

theymos 2010年2月26日 19:37 UTC 原文 ·

DB-4.7.25 を使ったらその問題は解決した。

しかし、今度はこのエラーが出ている:

g++ -O0 -Wno-invalid-offsetof -Wformat -g -D__WXDEBUG__ -D__WXGTK__ -DNOPCH -I"/usr/include" -I"/opt/tdep/include" -o bitcoind -L"/usr/lib" -L"/usr/local/lib" -L"/opt/tdep/lib" obj/nogui/util.o obj/nogui/script.o obj/nogui/db.o obj/nogui/net.o obj/nogui/irc.o obj/nogui/main.o obj/nogui/rpc.o obj/nogui/init.o obj/sha.o -l wx_baseu-2.9 -Wl,-Bstatic -l boost_system -l boost_filesystem -l db_cxx -Wl,-Bdynamic -l crypto -l gthread-2.0
obj/nogui/init.o: In function `wxArrayString::Item(unsigned int) const':
init.cpp:(.text._ZNK13wxArrayString4ItemEj[wxArrayString::Item(unsigned int) const]+0x7): undefined reference to `wxTheAssertHandler'
init.cpp:(.text._ZNK13wxArrayString4ItemEj[wxArrayString::Item(unsigned int) const]+0x42): undefined reference to `wxOnAssert(char const*, int, char const*, char const*, wchar_t const*)'
collect2: ld returned 1 exit status
make: *** [bitcoind] Error 1

wxWidgets 2.9.0 を使用しているか?2.9.0 以外の使用は推奨しない。

wx ヘッダー(arrstr.h)に wxBase 外の何かへの参照があるようだ。

Bitcoin の makefile から D__WXDEBUG__を削除すれば、おそらく解決するだろう。

それでも動作せず、とにかく動かしたい場合は、wxWidgets の include/wx/arrstr.h、167 行目を編集して wxASSERT_MSG をコメントアウトすることができる。

Cdecker 2010年2月27日 03:21 UTC 原文 ·

ヘッドレスモードは非常に便利だ。ようやく夜間にサーバーで生成を始められる。😁

theymos 2010年2月27日 07:18 UTC 原文 ·

いいね、動いた! 😁 助けてくれてありがとう!

こちらは 2.9.0 を使っている。

(自分の方ではメモリーの問題はない。)

The Madhatter 2010年3月2日 15:46 UTC 原文 ·

あの wchar の問題は、俺が OSX ビルドで行き詰まっていた部分だ。😁

解決されたのを見てうれしい。引き続きハックしていこう。

マルッティ・マルミの投稿(2010年2月24日 09:17 UTC)

これはおかしいですね…64ビットLinuxサーバーでBitcoinをデーモンとして起動すると、残りの250MBのRAMと700MBのスワップをすべて食い尽くして、最終的にクラッシュします。32ビットのUbuntuデスクトップでは問題なく動作し、メモリー使用量は15MBに留まります。サーバーでは64ビットビルドのBitcoinを実行しています。ビルドに何か問題があるのかもしれません。

sirius-m がこれをデバッグした。64 ビット関連の問題だった。

修正は SVN の util.cpp ファイルで利用可能になった。

dwdollar 2010年4月6日 07:07 UTC 原文 ·

シンプルな Python API のコードを置いておく。各メソッドはサーバーに接続し、リクエストを送り、レスポンスを受け取って、JSON に相当する Python の辞書を返す。標準の Python モジュールしか使っていない。エラーチェックは一切しておらず、rpc.cpp からは 3 つの関数しか実装していない。需要があればもっと書くこともできる。

使い方としては、Python のコードはこんな感じになる… access = BitcoinAPI() access.getInfo() access.getAmountReceived(“1JyEmxiMso2RsFVfBcCa616npBvGgxiBX”) access.sendToAddress(“1JyEmxiMso2RsFVfBcCa616npBvGgxiBX”, 100.00) # 自分のアドレスに 100 ビットコイン送る 😁

これが自分のサイトでの自動トランザクションの土台になる。何か質問や懸念があれば言ってくれ。ひどく間違っている点があれば、遠慮なく教えてくれ。

import httplib, simplejson

class BitcoinAPI(object):

    def __init__(self, host = "127.0.0.1", port = 8332, timeout = 3):
        self.host = host
        self.port = port
        self.timeout = timeout
        self.httpHeader = {"Content-type": "application/json"}    # I don't know what needs to be in the header, but this works
        return

    def connect(self):
        self.connection = httplib.HTTPConnection(self.host, self.port, timeout = self.timeout)
        return

    def disconnect(self):
        self.connection.close()
        return

    # Functions return a python dictionary which should be equivalent to the JSON syntax received from the server
    # ident or "id" is a constant 1, but can be overridden when calling.  E.g. getAmountReceived(address, ident = 23)
    def getInfo(self, ident = 1):
        self.connect()
        params = simplejson.dumps({"method": "getinfo", "params": ], "id": ident})
        self.connection.request("POST", "/", params, self.httpHeader)
        response = self.connection.getresponse()
        #print response.status, response.reason    # Use for troubleshooting
        dictionary = simplejson.loads(response.read())
        self.disconnect()
        return dictionary

    def getAmountReceived(self, address, ident = 1):
        self.connect()
        params = simplejson.dumps({"method": "getamountreceived", "params": [address], "id": ident})
        self.connection.request("POST", "/", params, self.httpHeader)
        response = self.connection.getresponse()
        #print response.status, response.reason    # Use for troubleshooting
        dictionary = simplejson.loads(response.read())
        self.disconnect()
        return dictionary

    def sendToAddress(self, address, amount, ident = 1):
        self.connect()
        params = simplejson.dumps({"method": "sendtoaddress", "params": [address, amount], "id": ident})
        self.connection.request("POST", "/", params, self.httpHeader)
        response = self.connection.getresponse()
        #print response.status, response.reason    # Use for troubleshooting
        dictionary = simplejson.loads(response.read())
        self.disconnect()
        return dictionary
dwdollarの投稿(2010年4月6日 07:07 UTC)

シンプルな Python API のコードを置いておく。各メソッドはサーバーに接続し、リクエストを送り、レスポンスを受け取って、JSON に相当する Python の辞書を返す。標準の Python モジュールしか使っていない。エラーチェックは一切しておらず、rpc.cpp からは 3 つの関数しか実装していない。需要があればもっと書くこともできる。

いやまあ、python-json-rpc (http://json-rpc.org/wiki/python-json-rpc) をインストールしてこうするだけでもいいですよ:

from jsonrpc import ServiceProxy
s = ServiceProxy("http://127.0.0.1:8332")
s.getinfo()

python の辞書を返します。それくらい簡単ですよ 😉

dwdollar 2010年4月6日 22:58 UTC 原文 ·
マルッティ・マルミの投稿(2010年4月6日 22:06 UTC)

いやまあ、python-json-rpc (http://json-rpc.org/wiki/python-json-rpc) をインストールしてこうするだけでもいいですよ:

Code:from jsonrpc import ServiceProxy s = ServiceProxy(“http://127.0.0.1:8332”) s.getinfo()

pythonの辞書を返します。それくらい簡単です

くそ、はは…まあ…少なくとも sirius-m の秘伝の一端を引き出せたわけだ。 😛

それを試してみる。

krepta3000 2011年6月26日 14:47 UTC 原文 ·
サトシ・ナカモトの投稿(2010年2月23日 22:15 UTC)

コマンドの一覧はrpc.cppを見てくれ。

本気か? つまり、自分以外みんな C++が分かるってことか? このファイルのどこにコマンド一覧があるのか分からない。ため息 何年も C++を理解しようとしてきたが、どういうわけか頭にまるで入ってこない。あんたが言っているのはこれのことか?

        //
        // Special case non-string parameter types
        //
        if (strMethod == "setgenerate"            && n > 0) ConvertTo<bool>(params[0]);
        if (strMethod == "setgenerate"            && n > 1) ConvertTo<boost::int64_t>(params[1]);
        if (strMethod == "sendtoaddress"          && n > 1) ConvertTo<double>(params[1]);
        if (strMethod == "settxfee"               && n > 0) ConvertTo<double>(params[0]);
        if (strMethod == "getamountreceived"      && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
        if (strMethod == "getreceivedbyaddress"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
        if (strMethod == "getreceivedbyaccount"   && n > 1) ConvertTo<boost::int64_t>(params[1]);
        if (strMethod == "getreceivedbylabel"     && n > 1) ConvertTo<boost::int64_t>(params[1]); // deprecated
        if (strMethod == "getallreceived"         && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
        if (strMethod == "getallreceived"         && n > 1) ConvertTo<bool>(params[1]);
        if (strMethod == "listreceivedbyaddress"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
        if (strMethod == "listreceivedbyaddress"  && n > 1) ConvertTo<bool>(params[1]);
        if (strMethod == "listreceivedbyaccount"  && n > 0) ConvertTo<boost::int64_t>(params[0]);
        if (strMethod == "listreceivedbyaccount"  && n > 1) ConvertTo<bool>(params[1]);
        if (strMethod == "listreceivedbylabel"    && n > 0) ConvertTo<boost::int64_t>(params[0]); // deprecated
        if (strMethod == "listreceivedbylabel"    && n > 1) ConvertTo<bool>(params[1]); // deprecated
        if (strMethod == "getbalance"             && n > 1) ConvertTo<boost::int64_t>(params[1]);
        if (strMethod == "move"                   && n > 2) ConvertTo<double>(params[2]);
        if (strMethod == "move"                   && n > 3) ConvertTo<boost::int64_t>(params[3]);
        if (strMethod == "sendfrom"               && n > 2) ConvertTo<double>(params[2]);
        if (strMethod == "sendfrom"               && n > 3) ConvertTo<boost::int64_t>(params[3]);
        if (strMethod == "listtransactions"       && n > 1) ConvertTo<boost::int64_t>(params[1]);
        if (strMethod == "listtransactions"       && n > 2) ConvertTo<boost::int64_t>(params[2]);
        if (strMethod == "listaccounts"           && n > 0) ConvertTo<boost::int64_t>(params[0]);
        if (strMethod == "sendmany"               && n > 1)
        {
            string s = params[1].get_str();
            Value v;
            if (!read_string(s, v) || v.type() != obj_type)
                throw runtime_error("type mismatch");
            params[1] = v.get_obj();
        }
        if (strMethod == "sendmany"                && n > 2) ConvertTo<boost::int64_t>(params[2]);

まあ、全体にコメントが付いているのは良いことだ。スパゲッティコードは本当にうんざりするからな。

galaxyAbstractor 2011年6月27日 12:16 UTC 原文 ·
krepta3000の投稿(2011年6月26日 14:47 UTC)
サトシ・ナカモトの投稿(2010年2月23日 22:15 UTC)

コマンドの一覧はrpc.cppを見てくれ。

本気か? つまり、自分以外みんなC++が分かるってことか? このファイルのどこにコマンド一覧があるのか分からない。ため息 何年もC++を理解しようとしてきたが、どういうわけか頭にまるで入ってこない。あんたが言っているのはこれのことか? Code: // // Special case non-string parameter types // if (strMethod == “setgenerate” && n > 0) ConvertTo(params[0]); if (strMethod == “setgenerate” && n > 1) ConvertTo(params[1]); if (strMethod == “sendtoaddress” && n > 1) ConvertTo(params[1]); if (strMethod == “settxfee” && n > 0) ConvertTo(params[0]); if (strMethod == “getamountreceived” && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == “getreceivedbyaddress” && n > 1) ConvertTo(params[1]); if (strMethod == “getreceivedbyaccount” && n > 1) ConvertTo(params[1]); if (strMethod == “getreceivedbylabel” && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == “getallreceived” && n > 0) ConvertTo(params[0]); // deprecated if (strMethod == “getallreceived” && n > 1) ConvertTo(params[1]); if (strMethod == “listreceivedbyaddress” && n > 0) ConvertTo(params[0]); if (strMethod == “listreceivedbyaddress” && n > 1) ConvertTo(params[1]); if (strMethod == “listreceivedbyaccount” && n > 0) ConvertTo(params[0]); if (strMethod == “listreceivedbyaccount” && n > 1) ConvertTo(params[1]); if (strMethod == “listreceivedbylabel” && n > 0) ConvertTo(params[0]); // deprecated if (strMethod == “listreceivedbylabel” && n > 1) ConvertTo(params[1]); // deprecated if (strMethod == “getbalance” && n > 1) ConvertTo(params[1]); if (strMethod == “move” && n > 2) ConvertTo(params[2]); if (strMethod == “move” && n > 3) ConvertTo(params[3]); if (strMethod == “sendfrom” && n > 2) ConvertTo(params[2]); if (strMethod == “sendfrom” && n > 3) ConvertTo(params[3]); if (strMethod == “listtransactions” && n > 1) ConvertTo(params[1]); if (strMethod == “listtransactions” && n > 2) ConvertTo(params[2]); if (strMethod == “listaccounts” && n > 0) ConvertTo(params[0]); if (strMethod == “sendmany” && n > 1) { string s = params[1].get_str(); Value v; if (!read_string(s, v) || v.type() != obj_type) throw runtime_error(“type mismatch”); params[1] = v.get_obj(); } if (strMethod == “sendmany” && n > 2) ConvertTo(params[2]);

まあ、全体にコメントが付いているのは良いことだ。スパゲッティコードは本当にうんざりするからな。

探しているのはこの一覧か? https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list