20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/LoadFeeTrack.h>
22 #include <ripple/app/tx/apply.h>
23 #include <ripple/app/tx/impl/SignerEntries.h>
24 #include <ripple/app/tx/impl/Transactor.h>
25 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
26 #include <ripple/basics/Log.h>
27 #include <ripple/basics/contract.h>
28 #include <ripple/core/Config.h>
29 #include <ripple/json/to_string.h>
30 #include <ripple/ledger/View.h>
31 #include <ripple/protocol/Feature.h>
32 #include <ripple/protocol/Indexes.h>
33 #include <ripple/protocol/Protocol.h>
34 #include <ripple/protocol/STAccount.h>
35 #include <ripple/protocol/UintTypes.h>
60 if (*txNID != nodeNID)
66 if (txID == beast::zero)
69 <<
"applyTransaction: transaction id may not be zero";
93 if (
id == beast::zero)
95 JLOG(ctx.
j.
warn()) <<
"preflight1: bad account id";
101 if (!fee.native() || fee.negative() || !
isLegalAmount(fee.xrp()))
103 JLOG(ctx.
j.
debug()) <<
"preflight1: invalid fee";
111 JLOG(ctx.
j.
debug()) <<
"preflight1: invalid signing key";
136 JLOG(ctx.
j.
debug()) <<
"preflight2: bad signature. " << sigValid.second;
150 : app(app_), tx(tx_), rules(rules_), flags(flags_), j(j_)
157 : ctx_(ctx), j_(ctx.journal), account_(ctx.tx.getAccountID(
sfAccount))
176 return baseFee + (signerCount * baseFee);
195 auto const feePaid = ctx.
tx[
sfFee].xrp();
205 if (feePaid < feeDue)
208 <<
"Insufficient fee paid: " <<
to_string(feePaid) <<
"/"
214 if (feePaid == beast::zero)
222 auto const balance = (*sle)[
sfBalance].xrp();
224 if (balance < feePaid)
226 JLOG(ctx.
j.
trace()) <<
"Insufficient balance:"
230 if ((balance > beast::zero) && !ctx.
view.
open())
275 <<
"applyTransaction: delay: source account does not exist "
283 if (t_seqProx.
isSeq())
288 JLOG(j.
trace()) <<
"applyTransaction: has both a TicketSequence "
289 "and a non-zero Sequence number";
292 if (t_seqProx != a_seq)
294 if (a_seq < t_seqProx)
297 <<
"applyTransaction: has future sequence number "
298 <<
"a_seq=" << a_seq <<
" t_seq=" << t_seqProx;
302 JLOG(j.
trace()) <<
"applyTransaction: has past sequence number "
303 <<
"a_seq=" << a_seq <<
" t_seq=" << t_seqProx;
316 JLOG(j.
trace()) <<
"applyTransaction: has future ticket id "
317 <<
"a_seq=" << a_seq <<
" t_seq=" << t_seqProx;
325 <<
"applyTransaction: ticket already used or never created "
326 <<
"a_seq=" << a_seq <<
" t_seq=" << t_seqProx;
344 <<
"applyTransaction: delay: source account does not exist "
394 JLOG(j.
fatal()) <<
"Ticket disappeared from ledger.";
401 JLOG(j.
fatal()) <<
"Unable to delete Ticket from owner.";
410 JLOG(j.
fatal()) <<
"Could not find Ticket owner account root.";
416 if (*ticketCount == 1)
419 ticketCount = *ticketCount - 1;
423 JLOG(j.
fatal()) <<
"TicketCount field missing from account root.";
453 assert(sle !=
nullptr ||
account_ == beast::zero);
495 <<
"checkSingleSign: signing public key type is unknown";
517 if (!isMasterDisabled && idAccount == idSigner)
523 if (isMasterDisabled && idAccount == idSigner)
532 if (idSigner == idAccount)
535 if (isMasterDisabled)
546 <<
"checkSingleSign: Not authorized to use account.";
554 <<
"checkSingleSign: Not authorized to use account.";
569 if (!sleAccountSigners)
572 <<
"applyTransaction: Invalid: Not a multi-signing account.";
581 auto accountSigners =
584 return accountSigners.error();
596 auto iter = accountSigners->begin();
597 for (
auto const& txSigner : txSigners)
602 while (iter->account < txSignerAcctID)
604 if (++iter == accountSigners->end())
607 <<
"applyTransaction: Invalid SigningAccount.Account.";
611 if (iter->account != txSignerAcctID)
615 <<
"applyTransaction: Invalid SigningAccount.Account.";
627 <<
"checkMultiSign: signing public key type is unknown";
631 AccountID const signingAcctIDFromPubKey =
661 if (signingAcctIDFromPubKey == txSignerAcctID)
668 sleTxSignerRoot->getFieldU32(
sfFlags);
673 <<
"applyTransaction: Signer:Account lsfDisableMaster.";
682 if (!sleTxSignerRoot)
684 JLOG(ctx.
j.
trace()) <<
"applyTransaction: Non-phantom signer "
685 "lacks account root.";
692 <<
"applyTransaction: Account lacks RegularKey.";
695 if (signingAcctIDFromPubKey !=
699 <<
"applyTransaction: Account doesn't match RegularKey.";
704 weightSum += iter->weight;
711 <<
"applyTransaction: Signers failed to meet quorum.";
729 for (
auto const& index : offers)
749 for (
auto const& index : offers)
773 auto const balance = txnAcct->getFieldAmount(
sfBalance).xrp();
776 assert(balance != beast::zero && (!
view().
open() || balance >= fee));
789 txnAcct->setFieldAmount(
sfBalance, balance - fee);
817 JLOG(
j_.
fatal()) <<
"Transaction serdes mismatch";
834 stream <<
"preclaim result: " <<
transToken(result);
871 assert(before &&
after);
872 if (before &&
after && (before->getType() ==
ltOFFER) &&
894 assert(before &&
after);
895 if (before &&
after &&
904 auto const resetResult =
reset(fee);
906 result = resetResult.first;
908 fee = resetResult.second;
933 auto const resetResult =
reset(fee);
935 result = resetResult.first;
937 fee = resetResult.second;
959 if (fee < beast::zero)
960 Throw<std::logic_error>(
"fee charged is negative!");
966 if (!
view().
open() && fee != beast::zero)
973 JLOG(
j_.
trace()) << (applied ?
"applied" :
"not applied")
976 return {result, applied};
static NotTEC checkPriorTxAndLastLedger(PreclaimContext const &ctx)
const SF_UINT32 sfSignerListID
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
const STArray & getFieldArray(SField const &field) const
RAII class to set and restore the STAmount canonicalize switchover.
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
static XRPAmount minimumFee(Application &app, XRPAmount baseFee, Fees const &fees, ApplyFlags flags)
Compute the minimum fee required to process a transaction with a given baseFee based on the current s...
static NotTEC checkMultiSign(PreclaimContext const &ctx)
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
TER checkInvariants(TER const result, XRPAmount const fee)
Applies all invariant checkers one by one.
bool isLegalAmount(XRPAmount const &amount)
Returns true if the amount does not exceed the initial XRP in existence.
const SF_UINT64 sfOwnerNode
Stream trace() const
Severity stream access functions.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static Expected< std::vector< SignerEntry >, NotTEC > deserialize(STObject const &obj, beast::Journal journal, std::string const &annotation)
static NotTEC checkSingleSign(PreclaimContext const &ctx)
const SF_UINT32 sfSequence
const SF_ACCOUNT sfRegularKey
std::pair< TER, bool > operator()()
Process the transaction.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
RAII class to set and restore the Number switchover.
const SF_VL sfSigningPubKey
const uint256 fixSTAmountCanonicalize
constexpr std::size_t expiredOfferRemoveLimit
The maximum number of expired offers to delete at once.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
static NotTEC checkSeqProxy(ReadView const &view, STTx const &tx, beast::Journal j)
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
std::string transToken(TER code)
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
@ telNETWORK_ID_MAKES_TX_NON_CANONICAL
SeqProxy getSeqProxy() const
const SF_UINT32 sfTicketSequence
static const ticket_t ticket
virtual bool txExists(key_type const &key) const =0
Returns true if a tx exists in the tx map.
constexpr std::size_t unfundedOfferRemoveLimit
The maximum number of unfunded offers to delete at once.
static TER ticketDelete(ApplyView &view, AccountID const &account, uint256 const &ticketIndex, beast::Journal j)
bool isTecClaimHardFail(TER ter, ApplyFlags flags)
Return true if the transaction can claim a fee (tec), and the ApplyFlags do not allow soft failures.
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Writeable view to a ledger, for applying a transaction.
virtual LoadFeeTrack & getFeeTrack()=0
constexpr bool isTicket() const
const SF_UINT32 sfSignerQuorum
bool isEquivalent(const STBase &t) const override
constexpr bool isSeq() const
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
const SF_AMOUNT sfTakerPays
NotTEC preflight0(PreflightContext const &ctx)
Performs early sanity checks on the txid.
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
@ ltOFFER
A ledger object which describes an offer on the DEX.
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
static NotTEC checkSign(PreclaimContext const &ctx)
Reflects the fee settings for a particular ledger.
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
Keylet account(AccountID const &id) noexcept
AccountID root.
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
AccountID getAccountID(SField const &field) const
void destroyXRP(XRPAmount const &fee)
virtual Config & config()=0
@ ltNFTOKEN_OFFER
A ledger object which identifies an offer to buy or sell an NFT.
AccountID calcAccountID(PublicKey const &pk)
const SF_UINT32 sfTicketCount
const SF_UINT256 sfAccountTxnID
void discard()
Discard changes and start fresh.
Slice slice() const noexcept
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
const uint256 fixMasterKeyAsRegularKey
State information when applying a tx.
Blob getSigningPubKey() const
A generic endpoint for log messages.
TER consumeSeqProxy(SLE::pointer const &sleAccount)
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
Json::Value getJson(JsonOptions options) const override
Transactor(Transactor const &)=delete
void apply(TER)
Apply the transaction result to the base.
void visit(std::function< void(uint256 const &key, bool isDelete, std::shared_ptr< SLE const > const &before, std::shared_ptr< SLE const > const &after)> const &func)
Visit unapplied changes.
uint256 getTransactionID() const
PreflightContext(Application &app_, STTx const &tx_, Rules const &rules_, ApplyFlags flags_, beast::Journal j_)
State information when determining if a tx is likely to claim a fee.
void add(Serializer &s) const override
constexpr std::uint32_t value() const
std::pair< TER, XRPAmount > reset(XRPAmount fee)
Reset the context, discarding any changes made and adjust the fee.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
virtual beast::Journal journal(std::string const &name)=0
constexpr std::size_t oversizeMetaDataCap
The maximum number of metadata entries allowed in one transaction.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool isFieldPresent(SField const &field) const
const uint256 fixUniversalNumber
const SF_AMOUNT sfBalance
A type that represents either a sequence value or a ticket value.
Rules controlling protocol behavior.
const uint256 featureTicketBatch
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
XRPAmount scaleFeeLoad(XRPAmount fee, LoadFeeTrack const &feeTrack, Fees const &fees, bool bUnlimited)
static TER checkFee(PreclaimContext const &ctx, XRPAmount baseFee)
const SF_ACCOUNT sfAccount
static void removeExpiredNFTokenOffers(ApplyView &view, std::vector< uint256 > const &offers, beast::Journal viewJ)
const SF_UINT32 sfNetworkID
std::uint32_t getFieldU32(SField const &field) const
State information when preflighting a tx.
@ SigBad
Signature is bad. Didn't do local checks.
const SF_UINT32 sfLastLedgerSequence
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
std::size_t size()
Get the number of unapplied changes.
static void removeUnfundedOffers(ApplyView &view, std::vector< uint256 > const &offers, beast::Journal viewJ)
virtual bool open() const =0
Returns true if this reflects an open ledger.
virtual HashRouter & getHashRouter()=0
virtual void preCompute()
STAmount const & getFieldAmount(SField const &field) const
bool deleteTokenOffer(ApplyView &view, std::shared_ptr< SLE > const &offer)
Deletes the given token offer.
void open(soci::session &s, BasicConfig const &config, std::string const &dbName)
Open a soci session.
TERSubset< CanCvtToNotTEC > NotTEC
uint256 getFieldH256(SField const &field) const