Skip to content

Commit 6fe0599

Browse files
authored
refactor: clean up CTID.h (#5681)
1 parent e6f8bc7 commit 6fe0599

File tree

1 file changed

+66
-23
lines changed

1 file changed

+66
-23
lines changed

src/xrpld/rpc/CTID.h

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,53 +39,96 @@ namespace RPC {
3939
// The Concise Transaction ID provides a way to identify a transaction
4040
// that includes which network the transaction was submitted to.
4141

42+
/**
43+
* @brief Encodes ledger sequence, transaction index, and network ID into a CTID
44+
* string.
45+
*
46+
* @param ledgerSeq Ledger sequence number (max 0x0FFF'FFFF).
47+
* @param txnIndex Transaction index within the ledger (max 0xFFFF).
48+
* @param networkID Network identifier (max 0xFFFF).
49+
* @return Optional CTID string in uppercase hexadecimal, or std::nullopt if
50+
* inputs are out of range.
51+
*/
4252
inline std::optional<std::string>
4353
encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
4454
{
45-
if (ledgerSeq > 0x0FFF'FFFF || txnIndex > 0xFFFF || networkID > 0xFFFF)
46-
return {};
55+
constexpr uint32_t maxLedgerSeq = 0x0FFF'FFFF;
56+
constexpr uint32_t maxTxnIndex = 0xFFFF;
57+
constexpr uint32_t maxNetworkID = 0xFFFF;
58+
59+
if (ledgerSeq > maxLedgerSeq || txnIndex > maxTxnIndex ||
60+
networkID > maxNetworkID)
61+
return std::nullopt;
4762

4863
uint64_t ctidValue =
49-
((0xC000'0000ULL + static_cast<uint64_t>(ledgerSeq)) << 32) +
50-
(static_cast<uint64_t>(txnIndex) << 16) + networkID;
64+
((0xC000'0000ULL + static_cast<uint64_t>(ledgerSeq)) << 32) |
65+
((static_cast<uint64_t>(txnIndex) << 16) | networkID);
5166

5267
std::stringstream buffer;
5368
buffer << std::hex << std::uppercase << std::setfill('0') << std::setw(16)
5469
<< ctidValue;
55-
return {buffer.str()};
70+
return buffer.str();
5671
}
5772

73+
/**
74+
* @brief Decodes a CTID string or integer into its component parts.
75+
*
76+
* @tparam T Type of the CTID input (string, string_view, char*, integral).
77+
* @param ctid CTID value to decode.
78+
* @return Optional tuple of (ledgerSeq, txnIndex, networkID), or std::nullopt
79+
* if invalid.
80+
*/
5881
template <typename T>
5982
inline std::optional<std::tuple<uint32_t, uint16_t, uint16_t>>
6083
decodeCTID(T const ctid) noexcept
6184
{
62-
uint64_t ctidValue{0};
85+
uint64_t ctidValue = 0;
86+
6387
if constexpr (
64-
std::is_same_v<T, std::string> || std::is_same_v<T, char*> ||
65-
std::is_same_v<T, char const*> || std::is_same_v<T, std::string_view>)
88+
std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view> ||
89+
std::is_same_v<T, char*> || std::is_same_v<T, char const*>)
6690
{
6791
std::string const ctidString(ctid);
6892

69-
if (ctidString.length() != 16)
70-
return {};
71-
72-
if (!boost::regex_match(ctidString, boost::regex("^[0-9A-Fa-f]+$")))
73-
return {};
74-
75-
ctidValue = std::stoull(ctidString, nullptr, 16);
93+
if (ctidString.size() != 16)
94+
return std::nullopt;
95+
96+
static boost::regex const hexRegex("^[0-9A-Fa-f]{16}$");
97+
if (!boost::regex_match(ctidString, hexRegex))
98+
return std::nullopt;
99+
100+
try
101+
{
102+
ctidValue = std::stoull(ctidString, nullptr, 16);
103+
}
104+
// LCOV_EXCL_START
105+
catch (...)
106+
{
107+
// should be impossible to hit given the length/regex check
108+
return std::nullopt;
109+
}
110+
// LCOV_EXCL_STOP
76111
}
77112
else if constexpr (std::is_integral_v<T>)
78-
ctidValue = ctid;
113+
{
114+
ctidValue = static_cast<uint64_t>(ctid);
115+
}
79116
else
80-
return {};
117+
{
118+
return std::nullopt;
119+
}
120+
121+
// Validate CTID prefix.
122+
constexpr uint64_t ctidPrefixMask = 0xF000'0000'0000'0000ULL;
123+
constexpr uint64_t ctidPrefix = 0xC000'0000'0000'0000ULL;
124+
if ((ctidValue & ctidPrefixMask) != ctidPrefix)
125+
return std::nullopt;
81126

82-
if ((ctidValue & 0xF000'0000'0000'0000ULL) != 0xC000'0000'0000'0000ULL)
83-
return {};
127+
uint32_t ledgerSeq = static_cast<uint32_t>((ctidValue >> 32) & 0x0FFF'FFFF);
128+
uint16_t txnIndex = static_cast<uint16_t>((ctidValue >> 16) & 0xFFFF);
129+
uint16_t networkID = static_cast<uint16_t>(ctidValue & 0xFFFF);
84130

85-
uint32_t ledger_seq = (ctidValue >> 32) & 0xFFFF'FFFUL;
86-
uint16_t txn_index = (ctidValue >> 16) & 0xFFFFU;
87-
uint16_t network_id = ctidValue & 0xFFFFU;
88-
return {{ledger_seq, txn_index, network_id}};
131+
return std::make_tuple(ledgerSeq, txnIndex, networkID);
89132
}
90133

91134
} // namespace RPC

0 commit comments

Comments
 (0)