Bitcoin API

This notebook takes the Bitcoin Developers Reference, specifically the Bitcoin API, and demonstrates the use of the Remote Procedure Calls (RPC) via python. We employ the regression testing mode of bitcoin, regtest, to start with a clean blockchain.

The notebook orders the RPC methods to illustrate how to use the API. In the Bitcoin Developers Reference the RPC methods are in alphabetical order while the python example code below is in discovery sequence, starting with creating the genesis block, mining our first bitcoins, sending some to another user and showing updates to the blockchain throughout the process.

The notebook may be useful for beginners looking for a simple python interface to the Bitcoin API; we use the python bitcoin module created by Peter Todd for its simplicity. As well, the value to the user who is new to python is a simple step by step walk thru of the various methods in the API in an incremental introduction without the confusion of thousands of transactions in a typical block on mainnet.

We create two users on the regression test network (regtest):

  • Bob on RPC port 16591
  • Mary on RPC port 16592.

We create independent peers on the same network.

Handy shell command to see current nodes:

ps aux |grep bitcoin

We could add as many nodes to regtest as we like (upper limit?) and connect them in a round-robin way so that node 1 listens to node 2... and node N listens to node 1. For our examples here, we use just two nodes in the dictionary connects.

The python script below is designed for Linux (Ubuntu) and would need to be modified for other platforms.


In [1]:
#!/bin/bash
#regtest_start_network.sh
import os
import shutil

#os.system("killall --regex bitcoin.*")

idir = os.environ['HOME']+'/regtest'
if os.path.isdir(idir):
    shutil.rmtree(idir)

os.mkdir(idir)
connects = {'17591' : '17592', '17592' : '17591'}

for port in connects.keys():
    adir = idir+'/'+port
    os.mkdir(adir)
    args = " -server -txindex=1 -listen -port=" + port + \
           " -rpcuser=bitcoinrpc -rpcpassword=P0 -rpcport="+\
           str(int(port)-1000) +\
           " -datadir=" + adir + " -connect=localhost:" + connects[port] +\
           " -regtest -pid="+port+".pid -daemon -debug"
    os.system("bitcoind" + args)

Import the python bitcoin module created by Peter Todd.


In [2]:
import bitcoin
import bitcoin.rpc

import bitcoin.core 
import bitcoin.core.script

Connect nodes to bitcoin-rpc module

We hard-code the username and passwords here for pedagogical ease. We display the blockchain information using the widely used, but deprecated getinfo() RPC.

getinfo() returns:

version - The version number of this bitcoin-qt or bitcoind program itself. Both of are equivalent. -qt is simply the graphical user interface version

protocolversion: The version of the bitcoin network protocol supported by this client (user agent software).

walletversion: The version of the wallet.dat file. Wallet.dat contains bitcoin addresses and public & private key pairs for these addresses. There is additional data on the wallet. Care must be taken to not restore from an old wallet backup. New addresses generated in the wallet since the old backup was made will not exist in the old backup! Source

balance: The total number of bitcoins held in the wallet.dat file.

blocks: The total number of blocks which constitute the shared block chain.

timeoffset: Seconds of difference between this node's "wall clock time" and the median reported by our network peers.

connections: the number of peers on the bitcoin P2P network that this node is connected to.

proxy: If using a proxy to connect to the network, listed here, otherwise blank.

difficulty: the current mining difficulty factor. Difficulty is increased as more miners and more hash compute power compete to be the next one to have a block of transactions added to the blockchain.

testnet: Boolean value (true OR false). There is a parallel bitcoin network, the testnet, where trials and experiments may be carried out without impacting the official, live bitcoin P2P network

keypoololdest: timestamp (UNIX epoch) of the oldest key in the keypool

keypoolsize: A number of addresses are kept in reserve by the client. This is the size of that reserve.

paytxfee: Specifies what fee the client is willing to pay to expedite transactions. Miners may choose to ignore transactions that do not pay a fee, and these fee-less transactions will have low priority on queue of pending transaction and may linger there for hours.

errors: This field may inform of different status conditions. Full list of error codes in source file bitcoinrpc.h (Examples: "Bitcoin not connected", "database error", "Keypool ran out"...)


In [3]:
bitcoin.SelectParams('regtest')

Bob  = bitcoin.rpc.RawProxy("http://bitcoinrpc:P0@127.0.0.1:16591")
Mary = bitcoin.rpc.RawProxy("http://bitcoinrpc:P0@127.0.0.1:16592")

info = Bob.getinfo()
for key in info.keys():
    print key + ' : ' + str(info[key])


connections : 2
errors : This is a pre-release test build - use at your own risk - do not use for mining or merchant applications
blocks : 0
paytxfee : 0E-8
keypoololdest : 1442934885
walletversion : 60000
difficulty : 0E-8
testnet : False
version : 119900
proxy : 
protocolversion : 70002
timeoffset : 0
balance : 0E-8
relayfee : 0.00001000
keypoolsize : 101

Network attributes

The following RCPs are used to determine the network attributes. We highlight the informational RPCs and leave the AddNode and GetAddedNodeInfo for later investigation.

Network RPCs

  • AddNode: attempts to add or remove a node from the addnode list, or to try a connection to a node once.
  • GetAddedNodeInfo: returns information about the given added node, or all added nodes (except onetry nodes). Only nodes which have been manually added using the addnode RPC will have their information displayed.
  • GetConnectionCount: returns the number of connections to other nodes.
  • GetNetTotals: returns information about network traffic, including bytes in, bytes out, and the current time.
  • GetNetworkInfo: returns information about the node’s connection to the network. New in 0.9.2, Updated in 0.10.0
  • GetPeerInfo: returns data about each connected network node. Updated in 0.10.0
  • Ping: sends a P2P ping message to all connected nodes to measure ping time. Results are provided by the getpeerinfo RPC pingtime and pingwait fields as decimal seconds. The P2P ping message is handled in a queue with all other commands, so it measures processing backlog, not just network ping.

In [4]:
getnetworkinfo = Bob.getnetworkinfo()
print '\ngetnetworkinfo\n'
print getnetworkinfo
getpeerinfo = Bob.getpeerinfo()
print '\ngetpeerinfo\n'
print getpeerinfo
getconnectioncount = Bob.getconnectioncount()
print '\ngetconnectioncount\n'
print getconnectioncount
getnettotals = Bob.getnettotals()
print '\ngetnettotals\n'
print getnettotals


getnetworkinfo

{u'localservices': u'0000000000000001', u'warnings': u'This is a pre-release test build - use at your own risk - do not use for mining or merchant applications', u'connections': 2, u'subversion': u'/Satoshi:0.11.99/', u'version': 119900, u'relayfee': Decimal('0.00001000'), u'protocolversion': 70002, u'timeoffset': 0, u'localaddresses': [], u'networks': [{u'limited': False, u'proxy_randomize_credentials': False, u'reachable': False, u'name': u'ipv4', u'proxy': u''}, {u'limited': False, u'proxy_randomize_credentials': False, u'reachable': False, u'name': u'ipv6', u'proxy': u''}, {u'limited': False, u'proxy_randomize_credentials': False, u'reachable': False, u'name': u'onion', u'proxy': u''}]}

getpeerinfo

[{u'inflight': [], u'lastsend': 1442934886, u'banscore': 0, u'addr': u'127.0.0.1:48758', u'whitelisted': False, u'inbound': True, u'version': 70002, u'synced_blocks': -1, u'subver': u'/Satoshi:0.11.99/', u'lastrecv': 1442934886, u'timeoffset': 0, u'pingtime': Decimal('0.03801600'), u'bytesrecv': 332, u'bytessent': 308, u'services': u'0000000000000001', u'startingheight': 0, u'id': 1, u'synced_headers': -1, u'conntime': 1442934886}, {u'inflight': [], u'lastsend': 1442934886, u'banscore': 0, u'addr': u'localhost:17592', u'whitelisted': False, u'inbound': False, u'version': 70002, u'synced_blocks': -1, u'subver': u'/Satoshi:0.11.99/', u'lastrecv': 1442934886, u'timeoffset': 0, u'pingtime': Decimal('0.03713500'), u'bytesrecv': 215, u'bytessent': 239, u'services': u'0000000000000001', u'startingheight': 0, u'id': 2, u'synced_headers': -1, u'conntime': 1442934886}]

getconnectioncount

2

getnettotals

{u'timemillis': 1442934908106, u'totalbytesrecv': 547, u'totalbytessent': 547}

Block Chain RPCs

  • GetBestBlockHash: returns the header hash of the most recent block on the best block chain. New in 0.9.0
  • GetBlock: gets a block with a particular header hash from the local block database either as a JSON object or as a serialized block.
  • GetBlockChainInfo: provides information about the current state of the block chain. New in 0.9.2, Updated in 0.10.0
  • GetBlockCount: returns the number of blocks in the local best block chain.
  • GetBlockHash: returns the header hash of a block at the given height in the local best block chain.
  • GetChainTips: returns information about the highest-height block (tip) of each local block chain. New in 0.10.0
  • GetDifficulty: returns the proof-of-work difficulty as a multiple of the minimum difficulty.
  • GetMemPoolInfo: returns information about the node’s current transaction memory pool. New in 0.10.0
  • GetRawMemPool: returns all transaction identifiers (TXIDs) in the memory pool as a JSON array, or detailed information about each transaction in the memory pool as a JSON object.
  • GetTxOut: returns details about a transaction output. Only unspent transaction outputs (UTXOs) are guaranteed to be available.
  • GetTxOutProof: returns a hex-encoded proof that one or more specified transactions were included in a block. New in 0.11.0
  • GetTxOutSetInfo: returns statistics about the confirmed unspent transaction output (UTXO) set. Note that this call may take some time and that it only counts outputs from confirmed transactions—it does not count outputs from the memory pool.
  • VerifyChain: verifies each entry in the local block chain database.
  • VerifyTxOutProof: verifies that a proof points to one or more transactions in a block, returning the transactions the proof commits to and throwing an RPC error if the block is not in our best block chain. New in 0.11.0

In [5]:
blockchaininfo = Bob.getblockchaininfo()
getblockcount  =  Bob.getblockcount()
getbestblockhash =  Bob.getbestblockhash()
getdifficulty  =  Bob.getdifficulty()
getchaintips   =  Bob.getchaintips()
getmempoolinfo = Bob.getmempoolinfo()

print '\nblockchaininfo\n'
print blockchaininfo
print '\ngetblockcount ' + str(getblockcount)
print '\ngetbestblockhash\n'
print getbestblockhash
print '\ngetdifficulty ' + str(getdifficulty)
print '\ngetchaintips\n'
print getchaintips
print '\ngetmempoolinfo\n'
print getmempoolinfo

print '\n\n'

bestblockhash  =  blockchaininfo['bestblockhash']
blocks         =  blockchaininfo['blocks']
print '\nblocks = ' + str(blocks)
print '\nbestblockhash = ' + str(bestblockhash)


blockchaininfo

{u'pruned': False, u'blocks': 0, u'chainwork': u'0000000000000000000000000000000000000000000000000000000000000002', u'chain': u'regtest', u'difficulty': Decimal('0E-8'), u'headers': 0, u'verificationprogress': Decimal('1.00000000'), u'bestblockhash': u'0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206'}

getblockcount 0

getbestblockhash

0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206

getdifficulty 0E-8

getchaintips

[{u'status': u'active', u'branchlen': 0, u'hash': u'0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206', u'height': 0}]

getmempoolinfo

{u'bytes': 0, u'size': 0}




blocks = 0

bestblockhash = 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206

Bootstrap

Bootstrap some bitcoins so we can spend them. In regtest, you use generate and mine 101 blocks rewarding you with 50 bitcoins in a coinbase transaction. On testnet, you use a faucet to get some bitcoins. On mainnet, you need actual bitcoins. We will stick with regtest for now.


In [6]:
## N.B. our balance is zero in the genesis block
print 'Initial balance, before any mining ' + str(Bob.getbalance())

Bob.generate(101)

print 'Balance after mining 101 blocks ' + str(Bob.getbalance())


Initial balance, before any mining 0E-8
Balance after mining 101 blocks 50.00000000

Raw Transaction RPCs

  • CreateRawTransaction: creates an unsigned serialized transaction that spends a previous output to a new output with a P2PKH or P2SH address. The transaction is not stored in the wallet or transmitted to the network.
  • DecodeRawTransaction: decodes a serialized transaction hex string into a JSON object describing the transaction.
  • DecodeScript: decodes a hex-encoded P2SH redeem script.
  • GetRawTransaction: gets a hex-encoded serialized transaction or a JSON object describing the transaction. By default, Bitcoin Core only stores complete transaction data for UTXOs and your own transactions, so the RPC may fail on historic transactions unless you use the non-default txindex=1 in your Bitcoin Core startup settings.
  • SendRawTransaction: validates a transaction and broadcasts it to the peer-to-peer network.
  • SignRawTransaction: signs a transaction in the serialized transaction format using private keys stored in the wallet or provided in the call.

Generate some bitcoins with a mining start

Now let's look at the block structure, rerunning code from above. Note that the block height is now 101. There is one transaction for 50BTC. Note that this is a coinbase transaction with just a vout and no vin.

How to make serialized transaction?


In [7]:
getblockcount = Bob.getblockcount()
print '\ngetblockcount = ' + str(getblockcount)

getblockhash = Bob.getblockhash(getblockcount)
print '\ngetblockhash = ' + str(getblockhash)

print '\ngetblock\n'
getblock = Bob.getblock(getblockhash)
print getblock

tx = getblock['tx']
print '\n' + str(len(tx)) + ' Transactions\n'
print tx

for i in range(len(tx)):
    print '\nSerialized Transaction #' + str(i) +'\n'
    serializedTX = Bob.getrawtransaction(tx[i],0)
    print serializedTX
    print '\nRaw Transaction\n'
    rawTX = Bob.getrawtransaction(tx[i],1)
    print rawTX
    print '\nDecoded Transaction\n'
    decodedTX    = Bob.decoderawtransaction(serializedTX)
    print decodedTX


getblockcount = 101

getblockhash = 76c772c5ecff24c2b1b7555b0c1f248bc206b70e9a254cdb7d439b01ed33f101

getblock

{u'merkleroot': u'4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da', u'nonce': 0, u'previousblockhash': u'2186de644157a5d047258725162ce75770fdbf30c78b0555d46f45eae39808e8', u'hash': u'76c772c5ecff24c2b1b7555b0c1f248bc206b70e9a254cdb7d439b01ed33f101', u'version': 3, u'tx': [u'4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da'], u'chainwork': u'00000000000000000000000000000000000000000000000000000000000000cc', u'height': 101, u'difficulty': Decimal('0E-8'), u'confirmations': 1, u'time': 1442934948, u'bits': u'207fffff', u'size': 180}

1 Transactions

[u'4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da']

Serialized Transaction #0

01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0100f2052a01000000232103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac00000000

Raw Transaction

{u'blockhash': u'76c772c5ecff24c2b1b7555b0c1f248bc206b70e9a254cdb7d439b01ed33f101', u'vout': [{u'scriptPubKey': {u'reqSigs': 1, u'hex': u'2103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac', u'addresses': [u'mrBtS4SfuekkY39a2FXAuYr3fjqBsyWcEY'], u'asm': u'03673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2 OP_CHECKSIG', u'type': u'pubkey'}, u'value': Decimal('50.00000000'), u'n': 0}], u'hex': u'01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0100f2052a01000000232103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac00000000', u'vin': [{u'coinbase': u'01650101', u'sequence': 4294967295}], u'txid': u'4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da', u'blocktime': 1442934948, u'version': 1, u'confirmations': 1, u'time': 1442934948, u'locktime': 0}

Decoded Transaction

{u'locktime': 0, u'version': 1, u'vin': [{u'coinbase': u'01650101', u'sequence': 4294967295}], u'vout': [{u'scriptPubKey': {u'reqSigs': 1, u'hex': u'2103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac', u'addresses': [u'mrBtS4SfuekkY39a2FXAuYr3fjqBsyWcEY'], u'asm': u'03673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2 OP_CHECKSIG', u'type': u'pubkey'}, u'value': Decimal('50.00000000'), u'n': 0}], u'txid': u'4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da'}

Now that we have a raw transaction, let's look at the details. As noted, the first 100 blocks in regtest are blank, necessary for mining our first coinbase reward of 50BTC. This shows in block 101 with a single transaction, denoted rawTX below. rawTX is a JSON object with:

  1. blockhash from block 101
  2. vout an array (len=1) of scriptPubKey, a JSON object of reqSigs and a value (50BTC here)
  3. vin an array (len=1) with a key called "coinbase", some value and a sequence number

We veirfy that the serialized transaction hex is the same as the "hex" entry in the transaction. We note that the txid is repeated in the raw transaction. We also note that the confirmations = 1 (no further mining has been done on this block), that there is a single transaction (the mining of 50btc) and the blocktime and time are the same, while the locktime is the beginning of the epoch.

Note that an address has been created, in general an array of addresses, each corresponding to a transaction output (vout). Here, a new address has been created corresponding to the miner's address for the 50BTC reward.


In [8]:
from datetime import datetime as dt
#import pytz

print rawTX 
print '\n\n'

print 'blockhash = ' + str(rawTX['blockhash']) + '\n'
for i in range(len(rawTX['vout'])):
    spk = rawTX['vout'][i]['scriptPubKey']
    print 'vout ' + str(i) + ' : ' + str(spk) + '\n'
    for field in spk.keys(): 
        #['reqSigs','hex','addresses','asm','type']:
        print 'vout ' + str(i) + ' ' + field + '  : ' + str(spk[field])
    print 'vout ' + str(i) + ' value : ' + str(rawTX['vout'][i]['value'])
    print 'vout ' + str(i) + ' n     : ' + str(rawTX['vout'][i]['n'])

print '\nserialized hex = ' + str(rawTX['hex'])
print 'Is serialized hex == rawTX["hex"]? ' + str(rawTX['hex']==serializedTX) + '\n'

for i in range(len(rawTX['vin'])):
    spk = rawTX['vin'][i]
    print 'vin ' + str(i) + ' : ' + str(spk) + '\n'
    for field in spk.keys(): 
        #['reqSigs','hex','addresses','asm','type']:
        print 'vin ' + str(i) + ' ' + field + '  : ' + str(spk[field])

print '\n'
for field in ['txid','blocktime','version','confirmations','time','locktime']:
    if field in ['blocktime','time','locktime']:
        print field + ' = ' + str(rawTX[field]) +\
        ' ' + dt.fromtimestamp(rawTX[field]).strftime('%Y-%m-%d:%H%M%S')
    else:
        print field + ' = ' + str(rawTX[field])


{u'blockhash': u'76c772c5ecff24c2b1b7555b0c1f248bc206b70e9a254cdb7d439b01ed33f101', u'vout': [{u'scriptPubKey': {u'reqSigs': 1, u'hex': u'2103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac', u'addresses': [u'mrBtS4SfuekkY39a2FXAuYr3fjqBsyWcEY'], u'asm': u'03673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2 OP_CHECKSIG', u'type': u'pubkey'}, u'value': Decimal('50.00000000'), u'n': 0}], u'hex': u'01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0100f2052a01000000232103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac00000000', u'vin': [{u'coinbase': u'01650101', u'sequence': 4294967295}], u'txid': u'4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da', u'blocktime': 1442934948, u'version': 1, u'confirmations': 1, u'time': 1442934948, u'locktime': 0}



blockhash = 76c772c5ecff24c2b1b7555b0c1f248bc206b70e9a254cdb7d439b01ed33f101

vout 0 : {u'reqSigs': 1, u'hex': u'2103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac', u'addresses': [u'mrBtS4SfuekkY39a2FXAuYr3fjqBsyWcEY'], u'asm': u'03673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2 OP_CHECKSIG', u'type': u'pubkey'}

vout 0 reqSigs  : 1
vout 0 hex  : 2103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac
vout 0 addresses  : [u'mrBtS4SfuekkY39a2FXAuYr3fjqBsyWcEY']
vout 0 asm  : 03673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2 OP_CHECKSIG
vout 0 type  : pubkey
vout 0 value : 50.00000000
vout 0 n     : 0

serialized hex = 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0100f2052a01000000232103673c2e4e82bc973ebd70a186aaa311913b4ca6c7f381c50890da5a481d2f38f2ac00000000
Is serialized hex == rawTX["hex"]? True

vin 0 : {u'coinbase': u'01650101', u'sequence': 4294967295}

vin 0 coinbase  : 01650101
vin 0 sequence  : 4294967295


txid = 4b5b6e11f5df587eca7414d24d25cf8070269368bb484f709532c603b04c84da
blocktime = 1442934948 2015-09-22:111548
version = 1
confirmations = 1
time = 1442934948 2015-09-22:111548
locktime = 0 1969-12-31:190000

Let's create an address and send some bitcoins there. Some things to notice:

  1. We set up a new proxy, using a different RPC port on regtest
  2. Address is NOT on blockchain, it is just a 32 byte hash that is almost certainly unique and never before used.
  3. We send some coins to new address, note the transaction structure
  4. The mempool shows the pending transaction
  5. We need to mine to write the transaction to the blockchain

In [12]:
print 'Mary\'s balance = ' + str(Mary.getbalance())
#print 'Mary\'s peers: '
#print Mary.getpeerinfo()

getnewaddress = Mary.getnewaddress()
print '\nNew address ' + str(getnewaddress)
print '\nMary\'s address has received how many BTC? ' +\
str(Mary.getreceivedbyaddress(getnewaddress,0))

##have Bob (proxy) send 25 bitcoins to Mary
txid = Bob.sendtoaddress(getnewaddress,25)


Mary's balance = 0E-8

New address mqvqUFePU68gRjuWtv8EApNVKeVmo7Qam3

Mary's address has received how many BTC? 0E-8

In [13]:
getmempoolinfo = Bob.getmempoolinfo()
getrawmempool = Bob.getrawmempool(True)
print '\ngetmempoolinfo ' + str(getmempoolinfo)
print '\ngetrawmempool'
print getrawmempool
print '\n'
for key in getrawmempool.keys():
    for field in getrawmempool[key].keys():
        print str(field) + ' : ' + str(getrawmempool[key][field])
#print '\ntxid from sendtoaddress output ' + str(txid)
print '\nIs the send txid the same as memory pool txid? ****' +\
    str(txid == getrawmempool.keys()[0]) + '****'

print '\nMary\'s balance before mining = ' + str(Mary.getbalance())
print 'Bob\'s balance before mining = ' + str(Bob.getbalance())

##how can I see transaction details before mining?
print '\nMemory Pool Raw Transaction Data\n'
import pprint
pprint.pprint(Bob.getrawtransaction(txid,1))

##N.B. no transaction on the blockchain yet!!!


getmempoolinfo {u'bytes': 191, u'size': 1}

getrawmempool
{u'0662e27d16d9d994ef061c46bd39eff18453d4980559804742946b63ccce0862': {u'fee': Decimal('0.00000192'), u'startingpriority': Decimal('6410256410.25641060'), u'height': 101, u'depends': [], u'time': 1442935017, u'currentpriority': Decimal('6410256410.25641060'), u'size': 191}}


fee : 0.00000192
startingpriority : 6410256410.25641060
height : 101
depends : []
time : 1442935017
currentpriority : 6410256410.25641060
size : 191

Is the send txid the same as memory pool txid? ****True****

Mary's balance before mining = 0E-8
Bob's balance before mining = 24.99999808

Memory Pool Raw Transaction Data

{u'hex': u'0100000001367dde5e9a7fe2e00f05ddcf5c64edeeda8c8116263be2f973d1523a78c82714000000004847304402207172abb58e8984af7549bf4eda0d84e01eafbd93e3efa664e34267256a5c4af00220009a31e8011ed7c61a5f815c89ba756d40ab7c27d51337325c551f6fa4ee02b201feffffff0200f90295000000001976a91472358b5e420dff0b75f286bfe7ca9af339ebf0e388ac40f80295000000001976a914750e41acd1c1a95e8b32d7d7e062be42faf1642288ac5b000000',
 u'locktime': 91,
 u'txid': u'0662e27d16d9d994ef061c46bd39eff18453d4980559804742946b63ccce0862',
 u'version': 1,
 u'vin': [{u'scriptSig': {u'asm': u'304402207172abb58e8984af7549bf4eda0d84e01eafbd93e3efa664e34267256a5c4af00220009a31e8011ed7c61a5f815c89ba756d40ab7c27d51337325c551f6fa4ee02b201',
                          u'hex': u'47304402207172abb58e8984af7549bf4eda0d84e01eafbd93e3efa664e34267256a5c4af00220009a31e8011ed7c61a5f815c89ba756d40ab7c27d51337325c551f6fa4ee02b201'},
           u'sequence': 4294967294,
           u'txid': u'1427c8783a52d173f9e23b2616818cdaeeed645ccfdd050fe0e27f9a5ede7d36',
           u'vout': 0}],
 u'vout': [{u'n': 0,
            u'scriptPubKey': {u'addresses': [u'mqvqUFePU68gRjuWtv8EApNVKeVmo7Qam3'],
                              u'asm': u'OP_DUP OP_HASH160 72358b5e420dff0b75f286bfe7ca9af339ebf0e3 OP_EQUALVERIFY OP_CHECKSIG',
                              u'hex': u'76a91472358b5e420dff0b75f286bfe7ca9af339ebf0e388ac',
                              u'reqSigs': 1,
                              u'type': u'pubkeyhash'},
            u'value': Decimal('25.00000000')},
           {u'n': 1,
            u'scriptPubKey': {u'addresses': [u'mrBtS4SfuekkY39a2FXAuYr3fjqBsyWcEY'],
                              u'asm': u'OP_DUP OP_HASH160 750e41acd1c1a95e8b32d7d7e062be42faf16422 OP_EQUALVERIFY OP_CHECKSIG',
                              u'hex': u'76a914750e41acd1c1a95e8b32d7d7e062be42faf1642288ac',
                              u'reqSigs': 1,
                              u'type': u'pubkeyhash'},
            u'value': Decimal('24.99999808')}]}

Bob mines 6 more blocks, after the fifth, the 25BTC sent to Mary is confirmed and shows in her balance. Note that the transaction created in block 101, when Bob sent Mary 25BTC shows up in the first block mined, but the balance isn't updated until some number of blocks have been processed.


In [14]:
for i in range(7):
    Bob.generate(1)
    getblockcount   =  Bob.getblockcount()
    getblockhash   =  Bob.getblockhash(getblockcount)
    getblock       =  Bob.getblock(getblockhash)
    print 'Block #' + str(getblockcount) + ' Mary\'s balance ' + str(Mary.getbalance())
    print 'txids ' + str(getblock['tx'])


Block #102 Mary's balance 0E-8
txids [u'e86d272c284e7e40d6ccc014c9b226adeeabe1965ea56890e94b069f3b9de36d', u'0662e27d16d9d994ef061c46bd39eff18453d4980559804742946b63ccce0862']
Block #103 Mary's balance 0E-8
txids [u'ef29e5a8963e7d2afcc30fc2253e0bc11f4f4891453c08924454406fadc38b00']
Block #104 Mary's balance 0E-8
txids [u'a8fe697da6ff182fc1c5b6b48e12f4d2632d15bb4f3a90fba80bb90674ba3da7']
Block #105 Mary's balance 0E-8
txids [u'fbfd13e139347f78b80d0ea5defa14cf3ae6ac6912001379aa2c4f8da258ec35']
Block #106 Mary's balance 25.00000000
txids [u'05a78dacc474931517dd8fc04f893b923c833fbca3663c73ddcf290cfa0faa24']
Block #107 Mary's balance 25.00000000
txids [u'fe30b45e5a6a8fde6832a13fca5543a88662757e70f99256b519109ca890fe63']
Block #108 Mary's balance 25.00000000
txids [u'c75bcce64bfe9f18b7aa73661adc72723c3d105cb29fa4c318868deb4717f826']

In [15]:
print ' Mary\'s balance ' + str(Mary.getbalance())


 Mary's balance 25.00000000

Wallet RPCs

Note: the wallet RPCs are only available if Bitcoin Core was built with wallet support, which is the default.

  • AddMultiSigAddress: adds a P2SH multisig address to the wallet.
  • BackupWallet: safely copies wallet.dat to the specified file, which can be a directory or a path with filename.
  • DumpPrivKey: returns the wallet-import-format (WIP) private key corresponding to an address. (But does not remove it from the wallet.)
  • DumpWallet: creates or overwrites a file with all wallet keys in a human-readable format.
  • EncryptWallet: encrypts the wallet with a passphrase. This is only to enable encryption for the first time. After encryption is enabled, you will need to enter the passphrase to use private keys.
  • GetAccountAddress: returns the current Bitcoin address for receiving payments to this account. If the account doesn’t exist, it creates both the account and a new address for receiving payment. Once a payment has been received to an address, future calls to this RPC for the same account will return a different address.
  • GetAccount: returns the name of the account associated with the given address.
  • GetAddressesByAccount: returns a list of every address assigned to a particular account.
  • GetBalance: gets the balance in decimal bitcoins across all accounts or for a particular account.
  • GetNewAddress: returns a new Bitcoin address for receiving payments. If an account is specified, payments received with the address will be credited to that account.
  • GetRawChangeAddress: returns a new Bitcoin address for receiving change. This is for use with raw transactions, not normal use.
  • GetReceivedByAccount: returns the total amount received by addresses in a particular account from transactions with the specified number of confirmations. It does not count coinbase transactions.
  • GetReceivedByAddress: returns the total amount received by the specified address in transactions with the specified number of confirmations. It does not count coinbase transactions.
  • GetTransaction: gets detailed information about an in-wallet transaction. Updated in 0.10.0
  • GetUnconfirmedBalance: returns the wallet’s total unconfirmed balance.
  • GetWalletInfo: provides information about the wallet. New in 0.9.2
  • ImportAddress: adds an address or pubkey script to the wallet without the associated private key, allowing you to watch for transactions affecting that address or pubkey script without being able to spend any of its outputs. New in 0.10.0
  • ImportPrivKey: adds a private key to your wallet. The key should be formatted in the wallet import format created by the dumpprivkey RPC.
  • ImportWallet: imports private keys from a file in wallet dump file format (see the dumpwallet RPC). These keys will be added to the keys currently in the wallet. This call may need to rescan all or parts of the block chain for transactions affecting the newly-added keys, which may take several minutes.
  • KeyPoolRefill: fills the cache of unused pre-generated keys (the keypool).
  • ListAccounts: lists accounts and their balances. Updated in 0.10.0
  • ListAddressGroupings: lists groups of addresses that may have had their common ownership made public by common use as inputs in the same transaction or from being used as change from a previous transaction.
  • ListLockUnspent: returns a list of temporarily unspendable (locked) outputs.
  • ListReceivedByAccount: lists the total number of bitcoins received by each account. Updated in 0.10.0
  • ListReceivedByAddress: lists the total number of bitcoins received by each address. Updated in 0.10.0
  • ListSinceBlock: gets all transactions affecting the wallet which have occurred since a particular block, plus the header hash of a block at a particular depth. Updated in 0.10.0
  • ListTransactions: returns the most recent transactions that affect the wallet. Updated in 0.10.0
  • ListUnspent: returns an array of unspent transaction outputs belonging to this wallet. Updated in 0.10.0
  • LockUnspent: temporarily locks or unlocks specified transaction outputs. A locked transaction output will not be chosen by automatic coin selection when spending bitcoins. Locks are stored in memory only, so nodes start with zero locked outputs and the locked output list is always cleared when a node stops or fails.
  • Move: moves a specified amount from one account in your wallet to another using an off-block-chain transaction.
  • SendFrom: spends an amount from a local account to a bitcoin address.
  • SendMany: creates and broadcasts a transaction which sends outputs to multiple addresses.
  • SendToAddress: spends an amount to a given address.
  • SetAccount: puts the specified address in the given account.
  • SetTxFee: sets the transaction fee per kilobyte paid by transactions created by this wallet.
  • SignMessage: signs a message with the private key of an address.
  • WalletLock: removes the wallet encryption key from memory, locking the wallet. After calling this method, you will need to call walletpassphrase again before being able to call any methods which require the wallet to be unlocked.
  • WalletPassphrase: stores the wallet decryption key in memory for the indicated number of seconds. Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock time that overrides the old one.
  • WalletPassphraseChange: changes the wallet passphrase from ‘old passphrase’ to ‘new passphrase’.

In [16]:
print '\nBob\'s Wallet\n'
wallet= Bob.getwalletinfo()
for key in wallet.keys():
    print key + '\t' + str(wallet[key])
print '\nMary\'s Wallet\n'
wallet= Mary.getwalletinfo()
for key in wallet.keys():
    print key + '\t' + str(wallet[key])


Bob's Wallet

unconfirmed_balance	0E-8
paytxfee	0E-8
keypoololdest	1442934885
walletversion	60000
immature_balance	5000.00000192
txcount	109
balance	374.99999808
keypoolsize	101

Mary's Wallet

unconfirmed_balance	0E-8
paytxfee	0E-8
keypoololdest	1442934885
walletversion	60000
immature_balance	0E-8
txcount	1
balance	25.00000000
keypoolsize	101

In [17]:
import time
print '\nMary has ' + str(len(Mary.listtransactions())) + ' transactions from Bob\'s largesse'

print '\nMary\'s first address has received how many BTC? ' +\
str(Mary.getreceivedbyaddress( Mary.listtransactions()[0]['address'],0))
#str(Mary.getreceivedbyaddress('mmT3ER6w98jZAKwtTZrr3DSxrchS7fGxKW',0))

print '\nBob has ' + str(len(Bob.listtransactions())) + ' transactions from all that mining'
#print Bob.listtransactions()




##let's send Mary some more of Bob's bitcoins so we can see her unconfirmed balance
getnewaddress = Mary.getnewaddress()
print '\nNew address ' + str(getnewaddress)

##have Bob (proxy) send 0.5 bitcoins to Mary
txid = Bob.sendtoaddress(getnewaddress,0.5)

time.sleep(2)

print '\nMary\'s unconfirmed balance ' + str(Mary.getunconfirmedbalance())
print '\nMary\'s confirmed balance ' + str(Mary.getbalance())

##let's mine 6 blocks
Bob.generate(6)

time.sleep(2)

print 'After Bob\'s mining'
print '\nMary\'s unconfirmed balance ' + str(Mary.getunconfirmedbalance())
print '\nMary\'s confirmed balance ' + str(Mary.getbalance())


Mary has 1 transactions from Bob's largesse

Mary's first address has received how many BTC? 25.00000000

Bob has 10 transactions from all that mining

New address msajHXSKjgoMS44jARCHPNajEczQohXYHj

Mary's unconfirmed balance 0.50000000

Mary's confirmed balance 25.00000000
After Bob's mining

Mary's unconfirmed balance 0E-8

Mary's confirmed balance 25.50000000

Wallet Programs

Permitting receiving and spending of satoshis is the only essential feature of wallet software—but a particular wallet program doesn’t need to do both things. Two wallet programs can work together, one program distributing public keys in order to receive satoshis and another program signing transactions spending those satoshis.

Wallet programs also need to interact with the peer-to-peer network to get information from the block chain and to broadcast new transactions. However, the programs which distribute public keys or sign transactions don’t need to interact with the peer-to-peer network themselves.

This leaves us with three necessary, but separable, parts of a wallet system: a public key distribution program, a signing program, and a networked program. In the subsections below, we will describe common combinations of these parts.

Full-Service Wallets

The simplest wallet is a program which performs all three functions: it generates private keys, derives the corresponding public keys, helps distribute those public keys as necessary, monitors for outputs spent to those public keys, creates and signs transactions spending those outputs, and broadcasts the signed transactions.

Full-Service Wallets

As of this writing, almost all popular wallets can be used as full-service wallets.

The main advantage of full-service wallets is that they are easy to use. A single program does everything the user needs to receive and spend satoshis.

The main disadvantage of full-service wallets is that they store the private keys on a device connected to the Internet. The compromise of such devices is a common occurrence, and an Internet connection makes it easy to transmit private keys from a compromised device to an attacker.


In [ ]:

Utility RPCs

  • CreateMultiSig: creates a P2SH multi-signature address.
  • EstimateFee: estimates the transaction fee per kilobyte that needs to be paid for a transaction to be included within a certain number of blocks. New in 0.10.0
  • EstimatePriority: estimates the priority that a transaction needs in order to be included within a certain number of blocks as a free high-priority transaction. New in 0.10.0
  • ValidateAddress: returns information about the given Bitcoin address.
  • VerifyMessage: verifies a signed message.

In [ ]:

This code determines whether a transaction is included in a Merkle Tree. From Luke Dashjr


In [ ]:
# Eloipool - Python Bitcoin pool server
# Copyright (C) 2011-2012  Luke Dashjr <luke-jr+eloipool@utopios.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

# original code https://github.com/Crypto-Expert/stratum-mining/blob/master/lib/merkletree.py
# http://code.runnable.com/U3jqtyYUmAUxtsSS/bitcoin-block-merkle-root-python

from hashlib import sha256
from util import doublesha

class MerkleTree:
    def __init__(self, data, detailed=False):
        self.data = data
        self.recalculate(detailed)
        self._hash_steps = None
    
    def recalculate(self, detailed=False):
        L = self.data
        steps = []
        if detailed:
            detail = []
            PreL = []
            StartL = 0
        else:
            detail = None
            PreL = [None]
            StartL = 2
        Ll = len(L)
        if detailed or Ll > 1:
            while True:
                if detailed:
                    detail += L
                if Ll == 1:
                    break
                steps.append(L[1])
                if Ll % 2:
                    L += [L[-1]]
                L = PreL + [doublesha(L[i] + L[i + 1]) for i in range(StartL, Ll, 2)]
                Ll = len(L)
        self._steps = steps
        self.detail = detail
    
    def hash_steps(self):
        if self._hash_steps == None:
            self._hash_steps = doublesha(''.join(self._steps))
        return self._hash_steps
        
    def withFirst(self, f):
        steps = self._steps
        for s in steps:
            f = doublesha(f + s)
        return f
    
    def merkleRoot(self):
        return self.withFirst(self.data[0])

# MerkleTree tests
def _test():
    import binascii
    import time    
        
    mt = MerkleTree([None] + [binascii.unhexlify(a) for a in [
        '999d2c8bb6bda0bf784d9ebeb631d711dbbbfe1bc006ea13d6ad0d6a2649a971',
        '3f92594d5a3d7b4df29d7dd7c46a0dac39a96e751ba0fc9bab5435ea5e22a19d',
        'a5633f03855f541d8e60a6340fc491d49709dc821f3acb571956a856637adcb6',
        '28d97c850eaf917a4c76c02474b05b70a197eaefb468d21c22ed110afe8ec9e0',
    ]])
    assert(
        b'82293f182d5db07d08acf334a5a907012bbb9990851557ac0ec028116081bd5a' ==
        binascii.b2a_hex(mt.withFirst(binascii.unhexlify('d43b669fb42cfa84695b844c0402d410213faa4f3e66cb7248f688ff19d5e5f7')))
    )
    
    print '82293f182d5db07d08acf334a5a907012bbb9990851557ac0ec028116081bd5a'
    txes = [binascii.unhexlify(a) for a in [
        'd43b669fb42cfa84695b844c0402d410213faa4f3e66cb7248f688ff19d5e5f7',
        '999d2c8bb6bda0bf784d9ebeb631d711dbbbfe1bc006ea13d6ad0d6a2649a971',
        '3f92594d5a3d7b4df29d7dd7c46a0dac39a96e751ba0fc9bab5435ea5e22a19d',
        'a5633f03855f541d8e60a6340fc491d49709dc821f3acb571956a856637adcb6',
        '28d97c850eaf917a4c76c02474b05b70a197eaefb468d21c22ed110afe8ec9e0',
    ]]
             
    s = time.time()
    mt = MerkleTree(txes)
    for x in range(100):
        y = int('d43b669fb42cfa84695b844c0402d410213faa4f3e66cb7248f688ff19d5e5f7', 16)
        #y += x
        coinbasehash = binascii.unhexlify("%x" % y)
        x = binascii.b2a_hex(mt.withFirst(coinbasehash))

    print x
    print time.time() - s

if __name__ == '__main__':
    _test()

This code snippet illustrates a simplified proof-of-work algorithm not used by miners; by incementing the nonce and trying difficulties from 1-31 bits (2 - 2^32). Note that this runs for a long time, more than 20 minutes on a 4GB-RAM Ubuntu box.

From Mastering Bitcoin


In [ ]:
#!/usr/bin/env python
# example of proof-of-work algorithm

import hashlib
import time

max_nonce = 2 ** 32 # 4 billion

def proof_of_work(header, difficulty_bits):

    # calculate the difficulty target
    target = 2 ** (256-difficulty_bits)

    for nonce in xrange(max_nonce):
        hash_result = hashlib.sha256(str(header)+str(nonce)).hexdigest()

        # check if this is a valid result, below the target
        if long(hash_result, 16) < target:
            print "Success with nonce %d" % nonce
            print "Hash is %s" % hash_result
            return (hash_result,nonce)

    print "Failed after %d (max_nonce) tries" % nonce
    return nonce


if __name__ == '__main__':

    nonce = 0
    hash_result = ''

    # difficulty from 0 to 31 bits
    for difficulty_bits in xrange(32):

        difficulty = 2 ** difficulty_bits
        print "Difficulty: %ld (%d bits)" % (difficulty, difficulty_bits)

        print "Starting search..."

        # checkpoint the current time
        start_time = time.time()

        # make a new block which includes the hash from the previous block
        # we fake a block of transactions - just a string
        new_block = 'test block with transactions' + hash_result

        # find a valid nonce for the new block
        (hash_result, nonce) = proof_of_work(new_block, difficulty_bits)

        # checkpoint how long it took to find a result
        end_time = time.time()

        elapsed_time = end_time - start_time
        print "Elapsed Time: %.4f seconds" % elapsed_time

        if elapsed_time > 0:

            # estimate the hashes per second
            hash_power = float(long(nonce)/elapsed_time)
            print "Hashing Power: %ld hashes per second" % hash_power

In [ ]: