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