22#include <xrpld/app/ledger/Ledger.h>
23#include <xrpld/app/misc/FeeVote.h>
24#include <xrpld/app/tx/apply.h>
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>
54 auto fill = [&](
auto& obj) {
56 obj.setFieldU32(sfLedgerSequence,
seq);
58 if (rules.
enabled(featureXRPFees))
69 sfReserveIncrementDrops,
87 return STTx(ttFEE, fill);
94 bool missingRequiredFields =
true,
95 bool wrongFeatureFields =
false,
98 auto fill = [&](
auto& obj) {
100 obj.setFieldU32(sfLedgerSequence,
seq);
102 if (wrongFeatureFields)
104 if (rules.
enabled(featureXRPFees))
106 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
107 obj.setFieldU32(sfReserveBase, 200000);
108 obj.setFieldU32(sfReserveIncrement, 50000);
109 obj.setFieldU32(sfReferenceFeeUnits, 10);
113 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
114 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
115 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
118 else if (!missingRequiredFields)
121 if (rules.
enabled(featureXRPFees))
123 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
124 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
125 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
129 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
130 obj.setFieldU32(sfReserveBase, 200000);
131 obj.setFieldU32(sfReserveIncrement, 50000);
132 obj.setFieldU32(sfReferenceFeeUnits, 10);
138 return STTx(ttFEE, fill);
159 auto checkEquality = [&](
auto const& field,
auto const& expected) {
160 if (!feeObject->isFieldPresent(field))
162 return feeObject->at(field) == expected;
165 if (rules.
enabled(featureXRPFees))
167 if (feeObject->isFieldPresent(sfBaseFee) ||
168 feeObject->isFieldPresent(sfReserveBase) ||
169 feeObject->isFieldPresent(sfReserveIncrement) ||
170 feeObject->isFieldPresent(sfReferenceFeeUnits))
181 sfReserveIncrementDrops,
187 if (feeObject->isFieldPresent(sfBaseFeeDrops) ||
188 feeObject->isFieldPresent(sfReserveBaseDrops) ||
189 feeObject->isFieldPresent(sfReserveIncrementDrops))
193 if (!checkEquality(sfBaseFee, expected.
baseFee))
195 if (!checkEquality(sfReserveBase, expected.
reserveBase))
210 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
212 auto const data = i->slice();
229 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
231 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
236 {
"reference_fee = 50",
237 "account_reserve = 1234567",
238 "owner_reserve = 1234"});
240 BEAST_EXPECT(setup.reference_fee == 50);
241 BEAST_EXPECT(setup.account_reserve == 1234567);
242 BEAST_EXPECT(setup.owner_reserve == 1234);
247 {
"reference_fee = blah",
248 "account_reserve = yada",
249 "owner_reserve = foo"});
252 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
254 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
259 {
"reference_fee = -50",
260 "account_reserve = -1234567",
261 "owner_reserve = -1234"});
264 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
266 setup.account_reserve ==
static_cast<std::uint32_t>(-1234567));
277 {
"reference_fee = " + big64,
278 "account_reserve = " + big64,
279 "owner_reserve = " + big64});
282 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
284 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
291 testcase(
"Basic SetFee transaction");
310 .reserveBase = 200000,
311 .reserveIncrement = 50000,
312 .referenceFeeUnits = 10};
313 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
317 accum.
apply(*ledger);
339 .reserveIncrementDrops =
XRPAmount{50000}};
341 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
345 accum.
apply(*ledger);
355 testcase(
"Fee Transaction Validation");
371 ledger->rules(), ledger->seq(),
true,
false, 1);
377 ledger->rules(), ledger->seq(),
false,
true, 2);
395 ledger->rules(), ledger->seq(),
true,
false, 3);
401 ledger->rules(), ledger->seq(),
false,
true, 4);
409 testcase(
"Pseudo Transaction Properties");
425 {.baseFeeDrops = XRPAmount{10},
427 .reserveIncrementDrops =
XRPAmount{50000}});
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));
448 testcase(
"Multiple Fee Updates");
463 .reserveIncrementDrops =
XRPAmount{50000}};
464 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
469 accum.
apply(*ledger);
481 .reserveIncrementDrops =
XRPAmount{75000}};
482 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
487 accum.
apply(*ledger);
497 testcase(
"Wrong Ledger Sequence");
513 {.baseFeeDrops = XRPAmount{10},
515 .reserveIncrementDrops =
XRPAmount{50000}});
528 testcase(
"Partial Field Updates");
530 jtx::Env env(*
this, jtx::testable_amendments() | featureXRPFees);
543 .reserveIncrementDrops =
XRPAmount{50000}};
544 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
549 accum.
apply(*ledger);
561 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
566 accum.
apply(*ledger);
576 testcase(
"Single Invalid Transaction");
578 jtx::Env env(*
this, jtx::testable_amendments() | featureXRPFees);
590 auto invalidTx =
STTx(ttFEE, [&](
auto& obj) {
594 obj.setFieldU32(sfLedgerSequence, ledger->seq());
595 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10});
596 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
597 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
607 testcase(
"doValidation");
641 auto const& currentFees = ledger->fees();
643 feeVote->doValidation(currentFees, ledger->rules(), *val);
645 BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops));
647 val->getFieldAmount(sfBaseFeeDrops) ==
674 auto const& currentFees = ledger->fees();
676 feeVote->doValidation(currentFees, ledger->rules(), *val);
679 BEAST_EXPECT(val->isFieldPresent(sfBaseFee));
680 BEAST_EXPECT(val->getFieldU64(sfBaseFee) == setup.
reference_fee);
687 testcase(
"doVoting");
713 for (
int i = 0; i < 256 - 1; ++i)
718 BEAST_EXPECT(ledger->isFlagLedger());
723 for (
int i = 0; i < 5; i++)
741 sfReserveIncrementDrops,
753 feeVote->doVoting(ledger, validations, txSet);
755 auto const txs =
getTxs(txSet);
756 BEAST_EXPECT(txs.size() == 1);
757 auto const& feeTx = txs[0];
759 BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
761 BEAST_EXPECT(feeTx.getAccountID(sfAccount) ==
AccountID());
762 BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
764 BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
765 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
766 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
769 BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
770 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
771 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
772 BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
776 feeTx.getFieldAmount(sfBaseFeeDrops) ==
779 feeTx.getFieldAmount(sfReserveBaseDrops) ==
782 feeTx.getFieldAmount(sfReserveIncrementDrops) ==
791 testTransactionValidation();
792 testPseudoTransactionProperties();
793 testMultipleFeeUpdates();
794 testWrongLedgerSequence();
795 testPartialFieldUpdates();
796 testSingleInvalidTransaction();
testcase_t testcase
Memberspace for declaring test cases.
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.
Writable ledger view that accumulates state and tx changes.
void apply(TxsRawView &to) const
Apply changes.
Rules controlling protocol behavior.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
void setFieldAmount(SField const &field, STAmount const &)
void setFieldU32(SField const &field, std::uint32_t)
Holds a collection of configuration values.
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.
time_point closeTime() const
Returns the predicted close time, in network time.
void testPartialFieldUpdates()
void testSingleInvalidTransaction()
void testMultipleFeeUpdates()
void testPseudoTransactionProperties()
void testWrongLedgerSequence()
void run() override
Runs the suite.
void testTransactionValidation()
A transaction testing environment.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
beast::Journal const journal
Keylet const & fees() noexcept
The (fixed) index of the object containing the ledger fees.
auto const data
General field definitions, or fields used in multiple transaction namespaces.
FeatureBitset testable_amendments()
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.
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
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.
ApplyResult apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
FeeSetup setup_FeeVote(Section const §ion)
create_genesis_t const create_genesis
Fee schedule for startup / standalone, and to vote for.
XRPAmount reference_fee
The cost of a reference transaction in drops.
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
XRPAmount account_reserve
The account reserve requirement in drops.
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.