20 #include <ripple/app/tx/impl/InvariantCheck.h>
22 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
23 #include <ripple/basics/FeeUnits.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/ledger/ReadView.h>
26 #include <ripple/ledger/View.h>
27 #include <ripple/protocol/Feature.h>
28 #include <ripple/protocol/STArray.h>
29 #include <ripple/protocol/SystemParameters.h>
30 #include <ripple/protocol/nftPageMask.h>
54 JLOG(j.
fatal()) <<
"Invariant failed: fee paid was negative: "
63 JLOG(j.
fatal()) <<
"Invariant failed: fee paid exceeds system limit: "
72 JLOG(j.
fatal()) <<
"Invariant failed: fee paid is " << fee.
drops()
73 <<
" exceeds fee specified in transaction.";
97 switch (before->getType())
116 switch (
after->getType())
149 JLOG(j.
fatal()) <<
"Invariant failed: XRP net change was positive: "
157 JLOG(j.
fatal()) <<
"Invariant failed: XRP net change of " <<
drops_
158 <<
" doesn't match fee " << fee.
drops();
173 auto isBad = [](
STAmount const& balance) {
174 if (!balance.native())
177 auto const drops = balance.xrp();
208 JLOG(j.
fatal()) <<
"Invariant failed: incorrect account XRP balance";
225 if (pays < beast::zero)
228 if (gets < beast::zero)
232 return pays.
native() && gets.native();
235 if (before && before->getType() ==
ltOFFER)
252 JLOG(j.
fatal()) <<
"Invariant failed: offer with a bad amount";
267 auto isBad = [](
STAmount const& amount) {
268 if (!amount.native())
280 if (before && before->getType() ==
ltESCROW)
297 JLOG(j.
fatal()) <<
"Invariant failed: escrow specifies invalid amount";
330 JLOG(j.
fatal()) <<
"Invariant failed: account deletion "
331 "succeeded without deleting an account";
333 JLOG(j.
fatal()) <<
"Invariant failed: account deletion "
334 "succeeded but deleted multiple accounts!";
341 JLOG(j.
fatal()) <<
"Invariant failed: an account root was deleted";
353 if (before &&
after && before->getType() !=
after->getType())
358 switch (
after->getType())
397 JLOG(j.
fatal()) <<
"Invariant failed: ledger entry type mismatch";
402 JLOG(j.
fatal()) <<
"Invariant failed: invalid ledger entry type added";
438 JLOG(j.
fatal()) <<
"Invariant failed: an XRP trust line was created";
470 JLOG(j.
fatal()) <<
"Invariant failed: multiple accounts "
471 "created in a single transaction";
483 JLOG(j.
fatal()) <<
"Invariant failed: account created with "
484 "wrong starting sequence number";
490 JLOG(j.
fatal()) <<
"Invariant failed: account root created "
491 "by a non-Payment or by an unsuccessful transaction";
504 static constexpr
uint256 const accountBits = ~pageBits;
507 uint256 const account = sle->key() & accountBits;
508 uint256 const hiLimit = sle->key() & pageBits;
516 if (account != (*prev & accountBits))
519 if (hiLimit <= (*prev & pageBits))
525 if (account != (*next & accountBits))
528 if (hiLimit >= (*next & pageBits))
533 auto const& nftokens = sle->getFieldArray(
sfNFTokens);
536 if (
std::size_t const nftokenCount = nftokens.size();
537 (!isDelete && nftokenCount == 0) ||
544 prev ? *prev & pageBits :
uint256(beast::zero);
548 for (
auto const& obj : nftokens)
557 if (
uint256 const tokenPageBits = tokenID & pageBits;
558 tokenPageBits < loLimit || tokenPageBits >= hiLimit)
561 if (
auto uri = obj[~
sfURI]; uri && uri->empty())
584 JLOG(j.
fatal()) <<
"Invariant failed: NFT page is improperly linked.";
590 JLOG(j.
fatal()) <<
"Invariant failed: NFT found in incorrect page.";
596 JLOG(j.
fatal()) <<
"Invariant failed: NFTs on page are not sorted.";
602 JLOG(j.
fatal()) <<
"Invariant failed: NFT contains empty URI.";
608 JLOG(j.
fatal()) <<
"Invariant failed: NFT page has invalid size.";
648 JLOG(j.
fatal()) <<
"Invariant failed: the number of minted tokens "
649 "changed without a mint transaction!";
655 JLOG(j.
fatal()) <<
"Invariant failed: the number of burned tokens "
656 "changed without a burn transaction!";
668 <<
"Invariant failed: successful minting didn't increase "
669 "the number of minted tokens.";
675 JLOG(j.
fatal()) <<
"Invariant failed: failed minting changed the "
676 "number of minted tokens.";
683 <<
"Invariant failed: minting changed the number of "
696 <<
"Invariant failed: successful burning didn't increase "
697 "the number of burned tokens.";
704 JLOG(j.
fatal()) <<
"Invariant failed: failed burning changed the "
705 "number of burned tokens.";
712 <<
"Invariant failed: burning changed the number of "
749 <<
"Invariant failed: more than one trustline changed.";
759 if (holderBalance.
signum() < 0)
762 <<
"Invariant failed: trustline balance is negative";
770 JLOG(j.
fatal()) <<
"Invariant failed: some trustlines were changed "
771 "despite failure of the transaction.";
TxType getTxnType() const
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
@ ttACCOUNT_DELETE
This transaction type deletes an existing account.
@ ltTICKET
A ledger object which describes a ticket.
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
@ ttCLAWBACK
This transaction claws back issued tokens.
const SF_UINT256 sfNFTokenID
@ ltLEDGER_HASHES
A ledger object that contains a list of ledger hashes.
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
constexpr value_type drops() const
Returns the number of drops.
const SF_UINT32 sfSequence
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
@ ltSIGNER_LIST
A ledger object which contains a signer list for an account.
const SF_UINT32 sfMintedNFTokens
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
constexpr std::size_t dirMaxTokensPerPage
The maximum number of items in an NFT page.
int signum() const noexcept
TxType
Transaction type identifiers.
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
std::uint32_t beforeMintedTotal
@ ltCHECK
A ledger object which describes a check.
@ ltFEE_SETTINGS
The ledger object which lists the network's fee settings.
std::uint32_t afterMintedTotal
bool compareTokens(uint256 const &a, uint256 const &b)
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
std::uint32_t accountSeq_
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
AccountID const & getIssuer() const
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
constexpr uint256 pageMask(std::string_view("0000000000000000000000000000000000000000ffffffffffffffffffffffff"))
const uint256 featureDeletableAccounts
@ ttPAYMENT
This transaction type executes a payment.
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
const SF_AMOUNT sfTakerPays
@ ltAMENDMENTS
The ledger object which lists details about amendments on the network.
const SF_AMOUNT sfLowLimit
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
@ ltOFFER
A ledger object which describes an offer on the DEX.
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 &)
std::uint32_t afterBurnedTotal
@ ltESCROW
A ledger object describing a single escrow.
AccountID getAccountID(SField const &field) const
@ ltNFTOKEN_OFFER
A ledger object which identifies an offer to buy or sell an NFT.
@ ttNFTOKEN_MINT
This transaction mints a new NFT.
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
std::uint32_t trustlinesChanged
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
@ ltDEPOSIT_PREAUTH
A ledger object which describes a deposit preauthorization.
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
const SF_AMOUNT sfTakerGets
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
A generic endpoint for log messages.
const SF_AMOUNT sfHighLimit
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 &)
std::uint32_t beforeBurnedTotal
bool native() const noexcept
@ ltNFTOKEN_PAGE
A ledger object which contains a list of NFTs.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
@ ltNEGATIVE_UNL
The ledger object which tracks the current negative UNL state.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
std::uint32_t accountsCreated_
virtual Rules const & rules() const =0
Returns the tx processing rules.
@ ltACCOUNT_ROOT
A ledger object which describes an account.
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
const SF_AMOUNT sfBalance
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
const SF_UINT256 sfNextPageMin
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
const SF_UINT256 sfPreviousPageMin
@ ttNFTOKEN_BURN
This transaction burns (i.e.
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
std::uint32_t accountsDeleted_
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
const SF_ACCOUNT sfAccount
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
const SF_UINT32 sfBurnedNFTokens
Currency const & getCurrency() const
STAmount const & getFieldAmount(SField const &field) const
@ ltPAYCHAN
A ledger object describing a single unidirectional XRP payment channel.