mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-10-11 03:53:22 +02:00
net: advertise support for ADDRv2 via new message
Introduce a new message `sendaddrv2` to signal support for ADDRv2. Send the new message immediately after sending the `VERACK` message. Add support for receiving and parsing ADDRv2 messages. Send ADDRv2 messages (instead of ADDR) to a peer if he has advertised support for it. Co-authored-by: Carl Dong <contact@carldong.me>
This commit is contained in:
@@ -136,12 +136,17 @@ def uint256_from_compact(c):
|
||||
return v
|
||||
|
||||
|
||||
def deser_vector(f, c):
|
||||
# deser_function_name: Allow for an alternate deserialization function on the
|
||||
# entries in the vector.
|
||||
def deser_vector(f, c, deser_function_name=None):
|
||||
nit = deser_compact_size(f)
|
||||
r = []
|
||||
for _ in range(nit):
|
||||
t = c()
|
||||
t.deserialize(f)
|
||||
if deser_function_name:
|
||||
getattr(t, deser_function_name)(f)
|
||||
else:
|
||||
t.deserialize(f)
|
||||
r.append(t)
|
||||
return r
|
||||
|
||||
@@ -204,38 +209,82 @@ def ToHex(obj):
|
||||
|
||||
|
||||
class CAddress:
|
||||
__slots__ = ("ip", "nServices", "pchReserved", "port", "time")
|
||||
__slots__ = ("net", "ip", "nServices", "port", "time")
|
||||
|
||||
# see https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki
|
||||
NET_IPV4 = 1
|
||||
|
||||
ADDRV2_NET_NAME = {
|
||||
NET_IPV4: "IPv4"
|
||||
}
|
||||
|
||||
ADDRV2_ADDRESS_LENGTH = {
|
||||
NET_IPV4: 4
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.time = 0
|
||||
self.nServices = 1
|
||||
self.pchReserved = b"\x00" * 10 + b"\xff" * 2
|
||||
self.net = self.NET_IPV4
|
||||
self.ip = "0.0.0.0"
|
||||
self.port = 0
|
||||
|
||||
def deserialize(self, f, *, with_time=True):
|
||||
"""Deserialize from addrv1 format (pre-BIP155)"""
|
||||
if with_time:
|
||||
# VERSION messages serialize CAddress objects without time
|
||||
self.time = struct.unpack("<i", f.read(4))[0]
|
||||
self.time = struct.unpack("<I", f.read(4))[0]
|
||||
self.nServices = struct.unpack("<Q", f.read(8))[0]
|
||||
self.pchReserved = f.read(12)
|
||||
# We only support IPv4 which means skip 12 bytes and read the next 4 as IPv4 address.
|
||||
f.read(12)
|
||||
self.net = self.NET_IPV4
|
||||
self.ip = socket.inet_ntoa(f.read(4))
|
||||
self.port = struct.unpack(">H", f.read(2))[0]
|
||||
|
||||
def serialize(self, *, with_time=True):
|
||||
"""Serialize in addrv1 format (pre-BIP155)"""
|
||||
assert self.net == self.NET_IPV4
|
||||
r = b""
|
||||
if with_time:
|
||||
# VERSION messages serialize CAddress objects without time
|
||||
r += struct.pack("<i", self.time)
|
||||
r += struct.pack("<I", self.time)
|
||||
r += struct.pack("<Q", self.nServices)
|
||||
r += self.pchReserved
|
||||
r += b"\x00" * 10 + b"\xff" * 2
|
||||
r += socket.inet_aton(self.ip)
|
||||
r += struct.pack(">H", self.port)
|
||||
return r
|
||||
|
||||
def deserialize_v2(self, f):
|
||||
"""Deserialize from addrv2 format (BIP155)"""
|
||||
self.time = struct.unpack("<I", f.read(4))[0]
|
||||
|
||||
self.nServices = deser_compact_size(f)
|
||||
|
||||
self.net = struct.unpack("B", f.read(1))[0]
|
||||
assert self.net == self.NET_IPV4
|
||||
|
||||
address_length = deser_compact_size(f)
|
||||
assert address_length == self.ADDRV2_ADDRESS_LENGTH[self.net]
|
||||
|
||||
self.ip = socket.inet_ntoa(f.read(4))
|
||||
|
||||
self.port = struct.unpack(">H", f.read(2))[0]
|
||||
|
||||
def serialize_v2(self):
|
||||
"""Serialize in addrv2 format (BIP155)"""
|
||||
assert self.net == self.NET_IPV4
|
||||
r = b""
|
||||
r += struct.pack("<I", self.time)
|
||||
r += ser_compact_size(self.nServices)
|
||||
r += struct.pack("B", self.net)
|
||||
r += ser_compact_size(self.ADDRV2_ADDRESS_LENGTH[self.net])
|
||||
r += socket.inet_aton(self.ip)
|
||||
r += struct.pack(">H", self.port)
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices,
|
||||
self.ip, self.port)
|
||||
return ("CAddress(nServices=%i net=%s addr=%s port=%i)"
|
||||
% (self.nServices, self.ADDRV2_NET_NAME[self.net], self.ip, self.port))
|
||||
|
||||
|
||||
class CInv:
|
||||
@@ -1064,6 +1113,40 @@ class msg_addr:
|
||||
return "msg_addr(addrs=%s)" % (repr(self.addrs))
|
||||
|
||||
|
||||
class msg_addrv2:
|
||||
__slots__ = ("addrs",)
|
||||
msgtype = b"addrv2"
|
||||
|
||||
def __init__(self):
|
||||
self.addrs = []
|
||||
|
||||
def deserialize(self, f):
|
||||
self.addrs = deser_vector(f, CAddress, "deserialize_v2")
|
||||
|
||||
def serialize(self):
|
||||
return ser_vector(self.addrs, "serialize_v2")
|
||||
|
||||
def __repr__(self):
|
||||
return "msg_addrv2(addrs=%s)" % (repr(self.addrs))
|
||||
|
||||
|
||||
class msg_sendaddrv2:
|
||||
__slots__ = ()
|
||||
msgtype = b"sendaddrv2"
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def deserialize(self, f):
|
||||
pass
|
||||
|
||||
def serialize(self):
|
||||
return b""
|
||||
|
||||
def __repr__(self):
|
||||
return "msg_sendaddrv2()"
|
||||
|
||||
|
||||
class msg_inv:
|
||||
__slots__ = ("inv",)
|
||||
msgtype = b"inv"
|
||||
|
Reference in New Issue
Block a user