rippled
Loading...
Searching...
No Matches
FeeVote_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2019 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx.h>
21
22#include <xrpld/app/ledger/Ledger.h>
23#include <xrpld/app/misc/FeeVote.h>
24#include <xrpld/app/tx/apply.h>
25
26#include <xrpl/basics/BasicConfig.h>
27#include <xrpl/ledger/View.h>
28#include <xrpl/protocol/Feature.h>
29#include <xrpl/protocol/Indexes.h>
30#include <xrpl/protocol/PublicKey.h>
31#include <xrpl/protocol/STTx.h>
32#include <xrpl/protocol/SecretKey.h>
33
34namespace ripple {
35namespace test {
36
47
48STTx
50 Rules const& rules,
52 FeeSettingsFields const& fields)
53{
54 auto fill = [&](auto& obj) {
55 obj.setAccountID(sfAccount, AccountID());
56 obj.setFieldU32(sfLedgerSequence, seq);
57
58 if (rules.enabled(featureXRPFees))
59 {
60 // New XRPFees format - all three fields are REQUIRED
61 obj.setFieldAmount(
62 sfBaseFeeDrops,
63 fields.baseFeeDrops ? *fields.baseFeeDrops : XRPAmount{0});
64 obj.setFieldAmount(
65 sfReserveBaseDrops,
66 fields.reserveBaseDrops ? *fields.reserveBaseDrops
67 : XRPAmount{0});
68 obj.setFieldAmount(
69 sfReserveIncrementDrops,
71 : XRPAmount{0});
72 }
73 else
74 {
75 // Legacy format - all four fields are REQUIRED
76 obj.setFieldU64(sfBaseFee, fields.baseFee ? *fields.baseFee : 0);
77 obj.setFieldU32(
78 sfReserveBase, fields.reserveBase ? *fields.reserveBase : 0);
79 obj.setFieldU32(
80 sfReserveIncrement,
81 fields.reserveIncrement ? *fields.reserveIncrement : 0);
82 obj.setFieldU32(
83 sfReferenceFeeUnits,
84 fields.referenceFeeUnits ? *fields.referenceFeeUnits : 0);
85 }
86 };
87 return STTx(ttFEE, fill);
88}
89
90STTx
92 Rules const& rules,
94 bool missingRequiredFields = true,
95 bool wrongFeatureFields = false,
96 std::uint32_t uniqueValue = 42)
97{
98 auto fill = [&](auto& obj) {
99 obj.setAccountID(sfAccount, AccountID());
100 obj.setFieldU32(sfLedgerSequence, seq);
101
102 if (wrongFeatureFields)
103 {
104 if (rules.enabled(featureXRPFees))
105 {
106 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
107 obj.setFieldU32(sfReserveBase, 200000);
108 obj.setFieldU32(sfReserveIncrement, 50000);
109 obj.setFieldU32(sfReferenceFeeUnits, 10);
110 }
111 else
112 {
113 obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10 + uniqueValue});
114 obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000});
115 obj.setFieldAmount(sfReserveIncrementDrops, XRPAmount{50000});
116 }
117 }
118 else if (!missingRequiredFields)
119 {
120 // Create valid transaction (all required fields present)
121 if (rules.enabled(featureXRPFees))
122 {
123 obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10 + uniqueValue});
124 obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000});
125 obj.setFieldAmount(sfReserveIncrementDrops, XRPAmount{50000});
126 }
127 else
128 {
129 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
130 obj.setFieldU32(sfReserveBase, 200000);
131 obj.setFieldU32(sfReserveIncrement, 50000);
132 obj.setFieldU32(sfReferenceFeeUnits, 10);
133 }
134 }
135 // If missingRequiredFields is true, we don't add the required fields
136 // (default behavior)
137 };
138 return STTx(ttFEE, fill);
139}
140
141bool
143{
144 auto const res =
145 apply(env.app(), view, tx, ApplyFlags::tapNONE, env.journal);
146 return res.ter == tesSUCCESS;
147}
148
149bool
151 std::shared_ptr<Ledger const> const& ledger,
152 Rules const& rules,
153 FeeSettingsFields const& expected)
154{
155 auto const feeObject = ledger->read(keylet::fees());
156 if (!feeObject)
157 return false;
158
159 auto checkEquality = [&](auto const& field, auto const& expected) {
160 if (!feeObject->isFieldPresent(field))
161 return false;
162 return feeObject->at(field) == expected;
163 };
164
165 if (rules.enabled(featureXRPFees))
166 {
167 if (feeObject->isFieldPresent(sfBaseFee) ||
168 feeObject->isFieldPresent(sfReserveBase) ||
169 feeObject->isFieldPresent(sfReserveIncrement) ||
170 feeObject->isFieldPresent(sfReferenceFeeUnits))
171 return false;
172
173 if (!checkEquality(
174 sfBaseFeeDrops, expected.baseFeeDrops.value_or(XRPAmount{0})))
175 return false;
176 if (!checkEquality(
177 sfReserveBaseDrops,
178 expected.reserveBaseDrops.value_or(XRPAmount{0})))
179 return false;
180 if (!checkEquality(
181 sfReserveIncrementDrops,
182 expected.reserveIncrementDrops.value_or(XRPAmount{0})))
183 return false;
184 }
185 else
186 {
187 if (feeObject->isFieldPresent(sfBaseFeeDrops) ||
188 feeObject->isFieldPresent(sfReserveBaseDrops) ||
189 feeObject->isFieldPresent(sfReserveIncrementDrops))
190 return false;
191
192 // Read sfBaseFee as a hex string and compare to expected.baseFee
193 if (!checkEquality(sfBaseFee, expected.baseFee))
194 return false;
195 if (!checkEquality(sfReserveBase, expected.reserveBase))
196 return false;
197 if (!checkEquality(sfReserveIncrement, expected.reserveIncrement))
198 return false;
199 if (!checkEquality(sfReferenceFeeUnits, expected.referenceFeeUnits))
200 return false;
201 }
202
203 return true;
204}
205
208{
210 for (auto i = txSet->begin(); i != txSet->end(); ++i)
211 {
212 auto const data = i->slice();
213 auto serialIter = SerialIter(data);
214 txs.push_back(STTx(serialIter));
215 }
216 return txs;
217};
218
220{
221 void
223 {
224 FeeSetup const defaultSetup;
225 {
226 // defaults
227 Section config;
228 auto setup = setup_FeeVote(config);
229 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
230 BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
231 BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
232 }
233 {
234 Section config;
235 config.append(
236 {"reference_fee = 50",
237 "account_reserve = 1234567",
238 "owner_reserve = 1234"});
239 auto setup = setup_FeeVote(config);
240 BEAST_EXPECT(setup.reference_fee == 50);
241 BEAST_EXPECT(setup.account_reserve == 1234567);
242 BEAST_EXPECT(setup.owner_reserve == 1234);
243 }
244 {
245 Section config;
246 config.append(
247 {"reference_fee = blah",
248 "account_reserve = yada",
249 "owner_reserve = foo"});
250 // Illegal values are ignored, and the defaults left unchanged
251 auto setup = setup_FeeVote(config);
252 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
253 BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
254 BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
255 }
256 {
257 Section config;
258 config.append(
259 {"reference_fee = -50",
260 "account_reserve = -1234567",
261 "owner_reserve = -1234"});
262 // Illegal values are ignored, and the defaults left unchanged
263 auto setup = setup_FeeVote(config);
264 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
265 BEAST_EXPECT(
266 setup.account_reserve == static_cast<std::uint32_t>(-1234567));
267 BEAST_EXPECT(
268 setup.owner_reserve == static_cast<std::uint32_t>(-1234));
269 }
270 {
271 auto const big64 = std::to_string(
272 static_cast<std::uint64_t>(
274 1);
275 Section config;
276 config.append(
277 {"reference_fee = " + big64,
278 "account_reserve = " + big64,
279 "owner_reserve = " + big64});
280 // Illegal values are ignored, and the defaults left unchanged
281 auto setup = setup_FeeVote(config);
282 BEAST_EXPECT(setup.reference_fee == defaultSetup.reference_fee);
283 BEAST_EXPECT(setup.account_reserve == defaultSetup.account_reserve);
284 BEAST_EXPECT(setup.owner_reserve == defaultSetup.owner_reserve);
285 }
286 }
287
288 void
290 {
291 testcase("Basic SetFee transaction");
292
293 // Test with XRPFees disabled (legacy format)
294 {
295 jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees);
296 auto ledger = std::make_shared<Ledger>(
298 env.app().config(),
300 env.app().getNodeFamily());
301
302 // Create the next ledger to apply transaction to
304 *ledger, env.app().timeKeeper().closeTime());
305
306 // Test successful fee transaction with legacy fields
307
308 FeeSettingsFields fields{
309 .baseFee = 10,
310 .reserveBase = 200000,
311 .reserveIncrement = 50000,
312 .referenceFeeUnits = 10};
313 auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
314
315 OpenView accum(ledger.get());
316 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
317 accum.apply(*ledger);
318
319 // Verify fee object was created/updated correctly
320 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields));
321 }
322
323 // Test with XRPFees enabled (new format)
324 {
325 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
326 auto ledger = std::make_shared<Ledger>(
328 env.app().config(),
330 env.app().getNodeFamily());
331
332 // Create the next ledger to apply transaction to
334 *ledger, env.app().timeKeeper().closeTime());
335
336 FeeSettingsFields fields{
337 .baseFeeDrops = XRPAmount{10},
338 .reserveBaseDrops = XRPAmount{200000},
339 .reserveIncrementDrops = XRPAmount{50000}};
340 // Test successful fee transaction with new fields
341 auto feeTx = createFeeTx(ledger->rules(), ledger->seq(), fields);
342
343 OpenView accum(ledger.get());
344 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
345 accum.apply(*ledger);
346
347 // Verify fee object was created/updated correctly
348 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields));
349 }
350 }
351
352 void
354 {
355 testcase("Fee Transaction Validation");
356
357 {
358 jtx::Env env(*this, jtx::testable_amendments() - featureXRPFees);
359 auto ledger = std::make_shared<Ledger>(
361 env.app().config(),
363 env.app().getNodeFamily());
364
365 // Create the next ledger to apply transaction to
367 *ledger, env.app().timeKeeper().closeTime());
368
369 // Test transaction with missing required legacy fields
370 auto invalidTx = createInvalidFeeTx(
371 ledger->rules(), ledger->seq(), true, false, 1);
372 OpenView accum(ledger.get());
373 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
374
375 // Test transaction with new format fields when XRPFees is disabled
376 auto disallowedTx = createInvalidFeeTx(
377 ledger->rules(), ledger->seq(), false, true, 2);
378 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx));
379 }
380
381 {
382 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
383 auto ledger = std::make_shared<Ledger>(
385 env.app().config(),
387 env.app().getNodeFamily());
388
389 // Create the next ledger to apply transaction to
391 *ledger, env.app().timeKeeper().closeTime());
392
393 // Test transaction with missing required new fields
394 auto invalidTx = createInvalidFeeTx(
395 ledger->rules(), ledger->seq(), true, false, 3);
396 OpenView accum(ledger.get());
397 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
398
399 // Test transaction with legacy fields when XRPFees is enabled
400 auto disallowedTx = createInvalidFeeTx(
401 ledger->rules(), ledger->seq(), false, true, 4);
402 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, disallowedTx));
403 }
404 }
405
406 void
408 {
409 testcase("Pseudo Transaction Properties");
410
412 auto ledger = std::make_shared<Ledger>(
414 env.app().config(),
416 env.app().getNodeFamily());
417
418 // Create the next ledger to apply transaction to
420 *ledger, env.app().timeKeeper().closeTime());
421
422 auto feeTx = createFeeTx(
423 ledger->rules(),
424 ledger->seq(),
425 {.baseFeeDrops = XRPAmount{10},
426 .reserveBaseDrops = XRPAmount{200000},
427 .reserveIncrementDrops = XRPAmount{50000}});
428
429 // Verify pseudo-transaction properties
430 BEAST_EXPECT(feeTx.getAccountID(sfAccount) == AccountID());
431 BEAST_EXPECT(feeTx.getFieldAmount(sfFee) == XRPAmount{0});
432 BEAST_EXPECT(feeTx.getSigningPubKey().empty());
433 BEAST_EXPECT(feeTx.getSignature().empty());
434 BEAST_EXPECT(!feeTx.isFieldPresent(sfSigners));
435 BEAST_EXPECT(feeTx.getFieldU32(sfSequence) == 0);
436 BEAST_EXPECT(!feeTx.isFieldPresent(sfPreviousTxnID));
437
438 // But can be applied to a closed ledger
439 {
440 OpenView closedAccum(ledger.get());
441 BEAST_EXPECT(applyFeeAndTestResult(env, closedAccum, feeTx));
442 }
443 }
444
445 void
447 {
448 testcase("Multiple Fee Updates");
449
450 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
451 auto ledger = std::make_shared<Ledger>(
453 env.app().config(),
455 env.app().getNodeFamily());
456
458 *ledger, env.app().timeKeeper().closeTime());
459
460 FeeSettingsFields fields1{
461 .baseFeeDrops = XRPAmount{10},
462 .reserveBaseDrops = XRPAmount{200000},
463 .reserveIncrementDrops = XRPAmount{50000}};
464 auto feeTx1 = createFeeTx(ledger->rules(), ledger->seq(), fields1);
465
466 {
467 OpenView accum(ledger.get());
468 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx1));
469 accum.apply(*ledger);
470 }
471
472 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields1));
473
474 // Apply second fee transaction with different values
476 *ledger, env.app().timeKeeper().closeTime());
477
478 FeeSettingsFields fields2{
479 .baseFeeDrops = XRPAmount{20},
480 .reserveBaseDrops = XRPAmount{300000},
481 .reserveIncrementDrops = XRPAmount{75000}};
482 auto feeTx2 = createFeeTx(ledger->rules(), ledger->seq(), fields2);
483
484 {
485 OpenView accum(ledger.get());
486 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx2));
487 accum.apply(*ledger);
488 }
489
490 // Verify second update overwrote the first
491 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields2));
492 }
493
494 void
496 {
497 testcase("Wrong Ledger Sequence");
498
499 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
500 auto ledger = std::make_shared<Ledger>(
502 env.app().config(),
504 env.app().getNodeFamily());
505
507 *ledger, env.app().timeKeeper().closeTime());
508
509 // Test transaction with wrong ledger sequence
510 auto feeTx = createFeeTx(
511 ledger->rules(),
512 ledger->seq() + 5, // Wrong sequence (should be ledger->seq())
513 {.baseFeeDrops = XRPAmount{10},
514 .reserveBaseDrops = XRPAmount{200000},
515 .reserveIncrementDrops = XRPAmount{50000}});
516
517 OpenView accum(ledger.get());
518
519 // The transaction should still succeed as long as other fields are
520 // valid
521 // The ledger sequence field is only used for informational purposes
522 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx));
523 }
524
525 void
527 {
528 testcase("Partial Field Updates");
529
530 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
531 auto ledger = std::make_shared<Ledger>(
533 env.app().config(),
535 env.app().getNodeFamily());
536
538 *ledger, env.app().timeKeeper().closeTime());
539
540 FeeSettingsFields fields1{
541 .baseFeeDrops = XRPAmount{10},
542 .reserveBaseDrops = XRPAmount{200000},
543 .reserveIncrementDrops = XRPAmount{50000}};
544 auto feeTx1 = createFeeTx(ledger->rules(), ledger->seq(), fields1);
545
546 {
547 OpenView accum(ledger.get());
548 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx1));
549 accum.apply(*ledger);
550 }
551
552 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields1));
553
555 *ledger, env.app().timeKeeper().closeTime());
556
557 // Apply partial update (only some fields)
558 FeeSettingsFields fields2{
559 .baseFeeDrops = XRPAmount{20},
560 .reserveBaseDrops = XRPAmount{200000}};
561 auto feeTx2 = createFeeTx(ledger->rules(), ledger->seq(), fields2);
562
563 {
564 OpenView accum(ledger.get());
565 BEAST_EXPECT(applyFeeAndTestResult(env, accum, feeTx2));
566 accum.apply(*ledger);
567 }
568
569 // Verify the partial update worked
570 BEAST_EXPECT(verifyFeeObject(ledger, ledger->rules(), fields2));
571 }
572
573 void
575 {
576 testcase("Single Invalid Transaction");
577
578 jtx::Env env(*this, jtx::testable_amendments() | featureXRPFees);
579 auto ledger = std::make_shared<Ledger>(
581 env.app().config(),
583 env.app().getNodeFamily());
584
586 *ledger, env.app().timeKeeper().closeTime());
587
588 // Test invalid transaction with non-zero account - this should fail
589 // validation
590 auto invalidTx = STTx(ttFEE, [&](auto& obj) {
591 obj.setAccountID(
592 sfAccount,
593 AccountID(1)); // Should be zero (this makes it invalid)
594 obj.setFieldU32(sfLedgerSequence, ledger->seq());
595 obj.setFieldAmount(sfBaseFeeDrops, XRPAmount{10});
596 obj.setFieldAmount(sfReserveBaseDrops, XRPAmount{200000});
597 obj.setFieldAmount(sfReserveIncrementDrops, XRPAmount{50000});
598 });
599
600 OpenView accum(ledger.get());
601 BEAST_EXPECT(!applyFeeAndTestResult(env, accum, invalidTx));
602 }
603
604 void
606 {
607 testcase("doValidation");
608
609 using namespace jtx;
610
611 FeeSetup setup;
612 setup.reference_fee = 42;
613 setup.account_reserve = 1234567;
614 setup.owner_reserve = 7654321;
615
616 // Test with XRPFees enabled
617 {
618 Env env(*this, testable_amendments() | featureXRPFees);
619 auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote"));
620
621 auto ledger = std::make_shared<Ledger>(
623 env.app().config(),
625 env.app().getNodeFamily());
626
627 auto sec = randomSecretKey();
628 auto pub = derivePublicKey(KeyType::secp256k1, sec);
629
631 env.app().timeKeeper().now(),
632 pub,
633 sec,
634 calcNodeID(pub),
635 [](STValidation& v) {
636 v.setFieldU32(sfLedgerSequence, 12345);
637 });
638
639 // Use the current ledger's fees as the "current" fees for
640 // doValidation
641 auto const& currentFees = ledger->fees();
642
643 feeVote->doValidation(currentFees, ledger->rules(), *val);
644
645 BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops));
646 BEAST_EXPECT(
647 val->getFieldAmount(sfBaseFeeDrops) ==
648 XRPAmount(setup.reference_fee));
649 }
650
651 // Test with XRPFees disabled (legacy format)
652 {
653 Env env(*this, testable_amendments() - featureXRPFees);
654 auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote"));
655
656 auto ledger = std::make_shared<Ledger>(
658 env.app().config(),
660 env.app().getNodeFamily());
661
662 auto sec = randomSecretKey();
663 auto pub = derivePublicKey(KeyType::secp256k1, sec);
664
666 env.app().timeKeeper().now(),
667 pub,
668 sec,
669 calcNodeID(pub),
670 [](STValidation& v) {
671 v.setFieldU32(sfLedgerSequence, 12345);
672 });
673
674 auto const& currentFees = ledger->fees();
675
676 feeVote->doValidation(currentFees, ledger->rules(), *val);
677
678 // In legacy mode, should vote using legacy fields
679 BEAST_EXPECT(val->isFieldPresent(sfBaseFee));
680 BEAST_EXPECT(val->getFieldU64(sfBaseFee) == setup.reference_fee);
681 }
682 }
683
684 void
686 {
687 testcase("doVoting");
688
689 using namespace jtx;
690
691 FeeSetup setup;
692 setup.reference_fee = 42;
693 setup.account_reserve = 1234567;
694 setup.owner_reserve = 7654321;
695
696 Env env(*this, testable_amendments() | featureXRPFees);
697
698 // establish what the current fees are
699 BEAST_EXPECT(
700 env.current()->fees().base == XRPAmount{UNIT_TEST_REFERENCE_FEE});
701 BEAST_EXPECT(env.current()->fees().reserve == XRPAmount{200'000'000});
702 BEAST_EXPECT(env.current()->fees().increment == XRPAmount{50'000'000});
703
704 auto feeVote = make_FeeVote(setup, env.app().journal("FeeVote"));
705 auto ledger = std::make_shared<Ledger>(
707 env.app().config(),
709 env.app().getNodeFamily());
710
711 // doVoting requires a flag ledger (every 256th ledger)
712 // We need to create a ledger at sequence 256 to make it a flag ledger
713 for (int i = 0; i < 256 - 1; ++i)
714 {
716 *ledger, env.app().timeKeeper().closeTime());
717 }
718 BEAST_EXPECT(ledger->isFlagLedger());
719
720 // Create some mock validations with fee votes
722
723 for (int i = 0; i < 5; i++)
724 {
725 auto sec = randomSecretKey();
726 auto pub = derivePublicKey(KeyType::secp256k1, sec);
727
729 env.app().timeKeeper().now(),
730 pub,
731 sec,
732 calcNodeID(pub),
733 [&](STValidation& v) {
734 v.setFieldU32(sfLedgerSequence, ledger->seq());
735 // Vote for different fees than current
737 sfBaseFeeDrops, XRPAmount{setup.reference_fee});
739 sfReserveBaseDrops, XRPAmount{setup.account_reserve});
741 sfReserveIncrementDrops,
742 XRPAmount{setup.owner_reserve});
743 });
744 if (i % 2)
745 val->setTrusted();
746 validations.push_back(val);
747 }
748
749 auto txSet = std::make_shared<SHAMap>(
751
752 // This should not throw since we have a flag ledger
753 feeVote->doVoting(ledger, validations, txSet);
754
755 auto const txs = getTxs(txSet);
756 BEAST_EXPECT(txs.size() == 1);
757 auto const& feeTx = txs[0];
758
759 BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
760
761 BEAST_EXPECT(feeTx.getAccountID(sfAccount) == AccountID());
762 BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
763
764 BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
765 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
766 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
767
768 // The legacy fields should NOT be present
769 BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
770 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
771 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
772 BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
773
774 // Check the values
775 BEAST_EXPECT(
776 feeTx.getFieldAmount(sfBaseFeeDrops) ==
777 XRPAmount{setup.reference_fee});
778 BEAST_EXPECT(
779 feeTx.getFieldAmount(sfReserveBaseDrops) ==
780 XRPAmount{setup.account_reserve});
781 BEAST_EXPECT(
782 feeTx.getFieldAmount(sfReserveIncrementDrops) ==
783 XRPAmount{setup.owner_reserve});
784 }
785
786 void
787 run() override
788 {
789 testSetup();
790 testBasic();
791 testTransactionValidation();
792 testPseudoTransactionProperties();
793 testMultipleFeeUpdates();
794 testWrongLedgerSequence();
795 testPartialFieldUpdates();
796 testSingleInvalidTransaction();
797 testDoValidation();
798 testDoVoting();
799 }
800};
801
802BEAST_DEFINE_TESTSUITE(FeeVote, app, ripple);
803
804} // namespace test
805} // namespace ripple
A testsuite class.
Definition suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:155
virtual Config & config()=0
virtual beast::Journal journal(std::string const &name)=0
virtual TimeKeeper & timeKeeper()=0
virtual Family & getNodeFamily()=0
Manager to process fee votes.
Definition FeeVote.h:32
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:65
void apply(TxsRawView &to) const
Apply changes.
Definition OpenView.cpp:128
Rules controlling protocol behavior.
Definition Rules.h:38
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:130
void setFieldAmount(SField const &field, STAmount const &)
Definition STObject.cpp:801
void setFieldU32(SField const &field, std::uint32_t)
Definition STObject.cpp:747
Holds a collection of configuration values.
Definition BasicConfig.h:45
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
time_point now() const override
Returns the current time, using the server's clock.
Definition TimeKeeper.h:64
time_point closeTime() const
Returns the predicted close time, in network time.
Definition TimeKeeper.h:76
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:121
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:331
Application & app()
Definition Env.h:261
beast::Journal const journal
Definition Env.h:162
T is_same_v
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
Definition Indexes.cpp:222
auto const data
General field definitions, or fields used in multiple transaction namespaces.
FeatureBitset testable_amendments()
Definition Env.h:74
bool applyFeeAndTestResult(jtx::Env &env, OpenView &view, STTx const &tx)
STTx createFeeTx(Rules const &rules, std::uint32_t seq, FeeSettingsFields const &fields)
std::vector< STTx > getTxs(std::shared_ptr< SHAMap > const &txSet)
STTx createInvalidFeeTx(Rules const &rules, std::uint32_t seq, bool missingRequiredFields=true, bool wrongFeatureFields=false, std::uint32_t uniqueValue=42)
bool verifyFeeObject(std::shared_ptr< Ledger const > const &ledger, Rules const &rules, FeeSettingsFields const &expected)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:48
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.
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
@ tesSUCCESS
Definition TER.h:244
ApplyResult apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition apply.cpp:148
FeeSetup setup_FeeVote(Section const &section)
Definition Config.cpp:1129
create_genesis_t const create_genesis
Definition Ledger.cpp:51
@ tapNONE
Definition ApplyView.h:31
T push_back(T... args)
Fee schedule for startup / standalone, and to vote for.
Definition Config.h:66
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition Config.h:68
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
Definition Config.h:74
XRPAmount account_reserve
The account reserve requirement in drops.
Definition Config.h:71
std::optional< XRPAmount > reserveBaseDrops
std::optional< std::uint32_t > reserveBase
std::optional< std::uint32_t > reserveIncrement
std::optional< XRPAmount > reserveIncrementDrops
std::optional< std::uint32_t > referenceFeeUnits
std::optional< std::uint64_t > baseFee
std::optional< XRPAmount > baseFeeDrops
Set the sequence number on a JTx.
Definition seq.h:34
T to_string(T... args)