Skip to main content
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user

I am trying to implement an SPV client in python (for my own learning). I want to start by making a simple TCP connection to a full node, but I either cannot get a response to my version message, or to my verack message if the version message goes through. I have referenced thisthis and this is the code that I am trying to run:

I am trying to implement an SPV client in python (for my own learning). I want to start by making a simple TCP connection to a full node, but I either cannot get a response to my version message, or to my verack message if the version message goes through. I have referenced this and this is the code that I am trying to run:

I am trying to implement an SPV client in python (for my own learning). I want to start by making a simple TCP connection to a full node, but I either cannot get a response to my version message, or to my verack message if the version message goes through. I have referenced this and this is the code that I am trying to run:

Bumped by Community user
Source Link

SPV client TCP connection in python

I am trying to implement an SPV client in python (for my own learning). I want to start by making a simple TCP connection to a full node, but I either cannot get a response to my version message, or to my verack message if the version message goes through. I have referenced this and this is the code that I am trying to run:

#Import dependencies
import socket
import time
import random
import struct
import hashlib
import binascii
import ssl
import socks

# Binary encode the sub-version
def create_sub_version():
    sub_version = "/Satoshi:0.7.2/"
    return b'\x0F' + sub_version.encode()

# Binary encode the network addresses
def create_network_address(ip_address, port):
    network_address = struct.pack('>8s16sH', b'\x01', 
        bytearray.fromhex("00000000000000000000ffff") + socket.inet_aton(ip_address), port)
    return(network_address)

# Create the TCP request object
def create_message(magic, command, payload):
    checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[0:4]
    return(struct.pack('L12sL4s', magic, command.encode(), len(payload), checksum) + payload)

# Create the "version" request payload
def create_payload_version(peer_ip_address):
    version = 60002
    services = 1
    timestamp = int(time.time())
    addr_local = create_network_address("127.0.0.1", 8333)
    addr_peer = create_network_address(peer_ip_address, 8333)
    nonce = random.getrandbits(64)
    start_height = 645953
    payload = struct.pack('<LQQ26s26sQ16sL', version, services, timestamp, addr_peer,
                          addr_local, nonce, create_sub_version(), start_height)
    return(payload)

# Create the "verack" request message
def create_message_verack():
    return bytearray.fromhex("f9beb4d976657261636b000000000000000000005df6e0e2")


# Create the "getdata" request payload
def create_payload_getdata(tx_id):
    count = 1
    type = 1
    hash = bytearray.fromhex(tx_id)
    payload = struct.pack('<bb32s', count, type, hash)
    return(payload)

# Print request/response data
def print_response(command, request_data, response_data):
    print("")
    print("Command: " + command)
    print("Request:")
    print(binascii.hexlify(request_data))
    print("Response:")
    print(binascii.hexlify(response_data))

if __name__ == '__main__':
    # Set constants
    magic_value = 0xd9b4bef9
    tx_id = "a13e7979d3607e187d2ce81ca9fdadfe967b2f3fc1109ce47d46cc09ebd41c50"
    peer_ip_address = socket.gethostbyname('bitcoin.aranguren.org') 
    peer_tcp_port =  50002
    buffer_size = 1024

    # Create Request Objects
    version_payload = create_payload_version(peer_ip_address)
    version_message = create_message(magic_value, 'version', version_payload)
    verack_message = create_message_verack()
    getdata_payload = create_payload_getdata(tx_id)
    getdata_message = create_message(magic_value, 'getdata', getdata_payload)

    # Establish TCP Connection
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    ws = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
    ws.connect((peer_ip_address, peer_tcp_port))

    # Send message "version"
    ws.send(version_message)
    response_data = ws.recv(buffer_size)
    print_response("version", version_message, response_data)

    # Send message "verack"
    ws.send(verack_message)
    response_data = ws.recv(buffer_size)
    print_response("verack", verack_message, response_data)

    # Send message "getdata"
    ws.send(getdata_message)
    response_data = ws.recv(buffer_size)
    print_response("getdata", getdata_message, response_data)

    # Close the TCP connection
    ws.close()

The server I connect to in the code is among the only ones that would respond to the version message, returning b'7b226a736f6e727063223a2022322e30222c20226572726f72223a207b22636f6465223a202d33323730302c20226d657373616765223a20226d65737361676573206d75737420626520656e636f64656420696e205554462d38227d2c20226964223a206e756c6c7d0a'.

I also tried referencing: this stack exchange question and Ken Shirriff's github code, but none seem to work, either because I am using python3 or from other causes. I am a beginner in this, so if somebody could help me understand why I cannot get my messages across in the above code or has another implementation in python3, I would be grateful.