Estoy tratando de hacer una conexión simple entre pares usando Python.
Si entiendo correctamente, la comunicación comienza enviando un paquete de "versión" al nodo receptor. Luego, el nodo devuelve un paquete "verack", luego puede comenzar a consultar datos/empujar txs.
El blog de Ken Shirriff ha demostrado ser invaluable para llevarme tan lejos, pero no puedo hacer que sus ejemplos de código funcionen, ¿posiblemente porque están fechados?
En particular, cuando se ejecuta:
https://github.com/shirriff/bitcoin-code/blob/master/minimalPeerConnection.py
el zócalo se cierra inmediatamente. No puedo recibir un "verack" y no puedo continuar con el envío de mi tx. Tenga en cuenta que he reemplazado su IP codificada con un nodo actualmente operativo (124.248.237.178:8333).
Intenté construir un paquete de versión más "actualizado" (70002) que hace referencia a estos documentos , pero me encontré con el mismo problema:
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
¿Alguien puede señalarme en la dirección correcta?
Lo tengo funcionando.
El blog de Ken asume un entorno de Windows, en Linux de 64 bits, los recuentos de bytes son diferentes para ciertos tipos de datos, por lo que tuve que cambiar algunos de los formatos de "paquete".
Finalmente, había estado haciendo todo en hexadecimal y convirtiendo a binario solo para el envío de socket. Sin embargo, al calcular la suma de verificación sha256 (dos veces), debe estar en la carga útil BINARIA.
Código de trabajo (al menos para Linux de 64 bits):
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")