rippled
Loading...
Searching...
No Matches
FeeVote_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/app/misc/FeeVote.h>
4
5#include <xrpl/basics/BasicConfig.h>
6#include <xrpl/ledger/OpenView.h>
7#include <xrpl/protocol/Feature.h>
8#include <xrpl/protocol/Indexes.h>
9#include <xrpl/protocol/PublicKey.h>
10#include <xrpl/protocol/STTx.h>
11#include <xrpl/protocol/SecretKey.h>
12#include <xrpl/tx/apply.h>
13
14namespace xrpl {
15namespace test {
16
27
28STTx
30{
31 auto fill = [&](auto& obj) {
32 obj.setAccountID(sfAccount, AccountID());
33 obj.setFieldU32(sfLedgerSequence, seq);
34
35 if (rules.enabled(featureXRPFees))
36 {
37 // New XRPFees format - all three fields are REQUIRED
38 obj.setFieldAmount(
39 sfBaseFeeDrops, fields.baseFeeDrops ? *fields.baseFeeDrops : XRPAmount{0});
40 obj.setFieldAmount(
41 sfReserveBaseDrops,
42 fields.reserveBaseDrops ? *fields.reserveBaseDrops : XRPAmount{0});
43 obj.setFieldAmount(
44 sfReserveIncrementDrops,
46 }
47 else
48 {
49 // Legacy format - all four fields are REQUIRED
50 obj.setFieldU64(sfBaseFee, fields.baseFee ? *fields.baseFee : 0);
51 obj.setFieldU32(sfReserveBase, fields.reserveBase ? *fields.reserveBase : 0);
52 obj.setFieldU32(
53 sfReserveIncrement, fields.reserveIncrement ? *fields.reserveIncrement : 0);
54 obj.setFieldU32(
55 sfReferenceFeeUnits, fields.referenceFeeUnits ? *fields.referenceFeeUnits : 0);
56 }
57 };
58 return STTx(ttFEE, fill);
59}
60
61STTx
63 Rules const& rules,
65 bool missingRequiredFields = true,
66 bool wrongFeatureFields = false,
67 std::uint32_t uniqueValue = 42)
68{
69 auto fill = [&](auto& obj) {
70 obj.setAccountID(sfAccount, AccountID());
71 obj.setFieldU32(sfLedgerSequence, seq);
72
73 if (wrongFeatureFields)
74 {
75 if (rules.enabled(featureXRPFees))
76 {
77 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
78 obj.setFieldU32(sfReserveBase, 200000);
79 obj.setFieldU32(sfReserveIncrement, 50000);
80 obj.setFieldU32(sfReferenceFeeUnits, 10);
81 }
82 else
83 {
84 obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10 + uniqueValue});
85 obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000});
86 obj.setFieldAmount(sfReserveIncrementDrops, XRPAmount{50000});
87 }
88 }
89 else if (!missingRequiredFields)
90 {
91 // Create valid transaction (all required fields present)
92 if (rules.enabled(featureXRPFees))
93 {
94 obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10 + uniqueValue});
95 obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000});
96 obj.setFieldAmount(sfReserveIncrementDrops, XRPAmount{50000});
97 }
98 else
99 {
100 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
101 obj.setFieldU32(sfReserveBase, 200000);
102 obj.setFieldU32(sfReserveIncrement, 50000);
103 obj.setFieldU32(sfReferenceFeeUnits, 10);
104 }
105 }
106 // If missingRequiredFields is true, we don't add the required fields
107 // (default behavior)
108 };
109 return STTx(ttFEE, fill);
110}
111
112bool
114{
115 auto const res = apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
116 return isTesSuccess(res.ter);
117}
118
119bool
121 std::shared_ptr<Ledger const> const& ledger,
122 Rules const& rules,
123 FeeSettingsFields const& expected)
124{
125 auto const feeObject = ledger->read(keylet::fees());
126 if (!feeObject)
127 return false;
128
129 auto checkEquality = [&](auto const& field, auto const& expected) {
130 if (!feeObject->isFieldPresent(field))
131 return false;
132 return feeObject->at(field) == expected;
133 };
134
135 if (rules.enabled(featureXRPFees))
136 {
137 if (feeObject->isFieldPresent(sfBaseFee) || feeObject->isFieldPresent(sfReserveBase) ||
138 feeObject->isFieldPresent(sfReserveIncrement) ||
139 feeObject->isFieldPresent(sfReferenceFeeUnits))
140 return false;
141
142 if (!checkEquality(sfBaseFeeDrops, expected.baseFeeDrops.value_or(XRPAmount{0})))
143 return false;
144 if (!checkEquality(sfReserveBaseDrops, expected.reserveBaseDrops.value_or(XRPAmount{0})))
145 return false;
146 if (!checkEquality(
147 sfReserveIncrementDrops, expected.reserveIncrementDrops.value_or(XRPAmount{0})))
148 return false;
149 }
150 else
151 {
152 if (feeObject->isFieldPresent(sfBaseFeeDrops) ||
153 feeObject->isFieldPresent(sfReserveBaseDrops) ||
154 feeObject->isFieldPresent(sfReserveIncrementDrops))
155 return false;
156
157 // Read sfBaseFee as a hex string and compare to expected.baseFee
158 if (!checkEquality(sfBaseFee, expected.baseFee))
159 return false;
160 if (!checkEquality(sfReserveBase, expected.reserveBase))
161 return false;
162 if (!checkEquality(sfReserveIncrement, expected.reserveIncrement))
163 return false;
164 if (!checkEquality(sfReferenceFeeUnits, expected.referenceFeeUnits))
165 return false;
166 }
167
168 return true;
169}
170
173{
175 for (auto i = txSet->begin(); i != txSet->end(); ++i)
176 {
177 auto const data = i->slice();
178 auto serialIter = SerialIter(data);
179 txs.push_back(STTx(serialIter));
180 }
181 return txs;
182};
183
185{
186 void
188 {
189 FeeSetup const defaultSetup;
190 {
191 // defaults
192 Section const config;
193 auto setup = setup_FeeVote(config);
194 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
195 BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
196 BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
197 }
198 {
199 Section config;
200 config.append(
201 {"reference_fee = 50", "account_reserve = 1234567", "owner_reserve = 1234"});
202 auto setup = setup_FeeVote(config);
203 BEAST_EXPECT(setup.reference_fee == 50);
204 BEAST_EXPECT(setup.account_reserve == 1234567);
205 BEAST_EXPECT(setup.owner_reserve == 1234);
206 }
207 {
208 Section config;
209 config.append(
210 {"reference_fee = blah", "account_reserve = yada", "owner_reserve = foo"});
211 // Illegal values are ignored, and the defaults left unchanged
212 auto setup = setup_FeeVote(config);
213 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
214 BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
215 BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
216 }
217 {
218 Section config;
219 config.append(
220 {"reference_fee = -50", "account_reserve = -1234567", "owner_reserve = -1234"});
221 // Illegal values are ignored, and the defaults left unchanged
222 auto setup = setup_FeeVote(config);
223 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
224 BEAST_EXPECT(setup.account_reserve == static_cast<std::uint32_t>(-1234567));
225 BEAST_EXPECT(setup.owner_reserve == static_cast<std::uint32_t>(-1234));
226 }
227 {
228 auto const big64 = std::to_string(
230 Section config;
231 config.append(
232 {"reference_fee = " + big64,
233 "account_reserve = " + big64,
234 "owner_reserve = " + big64});
235 // Illegal values are ignored, and the defaults left unchanged
236 auto setup = setup_FeeVote(config);
237 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
238 BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
239 BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
240 }
241 }
242
243 void
245 {
246 testcase("Basic SetFee transaction");
247
248 // Test with XRPFees disabled (legacy format)
249 {
250 jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees);
251 auto ledger = std::make_shared<Ledger>(
253 Rules{env.app().config().features},
254 env.app().config().FEES.toFees(),
256 env.app().getNodeFamily());
257
258 // Create the next ledger to apply transaction to
259 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
260
261 // Test successful fee transaction with legacy fields
262
263 FeeSettingsFields const fields{
264 .baseFee = 10,
265 .reserveBase = 200000,
266 .reserveIncrement = 50000,
267 .referenceFeeUnits = 10};
268 auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
269
270 OpenView accum(ledger.get());
271 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
272 accum.apply(*ledger);
273
274 // Verify fee object was created/updated correctly
275 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields));
276 }
277
278 // Test with XRPFees enabled (new format)
279 {
280 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
281 auto ledger = std::make_shared<Ledger>(
283 Rules{env.app().config().features},
284 env.app().config().FEES.toFees(),
286 env.app().getNodeFamily());
287
288 // Create the next ledger to apply transaction to
289 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
290
291 FeeSettingsFields const fields{
292 .baseFeeDrops = XRPAmount{10},
293 .reserveBaseDrops = XRPAmount{200000},
294 .reserveIncrementDrops = XRPAmount{50000}};
295 // Test successful fee transaction with new fields
296 auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
297
298 OpenView accum(ledger.get());
299 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
300 accum.apply(*ledger);
301
302 // Verify fee object was created/updated correctly
303 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields));
304 }
305 }
306
307 void
309 {
310 testcase("Fee Transaction Validation");
311
312 {
313 jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees);
314 auto ledger = std::make_shared<Ledger>(
316 Rules{env.app().config().features},
317 env.app().config().FEES.toFees(),
319 env.app().getNodeFamily());
320
321 // Create the next ledger to apply transaction to
322 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
323
324 // Test transaction with missing required legacy fields
325 auto invalidTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), true, false, 1);
326 OpenView accum(ledger.get());
327 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
328
329 // Test transaction with new format fields when XRPFees is disabled
330 auto disallowedTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), false, true, 2);
331 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx));
332 }
333
334 {
335 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
336 auto ledger = std::make_shared<Ledger>(
338 Rules{env.app().config().features},
339 env.app().config().FEES.toFees(),
341 env.app().getNodeFamily());
342
343 // Create the next ledger to apply transaction to
344 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
345
346 // Test transaction with missing required new fields
347 auto invalidTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), true, false, 3);
348 OpenView accum(ledger.get());
349 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
350
351 // Test transaction with legacy fields when XRPFees is enabled
352 auto disallowedTx = createInvalidFeeTx(ledger->rules(), ledger->seq(), false, true, 4);
353 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx));
354 }
355 }
356
357 void
359 {
360 testcase("Pseudo Transaction Properties");
361
363 auto ledger = std::make_shared<Ledger>(
365 Rules{env.app().config().features},
366 env.app().config().FEES.toFees(),
368 env.app().getNodeFamily());
369
370 // Create the next ledger to apply transaction to
371 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
372
373 auto feeTx = createFeeTx(
374 ledger->rules(),
375 ledger->seq(),
376 {.baseFeeDrops = XRPAmount{10},
377 .reserveBaseDrops = XRPAmount{200000},
378 .reserveIncrementDrops = XRPAmount{50000}});
379
380 // Verify pseudo-transaction properties
381 BEAST_EXPECT(feeTx.getAccountID(sfAccount) == AccountID());
382 BEAST_EXPECT(feeTx.getFieldAmount(sfFee) == XRPAmount{0});
383 BEAST_EXPECT(feeTx.getSigningPubKey().empty());
384 BEAST_EXPECT(feeTx.getSignature().empty());
385 BEAST_EXPECT(!feeTx.isFieldPresent(sfSigners));
386 BEAST_EXPECT(feeTx.getFieldU32(sfSequence) == 0);
387 BEAST_EXPECT(!feeTx.isFieldPresent(sfPreviousTxnID));
388
389 // But can be applied to a closed ledger
390 {
391 OpenView closedAccum(ledger.get());
392 BEAST_EXPECT(applyFeeAndTestResult(env, closedAccum, feeTx));
393 }
394 }
395
396 void
398 {
399 testcase("Multiple Fee Updates");
400
401 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
402 auto ledger = std::make_shared<Ledger>(
404 Rules{env.app().config().features},
405 env.app().config().FEES.toFees(),
407 env.app().getNodeFamily());
408
409 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
410
411 FeeSettingsFields const fields1{
412 .baseFeeDrops = XRPAmount{10},
413 .reserveBaseDrops = XRPAmount{200000},
414 .reserveIncrementDrops = XRPAmount{50000}};
415 auto feeTx1 = createFeeTx(ledger->rules(), ledger->seq(), fields1);
416
417 {
418 OpenView accum(ledger.get());
419 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx1));
420 accum.apply(*ledger);
421 }
422
423 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields1));
424
425 // Apply second fee transaction with different values
426 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
427
428 FeeSettingsFields const fields2{
429 .baseFeeDrops = XRPAmount{20},
430 .reserveBaseDrops = XRPAmount{300000},
431 .reserveIncrementDrops = XRPAmount{75000}};
432 auto feeTx2 = createFeeTx(ledger->rules(), ledger->seq(), fields2);
433
434 {
435 OpenView accum(ledger.get());
436 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx2));
437 accum.apply(*ledger);
438 }
439
440 // Verify second update overwrote the first
441 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields2));
442 }
443
444 void
446 {
447 testcase("Wrong Ledger Sequence");
448
449 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
450 auto ledger = std::make_shared<Ledger>(
452 Rules{env.app().config().features},
453 env.app().config().FEES.toFees(),
455 env.app().getNodeFamily());
456
457 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
458
459 // Test transaction with wrong ledger sequence
460 auto feeTx = createFeeTx(
461 ledger->rules(),
462 ledger->seq() + 5, // Wrong sequence (should be ledger->seq())
463 {.baseFeeDrops = XRPAmount{10},
464 .reserveBaseDrops = XRPAmount{200000},
465 .reserveIncrementDrops = XRPAmount{50000}});
466
467 OpenView accum(ledger.get());
468
469 // The transaction should still succeed as long as other fields are
470 // valid
471 // The ledger sequence field is only used for informational purposes
472 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
473 }
474
475 void
477 {
478 testcase("Partial Field Updates");
479
480 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
481 auto ledger = std::make_shared<Ledger>(
483 Rules{env.app().config().features},
484 env.app().config().FEES.toFees(),
486 env.app().getNodeFamily());
487
488 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
489
490 FeeSettingsFields const fields1{
491 .baseFeeDrops = XRPAmount{10},
492 .reserveBaseDrops = XRPAmount{200000},
493 .reserveIncrementDrops = XRPAmount{50000}};
494 auto feeTx1 = createFeeTx(ledger->rules(), ledger->seq(), fields1);
495
496 {
497 OpenView accum(ledger.get());
498 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx1));
499 accum.apply(*ledger);
500 }
501
502 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields1));
503
504 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
505
506 // Apply partial update (only some fields)
507 FeeSettingsFields const fields2{
508 .baseFeeDrops = XRPAmount{20}, .reserveBaseDrops = XRPAmount{200000}};
509 auto feeTx2 = createFeeTx(ledger->rules(), ledger->seq(), fields2);
510
511 {
512 OpenView accum(ledger.get());
513 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx2));
514 accum.apply(*ledger);
515 }
516
517 // Verify the partial update worked
518 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields2));
519 }
520
521 void
523 {
524 testcase("Single Invalid Transaction");
525
526 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
527 auto ledger = std::make_shared<Ledger>(
529 Rules{env.app().config().features},
530 env.app().config().FEES.toFees(),
532 env.app().getNodeFamily());
533
534 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
535
536 // Test invalid transaction with non-zero account - this should fail
537 // validation
538 auto invalidTx = STTx(ttFEE, [&](auto& obj) {
539 obj.setAccountID(sfAccount,
540 AccountID(1)); // Should be zero (this makes it invalid)
541 obj.setFieldU32(sfLedgerSequence, ledger->seq());
542 obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10});
543 obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000});
544 obj.setFieldAmount(sfReserveIncrementDrops, XRPAmount{50000});
545 });
546
547 OpenView accum(ledger.get());
548 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
549 }
550
551 void
553 {
554 testcase("doValidation");
555
556 using namespace jtx;
557
558 FeeSetup setup;
559 setup.reference_fee = 42;
560 setup.account_reserve = 1234567;
561 setup.owner_reserve = 7654321;
562
563 // Test with XRPFees enabled
564 {
565 Env env(*this, testable_amendments() | featureXRPFees);
566 auto feeVote = make_FeeVote(setup, env.app().getJournal("FeeVote"));
567
568 auto ledger = std::make_shared<Ledger>(
570 Rules{env.app().config().features},
571 env.app().config().FEES.toFees(),
573 env.app().getNodeFamily());
574
575 auto sec = randomSecretKey();
576 auto pub = derivePublicKey(KeyType::secp256k1, sec);
577
579 env.app().getTimeKeeper().now(), pub, sec, calcNodeID(pub), [](STValidation& v) {
580 v.setFieldU32(sfLedgerSequence, 12345);
581 });
582
583 // Use the current ledger's fees as the "current" fees for
584 // doValidation
585 auto const& currentFees = ledger->fees();
586
587 feeVote->doValidation(currentFees, ledger->rules(), *val);
588
589 BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops));
590 BEAST_EXPECT(val->getFieldAmount(sfBaseFeeDrops) == XRPAmount(setup.reference_fee));
591 }
592
593 // Test with XRPFees disabled (legacy format)
594 {
595 Env env(*this, testable_amendments() - featureXRPFees);
596 auto feeVote = make_FeeVote(setup, env.app().getJournal("FeeVote"));
597
598 auto ledger = std::make_shared<Ledger>(
600 Rules{env.app().config().features},
601 env.app().config().FEES.toFees(),
603 env.app().getNodeFamily());
604
605 auto sec = randomSecretKey();
606 auto pub = derivePublicKey(KeyType::secp256k1, sec);
607
609 env.app().getTimeKeeper().now(), pub, sec, calcNodeID(pub), [](STValidation& v) {
610 v.setFieldU32(sfLedgerSequence, 12345);
611 });
612
613 auto const& currentFees = ledger->fees();
614
615 feeVote->doValidation(currentFees, ledger->rules(), *val);
616
617 // In legacy mode, should vote using legacy fields
618 BEAST_EXPECT(val->isFieldPresent(sfBaseFee));
619 BEAST_EXPECT(val->getFieldU64(sfBaseFee) == setup.reference_fee);
620 }
621 }
622
623 void
625 {
626 testcase("doVoting");
627
628 using namespace jtx;
629
630 FeeSetup setup;
631 setup.reference_fee = 42;
632 setup.account_reserve = 1234567;
633 setup.owner_reserve = 7654321;
634
635 Env env(*this, testable_amendments() | featureXRPFees);
636
637 // establish what the current fees are
638 BEAST_EXPECT(env.current()->fees().base == XRPAmount{UNIT_TEST_REFERENCE_FEE});
639 BEAST_EXPECT(env.current()->fees().reserve == XRPAmount{200'000'000});
640 BEAST_EXPECT(env.current()->fees().increment == XRPAmount{50'000'000});
641
642 auto feeVote = make_FeeVote(setup, env.app().getJournal("FeeVote"));
643 auto ledger = std::make_shared<Ledger>(
645 Rules{env.app().config().features},
646 env.app().config().FEES.toFees(),
648 env.app().getNodeFamily());
649
650 // doVoting requires a flag ledger (every 256th ledger)
651 // We need to create a ledger at sequence 256 to make it a flag ledger
652 for (int i = 0; i < 256 - 1; ++i)
653 {
654 ledger = std::make_shared<Ledger>(*ledger, env.app().getTimeKeeper().closeTime());
655 }
656 BEAST_EXPECT(ledger->isFlagLedger());
657
658 // Create some mock validations with fee votes
660
661 for (int i = 0; i < 5; i++)
662 {
663 auto sec = randomSecretKey();
664 auto pub = derivePublicKey(KeyType::secp256k1, sec);
665
667 env.app().getTimeKeeper().now(), pub, sec, calcNodeID(pub), [&](STValidation& v) {
668 v.setFieldU32(sfLedgerSequence, ledger->seq());
669 // Vote for different fees than current
670 v.setFieldAmount(sfBaseFeeDrops, XRPAmount{setup.reference_fee});
671 v.setFieldAmount(sfReserveBaseDrops, XRPAmount{setup.account_reserve});
672 v.setFieldAmount(sfReserveIncrementDrops, XRPAmount{setup.owner_reserve});
673 });
674 if ((i % 2) != 0)
675 val->setTrusted();
676 validations.push_back(val);
677 }
678
680
681 // This should not throw since we have a flag ledger
682 feeVote->doVoting(ledger, validations, txSet);
683
684 auto const txs = getTxs(txSet);
685 BEAST_EXPECT(txs.size() == 1);
686 auto const& feeTx = txs[0];
687
688 BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
689
690 BEAST_EXPECT(feeTx.getAccountID(sfAccount) == AccountID());
691 BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
692
693 BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
694 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
695 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
696
697 // The legacy fields should NOT be present
698 BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
699 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
700 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
701 BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
702
703 // Check the values
704 BEAST_EXPECT(feeTx.getFieldAmount(sfBaseFeeDrops) == XRPAmount{setup.reference_fee});
705 BEAST_EXPECT(feeTx.getFieldAmount(sfReserveBaseDrops) == XRPAmount{setup.account_reserve});
706 BEAST_EXPECT(
707 feeTx.getFieldAmount(sfReserveIncrementDrops) == XRPAmount{setup.owner_reserve});
708 }
709
710 void
711 run() override
712 {
713 testSetup();
714 testBasic();
715 testTransactionValidation();
716 testPseudoTransactionProperties();
717 testMultipleFeeUpdates();
718 testWrongLedgerSequence();
719 testPartialFieldUpdates();
720 testSingleInvalidTransaction();
721 testDoValidation();
722 testDoVoting();
723 }
724};
725
726BEAST_DEFINE_TESTSUITE(FeeVote, app, xrpl);
727
728} // namespace test
729} // namespace xrpl
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
Manager to process fee votes.
Definition FeeVote.h:11
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:45
void apply(TxsRawView &to) const
Apply changes.
Definition OpenView.cpp:109
Rules controlling protocol behavior.
Definition Rules.h:18
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:120
void setFieldU32(SField const &field, std::uint32_t)
Definition STObject.cpp:735
void setFieldAmount(SField const &field, STAmount const &)
Definition STObject.cpp:789
Holds a collection of configuration values.
Definition BasicConfig.h:24
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
virtual beast::Journal getJournal(std::string const &name)=0
virtual Family & getNodeFamily()=0
virtual TimeKeeper & getTimeKeeper()=0
time_point now() const override
Returns the current time, using the server's clock.
Definition TimeKeeper.h:44
time_point closeTime() const
Returns the predicted close time, in network time.
Definition TimeKeeper.h:56
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:122
Application & app()
Definition Env.h:259
beast::Journal const journal
Definition Env.h:163
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:329
T is_same_v
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:200
auto const data
General field definitions, or fields used in multiple transaction namespaces.
FeatureBitset testable_amendments()
Definition Env.h:78
bool verifyFeeObject(std::shared_ptr< Ledger const > const &ledger, Rules const &rules, FeeSettingsFields const &expected)
STTx createInvalidFeeTx(Rules const &rules, std::uint32_t seq, bool missingRequiredFields=true, bool wrongFeatureFields=false, std::uint32_t uniqueValue=42)
STTx createFeeTx(Rules const &rules, std::uint32_t seq, FeeSettingsFields const &fields)
bool applyFeeAndTestResult(jtx::Env &env, OpenView &view, STTx const &tx)
std::vector< STTx > getTxs(std::shared_ptr< SHAMap > const &txSet)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::unique_ptr< FeeVote > make_FeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
ApplyResult apply(ServiceRegistry &registry, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition apply.cpp:124
create_genesis_t const create_genesis
FeeSetup setup_FeeVote(Section const &section)
Definition Config.cpp:1159
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
@ tapNONE
Definition ApplyView.h:11
bool isTesSuccess(TER x) noexcept
Definition TER.h:651
T push_back(T... args)
Fee schedule for startup / standalone, and to vote for.
Definition Config.h:49
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition Config.h:51
XRPAmount account_reserve
The account reserve requirement in drops.
Definition Config.h:54
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
Definition Config.h:57
std::optional< std::uint64_t > baseFee
std::optional< XRPAmount > reserveIncrementDrops
std::optional< std::uint32_t > reserveBase
std::optional< XRPAmount > baseFeeDrops
std::optional< XRPAmount > reserveBaseDrops
std::optional< std::uint32_t > reserveIncrement
std::optional< std::uint32_t > referenceFeeUnits
Set the sequence number on a JTx.
Definition seq.h:14
T to_string(T... args)