3#include <xrpld/app/misc/FeeVote.h>
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>
31 auto fill = [&](
auto& obj) {
33 obj.setFieldU32(sfLedgerSequence,
seq);
35 if (rules.
enabled(featureXRPFees))
44 sfReserveIncrementDrops,
58 return STTx(ttFEE, fill);
65 bool missingRequiredFields =
true,
66 bool wrongFeatureFields =
false,
69 auto fill = [&](
auto& obj) {
71 obj.setFieldU32(sfLedgerSequence,
seq);
73 if (wrongFeatureFields)
75 if (rules.
enabled(featureXRPFees))
77 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
78 obj.setFieldU32(sfReserveBase, 200000);
79 obj.setFieldU32(sfReserveIncrement, 50000);
80 obj.setFieldU32(sfReferenceFeeUnits, 10);
84 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
85 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
86 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
89 else if (!missingRequiredFields)
92 if (rules.
enabled(featureXRPFees))
94 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
95 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
96 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
100 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
101 obj.setFieldU32(sfReserveBase, 200000);
102 obj.setFieldU32(sfReserveIncrement, 50000);
103 obj.setFieldU32(sfReferenceFeeUnits, 10);
109 return STTx(ttFEE, fill);
129 auto checkEquality = [&](
auto const& field,
auto const& expected) {
130 if (!feeObject->isFieldPresent(field))
132 return feeObject->at(field) == expected;
135 if (rules.
enabled(featureXRPFees))
137 if (feeObject->isFieldPresent(sfBaseFee) || feeObject->isFieldPresent(sfReserveBase) ||
138 feeObject->isFieldPresent(sfReserveIncrement) ||
139 feeObject->isFieldPresent(sfReferenceFeeUnits))
152 if (feeObject->isFieldPresent(sfBaseFeeDrops) ||
153 feeObject->isFieldPresent(sfReserveBaseDrops) ||
154 feeObject->isFieldPresent(sfReserveIncrementDrops))
158 if (!checkEquality(sfBaseFee, expected.
baseFee))
160 if (!checkEquality(sfReserveBase, expected.
reserveBase))
175 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
177 auto const data = i->slice();
194 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
196 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
201 {
"reference_fee = 50",
"account_reserve = 1234567",
"owner_reserve = 1234"});
203 BEAST_EXPECT(setup.reference_fee == 50);
204 BEAST_EXPECT(setup.account_reserve == 1234567);
205 BEAST_EXPECT(setup.owner_reserve == 1234);
210 {
"reference_fee = blah",
"account_reserve = yada",
"owner_reserve = foo"});
213 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
215 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
220 {
"reference_fee = -50",
"account_reserve = -1234567",
"owner_reserve = -1234"});
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));
232 {
"reference_fee = " + big64,
233 "account_reserve = " + big64,
234 "owner_reserve = " + big64});
237 BEAST_EXPECT(setup.reference_fee == defaultSetup.
reference_fee);
239 BEAST_EXPECT(setup.owner_reserve == defaultSetup.
owner_reserve);
246 testcase(
"Basic SetFee transaction");
254 env.
app().config().FEES.toFees(),
265 .reserveBase = 200000,
266 .reserveIncrement = 50000,
267 .referenceFeeUnits = 10};
268 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
272 accum.
apply(*ledger);
284 env.
app().config().FEES.toFees(),
294 .reserveIncrementDrops =
XRPAmount{50000}};
296 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
300 accum.
apply(*ledger);
310 testcase(
"Fee Transaction Validation");
317 env.
app().config().FEES.toFees(),
330 auto disallowedTx =
createInvalidFeeTx(ledger->rules(), ledger->seq(),
false,
true, 2);
339 env.
app().config().FEES.toFees(),
352 auto disallowedTx =
createInvalidFeeTx(ledger->rules(), ledger->seq(),
false,
true, 4);
360 testcase(
"Pseudo Transaction Properties");
366 env.
app().config().FEES.toFees(),
376 {.baseFeeDrops = XRPAmount{10},
378 .reserveIncrementDrops =
XRPAmount{50000}});
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));
399 testcase(
"Multiple Fee Updates");
405 env.
app().config().FEES.toFees(),
414 .reserveIncrementDrops =
XRPAmount{50000}};
415 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
420 accum.
apply(*ledger);
431 .reserveIncrementDrops =
XRPAmount{75000}};
432 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
437 accum.
apply(*ledger);
447 testcase(
"Wrong Ledger Sequence");
453 env.
app().config().FEES.toFees(),
463 {.baseFeeDrops = XRPAmount{10},
465 .reserveIncrementDrops =
XRPAmount{50000}});
478 testcase(
"Partial Field Updates");
480 jtx::Env env(*
this, jtx::testable_amendments() | featureXRPFees);
484 env.
app().config().FEES.toFees(),
493 .reserveIncrementDrops =
XRPAmount{50000}};
494 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
499 accum.
apply(*ledger);
509 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
514 accum.
apply(*ledger);
524 testcase(
"Single Invalid Transaction");
526 jtx::Env env(*
this, jtx::testable_amendments() | featureXRPFees);
530 env.
app().config().FEES.toFees(),
538 auto invalidTx =
STTx(ttFEE, [&](
auto& obj) {
539 obj.setAccountID(sfAccount,
541 obj.setFieldU32(sfLedgerSequence, ledger->seq());
542 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10});
543 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
544 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
554 testcase(
"doValidation");
571 env.
app().config().FEES.toFees(),
585 auto const& currentFees = ledger->fees();
587 feeVote->doValidation(currentFees, ledger->rules(), *val);
589 BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops));
601 env.
app().config().FEES.toFees(),
613 auto const& currentFees = ledger->fees();
615 feeVote->doValidation(currentFees, ledger->rules(), *val);
618 BEAST_EXPECT(val->isFieldPresent(sfBaseFee));
619 BEAST_EXPECT(val->getFieldU64(sfBaseFee) == setup.
reference_fee);
626 testcase(
"doVoting");
638 BEAST_EXPECT(env.
current()->fees().base ==
XRPAmount{UNIT_TEST_REFERENCE_FEE});
646 env.
app().config().FEES.toFees(),
652 for (
int i = 0; i < 256 - 1; ++i)
656 BEAST_EXPECT(ledger->isFlagLedger());
661 for (
int i = 0; i < 5; i++)
682 feeVote->doVoting(ledger, validations, txSet);
684 auto const txs =
getTxs(txSet);
685 BEAST_EXPECT(txs.size() == 1);
686 auto const& feeTx = txs[0];
688 BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
690 BEAST_EXPECT(feeTx.getAccountID(sfAccount) ==
AccountID());
691 BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
693 BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
694 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
695 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
698 BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
699 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
700 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
701 BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
704 BEAST_EXPECT(feeTx.getFieldAmount(sfBaseFeeDrops) ==
XRPAmount{setup.reference_fee});
705 BEAST_EXPECT(feeTx.getFieldAmount(sfReserveBaseDrops) ==
XRPAmount{setup.account_reserve});
707 feeTx.getFieldAmount(sfReserveIncrementDrops) ==
XRPAmount{setup.owner_reserve});
715 testTransactionValidation();
716 testPseudoTransactionProperties();
717 testMultipleFeeUpdates();
718 testWrongLedgerSequence();
719 testPartialFieldUpdates();
720 testSingleInvalidTransaction();
testcase_t testcase
Memberspace for declaring test cases.
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 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.
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(ServiceRegistry ®istry, 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.
bool isTesSuccess(TER x) noexcept
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.