rippled
Loading...
Searching...
No Matches
AccountSetTests.cpp
1// Auto-generated unit tests for transaction AccountSet
2
3
4#include <gtest/gtest.h>
5
6#include <protocol_autogen/TestHelpers.h>
7
8#include <xrpl/protocol/SecretKey.h>
9#include <xrpl/protocol/Seed.h>
10#include <xrpl/protocol/STTx.h>
11#include <xrpl/protocol_autogen/transactions/AccountSet.h>
12#include <xrpl/protocol_autogen/transactions/OfferCancel.h>
13
14#include <string>
15
16namespace xrpl::transactions {
17
18// 1 & 4) Set fields via builder setters, build, then read them back via
19// wrapper getters. After build(), validate() should succeed.
20TEST(TransactionsAccountSetTests, BuilderSettersRoundTrip)
21{
22 // Generate a deterministic keypair for signing
23 auto const [publicKey, secretKey] =
25
26 // Common transaction fields
27 auto const accountValue = calcAccountID(publicKey);
28 std::uint32_t const sequenceValue = 1;
29 auto const feeValue = canonical_AMOUNT();
30
31 // Transaction-specific field values
32 auto const emailHashValue = canonical_UINT128();
33 auto const walletLocatorValue = canonical_UINT256();
34 auto const walletSizeValue = canonical_UINT32();
35 auto const messageKeyValue = canonical_VL();
36 auto const domainValue = canonical_VL();
37 auto const transferRateValue = canonical_UINT32();
38 auto const setFlagValue = canonical_UINT32();
39 auto const clearFlagValue = canonical_UINT32();
40 auto const tickSizeValue = canonical_UINT8();
41 auto const nFTokenMinterValue = canonical_ACCOUNT();
42
43 AccountSetBuilder builder{
44 accountValue,
45 sequenceValue,
46 feeValue
47 };
48
49 // Set optional fields
50 builder.setEmailHash(emailHashValue);
51 builder.setWalletLocator(walletLocatorValue);
52 builder.setWalletSize(walletSizeValue);
53 builder.setMessageKey(messageKeyValue);
54 builder.setDomain(domainValue);
55 builder.setTransferRate(transferRateValue);
56 builder.setSetFlag(setFlagValue);
57 builder.setClearFlag(clearFlagValue);
58 builder.setTickSize(tickSizeValue);
59 builder.setNFTokenMinter(nFTokenMinterValue);
60
61 auto tx = builder.build(publicKey, secretKey);
62
63 std::string reason;
64 EXPECT_TRUE(tx.validate(reason)) << reason;
65
66 // Verify signing was applied
67 EXPECT_FALSE(tx.getSigningPubKey().empty());
68 EXPECT_TRUE(tx.hasTxnSignature());
69
70 // Verify common fields
71 EXPECT_EQ(tx.getAccount(), accountValue);
72 EXPECT_EQ(tx.getSequence(), sequenceValue);
73 EXPECT_EQ(tx.getFee(), feeValue);
74
75 // Verify required fields
76 // Verify optional fields
77 {
78 auto const& expected = emailHashValue;
79 auto const actualOpt = tx.getEmailHash();
80 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEmailHash should be present";
81 expectEqualField(expected, *actualOpt, "sfEmailHash");
82 EXPECT_TRUE(tx.hasEmailHash());
83 }
84
85 {
86 auto const& expected = walletLocatorValue;
87 auto const actualOpt = tx.getWalletLocator();
88 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletLocator should be present";
89 expectEqualField(expected, *actualOpt, "sfWalletLocator");
90 EXPECT_TRUE(tx.hasWalletLocator());
91 }
92
93 {
94 auto const& expected = walletSizeValue;
95 auto const actualOpt = tx.getWalletSize();
96 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletSize should be present";
97 expectEqualField(expected, *actualOpt, "sfWalletSize");
98 EXPECT_TRUE(tx.hasWalletSize());
99 }
100
101 {
102 auto const& expected = messageKeyValue;
103 auto const actualOpt = tx.getMessageKey();
104 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMessageKey should be present";
105 expectEqualField(expected, *actualOpt, "sfMessageKey");
106 EXPECT_TRUE(tx.hasMessageKey());
107 }
108
109 {
110 auto const& expected = domainValue;
111 auto const actualOpt = tx.getDomain();
112 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomain should be present";
113 expectEqualField(expected, *actualOpt, "sfDomain");
114 EXPECT_TRUE(tx.hasDomain());
115 }
116
117 {
118 auto const& expected = transferRateValue;
119 auto const actualOpt = tx.getTransferRate();
120 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferRate should be present";
121 expectEqualField(expected, *actualOpt, "sfTransferRate");
122 EXPECT_TRUE(tx.hasTransferRate());
123 }
124
125 {
126 auto const& expected = setFlagValue;
127 auto const actualOpt = tx.getSetFlag();
128 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSetFlag should be present";
129 expectEqualField(expected, *actualOpt, "sfSetFlag");
130 EXPECT_TRUE(tx.hasSetFlag());
131 }
132
133 {
134 auto const& expected = clearFlagValue;
135 auto const actualOpt = tx.getClearFlag();
136 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfClearFlag should be present";
137 expectEqualField(expected, *actualOpt, "sfClearFlag");
138 EXPECT_TRUE(tx.hasClearFlag());
139 }
140
141 {
142 auto const& expected = tickSizeValue;
143 auto const actualOpt = tx.getTickSize();
144 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTickSize should be present";
145 expectEqualField(expected, *actualOpt, "sfTickSize");
146 EXPECT_TRUE(tx.hasTickSize());
147 }
148
149 {
150 auto const& expected = nFTokenMinterValue;
151 auto const actualOpt = tx.getNFTokenMinter();
152 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenMinter should be present";
153 expectEqualField(expected, *actualOpt, "sfNFTokenMinter");
154 EXPECT_TRUE(tx.hasNFTokenMinter());
155 }
156
157}
158
159// 2 & 4) Start from an STTx, construct a builder from it, build a new wrapper,
160// and verify all fields match.
161TEST(TransactionsAccountSetTests, BuilderFromStTxRoundTrip)
162{
163 // Generate a deterministic keypair for signing
164 auto const [publicKey, secretKey] =
165 generateKeyPair(KeyType::secp256k1, generateSeed("testAccountSetFromTx"));
166
167 // Common transaction fields
168 auto const accountValue = calcAccountID(publicKey);
169 std::uint32_t const sequenceValue = 2;
170 auto const feeValue = canonical_AMOUNT();
171
172 // Transaction-specific field values
173 auto const emailHashValue = canonical_UINT128();
174 auto const walletLocatorValue = canonical_UINT256();
175 auto const walletSizeValue = canonical_UINT32();
176 auto const messageKeyValue = canonical_VL();
177 auto const domainValue = canonical_VL();
178 auto const transferRateValue = canonical_UINT32();
179 auto const setFlagValue = canonical_UINT32();
180 auto const clearFlagValue = canonical_UINT32();
181 auto const tickSizeValue = canonical_UINT8();
182 auto const nFTokenMinterValue = canonical_ACCOUNT();
183
184 // Build an initial transaction
185 AccountSetBuilder initialBuilder{
186 accountValue,
187 sequenceValue,
188 feeValue
189 };
190
191 initialBuilder.setEmailHash(emailHashValue);
192 initialBuilder.setWalletLocator(walletLocatorValue);
193 initialBuilder.setWalletSize(walletSizeValue);
194 initialBuilder.setMessageKey(messageKeyValue);
195 initialBuilder.setDomain(domainValue);
196 initialBuilder.setTransferRate(transferRateValue);
197 initialBuilder.setSetFlag(setFlagValue);
198 initialBuilder.setClearFlag(clearFlagValue);
199 initialBuilder.setTickSize(tickSizeValue);
200 initialBuilder.setNFTokenMinter(nFTokenMinterValue);
201
202 auto initialTx = initialBuilder.build(publicKey, secretKey);
203
204 // Create builder from existing STTx
205 AccountSetBuilder builderFromTx{initialTx.getSTTx()};
206
207 auto rebuiltTx = builderFromTx.build(publicKey, secretKey);
208
209 std::string reason;
210 EXPECT_TRUE(rebuiltTx.validate(reason)) << reason;
211
212 // Verify common fields
213 EXPECT_EQ(rebuiltTx.getAccount(), accountValue);
214 EXPECT_EQ(rebuiltTx.getSequence(), sequenceValue);
215 EXPECT_EQ(rebuiltTx.getFee(), feeValue);
216
217 // Verify required fields
218 // Verify optional fields
219 {
220 auto const& expected = emailHashValue;
221 auto const actualOpt = rebuiltTx.getEmailHash();
222 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfEmailHash should be present";
223 expectEqualField(expected, *actualOpt, "sfEmailHash");
224 }
225
226 {
227 auto const& expected = walletLocatorValue;
228 auto const actualOpt = rebuiltTx.getWalletLocator();
229 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletLocator should be present";
230 expectEqualField(expected, *actualOpt, "sfWalletLocator");
231 }
232
233 {
234 auto const& expected = walletSizeValue;
235 auto const actualOpt = rebuiltTx.getWalletSize();
236 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfWalletSize should be present";
237 expectEqualField(expected, *actualOpt, "sfWalletSize");
238 }
239
240 {
241 auto const& expected = messageKeyValue;
242 auto const actualOpt = rebuiltTx.getMessageKey();
243 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfMessageKey should be present";
244 expectEqualField(expected, *actualOpt, "sfMessageKey");
245 }
246
247 {
248 auto const& expected = domainValue;
249 auto const actualOpt = rebuiltTx.getDomain();
250 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfDomain should be present";
251 expectEqualField(expected, *actualOpt, "sfDomain");
252 }
253
254 {
255 auto const& expected = transferRateValue;
256 auto const actualOpt = rebuiltTx.getTransferRate();
257 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTransferRate should be present";
258 expectEqualField(expected, *actualOpt, "sfTransferRate");
259 }
260
261 {
262 auto const& expected = setFlagValue;
263 auto const actualOpt = rebuiltTx.getSetFlag();
264 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfSetFlag should be present";
265 expectEqualField(expected, *actualOpt, "sfSetFlag");
266 }
267
268 {
269 auto const& expected = clearFlagValue;
270 auto const actualOpt = rebuiltTx.getClearFlag();
271 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfClearFlag should be present";
272 expectEqualField(expected, *actualOpt, "sfClearFlag");
273 }
274
275 {
276 auto const& expected = tickSizeValue;
277 auto const actualOpt = rebuiltTx.getTickSize();
278 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfTickSize should be present";
279 expectEqualField(expected, *actualOpt, "sfTickSize");
280 }
281
282 {
283 auto const& expected = nFTokenMinterValue;
284 auto const actualOpt = rebuiltTx.getNFTokenMinter();
285 ASSERT_TRUE(actualOpt.has_value()) << "Optional field sfNFTokenMinter should be present";
286 expectEqualField(expected, *actualOpt, "sfNFTokenMinter");
287 }
288
289}
290
291// 3) Verify wrapper throws when constructed from wrong transaction type.
292TEST(TransactionsAccountSetTests, WrapperThrowsOnWrongTxType)
293{
294 // Build a valid transaction of a different type
295 auto const [pk, sk] =
297 auto const account = calcAccountID(pk);
298
299 OfferCancelBuilder wrongBuilder{account, canonical_UINT32(), 1, canonical_AMOUNT()};
300 auto wrongTx = wrongBuilder.build(pk, sk);
301
302 EXPECT_THROW(AccountSet{wrongTx.getSTTx()}, std::runtime_error);
303}
304
305// 4) Verify builder throws when constructed from wrong transaction type.
306TEST(TransactionsAccountSetTests, BuilderThrowsOnWrongTxType)
307{
308 // Build a valid transaction of a different type
309 auto const [pk, sk] =
310 generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder"));
311 auto const account = calcAccountID(pk);
312
313 OfferCancelBuilder wrongBuilder{account, canonical_UINT32(), 1, canonical_AMOUNT()};
314 auto wrongTx = wrongBuilder.build(pk, sk);
315
316 EXPECT_THROW(AccountSetBuilder{wrongTx.getSTTx()}, std::runtime_error);
317}
318
319// 5) Build with only required fields and verify optional fields return nullopt.
320TEST(TransactionsAccountSetTests, OptionalFieldsReturnNullopt)
321{
322 // Generate a deterministic keypair for signing
323 auto const [publicKey, secretKey] =
324 generateKeyPair(KeyType::secp256k1, generateSeed("testAccountSetNullopt"));
325
326 // Common transaction fields
327 auto const accountValue = calcAccountID(publicKey);
328 std::uint32_t const sequenceValue = 3;
329 auto const feeValue = canonical_AMOUNT();
330
331 // Transaction-specific required field values
332
333 AccountSetBuilder builder{
334 accountValue,
335 sequenceValue,
336 feeValue
337 };
338
339 // Do NOT set optional fields
340
341 auto tx = builder.build(publicKey, secretKey);
342
343 // Verify optional fields are not present
344 EXPECT_FALSE(tx.hasEmailHash());
345 EXPECT_FALSE(tx.getEmailHash().has_value());
346 EXPECT_FALSE(tx.hasWalletLocator());
347 EXPECT_FALSE(tx.getWalletLocator().has_value());
348 EXPECT_FALSE(tx.hasWalletSize());
349 EXPECT_FALSE(tx.getWalletSize().has_value());
350 EXPECT_FALSE(tx.hasMessageKey());
351 EXPECT_FALSE(tx.getMessageKey().has_value());
352 EXPECT_FALSE(tx.hasDomain());
353 EXPECT_FALSE(tx.getDomain().has_value());
354 EXPECT_FALSE(tx.hasTransferRate());
355 EXPECT_FALSE(tx.getTransferRate().has_value());
356 EXPECT_FALSE(tx.hasSetFlag());
357 EXPECT_FALSE(tx.getSetFlag().has_value());
358 EXPECT_FALSE(tx.hasClearFlag());
359 EXPECT_FALSE(tx.getClearFlag().has_value());
360 EXPECT_FALSE(tx.hasTickSize());
361 EXPECT_FALSE(tx.getTickSize().has_value());
362 EXPECT_FALSE(tx.hasNFTokenMinter());
363 EXPECT_FALSE(tx.getNFTokenMinter().has_value());
364}
365
366}
AccountSet build(PublicKey const &publicKey, SecretKey const &secretKey)
Build and return the AccountSet wrapper.
std::shared_ptr< STTx const > getSTTx() const
Get the underlying STTx object.
TEST(TransactionsAccountDeleteTests, BuilderSettersRoundTrip)
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition Seed.cpp:57
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
AccountID calcAccountID(PublicKey const &pk)
void expectEqualField(T const &expected, T const &actual, char const *fieldName)