xrpld
Loading...
Searching...
No Matches
STObject_test.cpp
1#include <test/jtx/Env.h>
2
3#include <xrpl/basics/Blob.h>
4#include <xrpl/basics/Buffer.h>
5#include <xrpl/basics/Slice.h>
6#include <xrpl/beast/unit_test/suite.h>
7#include <xrpl/json/json_writer.h>
8#include <xrpl/protocol/KeyType.h>
9#include <xrpl/protocol/SField.h>
10#include <xrpl/protocol/SOTemplate.h>
11#include <xrpl/protocol/STArray.h>
12#include <xrpl/protocol/STObject.h>
13#include <xrpl/protocol/STVector256.h>
14#include <xrpl/protocol/SecretKey.h>
15#include <xrpl/protocol/Seed.h>
16#include <xrpl/protocol/Serializer.h>
17
18#include <array>
19#include <cstdint>
20#include <cstring>
21#include <exception>
22#include <memory>
23#include <optional>
24#include <ostream>
25#include <stdexcept>
26#include <type_traits>
27#include <utility>
28#include <vector>
29
30namespace xrpl {
31
33{
34public:
35 void
37 {
38 testcase("serialization");
39
40 unexpected(sfGeneric.isUseful(), "sfGeneric must not be useful");
41 {
42 // Try to put sfGeneric in an SOTemplate.
44 [&]() { SOTemplate const elements{{sfGeneric, SoeRequired}}; });
45 }
46
47 unexpected(sfInvalid.isUseful(), "sfInvalid must not be useful");
48 {
49 // Test return of sfInvalid.
50 auto testInvalid = [this](SerializedTypeID tid, int fv) {
51 SField const& shouldBeInvalid{SField::getField(tid, fv)};
52 BEAST_EXPECT(shouldBeInvalid == sfInvalid);
53 };
54 testInvalid(STI_VL, 255);
55 testInvalid(STI_UINT256, 255);
56 testInvalid(STI_UINT32, 255);
57 testInvalid(STI_VECTOR256, 255);
58 testInvalid(STI_OBJECT, 255);
59 }
60 {
61 // Try to put sfInvalid in an SOTemplate.
63 [&]() { SOTemplate const elements{{sfInvalid, SoeRequired}}; });
64 }
65 {
66 // Try to put the same SField into an SOTemplate twice.
68 SOTemplate const elements{
69 {sfAccount, SoeRequired},
70 {sfAccount, SoeRequired},
71 };
72 });
73 }
74
75 // Put a variety of SFields of different types in an SOTemplate.
76 SField const& sfTestVL = sfMasterSignature;
77 SField const& sfTestH256 = sfCheckID;
78 SField const& sfTestU32 = sfSettleDelay;
79 SField const& sfTestV256 = sfAmendments;
80 SField const& sfTestObject = sfMajority;
81
82 SOTemplate const elements{
83 {sfFlags, SoeRequired},
84 {sfTestVL, SoeRequired},
85 {sfTestH256, SoeOptional},
86 {sfTestU32, SoeRequired},
87 {sfTestV256, SoeOptional},
88 };
89
90 STObject object1(elements, sfTestObject);
91 STObject const object2(object1);
92
93 unexpected(object1.getSerializer() != object2.getSerializer(), "STObject error 1");
94
96 object1.isFieldPresent(sfTestH256) || !object1.isFieldPresent(sfTestVL),
97 "STObject error");
98
99 object1.makeFieldPresent(sfTestH256);
100
101 unexpected(!object1.isFieldPresent(sfTestH256), "STObject Error 2");
102
103 unexpected(object1.getFieldH256(sfTestH256) != uint256(), "STObject error 3");
104
105 if (object1.getSerializer() == object2.getSerializer())
106 {
107 log << "O1: " << object1.getJson(JsonOptions::Values::None) << '\n'
108 << "O2: " << object2.getJson(JsonOptions::Values::None) << std::endl;
109 fail("STObject error 4");
110 }
111 else
112 {
113 pass();
114 }
115
116 object1.makeFieldAbsent(sfTestH256);
117
118 unexpected(object1.isFieldPresent(sfTestH256), "STObject error 5");
119
120 unexpected(object1.getFlags() != 0, "STObject error 6");
121
122 unexpected(object1.getSerializer() != object2.getSerializer(), "STObject error 7");
123
124 STObject copy(object1);
125
126 unexpected(object1.isFieldPresent(sfTestH256), "STObject error 8");
127
128 unexpected(copy.isFieldPresent(sfTestH256), "STObject error 9");
129
130 unexpected(object1.getSerializer() != copy.getSerializer(), "STObject error 10");
131
132 copy.setFieldU32(sfTestU32, 1);
133
134 unexpected(object1.getSerializer() == copy.getSerializer(), "STObject error 11");
135
136 for (int i = 0; i < 1000; i++)
137 {
138 Blob const j(i, 2);
139
140 object1.setFieldVL(sfTestVL, j);
141
142 Serializer s;
143 object1.add(s);
144 SerialIter it(s.slice());
145
146 STObject const object3(elements, it, sfTestObject);
147
148 unexpected(object1.getFieldVL(sfTestVL) != j, "STObject error");
149
150 unexpected(object3.getFieldVL(sfTestVL) != j, "STObject error");
151 }
152
153 {
155 uints.reserve(5);
156 for (int i = 0; i < uints.capacity(); ++i)
157 {
158 uints.emplace_back(i);
159 }
160 object1.setFieldV256(sfTestV256, STVector256(uints));
161
162 Serializer s;
163 object1.add(s);
164 SerialIter it(s.slice());
165
166 STObject const object3(elements, it, sfTestObject);
167
168 auto const& uints1 = object1.getFieldV256(sfTestV256);
169 auto const& uints3 = object3.getFieldV256(sfTestV256);
170
171 BEAST_EXPECT(uints1 == uints3);
172 }
173 }
174
175 // Exercise field accessors
176 void
178 {
179 testcase("fields");
180
181 auto const& sf1Outer = sfSequence;
182 auto const& sf2Outer = sfExpiration;
183 auto const& sf3Outer = sfQualityIn;
184 auto const& sf4Outer = sfAmount;
185 auto const& sf4 = sfSignature;
186 auto const& sf5 = sfPublicKey;
187
188 // read free object
189
190 {
191 auto const st = [&]() {
193 s.setFieldU32(sf1Outer, 1);
194 s.setFieldU32(sf2Outer, 2);
195 return s;
196 }();
197
198 BEAST_EXPECT(st[sf1Outer] == 1);
199 BEAST_EXPECT(st[sf2Outer] == 2);
200 except<STObject::FieldErr>([&]() { st[sf3Outer]; });
201 BEAST_EXPECT(*st[~sf1Outer] == 1); // NOLINT(bugprone-unchecked-optional-access)
202 BEAST_EXPECT(*st[~sf2Outer] == 2); // NOLINT(bugprone-unchecked-optional-access)
203 BEAST_EXPECT(st[~sf3Outer] == std::nullopt);
204 BEAST_EXPECT(!!st[~sf1Outer]);
205 BEAST_EXPECT(!!st[~sf2Outer]);
206 BEAST_EXPECT(!st[~sf3Outer]);
207 BEAST_EXPECT(st[sf1Outer] != st[sf2Outer]);
208 BEAST_EXPECT(st[~sf1Outer] != st[~sf2Outer]);
209 }
210
211 // read templated object
212 SOTemplate const sotOuter{
213 {sf1Outer, SoeRequired},
214 {sf2Outer, SoeOptional},
215 {sf3Outer, SoeDefault},
216 {sf4Outer, SoeOptional},
217 {sf4, SoeOptional},
218 {sf5, SoeDefault},
219 };
220
221 {
222 auto const st = [&]() {
223 STObject s(sotOuter, sfGeneric);
224 s.setFieldU32(sf1Outer, 1);
225 s.setFieldU32(sf2Outer, 2);
226 return s;
227 }();
228
229 BEAST_EXPECT(st[sf1Outer] == 1);
230 BEAST_EXPECT(st[sf2Outer] == 2);
231 BEAST_EXPECT(st[sf3Outer] == 0);
232 BEAST_EXPECT(*st[~sf1Outer] == 1); // NOLINT(bugprone-unchecked-optional-access)
233 BEAST_EXPECT(*st[~sf2Outer] == 2); // NOLINT(bugprone-unchecked-optional-access)
234 BEAST_EXPECT(*st[~sf3Outer] == 0); // NOLINT(bugprone-unchecked-optional-access)
235 BEAST_EXPECT(!!st[~sf1Outer]);
236 BEAST_EXPECT(!!st[~sf2Outer]);
237 BEAST_EXPECT(!!st[~sf3Outer]);
238 }
239
240 // write free object
241
242 {
244 unexcept([&]() { st[sf1Outer]; });
245 except([&]() { return st[sf1Outer] == 0; });
246 BEAST_EXPECT(st[~sf1Outer] == std::nullopt);
247 BEAST_EXPECT(st[~sf1Outer] == std::optional<std::uint32_t>{});
248 BEAST_EXPECT(st[~sf1Outer] != std::optional<std::uint32_t>(1));
249 BEAST_EXPECT(!st[~sf1Outer]);
250 st[sf1Outer] = 2;
251 BEAST_EXPECT(st[sf1Outer] == 2);
252 BEAST_EXPECT(st[~sf1Outer] != std::nullopt);
253 BEAST_EXPECT(st[~sf1Outer] == std::optional<std::uint32_t>(2));
254 BEAST_EXPECT(!!st[~sf1Outer]);
255 st[sf1Outer] = 1;
256 BEAST_EXPECT(st[sf1Outer] == 1);
257 BEAST_EXPECT(!!st[sf1Outer]);
258 BEAST_EXPECT(!!st[~sf1Outer]);
259 st[sf1Outer] = 0;
260 BEAST_EXPECT(!st[sf1Outer]);
261 BEAST_EXPECT(!!st[~sf1Outer]);
262 st[~sf1Outer] = std::nullopt;
263 BEAST_EXPECT(!st[~sf1Outer]);
264 BEAST_EXPECT(st[~sf1Outer] == std::nullopt);
265 BEAST_EXPECT(st[~sf1Outer] == std::optional<std::uint32_t>{});
266 st[~sf1Outer] = std::nullopt;
267 BEAST_EXPECT(!st[~sf1Outer]);
268 except([&]() { return st[sf1Outer] == 0; });
269 except([&]() { return *st[~sf1Outer]; });
270 st[sf1Outer] = 1;
271 BEAST_EXPECT(st[sf1Outer] == 1);
272 BEAST_EXPECT(!!st[sf1Outer]);
273 BEAST_EXPECT(!!st[~sf1Outer]);
274 st[sf1Outer] = 3;
275 st[sf2Outer] = st[sf1Outer];
276 BEAST_EXPECT(st[sf1Outer] == 3);
277 BEAST_EXPECT(st[sf2Outer] == 3);
278 BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]);
279 st[sf1Outer] = 4;
280 st[sf2Outer] = st[sf1Outer];
281 BEAST_EXPECT(st[sf1Outer] == 4);
282 BEAST_EXPECT(st[sf2Outer] == 4);
283 BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]);
284 st[sf1Outer] += 1;
285 BEAST_EXPECT(st[sf1Outer] == 5);
286 st[sf4Outer] = STAmount{1};
287 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
288 st[sf4Outer] += STAmount{1};
289 BEAST_EXPECT(st[sf4Outer] == STAmount{2});
290 st[sf1Outer] -= 1;
291 BEAST_EXPECT(st[sf1Outer] == 4);
292 st[sf4Outer] -= STAmount{1};
293 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
294 }
295
296 // Write templated object
297
298 {
299 STObject st(sotOuter, sfGeneric);
300 BEAST_EXPECT(!!st[~sf1Outer]);
301 BEAST_EXPECT(st[~sf1Outer] != std::nullopt);
302 BEAST_EXPECT(st[sf1Outer] == 0);
303 BEAST_EXPECT(*st[~sf1Outer] == 0);
304 BEAST_EXPECT(!st[~sf2Outer]);
305 BEAST_EXPECT(st[~sf2Outer] == std::nullopt);
306 except([&]() { return st[sf2Outer] == 0; });
307 BEAST_EXPECT(!!st[~sf3Outer]);
308 BEAST_EXPECT(st[~sf3Outer] != std::nullopt);
309 BEAST_EXPECT(st[sf3Outer] == 0);
310 except([&]() { st[~sf1Outer] = std::nullopt; });
311 st[sf1Outer] = 1;
312 BEAST_EXPECT(st[sf1Outer] == 1);
313 BEAST_EXPECT(*st[~sf1Outer] == 1);
314 BEAST_EXPECT(!!st[~sf1Outer]);
315 st[sf1Outer] = 0;
316 BEAST_EXPECT(st[sf1Outer] == 0);
317 BEAST_EXPECT(*st[~sf1Outer] == 0);
318 BEAST_EXPECT(!!st[~sf1Outer]);
319 st[sf2Outer] = 2;
320 BEAST_EXPECT(st[sf2Outer] == 2);
321 BEAST_EXPECT(*st[~sf2Outer] == 2);
322 BEAST_EXPECT(!!st[~sf2Outer]);
323 st[~sf2Outer] = std::nullopt;
324 except([&]() { return *st[~sf2Outer]; });
325 BEAST_EXPECT(!st[~sf2Outer]);
326 st[sf3Outer] = 3;
327 BEAST_EXPECT(st[sf3Outer] == 3);
328 BEAST_EXPECT(*st[~sf3Outer] == 3);
329 BEAST_EXPECT(!!st[~sf3Outer]);
330 st[sf3Outer] = 2;
331 BEAST_EXPECT(st[sf3Outer] == 2);
332 BEAST_EXPECT(*st[~sf3Outer] == 2);
333 BEAST_EXPECT(!!st[~sf3Outer]);
334 st[sf3Outer] = 0;
335 BEAST_EXPECT(st[sf3Outer] == 0);
336 BEAST_EXPECT(*st[~sf3Outer] == 0);
337 BEAST_EXPECT(!!st[~sf3Outer]);
338 except([&]() { st[~sf3Outer] = std::nullopt; });
339 BEAST_EXPECT(st[sf3Outer] == 0);
340 BEAST_EXPECT(*st[~sf3Outer] == 0);
341 BEAST_EXPECT(!!st[~sf3Outer]);
342 st[sf1Outer] += 1;
343 BEAST_EXPECT(st[sf1Outer] == 1);
344 st[sf4Outer] = STAmount{1};
345 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
346 st[sf4Outer] += STAmount{1};
347 BEAST_EXPECT(st[sf4Outer] == STAmount{2});
348 st[sf1Outer] -= 1;
349 BEAST_EXPECT(st[sf1Outer] == 0);
350 st[sf4Outer] -= STAmount{1};
351 BEAST_EXPECT(st[sf4Outer] == STAmount{1});
352 }
353
354 // coercion operator to std::optional
355
356 {
358 auto const v = ~st[~sf1Outer];
359 static_assert(std::is_same_v<std::decay_t<decltype(v)>, std::optional<std::uint32_t>>);
360 }
361
362 // UDT scalar fields
363
364 {
366 st[sfAmount] = STAmount{};
367 st[sfAccount] = AccountID{};
368 st[sfDigest] = uint256{};
369 [&](STAmount) {}(st[sfAmount]);
370 [&](AccountID) {}(st[sfAccount]);
371 [&](uint256) {}(st[sfDigest]);
372 }
373
374 // STBlob and slice
375
376 {
377 {
379 Buffer b(1);
380 BEAST_EXPECT(!b.empty());
381 st[sf4] = std::move(b);
382 BEAST_EXPECT(b.empty()); // NOLINT(bugprone-use-after-move)
383 BEAST_EXPECT(Slice(st[sf4]).size() == 1);
384 st[~sf4] = std::nullopt;
385 BEAST_EXPECT(!~st[~sf4]);
386 b = Buffer{2};
387 st[sf4] = Slice(b);
388 BEAST_EXPECT(b.size() == 2);
389 BEAST_EXPECT(Slice(st[sf4]).size() == 2);
390 st[sf5] = st[sf4];
391 BEAST_EXPECT(Slice(st[sf4]).size() == 2);
392 BEAST_EXPECT(Slice(st[sf5]).size() == 2);
393 }
394 {
395 STObject st(sotOuter, sfGeneric);
396 BEAST_EXPECT(st[sf5] == Slice{});
397 BEAST_EXPECT(!!st[~sf5]);
398 BEAST_EXPECT(!!~st[~sf5]);
399 Buffer b(1);
400 st[sf5] = std::move(b);
401 BEAST_EXPECT(b.empty()); // NOLINT(bugprone-use-after-move)
402 BEAST_EXPECT(Slice(st[sf5]).size() == 1);
403 st[~sf4] = std::nullopt;
404 BEAST_EXPECT(!~st[~sf4]);
405 }
406 }
407
408 // UDT blobs
409
410 {
412 BEAST_EXPECT(!st[~sf5]);
413 auto const kp = generateKeyPair(KeyType::Secp256k1, generateSeed("masterpassphrase"));
414 st[sf5] = kp.first;
415 st[~sf5] = std::nullopt;
416 }
417
418 // By reference fields
419
420 {
421 auto const& sf = sfIndexes;
424 v.emplace_back(1);
425 v.emplace_back(2);
426 st[sf] = v;
427 st[sf] = std::move(v);
428 auto const& cst = st;
429 BEAST_EXPECT(cst[sf].size() == 2);
430 BEAST_EXPECT(cst[~sf]->size() == 2); // NOLINT(bugprone-unchecked-optional-access)
431 BEAST_EXPECT(cst[sf][0] == 1);
432 BEAST_EXPECT(cst[sf][1] == 2);
433 static_assert(std::is_same_v<decltype(cst[sfIndexes]), std::vector<uint256> const&>);
434 }
435
436 // Default by reference field
437
438 {
439 auto const& sf1 = sfIndexes;
440 auto const& sf2 = sfHashes;
441 auto const& sf3 = sfAmendments;
442 SOTemplate const sot{
443 {sf1, SoeRequired},
444 {sf2, SoeOptional},
445 {sf3, SoeDefault},
446 };
447
448 STObject st(sot, sfGeneric);
449 auto const& cst(st);
450 BEAST_EXPECT(cst[sf1].empty());
451 BEAST_EXPECT(!cst[~sf2]);
452 BEAST_EXPECT(cst[sf3].empty());
454 v.emplace_back(1);
455 st[sf1] = v;
456 BEAST_EXPECT(cst[sf1].size() == 1);
457 BEAST_EXPECT(cst[sf1][0] == uint256{1});
458 st[sf2] = v;
459 BEAST_EXPECT(cst[sf2].size() == 1);
460 BEAST_EXPECT(cst[sf2][0] == uint256{1});
461 st[~sf2] = std::nullopt;
462 BEAST_EXPECT(!st[~sf2]);
463 st[sf3] = v;
464 BEAST_EXPECT(cst[sf3].size() == 1);
465 BEAST_EXPECT(cst[sf3][0] == uint256{1});
466 st[sf3] = std::vector<uint256>{};
467 BEAST_EXPECT(cst[sf3].empty());
468 }
469 } // namespace xrpl
470
471 void
473 {
474 testcase("Malformed serialized forms");
475
476 try
477 {
478 std::array<std::uint8_t, 7> const payload{{0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc}};
479 SerialIter sit{makeSlice(payload)};
480 auto obj = std::make_shared<STArray>(sit, sfMetadata);
481 BEAST_EXPECT(!obj);
482 }
483 catch (std::exception const& e)
484 {
485 BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0);
486 }
487
488 try
489 {
490 std::array<std::uint8_t, 3> const payload{{0xe2, 0xe1, 0xe2}};
491 SerialIter sit{makeSlice(payload)};
492 auto obj = std::make_shared<STObject>(sit, sfMetadata);
493 BEAST_EXPECT(!obj);
494 }
495 catch (std::exception const& e)
496 {
497 BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0);
498 }
499 }
500
501 void
502 run() override
503 {
504 // Instantiate a jtx::Env so debugLog writes are exercised.
505 test::jtx::Env const env(*this);
506
507 testFields();
510 }
511};
512
514
515} // namespace xrpl
T capacity(T... args)
A testsuite class.
Definition suite.h:52
bool except(F &&f, String const &reason)
Definition suite.h:465
bool unexpected(Condition shouldBeFalse, String const &reason)
DEPRECATED.
Definition suite.h:516
bool unexcept(F &&f, String const &reason)
Definition suite.h:499
void pass()
Record a successful test condition.
Definition suite.h:532
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
LogOs< char > log
Logging output stream.
Definition suite.h:150
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
Like std::vector<char> but better.
Definition Buffer.h:19
bool empty() const noexcept
Definition Buffer.h:129
std::size_t size() const noexcept
Returns the number of bytes in the buffer.
Definition Buffer.h:123
Identifies fields.
Definition SField.h:132
static SField const & getField(int fieldCode)
Definition SField.cpp:116
Defines the fields and their attributes within a STObject.
Definition SOTemplate.h:105
void run() override
Runs the suite.
Blob getFieldVL(SField const &field) const
Definition STObject.cpp:649
void setFieldV256(SField const &field, STVector256 const &v)
Definition STObject.cpp:779
void setFieldVL(SField const &field, Blob const &)
Definition STObject.cpp:791
void setFieldU32(SField const &field, std::uint32_t)
Definition STObject.cpp:743
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
Definition STObject.cpp:845
void add(Serializer &s) const override
Definition STObject.cpp:123
Serializer getSerializer() const
Definition STObject.h:1003
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:464
uint256 getFieldH256(SField const &field) const
Definition STObject.cpp:631
STBase * makeFieldPresent(SField const &field)
Definition STObject.cpp:528
STVector256 const & getFieldV256(SField const &field) const
Definition STObject.cpp:671
void makeFieldAbsent(SField const &field)
Definition STObject.cpp:550
std::uint32_t getFlags() const
Definition STObject.cpp:517
Slice slice() const noexcept
Definition Serializer.h:45
An immutable linear range of bytes.
Definition Slice.h:28
A transaction testing environment.
Definition Env.h:161
T emplace_back(T... args)
T endl(T... args)
T is_same_v
T make_shared(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ SoeDefault
Definition SOTemplate.h:24
@ SoeOptional
Definition SOTemplate.h:23
@ SoeRequired
Definition SOTemplate.h:22
SField const sfGeneric
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
Definition Seed.cpp:58
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Slice makeSlice(std::array< T, N > const &a)
Definition Slice.h:228
SerializedTypeID
Definition SField.h:94
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
SField const sfInvalid
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:11
BaseUInt< 256 > uint256
Definition base_uint.h:580
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)
T reserve(T... args)
T what(T... args)