@@ -915,9 +915,9 @@ size_t V1Transport::GetSendMemoryUsage() const noexcept
915915
916916V2Transport::V2Transport (NodeId nodeid, bool initiating, int type_in, int version_in) noexcept :
917917 m_cipher{}, m_initiating{initiating}, m_nodeid{nodeid},
918- m_recv_type{type_in}, m_recv_version{version_in},
919- m_recv_state{RecvState::KEY},
920- m_send_state{SendState::AWAITING_KEY}
918+ m_v1_fallback{nodeid, type_in, version_in}, m_recv_type{type_in}, m_recv_version{version_in},
919+ m_recv_state{initiating ? RecvState::KEY : RecvState::KEY_MAYBE_V1 },
920+ m_send_state{initiating ? SendState::AWAITING_KEY : SendState::MAYBE_V1 }
921921{
922922 // Initialize the send buffer with ellswift pubkey.
923923 m_send_buffer.resize (EllSwiftPubKey::size ());
@@ -926,9 +926,9 @@ V2Transport::V2Transport(NodeId nodeid, bool initiating, int type_in, int versio
926926
927927V2Transport::V2Transport (NodeId nodeid, bool initiating, int type_in, int version_in, const CKey& key, Span<const std::byte> ent32) noexcept :
928928 m_cipher{key, ent32}, m_initiating{initiating}, m_nodeid{nodeid},
929- m_recv_type{type_in}, m_recv_version{version_in},
930- m_recv_state{RecvState::KEY},
931- m_send_state{SendState::AWAITING_KEY}
929+ m_v1_fallback{nodeid, type_in, version_in}, m_recv_type{type_in}, m_recv_version{version_in},
930+ m_recv_state{initiating ? RecvState::KEY : RecvState::KEY_MAYBE_V1 },
931+ m_send_state{initiating ? SendState::AWAITING_KEY : SendState::MAYBE_V1 }
932932{
933933 // Initialize the send buffer with ellswift pubkey.
934934 m_send_buffer.resize (EllSwiftPubKey::size ());
@@ -940,6 +940,9 @@ void V2Transport::SetReceiveState(RecvState recv_state) noexcept
940940 AssertLockHeld (m_recv_mutex);
941941 // Enforce allowed state transitions.
942942 switch (m_recv_state) {
943+ case RecvState::KEY_MAYBE_V1:
944+ Assume (recv_state == RecvState::KEY || recv_state == RecvState::V1);
945+ break ;
943946 case RecvState::KEY:
944947 Assume (recv_state == RecvState::GARB_GARBTERM);
945948 break ;
@@ -958,6 +961,9 @@ void V2Transport::SetReceiveState(RecvState recv_state) noexcept
958961 case RecvState::APP_READY:
959962 Assume (recv_state == RecvState::APP);
960963 break ;
964+ case RecvState::V1:
965+ Assume (false ); // V1 state cannot be left
966+ break ;
961967 }
962968 // Change state.
963969 m_recv_state = recv_state;
@@ -968,11 +974,15 @@ void V2Transport::SetSendState(SendState send_state) noexcept
968974 AssertLockHeld (m_send_mutex);
969975 // Enforce allowed state transitions.
970976 switch (m_send_state) {
977+ case SendState::MAYBE_V1:
978+ Assume (send_state == SendState::V1 || send_state == SendState::AWAITING_KEY);
979+ break ;
971980 case SendState::AWAITING_KEY:
972981 Assume (send_state == SendState::READY);
973982 break ;
974983 case SendState::READY:
975- Assume (false ); // Final state
984+ case SendState::V1:
985+ Assume (false ); // Final states
976986 break ;
977987 }
978988 // Change state.
@@ -983,9 +993,48 @@ bool V2Transport::ReceivedMessageComplete() const noexcept
983993{
984994 AssertLockNotHeld (m_recv_mutex);
985995 LOCK (m_recv_mutex);
996+ if (m_recv_state == RecvState::V1) return m_v1_fallback.ReceivedMessageComplete ();
997+
986998 return m_recv_state == RecvState::APP_READY;
987999}
9881000
1001+ void V2Transport::ProcessReceivedMaybeV1Bytes () noexcept
1002+ {
1003+ AssertLockHeld (m_recv_mutex);
1004+ AssertLockNotHeld (m_send_mutex);
1005+ Assume (m_recv_state == RecvState::KEY_MAYBE_V1);
1006+ // We still have to determine if this is a v1 or v2 connection. The bytes being received could
1007+ // be the beginning of either a v1 packet (network magic + "version\x00"), or of a v2 public
1008+ // key. BIP324 specifies that a mismatch with this 12-byte string should trigger sending of the
1009+ // key.
1010+ std::array<uint8_t , V1_PREFIX_LEN> v1_prefix = {0 , 0 , 0 , 0 , ' v' , ' e' , ' r' , ' s' , ' i' , ' o' , ' n' , 0 };
1011+ std::copy (std::begin (Params ().MessageStart ()), std::end (Params ().MessageStart ()), v1_prefix.begin ());
1012+ Assume (m_recv_buffer.size () <= v1_prefix.size ());
1013+ if (!std::equal (m_recv_buffer.begin (), m_recv_buffer.end (), v1_prefix.begin ())) {
1014+ // Mismatch with v1 prefix, so we can assume a v2 connection.
1015+ SetReceiveState (RecvState::KEY); // Convert to KEY state, leaving received bytes around.
1016+ // Transition the sender to AWAITING_KEY state (if not already).
1017+ LOCK (m_send_mutex);
1018+ SetSendState (SendState::AWAITING_KEY);
1019+ } else if (m_recv_buffer.size () == v1_prefix.size ()) {
1020+ // Full match with the v1 prefix, so fall back to v1 behavior.
1021+ LOCK (m_send_mutex);
1022+ Span<const uint8_t > feedback{m_recv_buffer};
1023+ // Feed already received bytes to v1 transport. It should always accept these, because it's
1024+ // less than the size of a v1 header, and these are the first bytes fed to m_v1_fallback.
1025+ bool ret = m_v1_fallback.ReceivedBytes (feedback);
1026+ Assume (feedback.empty ());
1027+ Assume (ret);
1028+ SetReceiveState (RecvState::V1);
1029+ SetSendState (SendState::V1);
1030+ // Reset v2 transport buffers to save memory.
1031+ m_recv_buffer = {};
1032+ m_send_buffer = {};
1033+ } else {
1034+ // We have not received enough to distinguish v1 from v2 yet. Wait until more bytes come.
1035+ }
1036+ }
1037+
9891038void V2Transport::ProcessReceivedKeyBytes () noexcept
9901039{
9911040 AssertLockHeld (m_recv_mutex);
@@ -1143,6 +1192,15 @@ size_t V2Transport::GetMaxBytesToProcess() noexcept
11431192{
11441193 AssertLockHeld (m_recv_mutex);
11451194 switch (m_recv_state) {
1195+ case RecvState::KEY_MAYBE_V1:
1196+ // During the KEY_MAYBE_V1 state we do not allow more than the length of v1 prefix into the
1197+ // receive buffer.
1198+ Assume (m_recv_buffer.size () <= V1_PREFIX_LEN);
1199+ // As long as we're not sure if this is a v1 or v2 connection, don't receive more than what
1200+ // is strictly necessary to distinguish the two (12 bytes). If we permitted more than
1201+ // the v1 header size (24 bytes), we may not be able to feed the already-received bytes
1202+ // back into the m_v1_fallback V1 transport.
1203+ return V1_PREFIX_LEN - m_recv_buffer.size ();
11461204 case RecvState::KEY:
11471205 // During the KEY state, we only allow the 64-byte key into the receive buffer.
11481206 Assume (m_recv_buffer.size () <= EllSwiftPubKey::size ());
@@ -1171,6 +1229,10 @@ size_t V2Transport::GetMaxBytesToProcess() noexcept
11711229 case RecvState::APP_READY:
11721230 // No bytes can be processed until GetMessage() is called.
11731231 return 0 ;
1232+ case RecvState::V1:
1233+ // Not allowed (must be dealt with by the caller).
1234+ Assume (false );
1235+ return 0 ;
11741236 }
11751237 Assume (false ); // unreachable
11761238 return 0 ;
@@ -1180,6 +1242,8 @@ bool V2Transport::ReceivedBytes(Span<const uint8_t>& msg_bytes) noexcept
11801242{
11811243 AssertLockNotHeld (m_recv_mutex);
11821244 LOCK (m_recv_mutex);
1245+ if (m_recv_state == RecvState::V1) return m_v1_fallback.ReceivedBytes (msg_bytes);
1246+
11831247 // Process the provided bytes in msg_bytes in a loop. In each iteration a nonzero number of
11841248 // bytes (decided by GetMaxBytesToProcess) are taken from the beginning om msg_bytes, and
11851249 // appended to m_recv_buffer. Then, depending on the receiver state, one of the
@@ -1195,6 +1259,11 @@ bool V2Transport::ReceivedBytes(Span<const uint8_t>& msg_bytes) noexcept
11951259
11961260 // Process data in the buffer.
11971261 switch (m_recv_state) {
1262+ case RecvState::KEY_MAYBE_V1:
1263+ ProcessReceivedMaybeV1Bytes ();
1264+ if (m_recv_state == RecvState::V1) return true ;
1265+ break ;
1266+
11981267 case RecvState::KEY:
11991268 ProcessReceivedKeyBytes ();
12001269 break ;
@@ -1211,6 +1280,11 @@ bool V2Transport::ReceivedBytes(Span<const uint8_t>& msg_bytes) noexcept
12111280
12121281 case RecvState::APP_READY:
12131282 return true ;
1283+
1284+ case RecvState::V1:
1285+ // We should have bailed out before.
1286+ Assume (false );
1287+ break ;
12141288 }
12151289 // Make sure we have made progress before continuing.
12161290 Assume (max_read > 0 );
@@ -1254,6 +1328,8 @@ CNetMessage V2Transport::GetReceivedMessage(std::chrono::microseconds time, bool
12541328{
12551329 AssertLockNotHeld (m_recv_mutex);
12561330 LOCK (m_recv_mutex);
1331+ if (m_recv_state == RecvState::V1) return m_v1_fallback.GetReceivedMessage (time, reject_message);
1332+
12571333 Assume (m_recv_state == RecvState::APP_READY);
12581334 Span<const uint8_t > contents{m_recv_decode_buffer};
12591335 auto msg_type = GetMessageType (contents);
@@ -1282,6 +1358,7 @@ bool V2Transport::SetMessageToSend(CSerializedNetMsg& msg) noexcept
12821358{
12831359 AssertLockNotHeld (m_send_mutex);
12841360 LOCK (m_send_mutex);
1361+ if (m_send_state == SendState::V1) return m_v1_fallback.SetMessageToSend (msg);
12851362 // We only allow adding a new message to be sent when in the READY state (so the packet cipher
12861363 // is available) and the send buffer is empty. This limits the number of messages in the send
12871364 // buffer to just one, and leaves the responsibility for queueing them up to the caller.
@@ -1305,6 +1382,11 @@ Transport::BytesToSend V2Transport::GetBytesToSend(bool have_next_message) const
13051382{
13061383 AssertLockNotHeld (m_send_mutex);
13071384 LOCK (m_send_mutex);
1385+ if (m_send_state == SendState::V1) return m_v1_fallback.GetBytesToSend (have_next_message);
1386+
1387+ // We do not send anything in MAYBE_V1 state (as we don't know if the peer is v1 or v2),
1388+ // despite there being data in the send buffer in that state.
1389+ if (m_send_state == SendState::MAYBE_V1) return {{}, false , m_send_type};
13081390 Assume (m_send_pos <= m_send_buffer.size ());
13091391 return {
13101392 Span{m_send_buffer}.subspan (m_send_pos),
@@ -1319,6 +1401,8 @@ void V2Transport::MarkBytesSent(size_t bytes_sent) noexcept
13191401{
13201402 AssertLockNotHeld (m_send_mutex);
13211403 LOCK (m_send_mutex);
1404+ if (m_send_state == SendState::V1) return m_v1_fallback.MarkBytesSent (bytes_sent);
1405+
13221406 m_send_pos += bytes_sent;
13231407 Assume (m_send_pos <= m_send_buffer.size ());
13241408 if (m_send_pos == m_send_buffer.size ()) {
@@ -1331,6 +1415,8 @@ size_t V2Transport::GetSendMemoryUsage() const noexcept
13311415{
13321416 AssertLockNotHeld (m_send_mutex);
13331417 LOCK (m_send_mutex);
1418+ if (m_send_state == SendState::V1) return m_v1_fallback.GetSendMemoryUsage ();
1419+
13341420 return sizeof (m_send_buffer) + memusage::DynamicUsage (m_send_buffer);
13351421}
13361422
0 commit comments