Peer-Verbindung in Python herstellen

Ich versuche, eine einfache Peer-Verbindung mit Python herzustellen.

Wenn ich das richtig verstehe, beginnt die Kommunikation mit dem Senden eines "Versions" -Pakets an den empfangenden Knoten. Der Knoten sendet dann ein "Verack"-Paket zurück, danach können Sie mit der Abfrage nach Daten/Pushing-TXS beginnen.

Ken Shirriffs Blog hat sich als unschätzbar erwiesen, um mich so weit zu bringen, aber ich kann seine Codebeispiele nicht zum Laufen bringen, möglicherweise weil sie veraltet sind?

Insbesondere beim Laufen:

https://github.com/shirriff/bitcoin-code/blob/master/minimalPeerConnection.py

Die Steckdose schließt sofort. Ich erhalte kein "verack" zurück und kann nicht mit dem Pushen meines TX fortfahren. Beachten Sie, dass ich seine fest codierte IP durch einen aktuell funktionierenden Knoten (124.248.237.178:8333) ersetzt habe.

Ich habe versucht, ein "aktuelleres" Versionspaket (70002) zu erstellen, das auf diese Dokumente verweist , aber auf dasselbe Problem gestoßen ist:

import struct
import socket
import time
import hashlib
import binascii

magic = 0xd9b4bef9

def makeMessage(magic,command,payload):
    checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[0:4]
    return struct.pack('L12sL4s',magic,command,len(payload),checksum).encode("hex")+payload
def makeVersionPayload():
    version = 70002
    services = 1
    timestamp = int(time.time())

    adr_u = "::ffff:127.0.0.1"
    services_u = 1
    port_u = 8333

    adr_me = "::ffff:127.0.0.1"
    services_me = 1
    port_me = 8333

    nonce = 0

    user_agent_bytes = 0
    start_height = 0
    relay = 0

    #https://bitcoin.org/en/developer-reference#version
    payload_hex = "";
    payload_hex += struct.pack("<L",version).encode("hex")
    payload_hex += struct.pack("<Q",services).encode("hex")
    payload_hex += struct.pack("<Q",timestamp).encode("hex")
    payload_hex += struct.pack("<Q",services_u).encode("hex")
    payload_hex += struct.pack(">16s",adr_u).encode("hex")
    payload_hex += struct.pack(">H",port_u).encode("hex")
    payload_hex += struct.pack("<Q",services_me).encode("hex")
    payload_hex += struct.pack(">16s",adr_me).encode("hex")
    payload_hex += struct.pack(">H",port_me).encode("hex")
    payload_hex += struct.pack("<Q",nonce).encode("hex")
    payload_hex += struct.pack("<B",user_agent_bytes).encode("hex")
    payload_hex += struct.pack("<L",start_height).encode("hex")
    payload_hex += struct.pack("<B",relay).encode("hex")
    return payload_hex

ip = socket.gethostbyname("124.248.237.178")
port = 8333
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "connected to node..."
sock.connect((ip,port))

hex_msg = makeMessage(magic,"version",makeVersionPayload())
print "sending version packet"
sock.send(binascii.unhexlify(hex_msg))

while 1:
    msg = sock.recv(4096)
    if not msg:
        print "disconnected"
        exit()
    else:
        #expecting verack?
        print "response: ",msg

Kann mich jemand in die richtige Richtung weisen?

Antworten (1)

Habe es funktioniert.

Kens Blog geht von einer Windows-Umgebung aus, in 64-Bit-Linux sind die Bytezahlen für bestimmte Datentypen unterschiedlich, daher musste ich einige der "Pack" -Formate ändern.

Schließlich habe ich alles in Hex gemacht und nur für den Socket-Send in Binär konvertiert. Bei der Berechnung der sha256 (zweimal) Prüfsumme muss diese jedoch auf der BINARY Payload stehen.

Arbeitscode (mindestens für 64-Bit-Linux):

import struct
import socket
import time
import hashlib
import binascii

magic = "f9beb4d9"

def makeMessage(magic,command,payload):
    checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[0:4]
    return magic.decode("hex")+struct.pack('12sI4s',command,len(payload),checksum)+payload
def makeVersionPayload():
    version = 70002
    services = 0
    timestamp = int(time.time())

    addr_you = "127.0.0.1"
    services_you = 0
    port_you = 8333

    addr_me = "127.0.0.1"
    services_me = 0
    port_me = 8333

    nonce = 0

    user_agent_bytes = 0
    start_height = 0
    relay = 1

    #https://bitcoin.org/en/developer-reference#version
    payload = "";
    payload += struct.pack("i",version)
    payload += struct.pack("Q",services)
    payload += struct.pack("q",timestamp)
    payload += struct.pack("Q",services_you)
    payload += struct.pack(">16s",addr_you)
    payload += struct.pack(">H",port_you)
    payload += struct.pack("Q",services_me)
    payload += struct.pack(">16s",addr_me)
    payload += struct.pack(">H",port_me)
    payload += struct.pack("Q",nonce)
    payload += struct.pack("B",user_agent_bytes)
    payload += struct.pack("i",start_height)
    payload += struct.pack("B",relay)
    return payload

ip = socket.gethostbyname("124.248.237.178")
port = 8333
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "connected to node..."
sock.connect((ip,port))

msg = makeMessage(magic,"version",makeVersionPayload())
print "sending version packet"
sock.send(msg)

while 1:
    msg = sock.recv(2**10)
    if not msg:
        print "done"
        exit()
    else:
        print msg.encode("hex")