2#include <test/jtx/Env.h>
4#include <xrpld/app/misc/FeeVote.h>
5#include <xrpld/core/Config.h>
7#include <xrpl/basics/base_uint.h>
8#include <xrpl/beast/unit_test/suite.h>
9#include <xrpl/config/BasicConfig.h>
10#include <xrpl/ledger/ApplyView.h>
11#include <xrpl/ledger/Ledger.h>
12#include <xrpl/ledger/OpenView.h>
13#include <xrpl/protocol/Feature.h>
14#include <xrpl/protocol/Indexes.h>
15#include <xrpl/protocol/KeyType.h>
16#include <xrpl/protocol/PublicKey.h>
17#include <xrpl/protocol/Rules.h>
18#include <xrpl/protocol/SField.h>
19#include <xrpl/protocol/STTx.h>
20#include <xrpl/protocol/STValidation.h>
21#include <xrpl/protocol/SecretKey.h>
22#include <xrpl/protocol/Serializer.h>
23#include <xrpl/protocol/TER.h>
24#include <xrpl/protocol/TxFormats.h>
25#include <xrpl/protocol/XRPAmount.h>
26#include <xrpl/shamap/SHAMap.h>
27#include <xrpl/shamap/SHAMapMissingNode.h>
28#include <xrpl/tx/apply.h>
53 auto fill = [&](
auto& obj) {
55 obj.setFieldU32(sfLedgerSequence, seq);
57 if (rules.
enabled(featureXRPFees))
66 sfReserveIncrementDrops,
80 return STTx(ttFEE, fill);
87 bool missingRequiredFields =
true,
88 bool wrongFeatureFields =
false,
91 auto fill = [&](
auto& obj) {
93 obj.setFieldU32(sfLedgerSequence, seq);
95 if (wrongFeatureFields)
97 if (rules.
enabled(featureXRPFees))
99 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
100 obj.setFieldU32(sfReserveBase, 200000);
101 obj.setFieldU32(sfReserveIncrement, 50000);
102 obj.setFieldU32(sfReferenceFeeUnits, 10);
106 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
107 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
108 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
111 else if (!missingRequiredFields)
114 if (rules.
enabled(featureXRPFees))
116 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10 + uniqueValue});
117 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
118 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
122 obj.setFieldU64(sfBaseFee, 10 + uniqueValue);
123 obj.setFieldU32(sfReserveBase, 200000);
124 obj.setFieldU32(sfReserveIncrement, 50000);
125 obj.setFieldU32(sfReferenceFeeUnits, 10);
131 return STTx(ttFEE, fill);
151 auto checkEquality = [&](
auto const& field,
auto const& expected) {
152 if (!feeObject->isFieldPresent(field))
154 return feeObject->at(field) == expected;
157 if (rules.
enabled(featureXRPFees))
159 if (feeObject->isFieldPresent(sfBaseFee) || feeObject->isFieldPresent(sfReserveBase) ||
160 feeObject->isFieldPresent(sfReserveIncrement) ||
161 feeObject->isFieldPresent(sfReferenceFeeUnits))
174 if (feeObject->isFieldPresent(sfBaseFeeDrops) ||
175 feeObject->isFieldPresent(sfReserveBaseDrops) ||
176 feeObject->isFieldPresent(sfReserveIncrementDrops))
180 if (!checkEquality(sfBaseFee, expected.
baseFee))
182 if (!checkEquality(sfReserveBase, expected.
reserveBase))
197 for (
auto i = txSet->begin(); i != txSet->end(); ++i)
199 auto const data = i->slice();
216 BEAST_EXPECT(setup.referenceFee == defaultSetup.
referenceFee);
217 BEAST_EXPECT(setup.accountReserve == defaultSetup.
accountReserve);
218 BEAST_EXPECT(setup.ownerReserve == defaultSetup.
ownerReserve);
223 {
"reference_fee = 50",
"account_reserve = 1234567",
"owner_reserve = 1234"});
225 BEAST_EXPECT(setup.referenceFee == 50);
226 BEAST_EXPECT(setup.accountReserve == 1234567);
227 BEAST_EXPECT(setup.ownerReserve == 1234);
232 {
"reference_fee = blah",
"account_reserve = yada",
"owner_reserve = foo"});
235 BEAST_EXPECT(setup.referenceFee == defaultSetup.
referenceFee);
236 BEAST_EXPECT(setup.accountReserve == defaultSetup.
accountReserve);
237 BEAST_EXPECT(setup.ownerReserve == defaultSetup.
ownerReserve);
242 {
"reference_fee = -50",
"account_reserve = -1234567",
"owner_reserve = -1234"});
245 BEAST_EXPECT(setup.referenceFee == defaultSetup.
referenceFee);
246 BEAST_EXPECT(setup.accountReserve ==
static_cast<std::uint32_t>(-1234567));
247 BEAST_EXPECT(setup.ownerReserve ==
static_cast<std::uint32_t>(-1234));
254 {
"reference_fee = " + big64,
255 "account_reserve = " + big64,
256 "owner_reserve = " + big64});
259 BEAST_EXPECT(setup.referenceFee == defaultSetup.
referenceFee);
260 BEAST_EXPECT(setup.accountReserve == defaultSetup.
accountReserve);
261 BEAST_EXPECT(setup.ownerReserve == defaultSetup.
ownerReserve);
268 testcase(
"Basic SetFee transaction");
276 env.
app().config().fees.toFees(),
287 .reserveBase = 200000,
288 .reserveIncrement = 50000,
289 .referenceFeeUnits = 10};
290 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
294 accum.
apply(*ledger);
306 env.
app().config().fees.toFees(),
316 .reserveIncrementDrops =
XRPAmount{50000}};
318 auto feeTx =
createFeeTx(ledger->rules(), ledger->seq(), fields);
322 accum.
apply(*ledger);
332 testcase(
"Fee Transaction Validation");
339 env.
app().config().fees.toFees(),
352 auto disallowedTx =
createInvalidFeeTx(ledger->rules(), ledger->seq(),
false,
true, 2);
361 env.
app().config().fees.toFees(),
374 auto disallowedTx =
createInvalidFeeTx(ledger->rules(), ledger->seq(),
false,
true, 4);
382 testcase(
"Pseudo Transaction Properties");
388 env.
app().config().fees.toFees(),
398 {.baseFeeDrops = XRPAmount{10},
400 .reserveIncrementDrops =
XRPAmount{50000}});
403 BEAST_EXPECT(feeTx.getAccountID(sfAccount) ==
AccountID());
404 BEAST_EXPECT(feeTx.getFieldAmount(sfFee) ==
XRPAmount{0});
405 BEAST_EXPECT(feeTx.getSigningPubKey().empty());
406 BEAST_EXPECT(feeTx.getSignature().empty());
407 BEAST_EXPECT(!feeTx.isFieldPresent(sfSigners));
408 BEAST_EXPECT(feeTx.getFieldU32(sfSequence) == 0);
409 BEAST_EXPECT(!feeTx.isFieldPresent(sfPreviousTxnID));
427 env.
app().config().fees.toFees(),
436 .reserveIncrementDrops =
XRPAmount{50000}};
437 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
442 accum.
apply(*ledger);
453 .reserveIncrementDrops =
XRPAmount{75000}};
454 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
459 accum.
apply(*ledger);
475 env.
app().config().fees.toFees(),
485 {.baseFeeDrops = XRPAmount{10},
487 .reserveIncrementDrops =
XRPAmount{50000}});
506 env.
app().config().fees.toFees(),
515 .reserveIncrementDrops =
XRPAmount{50000}};
516 auto feeTx1 =
createFeeTx(ledger->rules(), ledger->seq(), fields1);
521 accum.
apply(*ledger);
531 auto feeTx2 =
createFeeTx(ledger->rules(), ledger->seq(), fields2);
536 accum.
apply(*ledger);
546 testcase(
"Single Invalid Transaction");
552 env.
app().config().fees.toFees(),
560 auto invalidTx =
STTx(ttFEE, [&](
auto& obj) {
561 obj.setAccountID(sfAccount,
563 obj.setFieldU32(sfLedgerSequence, ledger->seq());
564 obj.setFieldAmount(sfBaseFeeDrops,
XRPAmount{10});
565 obj.setFieldAmount(sfReserveBaseDrops,
XRPAmount{200000});
566 obj.setFieldAmount(sfReserveIncrementDrops,
XRPAmount{50000});
593 env.
app().config().fees.toFees(),
607 auto const& currentFees = ledger->fees();
609 feeVote->doValidation(currentFees, ledger->rules(), *val);
611 BEAST_EXPECT(val->isFieldPresent(sfBaseFeeDrops));
623 env.
app().config().fees.toFees(),
635 auto const& currentFees = ledger->fees();
637 feeVote->doValidation(currentFees, ledger->rules(), *val);
640 BEAST_EXPECT(val->isFieldPresent(sfBaseFee));
641 BEAST_EXPECT(val->getFieldU64(sfBaseFee) == setup.
referenceFee);
660 BEAST_EXPECT(env.
current()->fees().base ==
XRPAmount{UNIT_TEST_REFERENCE_FEE});
668 env.
app().config().fees.toFees(),
674 for (
int i = 0; i < 256 - 1; ++i)
678 BEAST_EXPECT(ledger->isFlagLedger());
683 for (
int i = 0; i < 5; i++)
704 feeVote->doVoting(ledger, validations, txSet);
706 auto const txs =
getTxs(txSet);
707 BEAST_EXPECT(txs.size() == 1);
708 auto const& feeTx = txs[0];
710 BEAST_EXPECT(feeTx.getTxnType() == ttFEE);
712 BEAST_EXPECT(feeTx.getAccountID(sfAccount) ==
AccountID());
713 BEAST_EXPECT(feeTx.getFieldU32(sfLedgerSequence) == ledger->seq() + 1);
715 BEAST_EXPECT(feeTx.isFieldPresent(sfBaseFeeDrops));
716 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveBaseDrops));
717 BEAST_EXPECT(feeTx.isFieldPresent(sfReserveIncrementDrops));
720 BEAST_EXPECT(!feeTx.isFieldPresent(sfBaseFee));
721 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveBase));
722 BEAST_EXPECT(!feeTx.isFieldPresent(sfReserveIncrement));
723 BEAST_EXPECT(!feeTx.isFieldPresent(sfReferenceFeeUnits));
726 BEAST_EXPECT(feeTx.getFieldAmount(sfBaseFeeDrops) ==
XRPAmount{setup.referenceFee});
727 BEAST_EXPECT(feeTx.getFieldAmount(sfReserveBaseDrops) ==
XRPAmount{setup.accountReserve});
729 feeTx.getFieldAmount(sfReserveIncrementDrops) ==
XRPAmount{setup.ownerReserve});
TestcaseT testcase
Memberspace for declaring test cases.
virtual Config & config()=0
std::unordered_set< uint256, beast::Uhash<> > features
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.
T emplace_back(T... args)
Keylet const & feeSettings() noexcept
The (fixed) index of the object containing the ledger fees.
FeatureBitset testableAmendments()
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)
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
STTx createFeeTx(Rules const &rules, std::uint32_t seq, FeeSettingsFields const &fields)
bool applyFeeAndTestResult(jtx::Env &env, OpenView &view, STTx const &tx)
constexpr XRPAmount
Convert XRP to drops (integral types).
std::vector< STTx > getTxs(std::shared_ptr< SHAMap > const &txSet)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
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.
CreateGenesisT const kCreateGenesis
std::unique_ptr< FeeVote > makeFeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
FeeSetup setupFeeVote(Section const §ion)
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.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
bool isTesSuccess(TER x) noexcept
Fee schedule for startup / standalone, and to vote for.
XRPAmount accountReserve
The account reserve requirement in drops.
XRPAmount ownerReserve
The per-owned item reserve requirement in drops.
XRPAmount referenceFee
The cost of a reference transaction 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