Skip to content

Python Query Example

Eric Voskuil edited this page Jan 6, 2018 · 12 revisions

Short version:

#!python3
import zmq
import struct
from binascii import hexlify, unhexlify

# Connect to the server.
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://mainnet.libbitcoin.net:9091")

# Make the request in parts.
socket.send(b'blockchain.fetch_transaction2', zmq.SNDMORE)
socket.send(struct.pack('I', 42), zmq.SNDMORE)
socket.send(unhexlify('60e030aba2f593caf913a7d96880ff227143bfc370d03dbaee37d582801ebd83')[::-1])

# Collect the response in parts.
response_command = socket.recv()
response_id = socket.recv()
response_body = socket.recv()

# Decode and print transaction from message payload.
print(hexlify(response_body[4:]).decode('ascii'))

Output:

010000000181d06e4403b989d1e003def4944080e9537ef38e219f58a3856333050d72fe4a080000008b483045022100943e28772ef850587034b447a76c1eb918d63c82a4619a01a34cf32dee13807a02204cbe75c49f8ced0ebc373a6d8e7cb7ecab31369861d8997873b94bac13c379b3014104dbfb10dd8a498b3431f4c7041bbba82aa33146d40b7def4315e9e6df7424d527e762042f9fcc5450cbfc5f849bd3dace5cc9d9b3be8fadc3de92f96e303cf599ffffffff02a8101300000000001976a914b4dc57e35f93de9ec155872c1ad0136134fb08b188acbbe633000000000017a91461ec8bf07c6a3a04a08d1251d70178c1b3d273cc8700000000

Longer version:

#!python3
import zmq
import struct
from subprocess import call
from binascii import hexlify, unhexlify

# The default unsecured mainnet community server address.
# https://github.com/libbitcoin/libbitcoin-server/wiki/Community-Servers
server_url = "tcp://mainnet.libbitcoin.net:9091"

# This query returns a confirmed transaction (with witness encoding) by its hash.
# https://github.com/libbitcoin/libbitcoin-server/wiki/Query-Service#blockchainfetch_transaction
request_command = b'blockchain.fetch_transaction2'

# The arbitrary message id is for client response correlation.
request_id = struct.pack('I', 42)

# All integer and hash values are encoded in little-endian byte order.
request_hash = unhexlify('60e030aba2f593caf913a7d96880ff227143bfc370d03dbaee37d582801ebd83')[::-1]

# Connect to the server with 5 second timeouts.
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.setsockopt(zmq.RCVTIMEO, 5000)
socket.setsockopt(zmq.SNDTIMEO, 5000)
socket.connect(server_url)
    
# Make the request in parts.
socket.send(request_command, zmq.SNDMORE)
socket.send(request_id, zmq.SNDMORE)
socket.send(request_hash)

# Collect the response in parts.
response_command = socket.recv()
response_id = socket.recv()
response_body = socket.recv()

# These values allow the response to be correlated to the request.
# print(response_command.decode('ascii') + ":" + str(struct.unpack('I', response_id)[0]))

# Decode message payload according to blockchain.fetch_transaction specification.
ec = struct.unpack('<I', response_body[0:4])[0]
tx = hexlify(response_body[4:]).decode('ascii')

if ec == 3:
    # https://github.com/libbitcoin/libbitcoin/blob/master/include/bitcoin/bitcoin/error.hpp
    print("Transaction not found on server.")
elif ec != 0:
    # In the case of an error the remainder of the response may be missing and should be ignored.
    print("Error getting transaction from server: " + str(ec))
else:
    # Bitcoin objects (headers, blocks and transactions) are encoded in canonical serialization.
    assert call(["bx", "tx-decode", tx]) == 0

In the interest of simplicity the above example does not handle ZeroMQ exceptions, and assumes that BX is installed.

Output:

transaction
{
    hash 60e030aba2f593caf913a7d96880ff227143bfc370d03dbaee37d582801ebd83
    inputs
    {
        input
        {
            address_hash b4dc57e35f93de9ec155872c1ad0136134fb08b1
            previous_output
            {
                hash 4afe720d05336385a3589f218ef37e53e9804094f4de03e0d189b903446ed081
                index 8
            }
            script "[3045022100943e28772ef850587034b447a76c1eb918d63c82a4619a01a34cf32dee13807a02204cbe75c49f8ced0ebc373a6d8e7cb7ecab31369861d8997873b94bac13c379b301] [04dbfb10dd8a498b3431f4c7041bbba82aa33146d40b7def4315e9e6df7424d527e762042f9fcc5450cbfc5f849bd3dace5cc9d9b3be8fadc3de92f96e303cf599]"
            sequence 4294967295
        }
    }
    lock_time 0
    outputs
    {
        output
        {
            address_hash b4dc57e35f93de9ec155872c1ad0136134fb08b1
            script "dup hash160 [b4dc57e35f93de9ec155872c1ad0136134fb08b1] equalverify checksig"
            value 1249448
        }
        output
        {
            address_hash 61ec8bf07c6a3a04a08d1251d70178c1b3d273cc
            script "hash160 [61ec8bf07c6a3a04a08d1251d70178c1b3d273cc] equal"
            value 3401403
        }
    }
    version 1
}
Clone this wiki locally