Cómo construir un mensaje de ping

Estoy luchando mucho tratando de descubrir cómo enviar un mensaje básico "PING" y recibir una respuesta "PONG".

import random
import hashlib
import socket
PEER_IP = "35.187.200.6"
PEER_PORT = 8333

nonce = (random.getrandbits(64)).to_bytes(8, byteorder="little", signed=False)

magic_number = bytes.fromhex("f9beb4d9")
command_name = bytes.fromhex("ping".encode("utf-8").hex() + ("00")*8)
payload_size = (int(len(nonce))).to_bytes(4, byteorder="little", signed=False)
checksum = hashlib.sha256(hashlib.sha256(nonce).digest()).digest()[:4]

final_msg = (
    magic_number
    + command_name
    + payload_size
    + checksum
    + nonce
)

sock = socket.socket()
sock.connect((PEER_IP, PEER_PORT))
sock.send(final_msg)
pong = sock.recv(1024)
print(pong)

Estoy siguiendo este tutorial de YouTube y agregué la capa de socket yo mismo.

La única respuesta que recibo es

b''

Cualquier idea de lo que estoy haciendo mal aquí, sería muy apreciada.

Gracias

Creo que necesita negociar un versionmensaje antes de que pueda ocurrir cualquier otra comunicación. Además, recibir una matriz de longitud cero recvsignifica que el enchufe se ha desconectado.

Respuestas (1)

Es necesario enviar un versionmensaje (y recibir el correspondiente verack) antes de enviar cualquier otra cosa. Aquí hay una versión parcheada rápidamente de su secuencia de comandos que maneja el mensaje de versión:

import hashlib
import random
import socket
import time
import urllib.request

PEER_IP = "127.0.0.1"
PEER_PORT = 8333

nonce = (random.getrandbits(64)).to_bytes(8, byteorder="little", signed=False)

magic_number = bytes.fromhex("f9beb4d9")
command_name = bytes.fromhex("ping".encode("utf-8").hex() + ("00")*8)
payload_size = (int(len(nonce))).to_bytes(4, byteorder="little", signed=False)
checksum = hashlib.sha256(hashlib.sha256(nonce).digest()).digest()[:4]

pong_msg = (
    magic_number
    + command_name
    + payload_size
    + checksum
    + nonce
)

# Magic bytes, as usual
magic = bytes.fromhex('f9beb4d9')
# Version number (PROTOCOL_VERSION in core)
version = int(70015).to_bytes(4, 'little')
# Random services, we don't care
services = int(1).to_bytes(8, 'little')
timestamp = int(time.time()).to_bytes(8, 'little')
myip_str = urllib.request.urlopen('https://api.ipify.org').read().decode()
myip = socket.inet_aton(myip_str)
nodeip = socket.inet_aton(PEER_IP)
# https://en.bitcoin.it/wiki/Protocol_documentation#Network_address
addr_recv = services + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
addr_recv += nodeip + int(8333).to_bytes(2, 'big')
addr_from = services + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
addr_from += myip + int(8333).to_bytes(2, 'big')
nonce = 0x00.to_bytes(8, 'little')
# You can replace this with something more fun
user_agent = 0x00.to_bytes(1, 'big')
# Let's say zero, once again we don't care for this example
start_height = 0x00.to_bytes(4, 'little')
# The message content, which we'll compute the checksum from
payload = version + services + timestamp + addr_recv + addr_from + nonce
payload += user_agent + start_height
checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
payload_length = len(payload)
# The command type, as NULL padded ascii
version_message = magic + 'version'.encode('ascii') + b'\x00\x00\x00\x00\x00'
version_message += payload_length.to_bytes(4, 'little') + checksum + payload

sock = socket.socket()
sock.connect((PEER_IP, PEER_PORT))
print('Sending version message..',)
sock.send(version_message)
print('Received verack: {}'.format(sock.recv(24)), end='\n\n')
print('Sending ping..')
sock.send(pong_msg)
print('Received pong: {}'.format(sock.recv(1024)))

Y aquí hay una salida de muestra de mi nodo:

Sending version message..
Received verack: b'\xf9\xbe\xb4\xd9version\x00\x00\x00\x00\x00h\x00\x00\x00n\x8a\xbe\xc7'

Sending ping..
Received pong: b'\x7f\x11\x01\x00\r\x04\x00\x00\x00\x00\x00\x00\x86\xc5\x08^\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xa0vQ\x16V\xb1\xab\x12/Satoshi:0.19.0.1/\x14P\t\x00\x01\xf9\xbe\xb4\xd9verack\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xf6\xe0\xe2'

Aquí está la documentación del protocolo , en la que puede confiar para implementar mensajes de protocolo.

Genial, muchas gracias por tu ayuda. Muy apreciado.