dinsdag 13 februari 2018

rpc call to bitcoind


Introduction

Lately, in the news you can find a lot of material about bitcoins or the technique behind it. I have been reading a lot about this the last couple of months. It made me curious howto connect to the bitcoind myself. It must be possible too connect to the daemon and get that information yourself. I know, curiousity killed the cat. But I am still alive. Lets dive into the code and see what we should do.

The example

So lets get started with the fun shall we? The surprising part is that it was less difficult then I thought it would be. Too get the right parts of all the different examples together and make it work was the hardest part.
First of all we need the bitcoind. We can install the daemon and ask if it is still alive. That is why I prefer too install bitcoin-qt. This has an interface where you can see some things like if it is running on testnet. Install it like:

sudo add-apt-repository ppa:bitcoin/bitcoin 
sudo apt-get update
sudo apt-get install bitcoin-qt
place in the ~/.bitcoin folder the file bitcoin.conf. The content should be als followed to run on testnet:
## bitcoin.conf configuration file. Lines beginning with # are comments.
### Uncomment and edit options you wish to use.

## JSON-RPC options (for controlling a running bitcoin-qt/bitcoind process)

# server=1 tells Bitcoin to accept JSON-RPC commands.
server=1

# You must set rpcuser and rpcpassword to secure the JSON-RPC api
# You should create your own new random password.
# The username and password MUST NOT be the same.

rpcuser=user
rpcpassword=password

# How many seconds bitcoin will wait for a complete RPC HTTP request
# after the HTTP connection is established.
rpctimeout=30

# By default, only RPC connections from localhost are allowed. Specify
# as many rpcallowip= settings as you like to allow connections from
# other hosts (and you may use * as a wildcard character):
#rpcallowip=10.1.1.*
#rpcallowip=192.168.1.*

# Listen for RPC connections on this TCP port:
rpcport=8332

# You can use bitcoind to send commands to bitcoin-qt/bitcoind
# running on another host using this option:
rpcconnect=127.0.0.1

# Use Secure Sockets Layer (also known as TLS or HTTPS) to communicate
# with Bitcoin -server or bitcoind
#rpcssl=1

# OpenSSL settings used when rpcssl=1
rpcsslciphers=TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH
rpcsslcertificatechainfile=server.cert
rpcsslprivatekeyfile=server.pem


## Network-related settings:

# Run on the test network instead of the real bitcoin network.
testnet=1

# Connect via a socks proxy
#proxy=127.0.0.1:9050

# Select the version of socks proxy to use (4-5, default: 5)
#socks=5

# Use proxy to reach tor hidden services (default: same as -proxy)
#tor=       

##############################################################
## Quick Primer on addnode vs connect ##
## Let's say for instance you use addnode=4.2.2.4 ##
## addnode will connect you to and tell you about the ##
## nodes connected to 4.2.2.4. In addition it will tell##
## the other nodes connected to it that you exist so ##
## they can connect to you. ##
## connect will not do the above when you 'connect' to it.##
## It will *only* connect you to 4.2.2.4 and no one else.##
## ##
## So if you're behind a firewall, or have other problems ##
## finding nodes, add some using 'addnode'. ##
## ##
## If you want to stay private, use 'connect' to only ##
## connect to "trusted" nodes. ##
## ##
## If you run multiple nodes on a LAN, there's no need for##
## all of them to open lots of connections. Instead ##
## 'connect' them all to one node that is port forwarded ##
## and has lots of connections. ##
## Thanks goes to [Noodle] on Freenode. ##
##############################################################

# Use as many addnode= settings as you like to attempt connection to specific peers
#addnode=69.164.218.197
#addnode=10.0.0.2:8333

# or use as many connect= settings as you like to connect ONLY to specific peers:
#connect=69.164.218.197
#connect=192.168.1.20:8333

# Do not use Internet Relay Chat to find peers.
noirc=0

# Maximum number of inbound+outbound connections.
#maxconnections=125

# Miscellaneous options

# Pre-generate this many public/private key pairs, so wallet backups will be valid
# after future transactions.
#keypool=100

# Add an optional transaction fee every time you send bitcoins.
#paytxfee=0.01

# Add timestamps to debug.log
#logtimestamps=1       


# User interface options

# Start Bitcoin minimized
#min=1

# Minimize to the system tray
minimizetotray=0

I post  a lot of options so you can play with it if you like.

The whole thing is actually working on apache httpClient:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.3</version>
</dependency>


To start we have too do some boilerplate coding:
//To start with a Logger is like coffee in the morning.
Logger log = LoggerFactory.getLogger(RpcServer.class.getName());
//We have to provide some cred. too login to the bitcoind
//The username and password should match the ones in the conf file.
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
        new AuthScope("127.0.0.1", 8332),
        new UsernamePasswordCredentials("user", "password"));
//Building a HttpClient for the start of the communication.
CloseableHttpClient client = HttpClients.custom()
        .setDefaultCredentialsProvider(credsProvider)
        .build();

//Setting up the request to the server. get ip and port from the
//~/.bitcoin/bitcoin.conf.

HttpPost request = new HttpPost("http://127.0.0.1:8332");

// no we start with the interesting part:
try {
    //This is the most interesting part. Here we setup the 
    //rpc call to the daemon. 
request.setEntity(new StringEntity("{\"jsonrpc\":\"1.0\" + 
,\"id\":\"curltext\",\"method\":\"getblockchaininfo\",\"params\":[]}"));
    // retrieving the response from the daemon
    HttpResponse response = client.execute(request);
    // converting the result to a string and print it.
    ByteArrayOutputStream byteArrayOutputStream = 
new ByteArrayOutputStream();
    response.getEntity().writeTo(byteArrayOutputStream);
    String theString = new String(byteArrayOutputStream.toByteArray());
    log.info(theString);
} catch (UnsupportedEncodingException e) {
    log.error("wrong url", e);
} catch (ClientProtocolException e) {
    log.error("wrong protocol", e);
} catch (IOException e) {
    log.error("io", e);
}


Conclusion

After a day of searching it was blissfully simple. 
I enjoyed talking to the legendary bitcoin daemon and 
get some information out of it. This is still a simple method.
The daemon has some more complex ones where you also might need some
parameters. At the line of request.setEntity, in the json part there
is also a parameter section. You can address all the parameters there.
Don't forget too change the method section.
For this see:
https://bitcoin.org/en/release/v0.15.0

Have fun!