Skip to content

Commit 05bddb2

Browse files
committed
[test] Perform initial v2 handshake
1 parent a049d1b commit 05bddb2

File tree

1 file changed

+50
-1
lines changed
  • test/functional/test_framework

1 file changed

+50
-1
lines changed

test/functional/test_framework/p2p.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,62 @@ def connection_lost(self, exc):
232232
self.recvbuf = b""
233233
self.on_close()
234234

235+
# v2 handshake method
236+
def v2_handshake(self):
237+
"""v2 handshake performed before P2P messages are exchanged (see BIP324). P2PConnection is the initiator
238+
(in inbound connections to TestNode) and the responder (in outbound connections from TestNode).
239+
Performed by:
240+
* initiator using `initiate_v2_handshake()`, `complete_handshake()` and `authenticate_handshake()`
241+
* responder using `respond_v2_handshake()`, `complete_handshake()` and `authenticate_handshake()`
242+
243+
`initiate_v2_handshake()` is immediately done by the initiator when the connection is established in
244+
`connection_made()`. The rest of the initial v2 handshake functions are handled here.
245+
"""
246+
if not self.v2_state.peer:
247+
if not self.v2_state.initiating and not self.v2_state.sent_garbage:
248+
# if the responder hasn't sent garbage yet, the responder is still reading ellswift bytes
249+
# reads ellswift bytes till the first mismatch from 12 bytes V1_PREFIX
250+
length, send_handshake_bytes = self.v2_state.respond_v2_handshake(BytesIO(self.recvbuf))
251+
self.recvbuf = self.recvbuf[length:]
252+
if send_handshake_bytes == -1:
253+
self.v2_state = None
254+
return
255+
elif send_handshake_bytes:
256+
self.send_raw_message(send_handshake_bytes)
257+
elif send_handshake_bytes == b"":
258+
return # only after send_handshake_bytes are sent can `complete_handshake()` be done
259+
260+
# `complete_handshake()` reads the remaining ellswift bytes from recvbuf
261+
# and sends response after deriving shared ECDH secret using received ellswift bytes
262+
length, response = self.v2_state.complete_handshake(BytesIO(self.recvbuf))
263+
self.recvbuf = self.recvbuf[length:]
264+
if response:
265+
self.send_raw_message(response)
266+
else:
267+
return # only after response is sent can `authenticate_handshake()` be done
268+
269+
# `self.v2_state.peer` is instantiated only after shared ECDH secret/BIP324 derived keys and ciphers
270+
# is derived in `complete_handshake()`.
271+
# so `authenticate_handshake()` which uses the BIP324 derived ciphers gets called after `complete_handshake()`.
272+
assert self.v2_state.peer
273+
length, is_mac_auth = self.v2_state.authenticate_handshake(self.recvbuf)
274+
if not is_mac_auth:
275+
raise ValueError("invalid v2 mac tag in handshake authentication")
276+
self.recvbuf = self.recvbuf[length:]
277+
while self.v2_state.tried_v2_handshake and self.queue_messages:
278+
message = self.queue_messages.pop(0)
279+
self.send_message(message)
280+
235281
# Socket read methods
236282

237283
def data_received(self, t):
238284
"""asyncio callback when data is read from the socket."""
239285
if len(t) > 0:
240286
self.recvbuf += t
241-
self._on_data()
287+
if self.supports_v2_p2p and not self.v2_state.tried_v2_handshake:
288+
self.v2_handshake()
289+
else:
290+
self._on_data()
242291

243292
def _on_data(self):
244293
"""Try to read P2P messages from the recv buffer.

0 commit comments

Comments
 (0)