@@ -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