From 4d15f0aad33822ed5d4844a0748b4d3bf5df54b6 Mon Sep 17 00:00:00 2001 From: "Andreas M. Antonopoulos" Date: Thu, 4 Feb 2016 20:52:15 -0600 Subject: [PATCH] ch03 rpc API, code examples, libraries --- ch03.asciidoc | 117 ++++++++++++++++++++++++++++++++++++---- code/rpc_block.py | 37 +++++++++++++ code/rpc_example.py | 10 ++++ code/rpc_transaction.py | 16 ++++++ 4 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 code/rpc_block.py create mode 100644 code/rpc_example.py create mode 100644 code/rpc_transaction.py diff --git a/ch03.asciidoc b/ch03.asciidoc index f0f22922..8ceb4b7e 100644 --- a/ch03.asciidoc +++ b/ch03.asciidoc @@ -664,21 +664,120 @@ $ bitcoin-cli getblock 0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b3&#x The block contains 419 transactions the 64th transaction listed (+0627052b...+) is Alice's coffee payment. The +height+ entry tells us this is the 277316th block in the blockchain. +==== Using Bitcoin Core's Programmatic Interface + +The +bitcoin-cli+ helper is very useful for exploring the Bitcoin Core API and testing functions. But the whole point of an Application Programming Interface is to access functions programmatically. In this section we will demonstrate accessing Bitcoin Core from another program. + +Bitcoin Core's API is a JSON-RPC interface. JSON stands for JavaScript Object Notation and it is a very convenient way to present data that both humans and programs can easily read. RPC stands for Remote Procedure Call, which means that we are calling procedures (functions) that are remote (on the Bitcoin Core node) via a network protocol. In this case, the network protocol is HTTP, or HTTPS (for encrypted connections). + +When we used the +bitcoin-cli+ command to get help on a command, it showed us an example of using +curl+, the versatile command-line HTTP client to construct one of these JSON-RPC calls: + +---- +$ curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getinfo", "params": [] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/ +---- + +This command shows that +curl+ submits an HTTP request to the local host (127.0.0.1), connecting to the default bitcoin port (8332), and submitting a +jsonrpc+ request for the +getinfo+ method, using a +text/plain+ encoding. + +If you're implementing a JSON-RPC call in your own program, you can use a generic HTTP library to construct the call, similar to what is shown in the +curl+ example above. + +However, there are libraries in most every programming language that "wrap" the Bitcoin Core API in a way that makes this a lot simpler. We will use the +python-bitcoinlib+ library to simplify API access. Remember, this requires you to have a running Bitcoin Core instance which will be used to make JSON-RPC calls. + +The Python script below makes a simple +getinfo+ call and prints the +block+ parameter from the data returned by Bitcoin Core: + +[[rpc_example]] +.Running +getinfo+ via Bitcoin Core's JSON-RPC API +==== +[source,python] +---- +include::code/rpc_example.py[] +---- +==== + +Running it, gives us the following result: +---- +$ python rpc_example.py +394075 +---- + +It tells us that our local Bitcoin Core node has 394075 blocks in its blockchain. Not a spectacular result, but it demonstrates the basic use of the library as a simplified interface to Bitcoin Core's JSON-RPC API. + +Next, let's use the +getrawtransaction+ and +decodetransaction+ calls to retrieve the details of Alice's coffee payment. In the following example, we retrieve Alice's transaction and list the transaction's outputs. For each output, we show the recipient address and value. As a reminder, Alice's transaction had one output paying Bob's Cafe and one output for change back to Alice. + +[[rpc_transaction]] +.Retrieving a transaction and iterating its outputs +==== +[source,python] +---- +include::code/rpc_transaction.py[] +---- +==== + +Running this code, we get: +---- +$ python rpc_transaction.py +([u'1GdK9UzpHBzqzX2A9JFP3Di4weBwqgmoQA'], Decimal('0.01500000')) +([u'1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK'], Decimal('0.08450000')) +---- + +Both of the examples above are rather simple. You don't really need a program to run them, you could just as easily use the +bitcoin-cli+ helper. The next example, however, requires several hundred RPC calls and more clearly demonstrates the use of a programmatic interface. + +In <>, we first retrieve block 277316, then retrieve each of the 419 transactions within by reference to each transaction ID. Next, iterate through each of the transaction's outputs and add up the value. + +[[rpc_block]] +.Retrieving a block and adding all the transaction outputs +==== +[source,python] +---- +include::code/rpc_block.py[] +---- +==== + +Running this code, we get: +---- +$ python rpc_block.py + +('Total value in block: ', Decimal('10322.07722534')) +---- + [[alt_libraries]] === Alternative Clients, Libraries, and Toolkits -((("clients, alternative", id="ix_ch03-asciidoc47", range="startofrange")))((("libraries, alternative", id="ix_ch03-asciidoc48", range="startofrange")))((("toolkits, alternative", id="ix_ch03-asciidoc49", range="startofrange")))Beyond the reference client (bitcoind), other clients and libraries can be used to interact with the bitcoin network and data structures. These are implemented in a variety of programming languages, offering programmers native interfaces in their own language. +((("clients, alternative", id="ix_ch03-asciidoc47", range="startofrange")))((("libraries, alternative", id="ix_ch03-asciidoc48", range="startofrange")))((("toolkits, alternative", id="ix_ch03-asciidoc49", range="startofrange"))) There are many alternative clients, libraries, toolkits and even full-node implementations in the bitcoin ecosystem. These are implemented in a variety of programming languages, offering programmers native interfaces in their preferred language. + +Below we list some of the best libraries, clients and toolkits, organized by programming languages: -Alternative implementations include: +==== C/C++ +https://github.com/bitcoin/bitcoin[Bitcoin Core] :: The reference implementation of bitcoin +https://github.com/libbitcoin/libbitcoin[libbitcoin]:: ((("libbitcoin library")))Cross-Platform C++ development toolkit, node and consensus library +https://github.com/libbitcoin/libbitcoin-explorer[bitcoin explorer]:: ((("Bitcoin Explorer")))Libbitcoin's command-line tool +https://github.com/jgarzik/picocoin[picocoin]:: ((("picocoin")))A C language lightweight client library for bitcoin by Jeff Garzik -https://github.com/libbitcoin/libbitcoin[libbitcoin]:: ((("libbitcoin library")))Bitcoin Cross-Platform C++ Development Toolkit -https://github.com/libbitcoin/libbitcoin-explorer[bitcoin explorer]:: ((("Bitcoin Explorer")))Bitcoin Command Line Tool -https://github.com/libbitcoin/libbitcoin-server[bitcoin server]:: ((("Bitcoin Server")))Bitcoin Full Node and Query Server +==== JavaScript +https://bitcore.io/[Bitcore] :: Full node, API and library by Bitpay +https://github.com/bitcoinjs/bitcoinjs-lib[BitcoinJS] :: A pure JavaScript Bitcoin library for node.js and browsers + +==== Java https://code.google.com/p/bitcoinj/[bitcoinj]:: ((("BitcoinJ library")))A Java full-node client library -https://opensource.conformal.com/wiki/btcd[btcd]:: ((("btcd","client")))A Go language full-node bitcoin client https://bitsofproof.com[Bits of Proof (BOP)]:: ((("Bits of Proof (BOP)")))A Java enterprise-class implementation of bitcoin -https://github.com/jgarzik/picocoin[picocoin]:: ((("picocoin")))A C implementation of a lightweight client library for bitcoin -https://github.com/vbuterin/pybitcointools[pybitcointools]:: ((("pybitcointools library")))A Python bitcoin library -https://github.com/richardkiss/pycoin[pycoin]:: ((("pycoin library")))Another Python bitcoin library + +==== Python +https://github.com/petertodd/python-bitcoinlib[python-bitcoinlib]:: ((("python-bitcoinlib library"))) A Python bitcoin library, consensus library and node by Peter Todd +https://github.com/richardkiss/pycoin[pycoin]:: ((("pycoin library")))A Python bitcoin library by Richard Kiss +https://github.com/vbuterin/pybitcointools[pybitcointools]:: ((("pybitcointools library")))A Python bitcoin library by Vitalik Buterin + +==== Ruby +https://github.com/sinisterchipmunk/bitcoin-client[bitcoin-client]:: A Ruby library wrapper for the JSON-RPC API + +==== Go +https://opensource.conformal.com/wiki/btcd[btcd]:: ((("btcd","client")))A Go language full-node bitcoin client + +==== Rust +https://github.com/apoelstra/rust-bitcoin[rust-bitcoin]:: Rust Bitcoin Library for serialization, parsing and API calls + +==== C# +https://github.com/MetacoSA/NBitcoin[NBitcoin]:: Comprehensive Bitcoin library for the .NET framework. + +==== Objective-C +https://github.com/oleganza/CoreBitcoin[CoreBitcoin]:: Bitcoin toolkit for ObjC and Swift Many more libraries exist in a variety of other programming languages and more are created all the time. diff --git a/code/rpc_block.py b/code/rpc_block.py new file mode 100644 index 00000000..bd7899ab --- /dev/null +++ b/code/rpc_block.py @@ -0,0 +1,37 @@ +from bitcoin.rpc import RawProxy + +p = RawProxy() + +# The block height where Alice's transaction was recorded +blockheight = 277316 + +# Get the block hash of block with height 277316 +blockhash = p.getblockhash(blockheight) + +# Retrieve the block by its hash +block = p.getblock(blockhash) + +# Element tx contains the list of all transaction IDs in the block +transactions = block['tx'] + +block_value = 0 + +# Iterate through each transaction ID in the block +for txid in transactions: + tx_value = 0 + # Retrieve the raw transaction by ID + raw_tx = p.getrawtransaction(txid) + # Decode the transaction + decoded_tx = p.decoderawtransaction(raw_tx) + # Iterate through each output in the transaction + for output in decoded_tx['vout']: + # Add up the value of each output + tx_value = tx_value + output['value'] + + # Add the value of this transaction to the total + block_value = block_value + tx_value + +print("Total value in block: ", block_value) + + + diff --git a/code/rpc_example.py b/code/rpc_example.py new file mode 100644 index 00000000..87fe06b4 --- /dev/null +++ b/code/rpc_example.py @@ -0,0 +1,10 @@ +from bitcoin.rpc import RawProxy + +# Create a connection to local Bitcoin Core node +p = RawProxy() + +# Run the getinfo command, store the resulting data in info +info = p.getinfo() + +# Retrieve the 'blocks' element from the info +print(info['blocks']) diff --git a/code/rpc_transaction.py b/code/rpc_transaction.py new file mode 100644 index 00000000..f3686635 --- /dev/null +++ b/code/rpc_transaction.py @@ -0,0 +1,16 @@ +from bitcoin.rpc import RawProxy + +p = RawProxy() + +# Alice's transaction ID +txid = "0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2" + +# First, retrieve the raw transaction in hex +raw_tx = p.getrawtransaction(txid) + +# Decode the transaction hex into a JSON object +decoded_tx = p.decoderawtransaction(raw_tx) + +# Retrieve each of the outputs from the transaction +for output in decoded_tx['vout']: + print(output['scriptPubKey']['addresses'], output['value'])