2

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.

3
  • 1
    It is probably helpful to run a full node with debugging enabled (e.g. Bitcoin Core with -debug=net), and connect to that. The output in debug.log may tell you what you're doing wrong. Commented Aug 30, 2020 at 16:09
  • Have you tried with magic = f9beb4d9? Commented Aug 30, 2020 at 19:03
  • This is the message you are getting back: {"code": -32700, "message": "messages must be encoded in UTF-8"}, "id": null Commented Aug 30, 2020 at 19:37

1 Answer 1

0

I think you have your magic byte order backwards. It should be 0xf9beb4d9.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.