This PR factors out transport packaging logic from CConnman::PushMessage()
.
It’s similar to #16202 (where we refactor deserialization).
This allows implementing a new message transport protocol like BIP324.
This PR factors out transport packaging logic from CConnman::PushMessage()
.
It’s similar to #16202 (where we refactor deserialization).
This allows implementing a new message transport protocol like BIP324.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
No conflicts as of last run.
613@@ -614,12 +614,27 @@ class CNetMessage {
614 int readData(const char *pch, unsigned int nBytes);
615 };
616
617+/** The TransportSerializer prepares messages for the network transport
618+ */
619+class TransportSerializer {
620+public:
621+ // prepare message for transport (insert header, etc.)
622+ virtual bool prepareForTransport(CSerializedNetMsg& msg) = 0;
void
or assert(result)
?
CConnman::PushMessage
have you considered something like class MessageWriterV1 : public MessageWriter
? The message writer V1 would still push 2 buffers to vSendMsg
(vSendMsg
should be accessible to the message writer). In other words, CConnman
wouldn’t be responsible to push to vSendMsg
).
@promag: yes. You’r right. The insert/reallocation was stupid. Slighly changed the approach. It is now also avoiding the behavior change.
Also removed the unused return value (will eventually come back with the v2 implementation).
618+ */
619+class TransportSerializer {
620+public:
621+ // prepare message for transport (insert header, etc.)
622+ virtual void prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) = 0;
623+ virtual ~TransportSerializer() {}
631 /** Information about a peer */
632 class CNode
633 {
634 friend class CConnman;
635 public:
636+ std::unique_ptr<TransportSerializer> m_serializer;
ConnectNode
/AcceptConnection
, if we make an outbound connection, thanks to NODE_P2P_V2
we can be sure to have right serializer, but in case of inbound we may need to update it. Maybe comment this logic here?
Thanks for the comment. Your concerns are valid but not part of this PR. For a BIP324 (NODE_P2P_V2) inbound connection (also outbound) we always start with a V1 serializer/deserializer to perform the handshake. I think the handshake/a.k.a. protocol upgrade belongs to the V1 protocol.
Once the handshake has been completed, we exchange the node objects serializer/deserializer with a V2 instance.
613@@ -614,12 +614,27 @@ class CNetMessage {
614 int readData(const char *pch, unsigned int nBytes);
615 };
616
617+/** The TransportSerializer prepares messages for the network transport
618+ */
619+class TransportSerializer {
620+public:
621+ // prepare message for transport (insert header, etc.)
689@@ -690,6 +690,19 @@ const uint256& CNetMessage::GetMessageHash() const
690 return data_hash;
691 }
692
693+void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vector<unsigned char>& header) {
override
?
semiACK 16d6113f4faa901e248adb693d4768a9e5019a16 ran functional+unit tests.
While reading the code I found one observable difference which is the replacement of HEADER_SIZE
with serializedHeader.size()
. I’m not exactly sure which should be used here(they should be the same but maybe there’s some DOS vector i’m missing)
other than that the pointer is allocated in the constructor so there shouldn’t be a way to call it when null.
ACK 16d6113f4faa901e248adb693d4768a9e5019a16 FWIW
Possible followup:
Add properly formatted Doxygen comments (something like what’s already in the abstract class) for, and/or rename TransportSerializer::prepareForTransport
as the name can be misinterpreted as: “do everything that we need to do before we send it to transport layer.”
Code review ACK 16d6113
I’m not exactly sure which should be used here(they should be the same but maybe there’s some DOS vector i’m missing) @elichai I don’t think there is a risk of DoS here,
serializerHeader
as allCMessageHeader
components have a fixed-length. Bandwidth-DoS is already left unbounded (see default of-maxuploadtarget
)
2715@@ -2703,6 +2716,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
2716 }
2717
2718 m_deserializer = MakeUnique<V1TransportDeserializer>(V1TransportDeserializer(Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION));
2719+ m_serializer = MakeUnique<V1TransportSerializer>(V1TransportSerializer());
Any reason this needs to call the copy(or move) constructor?
0 m_serializer = MakeUnique<V1TransportSerializer>();
ACK 16d6113f4faa901e248adb693d4768a9e5019a16 🙎
Signature:
0-----BEGIN PGP SIGNED MESSAGE-----
1Hash: SHA512
2
3ACK 16d6113f4faa901e248adb693d4768a9e5019a16 🙎
4-----BEGIN PGP SIGNATURE-----
5
6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
7pUhcGwv+Igl6tmkV78gSSi8EZt3582CuubMrSdBrB8UJ62ukEZVAmotmNR3ShTjM
8rAmpiY7bxU0/2hW6Nr1YFo7t3FZ15dNPX2fTClctXXeLVFJdc1fSUwUg/oeRoJtm
9T2CftFTfDrbU2o7HeX7rZvYSuieIl/SFBmNQ+w4jG8AFh4bCHH3pQVC7ueJhIHIx
10qxKx9GNzwGOn3/rKCXj9vkEKRxHs/vGFDh4WYRezhEWkVvpe6996IiUMYVsIgyqm
11npuGyOYoBmaSxj4z9PFHrL58AnnuRlUKy/1B0MyHz5v789b2swFn1iw5L9JTzOvh
12dI9W2w7vkUnIaudUn1Z5dNPmVG8k7tmMAYvxE7TrhD1UgBRe2QYyNMt8CEJerxOd
1350xlIKikLZxzL1ASwxatzPSKMl2ITprvIMrtoI0RrS1tPtfcXLnx10yr7EJ0dAxB
14ZLs3GWZah5d/XLMDcyBSGWtiuWS+nkws4dAmZIlwBI/Qcm55dXAuW+Wocj59mtDE
15QdnFfvp/
16=gFtP
17-----END PGP SIGNATURE-----
Timestamp of file with hash 2ae5b6b8bcff0b2640a243d5665c57ba947e1d6ef581e8eb4aa04cfd1b160d31 -
Any chance we can move forward with the V1TransportSerializer
fuzzer in #17771 to get additional robustness testing of this code before proceeding with the V1TransportSerializer
refactoring(s)?
It should hopefully be trivial to review :)
@practicalswift: are you working on fuzz testing the serializing part? @jonasschnelli: I’ve attempt to extend the test to serialization in #22029. I’ve also discovered that the deserialization does not proceed 60-70% of the time due to a failed checksum test. Will try to address that and increase coverage in another commit this week.