mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-12 22:02:28 +02:00
Merge #19954: Complete the BIP155 implementation and upgrade to TORv3
dcf0cb4776
tor: make a TORv3 hidden service instead of TORv2 (Vasil Dimov)353a3fdaad
net: advertise support for ADDRv2 via new message (Vasil Dimov)201a4596d9
net: CAddress & CAddrMan: (un)serialize as ADDRv2 (Vasil Dimov)1d3ec2a1fd
Support bypassing range check in ReadCompactSize (Pieter Wuille) Pull request description: This PR contains the two remaining commits from #19031 to complete the [BIP155](https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki) implementation: `net: CAddress & CAddrMan: (un)serialize as ADDRv2` `net: advertise support for ADDRv2 via new message` plus one more commit: `tor: make a TORv3 hidden service instead of TORv2` ACKs for top commit: jonatack: re-ACKdcf0cb4776
per `git diff 9b56a68 dcf0cb4` only change since last review is an update to the release notes which partially picked up the suggested text. Running a node on this branch and addnode-ing to 6 other Tor v3 nodes, I see "addrv2" and "sendaddrv2" messages in getpeerinfo in both the "bytesrecv_per_msg" and "bytessent_per_msg" JSON objects. sipa: ACKdcf0cb4776
hebasto: re-ACKdcf0cb4776
, the node works flawlessly in all of the modes: Tor-only, clearnet-only, mixed. laanwj: Edit: I have to retract this ACK for now, I'm having some problems with this PR on a FreeBSD node. It drops all outgoing connections with thisdcf0cb4776
merged on master (12a1c3ad1a
). ariard: Code Review ACKdcf0cb4
Tree-SHA512: 28d4d0d817b8664d2f4b18c0e0f31579b2f0f2d23310ed213f1f436a4242afea14dfbf99e07e15889bc5c5c71ad50056797e9307ff8a90e96704f588a6171308
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"
|
||||
|
@ -33,6 +33,7 @@ from test_framework.messages import (
|
||||
MAX_HEADERS_RESULTS,
|
||||
MIN_VERSION_SUPPORTED,
|
||||
msg_addr,
|
||||
msg_addrv2,
|
||||
msg_block,
|
||||
MSG_BLOCK,
|
||||
msg_blocktxn,
|
||||
@ -56,6 +57,7 @@ from test_framework.messages import (
|
||||
msg_notfound,
|
||||
msg_ping,
|
||||
msg_pong,
|
||||
msg_sendaddrv2,
|
||||
msg_sendcmpct,
|
||||
msg_sendheaders,
|
||||
msg_tx,
|
||||
@ -75,6 +77,7 @@ logger = logging.getLogger("TestFramework.p2p")
|
||||
|
||||
MESSAGEMAP = {
|
||||
b"addr": msg_addr,
|
||||
b"addrv2": msg_addrv2,
|
||||
b"block": msg_block,
|
||||
b"blocktxn": msg_blocktxn,
|
||||
b"cfcheckpt": msg_cfcheckpt,
|
||||
@ -97,6 +100,7 @@ MESSAGEMAP = {
|
||||
b"notfound": msg_notfound,
|
||||
b"ping": msg_ping,
|
||||
b"pong": msg_pong,
|
||||
b"sendaddrv2": msg_sendaddrv2,
|
||||
b"sendcmpct": msg_sendcmpct,
|
||||
b"sendheaders": msg_sendheaders,
|
||||
b"tx": msg_tx,
|
||||
@ -285,7 +289,7 @@ class P2PInterface(P2PConnection):
|
||||
|
||||
Individual testcases should subclass this and override the on_* methods
|
||||
if they want to alter message handling behaviour."""
|
||||
def __init__(self):
|
||||
def __init__(self, support_addrv2=False):
|
||||
super().__init__()
|
||||
|
||||
# Track number of messages of each type received.
|
||||
@ -303,6 +307,8 @@ class P2PInterface(P2PConnection):
|
||||
# The network services received from the peer
|
||||
self.nServices = 0
|
||||
|
||||
self.support_addrv2 = support_addrv2
|
||||
|
||||
def peer_connect(self, *args, services=NODE_NETWORK|NODE_WITNESS, send_version=True, **kwargs):
|
||||
create_conn = super().peer_connect(*args, **kwargs)
|
||||
|
||||
@ -345,6 +351,7 @@ class P2PInterface(P2PConnection):
|
||||
pass
|
||||
|
||||
def on_addr(self, message): pass
|
||||
def on_addrv2(self, message): pass
|
||||
def on_block(self, message): pass
|
||||
def on_blocktxn(self, message): pass
|
||||
def on_cfcheckpt(self, message): pass
|
||||
@ -365,6 +372,7 @@ class P2PInterface(P2PConnection):
|
||||
def on_merkleblock(self, message): pass
|
||||
def on_notfound(self, message): pass
|
||||
def on_pong(self, message): pass
|
||||
def on_sendaddrv2(self, message): pass
|
||||
def on_sendcmpct(self, message): pass
|
||||
def on_sendheaders(self, message): pass
|
||||
def on_tx(self, message): pass
|
||||
@ -389,6 +397,8 @@ class P2PInterface(P2PConnection):
|
||||
if message.nVersion >= 70016:
|
||||
self.send_message(msg_wtxidrelay())
|
||||
self.send_message(msg_verack())
|
||||
if self.support_addrv2:
|
||||
self.send_message(msg_sendaddrv2())
|
||||
self.nServices = message.nServices
|
||||
|
||||
# Connection helper methods
|
||||
|
Reference in New Issue
Block a user