Command Line and JSON-RPC

Satoshi Nakamoto February 23, 2010 22:15 UTC Source ·

Version 0.2.6 on SVN can now run as a daemon and be controlled by command line or JSON-RPC.

On Linux it needs libgtk2.0-0 installed, but does not need a GUI running.  Hopefully gtk can be installed without having a windowing system installed.

The command to start as a daemon is: bitcoin -daemon [switches…]

Or, to run the UI normally and also be able to control it from command line or JSON-RPC, use the “-server” switch. bitcoin -server [switches…]

With either switch, it runs an HTTP JSON-RPC server that accepts local socket connections on 127.0.0.1:8332.  The port is bound to loopback and can only be accessed from the local machine, but from any account, not just the user it’s running under.

To control it from the command line, the interface is a command name without any switches, followed by parameters if any. bitcoin [params…]

For example:

bitcoin getinfo
bitcoin getdifficulty
bitcoin setgenerate true
bitcoin stop

It’s a simple JSON-RPC client and prints the JSON result.  Look at rpc.cpp for the list of commands.

Web apps or anything automated will normally use JSON-RPC directly, not command line.  There are JSON-RPC libraries for all the major languages.  In script languages like PHP and Python the syntax is as natural as calling a local function.

The Madhatter February 24, 2010 02:29 UTC Source ·

Oh thank you!

You have no idea how badly I needed something like this.

I will have a payment library built in no time. 😄

theymos February 24, 2010 03:07 UTC Source ·
Quote from: satoshi on February 23, 2010, 1:15:41 PM UTC

On Linux it needs libgtk2.0-0 installed

Will this requirement be removed sometime? I’d rather not have to deal with GTK.

Martti Malmi (sirius) February 24, 2010 03:18 UTC Source ·

Gtk is required by the GUI, so it must be linked if you want to use the same binary. Making a separate binary is another option, dunno how much code tweaking and ifdeffing that would take.

The Madhatter February 24, 2010 05:00 UTC Source ·
  • madhatter2 pulls out razor sharp hex editor
Satoshi Nakamoto February 24, 2010 06:17 UTC Source ·
Quote from: theymos on February 23, 2010, 6:07:37 PM UTC
Quote from: satoshi on February 23, 2010, 1:15:41 PM UTC

On Linux it needs libgtk2.0-0 installed

Will this requirement be removed sometime? I’d rather not have to deal with GTK.

How much “dealing with” does GTK actually require?  Is it just a matter of “sudo apt-get install libgtk2.0-0” and having some extra libraries sitting around?  GTK doesn’t have to do anything, just be there for bitcoin to link to when it loads up, have the gtk-init-check call fail because no GUI present, then it’s done. 

It saves us butchering everything with ifdefs and a separate compile and binary to use wxBase just to try to avoid linking GTK.

The Madhatter February 24, 2010 06:38 UTC Source ·

*NIX peoples are “purists” of sorts. They don’t like to pollute their OS installs with libraries that shouldn’t be necessary.

A million ifdefs are not the answer either. Hmm.. more thought to this may be required.

Quote from: satoshi on February 24, 2010, 6:17:23 AM UTC
Quote from: theymos on February 24, 2010, 3:07:37 AM UTC
Quote from: satoshi on February 23, 2010, 10:15:41 PM UTC

On Linux it needs libgtk2.0-0 installed

Will this requirement be removed sometime? I’d rather not have to deal with GTK.

How much “dealing with” does GTK actually require? Is it just a matter of “sudo apt-get install libgtk2.0-0” and having some extra libraries sitting around? GTK doesn’t have to do anything, just be there for bitcoin to link to when it loads up, have the gtk-init-check call fail because no GUI present, then it’s done.

It saves us butchering everything with ifdefs and a separate compile and binary to use wxBase just to try to avoid linking GTK.

theymos February 24, 2010 06:51 UTC Source ·

I’m using Linux From Scratch, so installing a dependency-ridden package like GTK would be a bit of a pain. Why should I add a dozen additional packages and hundreds of megabytes to my system when BitCoin doesn’t even use them?

The Madhatter February 24, 2010 07:56 UTC Source ·

Why would you install them? Because you currently have to. I know the feeling. I run minimalist FreeBSD servers and to clutter them with X libraries is a pain.

However, installing them onto a X workstation is totally fine — you usually have all of the correct dependancies already. 😛

Martti Malmi (sirius) February 24, 2010 18:17 UTC Source ·

This is strange… When I start Bitcoin as a daemon on my 64 bit Linux server, it eats up all the 250MB of remaining RAM, 700MB of swap and eventually crashes. On my 32 bit Ubuntu desktop, it works fine and stays at 15MB of memory usage. The server is running a 64 bit build of Bitcoin. Maybe there’s something wrong with the build or something.

Satoshi Nakamoto February 24, 2010 22:08 UTC Source ·

When and how fast did memory usage increase?  Right away, slowly over a long time, or starting at some later event?

I have -daemon running on ubuntu 9.10 64-bit and memory usage is steady.

It has to be something about the difference on the server besides 64-bit.  Maybe some malfunction from the lack of GUI.  A memory leak debug tool could give a clue.

Martti Malmi (sirius) February 25, 2010 16:32 UTC Source ·

It started increasing right away. I’ll see if valgrind can help me.

Satoshi Nakamoto February 25, 2010 22:54 UTC Source ·

OK, I made a build target bitcoind that only links wxBase and does not link GTK.  Version 0.2.7 on SVN.

I split out the init and shutdown stuff from ui.cpp into init.cpp, so now ui.cpp is pure UI.  ui.h provides inline stubs if wxUSE_GUI=0.  We only have four functions that interface from the node to the UI.  In the bitcoind build, we don’t link ui.o or uibase.o.

Quote from: sirius-m on February 25, 2010, 7:32:17 AM UTC

It started increasing right away. I’ll see if valgrind can help me.

Sure feels like it could be something in wxWidgets retrying endlessly because some UI thing failed or something wasn’t inited correctly.  Our hack to ignore the initialize failure and run anyway means we’re in uncharted territory.  We’re relying on the fact that we hardly use wx in this mode.  We do still use a few things like wxGetTranslation and wxMutex.

Another way to debug would be to run in gdb, wait until everything is quiet and all threads should be idle, and break it and see which thread is busily doing something and what it’s doing.

I suspect bitcoind will probably work fine, but I hope you can still debug the problem.

theymos February 26, 2010 09:18 UTC Source ·

I’m getting errors when trying to compile with just 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 isn’t installed with wxBase. Moving wxWidgets-2.9.0/include/wx/clipbrd.h to my include directory just eliminates those two “no such file” lines.

Satoshi Nakamoto February 26, 2010 16:29 UTC Source ·

wx/clipbrd.h isn’t used, move it inside the #if wxUSE_GUI.

Updated headers.h on SVN.

Sorry, I linked to wxbase but I had full wxWidgets on my computer.

The db.h:140 class Db no member named “exisits” is stranger.  pdb->get, pdb->put, pdb->del compiled before that.  Do you have version 4.7.25 of Berkeley DB?

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

I suppose they might have added exists recently, using get before that.

theymos February 26, 2010 16:58 UTC Source ·

I’m using Berkeley DB 4.5.20.

theymos February 26, 2010 19:37 UTC Source ·

Using DB-4.7.25 fixed that problem.

I’m now getting this error, though:

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
Satoshi Nakamoto February 26, 2010 23:48 UTC Source ·

Are you using wxWidgets 2.9.0?  I don’t recommend using anything other than 2.9.0.

It looks like they’ve got a reference in the wx headers (arrstr.h) to something outside of wxBase.

Removing -D__WXDEBUG__ from bitcoin’s makefile would probably solve it.

If that doesn’t work and you just want to get it working, you could edit wxWidgets include/wx/arrstr.h, line 167 and comment out the wxASSERT_MSG.

Cdecker February 27, 2010 03:21 UTC Source ·

The headless mode is incredibly usefull. Finally I can start generating on my servers in the night 😁

theymos February 27, 2010 07:18 UTC Source ·

Cool; it works! 😁 Thanks for your help!

I am using 2.9.0.

(No memory issues for me.)

The Madhatter March 2, 2010 15:46 UTC Source ·

That wchar thing was what I was stuck on for the OSX build. 😁

Glad to see it is ironed out. I’ll keep hacking away now.

Satoshi Nakamoto March 5, 2010 01:46 UTC Source ·
Quote from: sirius-m on February 24, 2010, 9:17:35 AM UTC

This is strange… When I start Bitcoin as a daemon on my 64 bit Linux server, it eats up all the 250MB of remaining RAM, 700MB of swap and eventually crashes. On my 32 bit Ubuntu desktop, it works fine and stays at 15MB of memory usage. The server is running a 64 bit build of Bitcoin. Maybe there’s something wrong with the build or something.

sirius-m debugged this, it was 64-bit related. 

The fix is now available on SVN, file util.cpp.

dwdollar April 6, 2010 07:07 UTC Source ·

Here is code for a simple Python API. Each method connects to the server, sends a request, gets a response, then returns a Python dictionary equivalent of the JSON. It uses standard Python modules. No error checking is done and only three functions from rpc.cpp are implemented. If there’s interest I can write more.

To use it, the Python code should be something like… access = BitcoinAPI() access.getInfo() access.getAmountReceived(“1JyEmxiMso2RsFVfBcCa616npBvGgxiBX”) access.sendToAddress(“1JyEmxiMso2RsFVfBcCa616npBvGgxiBX”, 100.00) # Send 100 Bitcoins to my Address 😁

This will be the base for automatic transactions on my site. If there are any questions or concerns let me know. If there is something severely wrong, feel free to school me.

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
Sirius (sirius) April 6, 2010 22:06 UTC Source ·
Quote from: dwdollar on April 06, 2010, 7:07:05 AM UTC

Here is code for a simple Python API. Each method connects to the server, sends a request, gets a response, then returns a Python dictionary equivalent of the JSON. It uses standard Python modules. No error checking is done and only three functions from rpc.cpp are implemented. If there’s interest I can write more.

Well, you could just install python-json-rpc (http://json-rpc.org/wiki/python-json-rpc) and do:

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

Returns a python dict. It’s that easy 😉

dwdollar April 6, 2010 22:58 UTC Source ·
Quote from: sirius-m on April 06, 2010, 10:06:57 PM UTC

Well, you could just install python-json-rpc (http://json-rpc.org/wiki/python-json-rpc) and do:

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

Returns a python dict. It’s that easy

D***, haha… Well… at least I got sirius-m to share some of his mojo. 😛

I’ll check it out.

krepta3000 June 26, 2011 14:47 UTC Source ·
Quote from: satoshi on February 23, 2010, 10:15:41 PM UTC

Look at rpc.cpp for the list of commands.

Seriously? So, everyone knows C++ but me? I don’t understand where this list of commands is in this file. sigh I have tried to understand C++ for years, things just are not clicking in my head for some reason. Do you mean this stuff?

        //
        // 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]);

Well, there are comments throughout, so that’s good, I really get annoyed by spaghetti code.

galaxyAbstractor June 27, 2011 12:16 UTC Source ·
Quote from: krepta3000 on June 26, 2011, 2:47:21 PM UTC
Quote from: satoshi on February 23, 2010, 10:15:41 PM UTC

Look at rpc.cpp for the list of commands.

Seriously? So, everyone knows C++ but me? I don’t understand where this list of commands is in this file. sigh I have tried to understand C++ for years, things just are not clicking in my head for some reason. Do you mean this stuff? 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]);

Well, there are comments throughout, so that’s good, I really get annoyed by spaghetti code.

Are you looking for this list? https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list