1#include <xrpl/tx/invariants/InvariantCheck.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/utility/Zero.h>
7#include <xrpl/beast/utility/instrumentation.h>
8#include <xrpl/ledger/ReadView.h>
9#include <xrpl/ledger/helpers/AccountRootHelpers.h>
10#include <xrpl/ledger/helpers/TokenHelpers.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/Feature.h>
13#include <xrpl/protocol/Indexes.h>
14#include <xrpl/protocol/Issue.h>
15#include <xrpl/protocol/Keylet.h>
16#include <xrpl/protocol/LedgerFormats.h>
17#include <xrpl/protocol/MPTIssue.h>
18#include <xrpl/protocol/Protocol.h>
19#include <xrpl/protocol/Rules.h>
20#include <xrpl/protocol/SField.h>
21#include <xrpl/protocol/STAmount.h>
22#include <xrpl/protocol/STLedgerEntry.h>
23#include <xrpl/protocol/STNumber.h>
24#include <xrpl/protocol/STTx.h>
25#include <xrpl/protocol/SystemParameters.h>
26#include <xrpl/protocol/TER.h>
27#include <xrpl/protocol/TxFormats.h>
28#include <xrpl/protocol/TxSettings.h>
29#include <xrpl/protocol/UintTypes.h>
30#include <xrpl/protocol/XRPAmount.h>
31#include <xrpl/tx/invariants/InvariantCheckPrivilege.h>
44#pragma push_macro("UNWRAP")
46#pragma push_macro("TRANSACTION")
49#define UNWRAP(...) __VA_ARGS__
50#define TRANSACTION(tag, value, name, settings, ...) \
52 return ((TxSettings UNWRAP settings).privileges & priv) != Privilege::NoPriv; \
60#include <xrpl/protocol/detail/transactions.macro>
69#pragma pop_macro("TRANSACTION")
71#pragma pop_macro("UNWRAP")
83 UNREACHABLE(
"xrpl::ledgerEntryTypeName : ledger entry has no known ledger format");
87 return item->getName();
107 JLOG(j.
fatal()) <<
"Invariant failed: fee paid was negative: " << fee.
drops();
115 JLOG(j.
fatal()) <<
"Invariant failed: fee paid exceeds system limit: " << fee.
drops();
123 JLOG(j.
fatal()) <<
"Invariant failed: fee paid is " << fee.
drops()
124 <<
" exceeds fee specified in transaction.";
145 switch (before->getType())
148 drops_ -= (*before)[sfBalance].xrp().drops();
151 drops_ -= ((*before)[sfAmount] - (*before)[sfBalance]).xrp().drops();
154 if (
isXRP((*before)[sfAmount]))
155 drops_ -= (*before)[sfAmount].xrp().drops();
158 if (before->isFieldPresent(sfFeeAmount))
161 isXRP((*before)[sfFeeAmount]),
162 "XRPNotCreated::visitEntry : Sponsorship.FeeAmount is XRP");
163 drops_ -= (*before)[sfFeeAmount].xrp().drops();
174 UNREACHABLE(
"xrpl::XRPNotCreated::visitEntry : after can't be null");
178 switch (
after->getType())
181 drops_ += (*after)[sfBalance].xrp().drops();
185 drops_ += ((*after)[sfAmount] - (*after)[sfBalance]).xrp().drops();
189 drops_ += (*after)[sfAmount].xrp().drops();
192 if (!isDelete &&
after->isFieldPresent(sfFeeAmount))
196 "XRPNotCreated::visitEntry : Sponsorship.FeeAmount is XRP");
197 drops_ += (*after)[sfFeeAmount].xrp().drops();
217 JLOG(j.
fatal()) <<
"Invariant failed: XRP net change was positive: " <<
drops_;
224 JLOG(j.
fatal()) <<
"Invariant failed: XRP net change of " <<
drops_ <<
" doesn't match fee "
237 auto isBad = [](
STAmount const& balance) {
238 if (!balance.native())
241 auto const drops = balance.xrp();
255 if (before && before->getType() == ltACCOUNT_ROOT)
256 bad_ |= isBad((*before)[sfBalance]);
258 if (
after &&
after->getType() == ltACCOUNT_ROOT)
272 JLOG(j.
fatal()) <<
"Invariant failed: incorrect account XRP balance";
293 return pays.
native() && gets.native();
296 if (before && before->getType() == ltOFFER)
297 bad_ |= isBad((*before)[sfTakerPays], (*before)[sfTakerGets]);
313 JLOG(j.
fatal()) <<
"Invariant failed: offer with a bad amount";
325 auto isBad = [](
STAmount const& amount) {
337 return amount.asset().visit(
338 [&](
Issue const& issue) {
355 if (amount.mpt() >
MPTAmount{kMaxMpTokenAmount})
364 if (before && before->getType() == ltESCROW)
365 bad_ |= isBad((*before)[sfAmount]);
377 if (
after &&
after->getType() == ltMPTOKEN_ISSUANCE)
379 auto const outstanding = (*after)[sfOutstandingAmount];
380 checkAmount(outstanding);
381 if (
auto const locked = (*
after)[~sfLockedAmount])
383 checkAmount(*locked);
384 bool const isBad = outstanding < *locked;
385 if (overwriteFixEnabled)
398 auto const mptAmount = (*after)[sfMPTAmount];
399 checkAmount(mptAmount);
400 if (
auto const locked = (*
after)[~sfLockedAmount])
402 checkAmount(*locked);
417 JLOG(j.
fatal()) <<
"Invariant failed: escrow specifies invalid amount";
429 if (isDelete && before && before->getType() == ltACCOUNT_ROOT)
452 JLOG(j.
fatal()) <<
"Invariant failed: account deletion "
453 "succeeded without deleting an account";
457 JLOG(j.
fatal()) <<
"Invariant failed: account deletion "
458 "succeeded but deleted multiple accounts!";
472 JLOG(j.
fatal()) <<
"Invariant failed: an account root was deleted";
481 if (isDelete && before && before->getType() == ltACCOUNT_ROOT)
497 [[maybe_unused]]
bool const enforce = view.
rules().
enabled(fixCleanup3_2_0) ||
501 auto const objectExists = [&view, enforce, &j](
auto const&
keylet) {
506 JLOG(j.
fatal()) <<
"Invariant failed: account deletion left behind a "
512 "xrpl::AccountRootsDeletedClean::finalize::objectExists : "
513 "account deletion left no objects behind");
521 auto const accountID = before->getAccountID(sfAccount);
525 JLOG(j.
fatal()) <<
"Invariant failed: account deletion left "
526 "behind a non-zero balance";
529 "xrpl::AccountRootsDeletedClean::finalize : "
530 "deleted account has zero balance");
535 if (
after->at(sfOwnerCount) != 0)
537 JLOG(j.
fatal()) <<
"Invariant failed: account deletion left "
538 "behind a non-zero owner count";
541 "xrpl::AccountRootsDeletedClean::finalize : "
542 "deleted account has zero owner count");
547 if (
after->isFieldPresent(sfSponsoredOwnerCount) ||
548 after->isFieldPresent(sfSponsoringOwnerCount) ||
549 after->isFieldPresent(sfSponsoringAccountCount) ||
after->isFieldPresent(sfSponsor))
551 JLOG(j.
fatal()) <<
"Invariant failed: account deletion left "
552 "behind a sponsorship field";
555 "xrpl::AccountRootsDeletedClean::finalize : "
556 "deleted account has no sponsorship fields");
564 if (objectExists(
std::invoke(keyletfunc, accountID)) && enforce)
579 if (key && objectExists(
Keylet{ltNFTOKEN_PAGE, *key}) && enforce)
587 if (before->isFieldPresent(*field))
589 auto const key = before->getFieldH256(*field);
604 if (before &&
after && before->getType() !=
after->getType())
609#pragma push_macro("LEDGER_ENTRY")
612#define LEDGER_ENTRY(tag, ...) case tag:
614 switch (
after->getType())
616#include <xrpl/protocol/detail/ledger_entries.macro>
625#pragma pop_macro("LEDGER_ENTRY")
642 JLOG(j.
fatal()) <<
"Invariant failed: ledger entry type mismatch";
647 JLOG(j.
fatal()) <<
"Invariant failed: invalid ledger entry type added";
660 if (
after &&
after->getType() == ltRIPPLE_STATE)
665 bool const isXrp =
after->getFieldAmount(sfLowLimit).asset() ==
xrpIssue() ||
667 if (overwriteFixEnabled)
689 JLOG(j.
fatal()) <<
"Invariant failed: an XRP trust line was created";
698 if (
after &&
after->getType() == ltRIPPLE_STATE)
702 bool const lowFreeze =
after->isFlag(lsfLowFreeze);
703 bool const lowDeepFreeze =
after->isFlag(lsfLowDeepFreeze);
705 bool const highFreeze =
after->isFlag(lsfHighFreeze);
706 bool const highDeepFreeze =
after->isFlag(lsfHighDeepFreeze);
708 bool const bad = (lowDeepFreeze && !lowFreeze) || (highDeepFreeze && !highFreeze);
709 if (overwriteFixEnabled)
731 JLOG(j.
fatal()) <<
"Invariant failed: a trust line with deep freeze flag "
732 "without normal freeze was created";
741 if (!before &&
after->getType() == ltACCOUNT_ROOT)
763 JLOG(j.
fatal()) <<
"Invariant failed: multiple accounts "
764 "created in a single transaction";
772 bool const pseudoAccount =
774 (view.
rules().enabled(featureSingleAssetVault) ||
779 JLOG(j.
fatal()) <<
"Invariant failed: pseudo-account created by a "
780 "wrong transaction type";
788 JLOG(j.
fatal()) <<
"Invariant failed: account created with "
789 "wrong starting sequence number";
795 std::uint32_t const expected = (lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
798 JLOG(j.
fatal()) <<
"Invariant failed: pseudo-account created with "
807 JLOG(j.
fatal()) <<
"Invariant failed: account root created illegally";
823 if (sle->getType() != ltRIPPLE_STATE ||
829 STAmount balance = sle->getFieldAmount(sfBalance);
832 balance.
get<
Issue>().account = issuer;
839 if (before && before->getType() == ltRIPPLE_STATE)
842 iou_.before = before;
845 if (!isDelete &&
after &&
after->getType() == ltRIPPLE_STATE)
848 if (before && before->getType() == ltMPTOKEN)
851 mpt_.before = before;
854 if (!isDelete &&
after &&
after->getType() == ltMPTOKEN)
873 JLOG(j.
fatal()) <<
"Invariant failed: more than one trustline changed.";
879 JLOG(j.
fatal()) <<
"Invariant failed: more than one mptokens changed.";
883 bool const mptV2Enabled = view.
rules().
enabled(featureMPTokensV2);
886 JLOG(j.
fatal()) <<
"Invariant failed: trustline and MPToken both changed.";
896 [&](
Issue const& issue) {
902 if (holderBalance.
signum() < 0)
904 JLOG(j.
fatal()) <<
"Invariant failed: trustline or MPT balance is negative";
911 <<
"Invariant failed: trustline clawback changed the wrong line";
912 return !mptV2Enabled;
919 if (!beforeBalance || !afterBalance)
922 <<
"Invariant failed: trustline clawback changed the wrong line";
923 return !mptV2Enabled;
927 clawAmount.
get<
Issue>().account = issuer;
930 JLOG(j.
fatal()) <<
"Invariant failed: trustline clawback amount is invalid";
931 return !mptV2Enabled;
934 if (*afterBalance > *beforeBalance ||
935 (*beforeBalance - *afterBalance) !=
std::min(*beforeBalance, clawAmount))
938 <<
"Invariant failed: trustline clawback balance change is invalid";
939 return !mptV2Enabled;
945 auto const holder = tx[~sfHolder];
948 JLOG(j.
fatal()) <<
"Invariant failed: MPT clawback missing holder";
949 return !mptV2Enabled;
954 JLOG(j.
fatal()) <<
"Invariant failed: MPT clawback token is missing";
955 return !mptV2Enabled;
958 if (
mpt_.before->getAccountID(sfAccount) != *holder ||
959 mpt_.after->getAccountID(sfAccount) != *holder ||
960 (*
mpt_.before)[sfMPTokenIssuanceID] != issue.getMptID() ||
961 (*
mpt_.after)[sfMPTokenIssuanceID] != issue.getMptID())
963 JLOG(j.
fatal()) <<
"Invariant failed: MPT clawback changed the wrong token";
964 return !mptV2Enabled;
967 auto const before =
mpt_.before->getFieldU64(sfMPTAmount);
968 auto const after =
mpt_.after->getFieldU64(sfMPTAmount);
971 JLOG(j.
fatal()) <<
"Invariant failed: MPT clawback amount is invalid";
972 return !mptV2Enabled;
974 auto const clawAmount = amount.
mantissa();
981 <<
"Invariant failed: MPT clawback balance change is invalid";
982 return !mptV2Enabled;
993 JLOG(j.
fatal()) <<
"Invariant failed: some trustlines were changed "
994 "despite failure of the transaction.";
1000 JLOG(j.
fatal()) <<
"Invariant failed: some mptokens were changed "
1001 "despite failure of the transaction.";
1020 if (
after &&
after->getType() == ltACCOUNT_ROOT)
1022 bool const isPseudo = [&]() {
1029 if (
after->at(sfSequence) == 0)
1049 [&
after](
SField const* sf) ->
bool {
return after->isFieldPresent(*sf); });
1053 error <<
"pseudo-account has " << numFields <<
" pseudo-account fields set";
1057 if (before && before->at(sfSequence) !=
after->at(sfSequence))
1059 errors_.emplace_back(
"pseudo-account sequence changed");
1061 if (!
after->isFlag(lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth))
1063 errors_.emplace_back(
"pseudo-account flags are not set");
1065 if (
after->isFieldPresent(sfRegularKey))
1067 errors_.emplace_back(
"pseudo-account has a regular key");
1069 if (
after->isFieldPresent(sfSponsoredOwnerCount) ||
1070 after->isFieldPresent(sfSponsoringOwnerCount) ||
after->isFieldPresent(sfSponsor) ||
1071 after->isFieldPresent(sfSponsoringAccountCount))
1073 errors_.emplace_back(
"pseudo-account has a sponsorship field");
1087 bool const enforce = view.
rules().
enabled(featureSingleAssetVault);
1090 "xrpl::ValidPseudoAccounts::finalize : no bad "
1091 "changes or enforce invariant");
1094 for (
auto const& error :
errors_)
1096 JLOG(j.
fatal()) <<
"Invariant failed: " << error;
1109 if (isDelete || !before)
1126 auto const kFieldChanged = [&j, &tx](
auto const& before,
auto const&
after,
auto const& field) {
1127 bool const beforeField = before->isFieldPresent(field);
1128 bool const afterField =
after->isFieldPresent(field);
1129 bool const changed =
1130 beforeField != afterField || (afterField && before->at(field) !=
after->at(field));
1133 JLOG(j.
fatal()) <<
"Invariant failed: " << field.getName()
1140 auto const& before = slePair.first;
1141 auto const&
after = slePair.second;
1142 auto const type =
after->getType();
1147 bool const enforce = view.
rules().
enabled(featureLendingProtocol);
1148 bool bad = kFieldChanged(before,
after, sfLedgerEntryType) ||
1149 kFieldChanged(before,
after, sfLedgerIndex);
1153 bad = bad || kFieldChanged(before,
after, sfSequence) ||
1154 kFieldChanged(before,
after, sfOwnerNode) ||
1155 kFieldChanged(before,
after, sfVaultNode) ||
1156 kFieldChanged(before,
after, sfVaultID) ||
1157 kFieldChanged(before,
after, sfAccount) ||
1158 kFieldChanged(before,
after, sfOwner) ||
1159 kFieldChanged(before,
after, sfManagementFeeRate) ||
1160 kFieldChanged(before,
after, sfCoverRateMinimum) ||
1161 kFieldChanged(before,
after, sfCoverRateLiquidation);
1164 bad = bad || kFieldChanged(before,
after, sfSequence) ||
1165 kFieldChanged(before,
after, sfOwnerNode) ||
1166 kFieldChanged(before,
after, sfLoanBrokerNode) ||
1167 kFieldChanged(before,
after, sfLoanBrokerID) ||
1168 kFieldChanged(before,
after, sfBorrower) ||
1169 kFieldChanged(before,
after, sfLoanOriginationFee) ||
1170 kFieldChanged(before,
after, sfLoanServiceFee) ||
1171 kFieldChanged(before,
after, sfLatePaymentFee) ||
1172 kFieldChanged(before,
after, sfClosePaymentFee) ||
1173 kFieldChanged(before,
after, sfOverpaymentFee) ||
1174 kFieldChanged(before,
after, sfInterestRate) ||
1175 kFieldChanged(before,
after, sfLateInterestRate) ||
1176 kFieldChanged(before,
after, sfCloseInterestRate) ||
1177 kFieldChanged(before,
after, sfOverpaymentInterestRate) ||
1178 kFieldChanged(before,
after, sfStartDate) ||
1179 kFieldChanged(before,
after, sfPaymentInterval) ||
1180 kFieldChanged(before,
after, sfGracePeriod) ||
1181 kFieldChanged(before,
after, sfLoanScale);
1190 bool const overpaymentChanged =
1191 (beforeFlags & lsfLoanOverpayment) != (afterFlags & lsfLoanOverpayment);
1192 if (overpaymentChanged)
1194 JLOG(j.
fatal()) <<
"Invariant failed: lsfLoanOverpayment flag "
1195 "toggled on immutable ledger entry in "
1198 bad = bad || overpaymentChanged;
1199 bool const defaultCleared =
1200 (beforeFlags & lsfLoanDefault) != 0 && (afterFlags & lsfLoanDefault) == 0;
1203 JLOG(j.
fatal()) <<
"Invariant failed: lsfLoanDefault flag "
1204 "cleared on immutable ledger entry in "
1207 bad = bad || defaultCleared;
1219 bad = bad || kFieldChanged(before,
after, sfVaultKind) ||
1220 kFieldChanged(before,
after, sfSubscriptionDate) ||
1221 kFieldChanged(before,
after, sfRedemptionDate) ||
1222 kFieldChanged(before,
after, sfSequence) ||
1223 kFieldChanged(before,
after, sfOwnerNode) ||
1224 kFieldChanged(before,
after, sfOwner) ||
1225 kFieldChanged(before,
after, sfWithdrawalPolicy) ||
1226 kFieldChanged(before,
after, sfScale) ||
1227 kFieldChanged(before,
after, sfLEVersion) ||
1228 kFieldChanged(before,
after, sfAsset) ||
1229 kFieldChanged(before,
after, sfAccount) ||
1230 kFieldChanged(before,
after, sfShareMPTID);
1238 "xrpl::NoModifiedUnmodifiableFields::finalize : no bad "
1239 "changes or enforce invariant");
1242 JLOG(j.
fatal()) <<
"Invariant failed: changed an unchangeable field for "
1257 if (!isDelete &&
after)
1275 <<
"Invariant failed: ledger entry contains non-canonical MPT or XRP amount";
1293 "xrpl::ObjectHasPseudoAccount::visitEntry : deleted ledger entry missing before state");
1298 switch (before->getType())
1324 bool failed =
false;
1327 if (!sle->isFieldPresent(sfAccount))
1330 <<
" is missing pseudo-account field";
1339 <<
" without deleting its pseudo-account";
A generic endpoint for log messages.
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
std::vector< std::pair< SLE::const_pointer, SLE::const_pointer > > accountsDeleted_
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
std::uint32_t accountsDeleted_
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
A currency issued by an account.
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool deepFreezeWithoutFreeze_
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
std::set< std::pair< SLE::const_pointer, SLE::const_pointer > > changedEntries_
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
std::vector< SLE::const_pointer > deletedObjSles_
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
virtual std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const =0
Return the key of the next state item.
bool enabled(UInt256 const &feature) const
Returns true if a feature is enabled.
constexpr TIss const & get() const
std::uint64_t mantissa() const noexcept
int signum() const noexcept
bool negative() const noexcept
bool native() const noexcept
Asset const & asset() const
AccountID const & getIssuer() const
LedgerEntryType getType() const
std::shared_ptr< STLedgerEntry const > const & ConstRef
std::shared_ptr< STLedgerEntry const > const_pointer
AccountID getAccountID(SField const &field) const
STAmount const & getFieldAmount(SField const &field) const
TxType getTxnType() const
UInt256 getTransactionID() const
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
static bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
std::vector< SLE::const_pointer > afterEntries_
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
std::uint32_t mptokensChanged_
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
std::uint32_t trustlinesChanged_
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
std::uint32_t accountsCreated_
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
std::uint32_t accountSeq_
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
std::vector< std::string > errors_
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
constexpr value_type drops() const
Returns the number of drops.
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &) const
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
Keylet computation functions.
Keylet nftokenPageMin(AccountID const &owner)
NFT page keylets.
Keylet unchecked(UInt256 const &key) noexcept
Any ledger entry.
Keylet nftokenPageMax(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
std::vector< SField const * > const & getPseudoAccountFields()
Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if set.
bool isXRP(AccountID const &c)
bool isFeatureEnabled(UInt256 const &feature, bool resultIfNoRules)
Check whether a feature is enabled in the current ledger rules.
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Privilege
Operations a transaction is permitted to perform, as a bitfield.
bool hasPrivilege(STTx const &tx, Privilege priv)
static std::optional< STAmount > clawbackTrustLineBalanceInHolderTerms(SLE::const_pointer const &sle, AccountID const &holder, AccountID const &issuer, Currency const ¤cy)
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
static std::string ledgerEntryTypeName(SLE const &sle)
bool hasInvalidAmount(STBase const &field, beast::Journal j)
bool isPseudoAccount(SLE::const_pointer sleAcct)
Returns true if and only if sleAcct is a pseudo-account of any kind (i.e.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint64_t kMaxMpTokenAmount
The maximum amount of MPTokenIssuance.
constexpr XRPAmount kInitialXrp
Configure the native currency.
std::array< KeyletDesc< AccountID const & >, 6 > const kDirectAccountKeylets
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=SpendableHandling::SimpleBalance)
A pair of SHAMap key and LedgerEntryType.