Я пытаюсь установить простое одноранговое соединение с помощью Python.
Если я правильно понимаю, общение начинается с отправки пакета «версия» на принимающий узел. Затем узел отправляет обратно пакет «verack», после чего вы можете начать запрашивать данные/отправлять txs.
Блог Кена Ширриффа оказался неоценимым для меня, но я не могу заставить его примеры кода работать, возможно, потому, что они устарели?
В частности, при запуске:
https://github.com/shirriff/bitcoin-code/blob/master/minimalPeerConnection.py
сокет сразу закрывается. Я не могу получить обратно "verack" и не могу продолжить отправку моего tx. Обратите внимание, что я заменил его жестко запрограммированный IP-адрес на текущий работающий узел (124.248.237.178:8333).
Я попытался создать пакет более «актуальной» версии (70002), ссылаясь на эти документы , но столкнулся с той же проблемой:
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
Может кто-то указать мне верное направление?
Получил это работает.
В блоге Кена предполагается среда Windows, в 64-разрядной версии Linux количество байтов отличается для определенных типов данных, поэтому мне пришлось изменить некоторые форматы «упаковки».
Наконец, я делал все в шестнадцатеричном формате и преобразовывал в двоичный только для отправки через сокет. Однако при вычислении контрольной суммы sha256 (дважды) это должно быть в BINARY полезной нагрузке.
Рабочий код (по крайней мере, для 64-битной 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")