diff --git a/src/net.cpp b/src/net.cpp index 7bd90d0973..7ebff7d05b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1015,7 +1015,7 @@ namespace { * Only message types that are actually implemented in this codebase need to be listed, as other * messages get ignored anyway - whether we know how to decode them or not. */ -const std::array V2_MESSAGE_IDS = { +const std::array V2_BITCOIN_IDS = { "", // 12 bytes follow encoding the message type like in V1 NetMsgType::ADDR, NetMsgType::BLOCK, @@ -1052,6 +1052,91 @@ const std::array V2_MESSAGE_IDS = { "" }; +/** List of short messages allocated in Dash's reserved namespace, in order. + * + * Slots should not be reused unless the switchover has already been done + * by a protocol upgrade, the old message is no longer supported by the client + * and a new slot wasn't already allotted for the message. + */ +const std::array V2_DASH_IDS = { + NetMsgType::SPORK, + NetMsgType::GETSPORKS, + NetMsgType::SENDDSQUEUE, + NetMsgType::DSACCEPT, + NetMsgType::DSVIN, + NetMsgType::DSFINALTX, + NetMsgType::DSSIGNFINALTX, + NetMsgType::DSCOMPLETE, + NetMsgType::DSSTATUSUPDATE, + NetMsgType::DSTX, + NetMsgType::DSQUEUE, + NetMsgType::SYNCSTATUSCOUNT, + NetMsgType::MNGOVERNANCESYNC, + NetMsgType::MNGOVERNANCEOBJECT, + NetMsgType::MNGOVERNANCEOBJECTVOTE, + NetMsgType::GETMNLISTDIFF, + NetMsgType::MNLISTDIFF, + NetMsgType::QSENDRECSIGS, + NetMsgType::QFCOMMITMENT, + NetMsgType::QCONTRIB, + NetMsgType::QCOMPLAINT, + NetMsgType::QJUSTIFICATION, + NetMsgType::QPCOMMITMENT, + NetMsgType::QWATCH, + NetMsgType::QSIGSESANN, + NetMsgType::QSIGSHARESINV, + NetMsgType::QGETSIGSHARES, + NetMsgType::QBSIGSHARES, + NetMsgType::QSIGREC, + NetMsgType::QSIGSHARE, + NetMsgType::QGETDATA, + NetMsgType::QDATA, + NetMsgType::CLSIG, + NetMsgType::ISDLOCK, + NetMsgType::MNAUTH, + NetMsgType::GETHEADERS2, + NetMsgType::SENDHEADERS2, + NetMsgType::HEADERS2, + NetMsgType::GETQUORUMROTATIONINFO, + NetMsgType::QUORUMROTATIONINFO +}; + +/** A complete set of short IDs + * + * Bitcoin takes up short IDs upto 128 (lower half) while Dash can take + * up short IDs between 128 and 256 (upper half) most of the array will + * have entries that correspond to nothing. + * + * To distinguish between entries that are *meant* to correspond to + * nothing versus empty space, use IsValidV2ShortID() + */ +constexpr std::array V2ShortIDs() { + static_assert(std::size(V2_BITCOIN_IDS) <= 128); + static_assert(std::size(V2_DASH_IDS) <= 128); + + std::array ret{}; + for (size_t idx{0}; idx < std::size(ret); idx++) { + if (idx < 128 && idx < std::size(V2_BITCOIN_IDS)) { + ret[idx] = V2_BITCOIN_IDS[idx]; + } else if (idx >= 128 && idx - 128 < std::size(V2_DASH_IDS)) { + ret[idx] = V2_DASH_IDS[idx - 128]; + } else { + ret[idx] = ""; + } + } + + return ret; +} + +bool IsValidV2ShortID(uint8_t first_byte) { + // Since we have filled the namespace of short IDs, we have to preserve + // the expected behaviour of coming up short when going beyond Bitcoin's + // and Dash's *used* slots. We do this by checking if the byte is within + // the range where a valid message is expected to reside. + return first_byte < std::size(V2_BITCOIN_IDS) || + (first_byte >= 128 && static_cast(first_byte - 128) < std::size(V2_DASH_IDS)); +} + class V2MessageMap { std::unordered_map m_map; @@ -1059,8 +1144,10 @@ class V2MessageMap public: V2MessageMap() noexcept { - for (size_t i = 1; i < std::size(V2_MESSAGE_IDS); ++i) { - m_map.emplace(V2_MESSAGE_IDS[i], i); + for (size_t i = 1; i < std::size(V2ShortIDs()); ++i) { + if (IsValidV2ShortID(i)) { + m_map.emplace(V2ShortIDs()[i], i); + } } } @@ -1524,9 +1611,9 @@ std::optional V2Transport::GetMessageType(Span& cont if (first_byte != 0) { // Short (1 byte) encoding. - if (first_byte < std::size(V2_MESSAGE_IDS)) { + if (IsValidV2ShortID(first_byte)) { // Valid short message id. - return V2_MESSAGE_IDS[first_byte]; + return std::string{V2ShortIDs()[first_byte]}; } else { // Unknown short message id. return std::nullopt; diff --git a/src/protocol.cpp b/src/protocol.cpp index f77bda78fc..e3499646b1 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -166,7 +166,10 @@ const static std::string allNetMessageTypes[] = { NetMsgType::MNAUTH, NetMsgType::GETHEADERS2, NetMsgType::SENDHEADERS2, - NetMsgType::HEADERS2}; + NetMsgType::HEADERS2, + NetMsgType::GETQUORUMROTATIONINFO, + NetMsgType::QUORUMROTATIONINFO +}; const static std::vector allNetMessageTypesVec(std::begin(allNetMessageTypes), std::end(allNetMessageTypes)); /** Message types that are not allowed by blocks-relay-only policy. @@ -184,6 +187,7 @@ const static std::string netMessageTypesViolateBlocksOnly[] = { NetMsgType::DSSTATUSUPDATE, NetMsgType::DSTX, NetMsgType::DSVIN, + NetMsgType::GETQUORUMROTATIONINFO, NetMsgType::QBSIGSHARES, NetMsgType::QCOMPLAINT, NetMsgType::QCONTRIB, @@ -197,6 +201,7 @@ const static std::string netMessageTypesViolateBlocksOnly[] = { NetMsgType::QSIGSESANN, NetMsgType::QSIGSHARE, NetMsgType::QSIGSHARESINV, + NetMsgType::QUORUMROTATIONINFO, NetMsgType::QWATCH, NetMsgType::TX, }; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 806bf0daad..800aa6fea7 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -1537,7 +1537,13 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.CompareSessionIDs(); auto msg_data_1 = g_insecure_rand_ctx.randbytes(MAX_PROTOCOL_MESSAGE_LENGTH); // test that receiving max size payload works auto msg_data_2 = g_insecure_rand_ctx.randbytes(MAX_PROTOCOL_MESSAGE_LENGTH); // test that sending max size payload works - tester.SendMessage(uint8_t(InsecureRandRange(223) + 33), {}); // unknown short id + tester.SendMessage([]() { + if (g_insecure_rand_ctx.randbool()) { + return static_cast(InsecureRandRange(95) + 33); // Bitcoin's range + } else { + return static_cast(InsecureRandRange(88) + 40 + 128); // Dash's range + } + }(), {}); // unknown short id tester.SendMessage(uint8_t(2), msg_data_1); // "block" short id tester.AddMessage("blocktxn", msg_data_2); // schedule blocktxn to be sent to us ret = tester.Interact();