@@ -39,53 +39,96 @@ namespace RPC {
39
39
// The Concise Transaction ID provides a way to identify a transaction
40
40
// that includes which network the transaction was submitted to.
41
41
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
+ */
42
52
inline std::optional<std::string>
43
53
encodeCTID (uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
44
54
{
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 ;
47
62
48
63
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) ;
51
66
52
67
std::stringstream buffer;
53
68
buffer << std::hex << std::uppercase << std::setfill (' 0' ) << std::setw (16 )
54
69
<< ctidValue;
55
- return { buffer.str ()} ;
70
+ return buffer.str ();
56
71
}
57
72
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
+ */
58
81
template <typename T>
59
82
inline std::optional<std::tuple<uint32_t , uint16_t , uint16_t >>
60
83
decodeCTID (T const ctid) noexcept
61
84
{
62
- uint64_t ctidValue{0 };
85
+ uint64_t ctidValue = 0 ;
86
+
63
87
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 * >)
66
90
{
67
91
std::string const ctidString (ctid);
68
92
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
76
111
}
77
112
else if constexpr (std::is_integral_v<T>)
78
- ctidValue = ctid;
113
+ {
114
+ ctidValue = static_cast <uint64_t >(ctid);
115
+ }
79
116
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 ;
81
126
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 );
84
130
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);
89
132
}
90
133
91
134
} // namespace RPC
0 commit comments