3#include <xrpld/app/ledger/Ledger.h>
4#include <xrpld/app/misc/FeeVote.h>
5#include <xrpld/app/tx/apply.h>
7#include <xrpl/basics/BasicConfig.h>
8#include <xrpl/ledger/View.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/PublicKey.h>
12#include <xrpl/protocol/STTx.h>
13#include <xrpl/protocol/SecretKey.h>
32 auto fill = [&](
auto& obj) {
34 obj.setFieldU32(sfLedgerSequence,
seq);
36 if (rules.
enabled(featureXRPFees))
53 return STTx(ttFEE, fill);
60 bool missingRequiredFields =
true,
61 bool wrongFeatureFields =
false,
64 auto fill = [&](
auto& obj) {
66 obj.setFieldU32(sfLedgerSequence,
seq);
68 if (wrongFeatureFields)
70 if (rules.
enabled(featureXRPFees))
72 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
73 obj.setFieldU32(sfReserveBase, 200000);
74 obj.setFieldU32(sfReserveIncrement, 50000);
75 obj.setFieldU32(sfReferenceFeeUnits, 10);
79 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
80 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
81 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
84 else if (!missingRequiredFields)
87 if (rules.
enabled(featureXRPFees))
89 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
90 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
91 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
95 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
96 obj.setFieldU32(sfReserveBase, 200000);
97 obj.setFieldU32(sfReserveIncrement, 50000);
98 obj.setFieldU32(sfReferenceFeeUnits, 10);
104 return STTx(ttFEE, fill);
121 auto checkEquality = [&](
auto const& field,
auto const& expected) {
122 if (!feeObject->isFieldPresent(field))
124 return feeObject->at(field) == expected;
127 if (rules.
enabled(featureXRPFees))
129 if (feeObject->isFieldPresent(sfBaseFee) || feeObject->isFieldPresent(sfReserveBase) ||
130 feeObject->isFieldPresent(sfReserveIncrement) || feeObject->isFieldPresent(sfReferenceFeeUnits))
142 if (feeObject->isFieldPresent(sfBaseFeeDrops) || feeObject->isFieldPresent(sfReserveBaseDrops) ||
143 feeObject->isFieldPresent(sfReserveIncrementDrops))
147 if (!checkEquality(sfBaseFee, expected.
baseFee))
149 if (!checkEquality(sfReserveBase, expected.
reserveBase))
164 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
166 auto const data = i->slice();
183 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
185 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
189 config.
append({
"reference_fee = 50",
"account_reserve = 1234567",
"owner_reserve = 1234"});
191 BEAST_EXPECT(setup.reference_fee == 50);
192 BEAST_EXPECT(setup.account_reserve == 1234567);
193 BEAST_EXPECT(setup.owner_reserve == 1234);
197 config.
append({
"reference_fee = blah",
"account_reserve = yada",
"owner_reserve = foo"});
200 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
202 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
206 config.
append({
"reference_fee = -50",
"account_reserve = -1234567",
"owner_reserve = -1234"});
209 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
210 BEAST_EXPECT(setup.account_reserve ==
static_cast<std::uint32_t>(-1234567));
211 BEAST_EXPECT(setup.owner_reserve ==
static_cast<std::uint32_t>(-1234));
217 config.
append({
"reference_fee = " + big64,
"account_reserve = " + big64,
"owner_reserve = " + big64});
220 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
222 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
229 testcase(
"Basic SetFee transaction");
243 .
baseFee = 10, .reserveBase = 200000, .reserveIncrement = 50000, .referenceFeeUnits = 10};
244 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
248 accum.
apply(*ledger);
266 .reserveIncrementDrops =
XRPAmount{50000}};
268 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
272 accum.
apply(*ledger);
282 testcase(
"Fee Transaction Validation");
298 auto disallowedTx =
createInvalidFeeTx(ledger->rules(), ledger->seq(),
false,
true, 2);
316 auto disallowedTx =
createInvalidFeeTx(ledger->rules(), ledger->seq(),
false,
true, 4);
324 testcase(
"Pseudo Transaction Properties");
336 {.baseFeeDrops = XRPAmount{10},
338 .reserveIncrementDrops =
XRPAmount{50000}});
341 BEAST_EXPECT(feeTx.getAccountID(sfAccount) ==
AccountID());
342 BEAST_EXPECT(feeTx.getFieldAmount(sfFee) ==
XRPAmount{0});
343 BEAST_EXPECT(feeTx.getSigningPubKey().empty());
344 BEAST_EXPECT(feeTx.getSignature().empty());
345 BEAST_EXPECT(!feeTx.isFieldPresent(sfSigners));
346 BEAST_EXPECT(feeTx.getFieldU32(sfSequence) == 0);
347 BEAST_EXPECT(!feeTx.isFieldPresent(sfPreviousTxnID));
359 testcase(
"Multiple Fee Updates");
370 .reserveIncrementDrops =
XRPAmount{50000}};
371 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
376 accum.
apply(*ledger);
387 .reserveIncrementDrops =
XRPAmount{75000}};
388 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
393 accum.
apply(*ledger);
403 testcase(
"Wrong Ledger Sequence");
415 {.baseFeeDrops = XRPAmount{10},
417 .reserveIncrementDrops =
XRPAmount{50000}});
430 testcase(
"Partial Field Updates");
432 jtx::Env env(*
this, jtx::testable_amendments() | featureXRPFees);
441 .reserveIncrementDrops =
XRPAmount{50000}};
442 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
447 accum.
apply(*ledger);
456 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
461 accum.
apply(*ledger);
471 testcase(
"Single Invalid Transaction");
473 jtx::Env env(*
this, jtx::testable_amendments() | featureXRPFees);
481 auto invalidTx =
STTx(ttFEE, [&](
auto& obj) {
482 obj.setAccountID(sfAccount,
484 obj.setFieldU32(sfLedgerSequence, ledger->seq());
485 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10});
486 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
487 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
497 testcase(
"doValidation");
524 auto const& currentFees = ledger->fees();
526 feeVote->doValidation(currentFees, ledger->rules(), *val);
528 BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops));
548 auto const& currentFees = ledger->fees();
550 feeVote->doValidation(currentFees, ledger->rules(), *val);
553 BEAST_EXPECT(val->isFieldPresent(sfBaseFee));
554 BEAST_EXPECT(val->getFieldU64(sfBaseFee) == setup.
reference_fee);
561 testcase(
"doVoting");
573 BEAST_EXPECT(env.
current()->fees().base ==
XRPAmount{UNIT_TEST_REFERENCE_FEE});
583 for (
int i = 0; i < 256 - 1; ++i)
587 BEAST_EXPECT(ledger->isFlagLedger());
592 for (
int i = 0; i < 5; i++)
613 feeVote->doVoting(ledger, validations, txSet);
615 auto const txs =
getTxs(txSet);
616 BEAST_EXPECT(txs.size() == 1);
617 auto const& feeTx = txs[0];
619 BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
621 BEAST_EXPECT(feeTx.getAccountID(sfAccount) ==
AccountID());
622 BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
624 BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
625 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
626 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
629 BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
630 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
631 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
632 BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
635 BEAST_EXPECT(feeTx.getFieldAmount(sfBaseFeeDrops) ==
XRPAmount{setup.reference_fee});
636 BEAST_EXPECT(feeTx.getFieldAmount(sfReserveBaseDrops) ==
XRPAmount{setup.account_reserve});
637 BEAST_EXPECT(feeTx.getFieldAmount(sfReserveIncrementDrops) ==
XRPAmount{setup.owner_reserve});
645 testTransactionValidation();
646 testPseudoTransactionProperties();
647 testMultipleFeeUpdates();
648 testWrongLedgerSequence();
649 testPartialFieldUpdates();
650 testSingleInvalidTransaction();
testcase_t testcase
Memberspace for declaring test cases.
virtual Config & config()=0
virtual beast::Journal journal(std::string const &name)=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 setFieldU32(SField const &field, std::uint32_t)
void setFieldAmount(SField const &field, STAmount const &)
Holds a collection of configuration values.
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
virtual Family & getNodeFamily()=0
virtual TimeKeeper & timeKeeper()=0
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 testTransactionValidation()
void testPartialFieldUpdates()
void testPseudoTransactionProperties()
void testMultipleFeeUpdates()
void run() override
Runs the suite.
void testWrongLedgerSequence()
void testSingleInvalidTransaction()
A transaction testing environment.
beast::Journal const journal
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
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 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.
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(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
create_genesis_t const create_genesis
FeeSetup setup_FeeVote(Section const §ion)
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
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.
Fee schedule for startup / standalone, and to vote for.
XRPAmount reference_fee
The cost of a reference transaction in drops.
XRPAmount account_reserve
The account reserve requirement in drops.
XRPAmount owner_reserve
The per-owned item reserve requirement in drops.
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.