Friday, November 22, 2024

SPV consumer TCP connection in python

I’m attempting to implement an SPV consumer in python (for my very own studying). I need to begin by making a easy TCP connection to a full node, however I both can’t get a response to my model message, or to my verack message if the model message goes by means of. I’ve referenced this and that is the code that I’m attempting 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 community 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 "model" request payload
def create_payload_version(peer_ip_address):
    model = 60002
    companies = 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', model, companies, 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):
    rely = 1
    kind = 1
    hash = bytearray.fromhex(tx_id)
    payload = struct.pack('<bb32s', rely, kind, hash)
    return(payload)

# Print request/response knowledge
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, 'model', version_payload)
    verack_message = create_message_verack()
    getdata_payload = create_payload_getdata(tx_id)
    getdata_message = create_message(magic_value, 'getdata', getdata_payload)

    # Set up 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.join((peer_ip_address, peer_tcp_port))

    # Ship message "model"
    ws.ship(version_message)
    response_data = ws.recv(buffer_size)
    print_response("model", version_message, response_data)

    # Ship message "verack"
    ws.ship(verack_message)
    response_data = ws.recv(buffer_size)
    print_response("verack", verack_message, response_data)

    # Ship message "getdata"
    ws.ship(getdata_message)
    response_data = ws.recv(buffer_size)
    print_response("getdata", getdata_message, response_data)

    # Shut the TCP connection
    ws.shut()

The server I connect with within the code is among the many solely ones that might reply to the model message, returning b’7b226a736f6e727063223a2022322e30222c20226572726f72223a207b22636f6465223a202d33323730302c20226d657373616765223a20226d65737361676573206d75737420626520656e636f64656420696e205554462d38227d2c20226964223a206e756c6c7d0a’.

I additionally tried referencing: this stack change query and Ken Shirriff’s github code, however none appear to work, both as a result of I’m utilizing python3 or from different causes. I’m a newbie on this, so if any individual may assist me perceive why I can’t get my messages throughout within the above code or has one other implementation in python3, I’d be grateful.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles