From 9310eaec9f3e45878baa1684710c617ea3a892a0 Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Thu, 5 Dec 2024 18:18:48 -0500 Subject: [PATCH] Add STTx Wrapper --- include/xrpl/protocol/Permissions.h | 28 ++- include/xrpl/protocol/STTxWr.h | 210 ++++++++++++++++++ include/xrpl/protocol/jss.h | 1 + src/libxrpl/protocol/Indexes.cpp | 2 +- src/libxrpl/protocol/Permissions.cpp | 48 ++-- src/test/app/AMM_test.cpp | 9 +- src/test/app/Escrow_test.cpp | 6 +- src/test/app/NFTokenBurn_test.cpp | 8 +- src/test/app/TxQ_test.cpp | 6 +- src/test/ledger/Invariants_test.cpp | 4 +- src/xrpld/app/ledger/AcceptedLedgerTx.cpp | 4 +- src/xrpld/app/ledger/detail/LedgerToJson.cpp | 4 +- src/xrpld/app/ledger/detail/LocalTxs.cpp | 5 +- src/xrpld/app/misc/CredentialHelpers.cpp | 2 +- src/xrpld/app/misc/NetworkOPs.cpp | 4 +- src/xrpld/app/misc/detail/TxQ.cpp | 5 +- src/xrpld/app/tx/apply.h | 1 + src/xrpld/app/tx/applySteps.h | 27 +-- src/xrpld/app/tx/detail/AMMBid.cpp | 3 +- src/xrpld/app/tx/detail/AMMClawback.cpp | 10 +- src/xrpld/app/tx/detail/AMMCreate.cpp | 2 +- src/xrpld/app/tx/detail/AMMDeposit.cpp | 2 +- src/xrpld/app/tx/detail/AMMVote.cpp | 2 +- src/xrpld/app/tx/detail/AMMWithdraw.cpp | 8 +- .../app/tx/detail/AccountPermissionSet.cpp | 7 +- src/xrpld/app/tx/detail/ApplyContext.cpp | 12 +- src/xrpld/app/tx/detail/ApplyContext.h | 14 +- src/xrpld/app/tx/detail/CancelCheck.cpp | 2 +- src/xrpld/app/tx/detail/CancelOffer.cpp | 2 +- src/xrpld/app/tx/detail/CashCheck.cpp | 4 +- src/xrpld/app/tx/detail/Change.cpp | 16 +- src/xrpld/app/tx/detail/Clawback.cpp | 10 +- src/xrpld/app/tx/detail/CreateCheck.cpp | 4 +- src/xrpld/app/tx/detail/CreateOffer.cpp | 4 +- src/xrpld/app/tx/detail/CreateTicket.cpp | 4 +- src/xrpld/app/tx/detail/Credentials.cpp | 7 +- src/xrpld/app/tx/detail/DeleteAccount.cpp | 4 +- src/xrpld/app/tx/detail/DeleteOracle.cpp | 8 +- src/xrpld/app/tx/detail/DepositPreauth.cpp | 4 +- src/xrpld/app/tx/detail/Escrow.cpp | 17 +- src/xrpld/app/tx/detail/InvariantCheck.cpp | 28 +-- src/xrpld/app/tx/detail/InvariantCheck.h | 32 +-- src/xrpld/app/tx/detail/MPTokenAuthorize.cpp | 4 +- .../app/tx/detail/MPTokenIssuanceDestroy.cpp | 2 +- .../app/tx/detail/MPTokenIssuanceSet.cpp | 14 +- .../app/tx/detail/NFTokenAcceptOffer.cpp | 28 ++- src/xrpld/app/tx/detail/NFTokenBurn.cpp | 6 +- .../app/tx/detail/NFTokenCancelOffer.cpp | 2 +- .../app/tx/detail/NFTokenCreateOffer.cpp | 8 +- src/xrpld/app/tx/detail/NFTokenMint.cpp | 13 +- src/xrpld/app/tx/detail/PayChan.cpp | 39 ++-- src/xrpld/app/tx/detail/Payment.cpp | 14 +- src/xrpld/app/tx/detail/SetAccount.cpp | 22 +- src/xrpld/app/tx/detail/SetOracle.cpp | 12 +- src/xrpld/app/tx/detail/SetRegularKey.cpp | 2 +- src/xrpld/app/tx/detail/SetSignerList.cpp | 6 +- src/xrpld/app/tx/detail/SetTrust.cpp | 13 +- src/xrpld/app/tx/detail/Transactor.cpp | 46 ++-- src/xrpld/app/tx/detail/Transactor.h | 20 +- src/xrpld/app/tx/detail/XChainBridge.cpp | 69 +++--- src/xrpld/app/tx/detail/apply.cpp | 6 +- src/xrpld/app/tx/detail/applySteps.cpp | 53 ++--- src/xrpld/rpc/handlers/LedgerEntry.cpp | 32 ++- 63 files changed, 613 insertions(+), 378 deletions(-) create mode 100644 include/xrpl/protocol/STTxWr.h diff --git a/include/xrpl/protocol/Permissions.h b/include/xrpl/protocol/Permissions.h index cddbcc64f20..bb62af85e29 100644 --- a/include/xrpl/protocol/Permissions.h +++ b/include/xrpl/protocol/Permissions.h @@ -34,29 +34,29 @@ namespace ripple { */ enum GranularPermissionType : std::uint32_t { - gpTrustlineAuthorize = 65537, + TrustlineAuthorize = 65537, - gpTrustlineFreeze = 65538, + TrustlineFreeze = 65538, - gpTrustlineUnfreeze = 65539, + TrustlineUnfreeze = 65539, - gpAccountDomainSet = 65540, + AccountDomainSet = 65540, - gpAccountEmailHashSet = 65541, + AccountEmailHashSet = 65541, - gpAccountMessageKeySet = 65542, + AccountMessageKeySet = 65542, - gpAccountTransferRateSet = 65543, + AccountTransferRateSet = 65543, - gpAccountTickSizeSet = 65544, + AccountTickSizeSet = 65544, - gpPaymentMint = 65545, + PaymentMint = 65545, - gpPaymentBurn = 65546, + PaymentBurn = 65546, - gpMPTokenIssuanceLock = 65547, + MPTokenIssuanceLock = 65547, - gpMPTokenIssuanceUnlock = 65548, + MPTokenIssuanceUnlock = 65548, }; class Permission @@ -73,6 +73,10 @@ class Permission static Permission const& getInstance(); + Permission(const Permission&) = delete; + Permission& + operator=(const Permission&) = delete; + std::optional getGranularValue(std::string const& name) const; diff --git a/include/xrpl/protocol/STTxWr.h b/include/xrpl/protocol/STTxWr.h new file mode 100644 index 00000000000..5bd4354ec09 --- /dev/null +++ b/include/xrpl/protocol/STTxWr.h @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STTX_WRAPPER_H_INCLUDED +#define RIPPLE_PROTOCOL_STTX_WRAPPER_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +// This class is a wrapper to deal with delegating in AccountPermission +// amendment. It wraps STTx, and delegates to STTx methods. The key change is +// getAccountID and operator[]. We need to first check if the transaction is +// delegated by another account by checking if the sfOnBehalfOf field is +// present. If it is present, we need to return the sfOnBehalfOf field as the +// account when calling getAccountID(sfAccount) and tx[sfAccount]. +class STTxWr +{ +private: + STTx tx_; // Wrap an instance of STTx + bool isDelegated_; // if the transaction is delegated by another account + +public: + explicit STTxWr(STTx tx, bool isDelegated) + : tx_(tx), isDelegated_(isDelegated) + { + } + + STTx + getTx() const + { + return tx_; + } + + bool + isDelegated() const + { + return isDelegated_; + } + + AccountID + getAccountID(SField const& field) const + { + if (field == sfAccount) + return tx_.isFieldPresent(sfOnBehalfOf) ? *tx_[~sfOnBehalfOf] + : tx_[sfAccount]; + return tx_.getAccountID(field); + } + + template + typename std::enable_if< + !std::is_same, SF_ACCOUNT>::value, + typename T::value_type>::type + operator[](TypedField const& f) const + { + return tx_[f]; + } + + // When Type is SF_ACCOUNT and also field name is sfAccount, we need to + // check if the transaction is delegated by another account. If it is, + // return sfOnBehalfOf field instead. + template + typename std::enable_if< + std::is_same, SF_ACCOUNT>::value, + AccountID>::type + operator[](TypedField const& f) const + { + if (f == sfAccount) + return tx_.isFieldPresent(sfOnBehalfOf) ? *tx_[~sfOnBehalfOf] + : tx_[sfAccount]; + return tx_[f]; + } + + template + std::optional> + operator[](OptionaledField const& of) const + { + return tx_[of]; + } + + uint256 + getTransactionID() const + { + return tx_.getTransactionID(); + } + + TxType + getTxnType() const + { + return tx_.getTxnType(); + } + + std::uint32_t + getFlags() const + { + return tx_.getFlags(); + } + + bool + isFieldPresent(SField const& field) const + { + return tx_.isFieldPresent(field); + } + + Json::Value + getJson(JsonOptions options) const + { + return tx_.getJson(options); + } + + void + add(Serializer& s) const + { + tx_.add(s); + } + + unsigned char + getFieldU8(SField const& field) const + { + return tx_.getFieldU8(field); + } + + std::uint32_t + getFieldU32(SField const& field) const + { + return tx_.getFieldU32(field); + } + + uint256 + getFieldH256(SField const& field) const + { + return tx_.getFieldH256(field); + } + + Blob + getFieldVL(SField const& field) const + { + return tx_.getFieldVL(field); + } + + STAmount const& + getFieldAmount(SField const& field) const + { + return tx_.getFieldAmount(field); + } + + STPathSet const& + getFieldPathSet(SField const& field) const + { + return tx_.getFieldPathSet(field); + } + + const STVector256& + getFieldV256(SField const& field) const + { + return tx_.getFieldV256(field); + } + + const STArray& + getFieldArray(SField const& field) const + { + return tx_.getFieldArray(field); + } + + Blob + getSigningPubKey() const + { + return tx_.getSigningPubKey(); + } + + Blob + getSignature() const + { + return tx_.getSignature(); + } + + bool + isFlag(std::uint32_t f) const + { + return tx_.isFlag(f); + } + + SeqProxy + getSeqProxy() const + { + return tx_.getSeqProxy(); + } +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index fc1a2e68e2b..ce9827f8186 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -170,6 +170,7 @@ JSS(attestations); JSS(attestation_reward_account); JSS(auction_slot); // out: amm_info JSS(authorized); // out: AccountLines +JSS(authorize); // out: account_permission JSS(authorized_credentials); // in: ledger_entry DepositPreauth JSS(auth_accounts); // out: amm_info JSS(auth_change); // out: AccountInfo diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 80ca58a3897..d63dff10fb8 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -77,7 +77,7 @@ enum class LedgerNameSpace : std::uint16_t { MPTOKEN_ISSUANCE = '~', MPTOKEN = 't', CREDENTIAL = 'D', - ACCOUNT_PERMISSION = 'P', + ACCOUNT_PERMISSION = 'E', // No longer used or supported. Left here to reserve the space // to avoid accidental reuse. diff --git a/src/libxrpl/protocol/Permissions.cpp b/src/libxrpl/protocol/Permissions.cpp index 12ea4b12242..92f26acafdb 100644 --- a/src/libxrpl/protocol/Permissions.cpp +++ b/src/libxrpl/protocol/Permissions.cpp @@ -27,32 +27,32 @@ namespace ripple { Permission::Permission() { granularPermissionMap = { - {"TrustlineAuthorize", gpTrustlineAuthorize}, - {"TrustlineFreeze", gpTrustlineFreeze}, - {"TrustlineUnfreeze", gpTrustlineUnfreeze}, - {"AccountDomainSet", gpAccountDomainSet}, - {"AccountEmailHashSet", gpAccountEmailHashSet}, - {"AccountMessageKeySet", gpAccountMessageKeySet}, - {"AccountTransferRateSet", gpAccountTransferRateSet}, - {"AccountTickSizeSet", gpAccountTickSizeSet}, - {"PaymentMint", gpPaymentMint}, - {"PaymentBurn", gpPaymentBurn}, - {"MPTokenIssuanceLock", gpMPTokenIssuanceLock}, - {"MPTokenIssuanceUnlock", gpMPTokenIssuanceUnlock}}; + {"TrustlineAuthorize", TrustlineAuthorize}, + {"TrustlineFreeze", TrustlineFreeze}, + {"TrustlineUnfreeze", TrustlineUnfreeze}, + {"AccountDomainSet", AccountDomainSet}, + {"AccountEmailHashSet", AccountEmailHashSet}, + {"AccountMessageKeySet", AccountMessageKeySet}, + {"AccountTransferRateSet", AccountTransferRateSet}, + {"AccountTickSizeSet", AccountTickSizeSet}, + {"PaymentMint", PaymentMint}, + {"PaymentBurn", PaymentBurn}, + {"MPTokenIssuanceLock", MPTokenIssuanceLock}, + {"MPTokenIssuanceUnlock", MPTokenIssuanceUnlock}}; granularTxTypeMap = { - {gpTrustlineAuthorize, ttTRUST_SET}, - {gpTrustlineFreeze, ttTRUST_SET}, - {gpTrustlineUnfreeze, ttTRUST_SET}, - {gpAccountDomainSet, ttACCOUNT_SET}, - {gpAccountEmailHashSet, ttACCOUNT_SET}, - {gpAccountMessageKeySet, ttACCOUNT_SET}, - {gpAccountTransferRateSet, ttACCOUNT_SET}, - {gpAccountTickSizeSet, ttACCOUNT_SET}, - {gpPaymentMint, ttPAYMENT}, - {gpPaymentBurn, ttPAYMENT}, - {gpMPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET}, - {gpMPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET}}; + {TrustlineAuthorize, ttTRUST_SET}, + {TrustlineFreeze, ttTRUST_SET}, + {TrustlineUnfreeze, ttTRUST_SET}, + {AccountDomainSet, ttACCOUNT_SET}, + {AccountEmailHashSet, ttACCOUNT_SET}, + {AccountMessageKeySet, ttACCOUNT_SET}, + {AccountTransferRateSet, ttACCOUNT_SET}, + {AccountTickSizeSet, ttACCOUNT_SET}, + {PaymentMint, ttPAYMENT}, + {PaymentBurn, ttPAYMENT}, + {MPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET}, + {MPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET}}; } Permission const& diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index a6232417aa0..c32127a4531 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -3304,10 +3304,9 @@ struct AMM_test : public jtx::AMMTest env.app().config().features.erase(featureAMM); PreflightContext pfctx( env.app(), - *jtx.stx, + STTxWr(*jtx.stx, false), env.current()->rules(), tapNONE, - AccountID(0), env.journal); auto pf = AMMBid::preflight(pfctx); BEAST_EXPECT(pf == temDISABLED); @@ -3320,10 +3319,9 @@ struct AMM_test : public jtx::AMMTest jtx.stx = env.ust(jtx); PreflightContext pfctx( env.app(), - *jtx.stx, + STTxWr(*jtx.stx, false), env.current()->rules(), tapNONE, - AccountID(0), env.journal); auto pf = AMMBid::preflight(pfctx); BEAST_EXPECT(pf != tesSUCCESS); @@ -3336,10 +3334,9 @@ struct AMM_test : public jtx::AMMTest jtx.stx = env.ust(jtx); PreflightContext pfctx( env.app(), - *jtx.stx, + STTxWr(*jtx.stx, false), env.current()->rules(), tapNONE, - AccountID(0), env.journal); auto pf = AMMBid::preflight(pfctx); BEAST_EXPECT(pf == temBAD_AMM_TOKENS); diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 714fc7734d9..2af6be94cd8 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -1331,7 +1331,7 @@ struct Escrow_test : public beast::unit_test::suite auto const pf = preflight( env.app(), env.current()->rules(), - *jtx.stx, + STTxWr(*jtx.stx, false), tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); @@ -1345,7 +1345,7 @@ struct Escrow_test : public beast::unit_test::suite auto const pf = preflight( env.app(), env.current()->rules(), - *jtx.stx, + STTxWr(*jtx.stx, false), tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); @@ -1359,7 +1359,7 @@ struct Escrow_test : public beast::unit_test::suite auto const pf = preflight( env.app(), env.current()->rules(), - *jtx.stx, + STTxWr(*jtx.stx, false), tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index f7c8a80f332..3fceb822d21 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -807,12 +807,10 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite ApplyContext ac{ env.app(), ov, - tx, + STTxWr(tx, false), tesSUCCESS, env.current()->fees().base, tapNONE, - false, - AccountID(0), std::unordered_set{}, jlog}; @@ -854,12 +852,10 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite ApplyContext ac{ env.app(), ov, - tx, + STTxWr(tx, false), tesSUCCESS, env.current()->fees().base, tapNONE, - false, - AccountID(0), std::unordered_set{}, jlog}; diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index e7b70203c91..3fb5eeb1d79 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -2491,7 +2491,7 @@ class TxQPosNegFlows_test : public beast::unit_test::suite auto const pf = preflight( env.app(), env.current()->rules(), - *jtx.stx, + STTxWr(*jtx.stx, false), tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); @@ -2508,7 +2508,7 @@ class TxQPosNegFlows_test : public beast::unit_test::suite auto const pf = preflight( env.app(), env.current()->rules(), - *jtx.stx, + STTxWr(*jtx.stx, false), tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); @@ -2522,7 +2522,7 @@ class TxQPosNegFlows_test : public beast::unit_test::suite auto const pf = preflight( env.app(), env.current()->rules(), - *jtx.stx, + STTxWr(*jtx.stx, false), tapNONE, env.journal); BEAST_EXPECT(pf.ter == tesSUCCESS); diff --git a/src/test/ledger/Invariants_test.cpp b/src/test/ledger/Invariants_test.cpp index fb12e2d24fe..94f906dff7f 100644 --- a/src/test/ledger/Invariants_test.cpp +++ b/src/test/ledger/Invariants_test.cpp @@ -94,12 +94,10 @@ class Invariants_test : public beast::unit_test::suite ApplyContext ac{ env.app(), ov, - tx, + STTxWr(tx, false), tesSUCCESS, env.current()->fees().base, tapNONE, - false, - AccountID(0), std::unordered_set{}, jlog}; diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp index e1ad68dff37..1f4fe41951e 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp @@ -56,7 +56,9 @@ AcceptedLedgerTx::AcceptedLedgerTx( if (mTxn->getTxnType() == ttOFFER_CREATE) { - auto const& account = mTxn->getAccountID(sfAccount); + auto const& account = mTxn->isFieldPresent(sfOnBehalfOf) + ? mTxn->getAccountID(sfOnBehalfOf) + : mTxn->getAccountID(sfAccount); auto const amount = mTxn->getFieldAmount(sfTakerGets); // If the offer create is not self funded then add the owner balance diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 3f6869df1d8..eda1cfc0b22 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -206,7 +206,9 @@ fillJsonTx( if ((fill.options & LedgerFill::ownerFunds) && txn->getTxnType() == ttOFFER_CREATE) { - auto const account = txn->getAccountID(sfAccount); + auto const& account = txn->isFieldPresent(sfOnBehalfOf) + ? txn->getAccountID(sfOnBehalfOf) + : txn->getAccountID(sfAccount); auto const amount = txn->getFieldAmount(sfTakerGets); // If the offer create is not self funded then add the diff --git a/src/xrpld/app/ledger/detail/LocalTxs.cpp b/src/xrpld/app/ledger/detail/LocalTxs.cpp index a6eb7721a3e..aaeb6245415 100644 --- a/src/xrpld/app/ledger/detail/LocalTxs.cpp +++ b/src/xrpld/app/ledger/detail/LocalTxs.cpp @@ -62,7 +62,10 @@ class LocalTx : m_txn(txn) , m_expire(index + holdLedgers) , m_id(txn->getTransactionID()) - , m_account(txn->getAccountID(sfAccount)) + , m_account( + txn->isFieldPresent(sfOnBehalfOf) + ? txn->getAccountID(sfOnBehalfOf) + : txn->getAccountID(sfAccount)) , m_seqProxy(txn->getSeqProxy()) { if (txn->isFieldPresent(sfLastLedgerSequence)) diff --git a/src/xrpld/app/misc/CredentialHelpers.cpp b/src/xrpld/app/misc/CredentialHelpers.cpp index 08b5d804d4b..032f8eb94ac 100644 --- a/src/xrpld/app/misc/CredentialHelpers.cpp +++ b/src/xrpld/app/misc/CredentialHelpers.cpp @@ -243,7 +243,7 @@ verifyDepositPreauth( bool const credentialsPresent = ctx.tx.isFieldPresent(sfCredentialIDs); if (credentialsPresent && - credentials::removeExpired(ctx.view(), ctx.tx, ctx.journal)) + credentials::removeExpired(ctx.view(), ctx.tx.getTx(), ctx.journal)) return tecEXPIRED; if (sleDst && (sleDst->getFlags() & lsfDepositAuth)) diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index d647df91f1e..6c598343988 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -2993,7 +2993,9 @@ NetworkOPsImp::transJson( if (transaction->getTxnType() == ttOFFER_CREATE) { - auto const account = transaction->getAccountID(sfAccount); + auto const& account = transaction->isFieldPresent(sfOnBehalfOf) + ? transaction->getAccountID(sfOnBehalfOf) + : transaction->getAccountID(sfAccount); auto const amount = transaction->getFieldAmount(sfTakerGets); // If the offer create is not self funded then add the owner balance diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index a4e62b382a7..e1b28caf449 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -736,7 +736,10 @@ TxQ::apply( // See if the transaction is valid, properly formed, // etc. before doing potentially expensive queue // replace and multi-transaction operations. - auto const pfresult = preflight(app, view.rules(), *tx, flags, j); + bool const isDelegated = view.rules().enabled(featureAccountPermission) && + tx->isFieldPresent(sfOnBehalfOf); + STTxWr txWr(*tx, isDelegated); + auto const pfresult = preflight(app, view.rules(), txWr, flags, j); if (pfresult.ter != tesSUCCESS) return {pfresult.ter, false}; diff --git a/src/xrpld/app/tx/apply.h b/src/xrpld/app/tx/apply.h index 6a0401e2b55..73093e8db30 100644 --- a/src/xrpld/app/tx/apply.h +++ b/src/xrpld/app/tx/apply.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/app/tx/applySteps.h b/src/xrpld/app/tx/applySteps.h index cc23b8aca39..07c2918e73a 100644 --- a/src/xrpld/app/tx/applySteps.h +++ b/src/xrpld/app/tx/applySteps.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ripple { @@ -152,7 +153,7 @@ struct PreflightResult { public: /// From the input - the transaction - STTx const& tx; + STTxWr const& tx; /// From the input - the rules Rules const rules; /// Consequences of the transaction @@ -161,10 +162,6 @@ struct PreflightResult ApplyFlags const flags; /// From the input - the journal beast::Journal const j; - /// If the transaction is a delegated transaction - bool const isDelegated; - /// the account that the transaction is operated on - AccountID const account; /// Intermediate transaction result NotTEC const ter; @@ -172,16 +169,12 @@ struct PreflightResult template PreflightResult( Context const& ctx_, - bool const isDelegated, - AccountID const account, std::pair const& result) : tx(ctx_.tx) , rules(ctx_.rules) , consequences(result.second) , flags(ctx_.flags) , j(ctx_.j) - , isDelegated(isDelegated) - , account(account) , ter(result.first) { } @@ -204,21 +197,17 @@ struct PreclaimResult /// From the input - the ledger view ReadView const& view; /// From the input - the transaction - STTx const& tx; + STTxWr const& tx; /// From the input - the flags ApplyFlags const flags; /// From the input - the journal beast::Journal const j; - /// If the transaction is a delegated transaction - bool const isDelegated; - /// the account that the transaction is operated on - AccountID const account; /// Intermediate transaction result TER const ter; /// granular permissions enabled for the transaction. If empty and /// isDelegated=true, then the entire transaction is authorized. - std::unordered_set gpSet; + std::unordered_set permissions; /// Success flag - whether the transaction is likely to /// claim a fee bool const likelyToClaimFee; @@ -228,15 +217,13 @@ struct PreclaimResult PreclaimResult( Context const& ctx_, TER ter_, - std::unordered_set gpSet_) + std::unordered_set permissions_) : view(ctx_.view) , tx(ctx_.tx) , flags(ctx_.flags) , j(ctx_.j) - , isDelegated(ctx_.isDelegated) - , account(ctx_.account) , ter(ter_) - , gpSet(std::move(gpSet_)) + , permissions(std::move(permissions_)) , likelyToClaimFee(ter == tesSUCCESS || isTecClaimHardFail(ter, flags)) { } @@ -267,7 +254,7 @@ PreflightResult preflight( Application& app, Rules const& rules, - STTx const& tx, + STTxWr const& tx, ApplyFlags flags, beast::Journal j); diff --git a/src/xrpld/app/tx/detail/AMMBid.cpp b/src/xrpld/app/tx/detail/AMMBid.cpp index 66496b4dc1e..9de3762d2e3 100644 --- a/src/xrpld/app/tx/detail/AMMBid.cpp +++ b/src/xrpld/app/tx/detail/AMMBid.cpp @@ -110,7 +110,8 @@ AMMBid::preclaim(PreclaimContext const& ctx) } } - auto const lpTokens = ammLPHolds(ctx.view, *ammSle, ctx.account, ctx.j); + auto const lpTokens = + ammLPHolds(ctx.view, *ammSle, ctx.tx[sfAccount], ctx.j); // Not LP if (lpTokens == beast::zero) { diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp index d3f4c94b1cf..64150ded6da 100644 --- a/src/xrpld/app/tx/detail/AMMClawback.cpp +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -45,7 +45,7 @@ AMMClawback::preflight(PreflightContext const& ctx) if (ctx.tx.getFlags() & tfAMMClawbackMask) return temINVALID_FLAG; - AccountID const issuer = ctx.account; + AccountID const issuer = ctx.tx[sfAccount]; AccountID const holder = ctx.tx[sfHolder]; if (issuer == holder) @@ -86,7 +86,7 @@ AMMClawback::preclaim(PreclaimContext const& ctx) { auto const asset = ctx.tx[sfAsset]; auto const asset2 = ctx.tx[sfAsset2]; - auto const sleIssuer = ctx.view.read(keylet::account(ctx.account)); + auto const sleIssuer = ctx.view.read(keylet::account(ctx.tx[sfAccount])); if (!sleIssuer) return terNO_ACCOUNT; // LCOV_EXCL_LINE @@ -136,6 +136,7 @@ TER AMMClawback::applyGuts(Sandbox& sb) { std::optional const clawAmount = ctx_.tx[~sfAmount]; + AccountID const issuer = ctx_.tx[sfAccount]; AccountID const holder = ctx_.tx[sfHolder]; Issue const asset = ctx_.tx[sfAsset]; Issue const asset2 = ctx_.tx[sfAsset2]; @@ -215,8 +216,7 @@ AMMClawback::applyGuts(Sandbox& sb) << to_string(newLPTokenBalance.iou()) << " old balance: " << to_string(lptAMMBalance.iou()); - auto const ter = - rippleCredit(sb, holder, account_, amountWithdraw, true, j_); + auto const ter = rippleCredit(sb, holder, issuer, amountWithdraw, true, j_); if (ter != tesSUCCESS) return ter; // LCOV_EXCL_LINE @@ -229,7 +229,7 @@ AMMClawback::applyGuts(Sandbox& sb) auto const flags = ctx_.tx.getFlags(); if (flags & tfClawTwoAssets) - return rippleCredit(sb, holder, account_, *amount2Withdraw, true, j_); + return rippleCredit(sb, holder, issuer, *amount2Withdraw, true, j_); return tesSUCCESS; } diff --git a/src/xrpld/app/tx/detail/AMMCreate.cpp b/src/xrpld/app/tx/detail/AMMCreate.cpp index 5aeb630445e..31773166d4a 100644 --- a/src/xrpld/app/tx/detail/AMMCreate.cpp +++ b/src/xrpld/app/tx/detail/AMMCreate.cpp @@ -88,7 +88,7 @@ AMMCreate::calculateBaseFee(ReadView const& view, STTx const& tx) TER AMMCreate::preclaim(PreclaimContext const& ctx) { - auto const accountID = ctx.account; + auto const accountID = ctx.tx[sfAccount]; auto const amount = ctx.tx[sfAmount]; auto const amount2 = ctx.tx[sfAmount2]; diff --git a/src/xrpld/app/tx/detail/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp index 334a34a7909..3448401eb79 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.cpp +++ b/src/xrpld/app/tx/detail/AMMDeposit.cpp @@ -168,7 +168,7 @@ AMMDeposit::preflight(PreflightContext const& ctx) TER AMMDeposit::preclaim(PreclaimContext const& ctx) { - auto const accountID = ctx.account; + auto const accountID = ctx.tx[sfAccount]; auto const ammSle = ctx.view.read(keylet::amm(ctx.tx[sfAsset], ctx.tx[sfAsset2])); diff --git a/src/xrpld/app/tx/detail/AMMVote.cpp b/src/xrpld/app/tx/detail/AMMVote.cpp index 70a24789940..c4b6c612c63 100644 --- a/src/xrpld/app/tx/detail/AMMVote.cpp +++ b/src/xrpld/app/tx/detail/AMMVote.cpp @@ -72,7 +72,7 @@ AMMVote::preclaim(PreclaimContext const& ctx) else if (ammSle->getFieldAmount(sfLPTokenBalance) == beast::zero) return tecAMM_EMPTY; else if (auto const lpTokensNew = - ammLPHolds(ctx.view, *ammSle, ctx.account, ctx.j); + ammLPHolds(ctx.view, *ammSle, ctx.tx[sfAccount], ctx.j); lpTokensNew == beast::zero) { JLOG(ctx.j.debug()) << "AMM Vote: account is not LP."; diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index f53d64ee062..a6372e5c148 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -170,7 +170,7 @@ tokensWithdraw( TER AMMWithdraw::preclaim(PreclaimContext const& ctx) { - auto const accountID = ctx.account; + auto const accountID = ctx.tx[sfAccount]; auto const ammSle = ctx.view.read(keylet::amm(ctx.tx[sfAsset], ctx.tx[sfAsset2])); @@ -304,7 +304,7 @@ AMMWithdraw::applyGuts(Sandbox& sb) if (!accountSle) return {tecINTERNAL, false}; // LCOV_EXCL_LINE auto const lpTokens = - ammLPHolds(ctx_.view(), *ammSle, account_, ctx_.journal); + ammLPHolds(ctx_.view(), *ammSle, ctx_.tx[sfAccount], ctx_.journal); auto const lpTokensWithdraw = tokensWithdraw(lpTokens, ctx_.tx[~sfLPTokenIn], ctx_.tx.getFlags()); @@ -470,7 +470,7 @@ AMMWithdraw::withdraw( lpTokensWithdraw, tfee, FreezeHandling::fhZERO_IF_FROZEN, - isWithdrawAll(ctx_.tx), + isWithdrawAll(ctx_.tx.getTx()), mPriorBalance, j_); return {ter, newLPTokenBalance}; @@ -707,7 +707,7 @@ AMMWithdraw::equalWithdrawTokens( lpTokensWithdraw, tfee, FreezeHandling::fhZERO_IF_FROZEN, - isWithdrawAll(ctx_.tx), + isWithdrawAll(ctx_.tx.getTx()), mPriorBalance, ctx_.journal); return {ter, newLPTokenBalance}; diff --git a/src/xrpld/app/tx/detail/AccountPermissionSet.cpp b/src/xrpld/app/tx/detail/AccountPermissionSet.cpp index 1d31b9f1e57..33bb0f533f7 100644 --- a/src/xrpld/app/tx/detail/AccountPermissionSet.cpp +++ b/src/xrpld/app/tx/detail/AccountPermissionSet.cpp @@ -46,11 +46,6 @@ AccountPermissionSet::preflight(PreflightContext const& ctx) for (auto const& permission : permissions) { - auto permissionObj = dynamic_cast(&permission); - - if (!permissionObj || (permissionObj->getFName() != sfPermission)) - return temMALFORMED; - auto const permissionValue = permission[sfPermissionValue]; if (permissionSet.find(permissionValue) != permissionSet.end()) @@ -65,7 +60,7 @@ AccountPermissionSet::preflight(PreflightContext const& ctx) TER AccountPermissionSet::preclaim(PreclaimContext const& ctx) { - auto const account = ctx.view.read(keylet::account(ctx.account)); + auto const account = ctx.view.read(keylet::account(ctx.tx[sfAccount])); if (!account) return terNO_ACCOUNT; // LCOV_EXCL_LINE diff --git a/src/xrpld/app/tx/detail/ApplyContext.cpp b/src/xrpld/app/tx/detail/ApplyContext.cpp index ac73bc499f5..54ccdfde2db 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.cpp +++ b/src/xrpld/app/tx/detail/ApplyContext.cpp @@ -31,21 +31,17 @@ namespace ripple { ApplyContext::ApplyContext( Application& app_, OpenView& base, - STTx const& tx_, + STTxWr const& tx_, TER preclaimResult_, XRPAmount baseFee_, ApplyFlags flags, - bool isDelegated, - AccountID const account, - std::unordered_set const gpSet, + std::unordered_set const permissions, beast::Journal journal_) : app(app_) , tx(tx_) , preclaimResult(preclaimResult_) , baseFee(baseFee_) - , isDelegated(isDelegated) - , account(account) - , gpSet(std::move(gpSet)) + , permissions(std::move(permissions)) , journal(journal_) , base_(base) , flags_(flags) @@ -62,7 +58,7 @@ ApplyContext::discard() void ApplyContext::apply(TER ter) { - view_->apply(base_, tx, ter, journal); + view_->apply(base_, tx.getTx(), ter, journal); } std::size_t diff --git a/src/xrpld/app/tx/detail/ApplyContext.h b/src/xrpld/app/tx/detail/ApplyContext.h index 5ee3f1f092b..2f8a287acf7 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.h +++ b/src/xrpld/app/tx/detail/ApplyContext.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -39,22 +39,18 @@ class ApplyContext explicit ApplyContext( Application& app, OpenView& base, - STTx const& tx, + STTxWr const& tx, TER preclaimResult, XRPAmount baseFee, ApplyFlags flags, - bool isDelegated, - AccountID const account, - std::unordered_set const gpSet, + std::unordered_set const permissions, beast::Journal = beast::Journal{beast::Journal::getNullSink()}); Application& app; - STTx const& tx; + STTxWr const& tx; TER const preclaimResult; XRPAmount const baseFee; - bool isDelegated; - AccountID const account; - std::unordered_set gpSet; + std::unordered_set permissions; beast::Journal const journal; ApplyView& diff --git a/src/xrpld/app/tx/detail/CancelCheck.cpp b/src/xrpld/app/tx/detail/CancelCheck.cpp index 39231e70e54..7954e86cf3b 100644 --- a/src/xrpld/app/tx/detail/CancelCheck.cpp +++ b/src/xrpld/app/tx/detail/CancelCheck.cpp @@ -73,7 +73,7 @@ CancelCheck::preclaim(PreclaimContext const& ctx) { // If the check is not yet expired, then only the creator or the // destination may cancel the check. - AccountID const acctId{ctx.account}; + AccountID const acctId{ctx.tx[sfAccount]}; if (acctId != (*sleCheck)[sfAccount] && acctId != (*sleCheck)[sfDestination]) { diff --git a/src/xrpld/app/tx/detail/CancelOffer.cpp b/src/xrpld/app/tx/detail/CancelOffer.cpp index f693f4cb394..30e955a8282 100644 --- a/src/xrpld/app/tx/detail/CancelOffer.cpp +++ b/src/xrpld/app/tx/detail/CancelOffer.cpp @@ -53,7 +53,7 @@ CancelOffer::preflight(PreflightContext const& ctx) TER CancelOffer::preclaim(PreclaimContext const& ctx) { - auto const id = ctx.account; + auto const id = ctx.tx[sfAccount]; auto const offerSequence = ctx.tx[sfOfferSequence]; auto const sle = ctx.view.read(keylet::account(id)); diff --git a/src/xrpld/app/tx/detail/CashCheck.cpp b/src/xrpld/app/tx/detail/CashCheck.cpp index 776396b3e94..cbf30803abd 100644 --- a/src/xrpld/app/tx/detail/CashCheck.cpp +++ b/src/xrpld/app/tx/detail/CashCheck.cpp @@ -91,7 +91,7 @@ CashCheck::preclaim(PreclaimContext const& ctx) // Only cash a check with this account as the destination. AccountID const dstId = sleCheck->at(sfDestination); - if (ctx.account != dstId) + if (ctx.tx[sfAccount] != dstId) { JLOG(ctx.j.warn()) << "Cashing a check with wrong Destination."; return tecNO_PERMISSION; @@ -138,7 +138,7 @@ CashCheck::preclaim(PreclaimContext const& ctx) STAmount const value{[](STTx const& tx) { auto const optAmount = tx[~sfAmount]; return optAmount ? *optAmount : tx[sfDeliverMin]; - }(ctx.tx)}; + }(ctx.tx.getTx())}; STAmount const sendMax = sleCheck->at(sfSendMax); Currency const currency{value.getCurrency()}; diff --git a/src/xrpld/app/tx/detail/Change.cpp b/src/xrpld/app/tx/detail/Change.cpp index a924fbe0c96..0b466999e04 100644 --- a/src/xrpld/app/tx/detail/Change.cpp +++ b/src/xrpld/app/tx/detail/Change.cpp @@ -38,7 +38,7 @@ Change::preflight(PreflightContext const& ctx) if (!isTesSuccess(ret)) return ret; - auto account = ctx.account; + auto account = ctx.tx.getAccountID(sfAccount); if (account != beast::zero) { JLOG(ctx.j.warn()) << "Change: Bad source id"; @@ -358,9 +358,9 @@ Change::applyFee() }; if (view().rules().enabled(featureXRPFees)) { - set(feeObject, ctx_.tx, sfBaseFeeDrops); - set(feeObject, ctx_.tx, sfReserveBaseDrops); - set(feeObject, ctx_.tx, sfReserveIncrementDrops); + set(feeObject, ctx_.tx.getTx(), sfBaseFeeDrops); + set(feeObject, ctx_.tx.getTx(), sfReserveBaseDrops); + set(feeObject, ctx_.tx.getTx(), sfReserveIncrementDrops); // Ensure the old fields are removed feeObject->makeFieldAbsent(sfBaseFee); feeObject->makeFieldAbsent(sfReferenceFeeUnits); @@ -369,10 +369,10 @@ Change::applyFee() } else { - set(feeObject, ctx_.tx, sfBaseFee); - set(feeObject, ctx_.tx, sfReferenceFeeUnits); - set(feeObject, ctx_.tx, sfReserveBase); - set(feeObject, ctx_.tx, sfReserveIncrement); + set(feeObject, ctx_.tx.getTx(), sfBaseFee); + set(feeObject, ctx_.tx.getTx(), sfReferenceFeeUnits); + set(feeObject, ctx_.tx.getTx(), sfReserveBase); + set(feeObject, ctx_.tx.getTx(), sfReserveIncrement); } view().update(feeObject); diff --git a/src/xrpld/app/tx/detail/Clawback.cpp b/src/xrpld/app/tx/detail/Clawback.cpp index 332d039932c..f1040790a42 100644 --- a/src/xrpld/app/tx/detail/Clawback.cpp +++ b/src/xrpld/app/tx/detail/Clawback.cpp @@ -39,7 +39,7 @@ preflightHelper(PreflightContext const& ctx) if (ctx.tx.isFieldPresent(sfHolder)) return temMALFORMED; - AccountID const issuer = ctx.account; + AccountID const issuer = ctx.tx[sfAccount]; STAmount const clawAmount = ctx.tx[sfAmount]; // The issuer field is used for the token holder instead @@ -65,7 +65,7 @@ preflightHelper(PreflightContext const& ctx) return temMALFORMED; // issuer is the same as holder - if (ctx.account == *mptHolder) + if (ctx.tx[sfAccount] == *mptHolder) return temMALFORMED; if (clawAmount.mpt() > MPTAmount{maxMPTokenAmount} || @@ -197,7 +197,7 @@ preclaimHelper( TER Clawback::preclaim(PreclaimContext const& ctx) { - AccountID const issuer = ctx.account; + AccountID const issuer = ctx.tx[sfAccount]; auto const clawAmount = ctx.tx[sfAmount]; AccountID const holder = clawAmount.holds() ? clawAmount.getIssuer() : ctx.tx[sfHolder]; @@ -226,7 +226,7 @@ template <> TER applyHelper(ApplyContext& ctx) { - AccountID const issuer = ctx.account; + AccountID const issuer = ctx.tx[sfAccount]; STAmount clawAmount = ctx.tx[sfAmount]; AccountID const holder = clawAmount.getIssuer(); // cannot be reference @@ -257,7 +257,7 @@ template <> TER applyHelper(ApplyContext& ctx) { - AccountID const issuer = ctx.account; + AccountID const issuer = ctx.tx[sfAccount]; auto clawAmount = ctx.tx[sfAmount]; AccountID const holder = ctx.tx[sfHolder]; diff --git a/src/xrpld/app/tx/detail/CreateCheck.cpp b/src/xrpld/app/tx/detail/CreateCheck.cpp index bf3c97953fc..3a278eed738 100644 --- a/src/xrpld/app/tx/detail/CreateCheck.cpp +++ b/src/xrpld/app/tx/detail/CreateCheck.cpp @@ -44,7 +44,7 @@ CreateCheck::preflight(PreflightContext const& ctx) JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set."; return temINVALID_FLAG; } - if (ctx.account == ctx.tx[sfDestination]) + if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) { // They wrote a check to themselves. JLOG(ctx.j.warn()) << "Malformed transaction: Check to self."; @@ -125,7 +125,7 @@ CreateCheck::preclaim(PreclaimContext const& ctx) // // Note that we DO allow create check for a currency that the // account does not yet have a trustline to. - AccountID const srcId{ctx.account}; + AccountID const srcId{ctx.tx.getAccountID(sfAccount)}; if (issuerId != srcId) { // Check if the issuer froze the line diff --git a/src/xrpld/app/tx/detail/CreateOffer.cpp b/src/xrpld/app/tx/detail/CreateOffer.cpp index 65028b65de1..712303ddd00 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.cpp +++ b/src/xrpld/app/tx/detail/CreateOffer.cpp @@ -36,7 +36,7 @@ CreateOffer::makeTxConsequences(PreflightContext const& ctx) return amount.native() ? amount.xrp() : beast::zero; }; - return TxConsequences{ctx.tx, calculateMaxXRPSpend(ctx.tx)}; + return TxConsequences{ctx.tx.getTx(), calculateMaxXRPSpend(ctx.tx.getTx())}; } NotTEC @@ -128,7 +128,7 @@ CreateOffer::preflight(PreflightContext const& ctx) TER CreateOffer::preclaim(PreclaimContext const& ctx) { - auto const id = ctx.account; + auto const id = ctx.tx[sfAccount]; auto saTakerPays = ctx.tx[sfTakerPays]; auto saTakerGets = ctx.tx[sfTakerGets]; diff --git a/src/xrpld/app/tx/detail/CreateTicket.cpp b/src/xrpld/app/tx/detail/CreateTicket.cpp index b045498b183..ab6b277d7ce 100644 --- a/src/xrpld/app/tx/detail/CreateTicket.cpp +++ b/src/xrpld/app/tx/detail/CreateTicket.cpp @@ -31,7 +31,7 @@ TxConsequences CreateTicket::makeTxConsequences(PreflightContext const& ctx) { // Create TxConsequences identifying the number of sequences consumed. - return TxConsequences{ctx.tx, ctx.tx[sfTicketCount]}; + return TxConsequences{ctx.tx.getTx(), ctx.tx[sfTicketCount]}; } NotTEC @@ -56,7 +56,7 @@ CreateTicket::preflight(PreflightContext const& ctx) TER CreateTicket::preclaim(PreclaimContext const& ctx) { - auto const id = ctx.account; + auto const id = ctx.tx[sfAccount]; auto const sleAccountRoot = ctx.view.read(keylet::account(id)); if (!sleAccountRoot) return terNO_ACCOUNT; diff --git a/src/xrpld/app/tx/detail/Credentials.cpp b/src/xrpld/app/tx/detail/Credentials.cpp index 7de89bd783f..4da875f8d7c 100644 --- a/src/xrpld/app/tx/detail/Credentials.cpp +++ b/src/xrpld/app/tx/detail/Credentials.cpp @@ -101,7 +101,8 @@ CredentialCreate::preclaim(PreclaimContext const& ctx) return tecNO_TARGET; } - if (ctx.view.exists(keylet::credential(subject, ctx.account, credType))) + if (ctx.view.exists( + keylet::credential(subject, ctx.tx[sfAccount], credType))) { JLOG(ctx.j.trace()) << "Credential already exists."; return tecDUPLICATE; @@ -241,7 +242,7 @@ CredentialDelete::preflight(PreflightContext const& ctx) TER CredentialDelete::preclaim(PreclaimContext const& ctx) { - AccountID const account{ctx.account}; + AccountID const account{ctx.tx[sfAccount]}; auto const subject = ctx.tx[~sfSubject].value_or(account); auto const issuer = ctx.tx[~sfIssuer].value_or(account); auto const credType(ctx.tx[sfCredentialType]); @@ -308,7 +309,7 @@ CredentialAccept::preflight(PreflightContext const& ctx) TER CredentialAccept::preclaim(PreclaimContext const& ctx) { - AccountID const subject = ctx.account; + AccountID const subject = ctx.tx[sfAccount]; AccountID const issuer = ctx.tx[sfIssuer]; auto const credType(ctx.tx[sfCredentialType]); diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index 90fca354215..68f5bd20794 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -53,7 +53,7 @@ DeleteAccount::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; - if (ctx.account == ctx.tx[sfDestination]) + if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) // An account cannot be deleted and give itself the resulting XRP. return temDST_IS_SRC; @@ -229,7 +229,7 @@ nonObligationDeleter(LedgerEntryType t) TER DeleteAccount::preclaim(PreclaimContext const& ctx) { - AccountID const account{ctx.account}; + AccountID const account{ctx.tx[sfAccount]}; AccountID const dst{ctx.tx[sfDestination]}; auto sleDst = ctx.view.read(keylet::account(dst)); diff --git a/src/xrpld/app/tx/detail/DeleteOracle.cpp b/src/xrpld/app/tx/detail/DeleteOracle.cpp index 0b9b25103bb..807e52ee6b4 100644 --- a/src/xrpld/app/tx/detail/DeleteOracle.cpp +++ b/src/xrpld/app/tx/detail/DeleteOracle.cpp @@ -47,17 +47,17 @@ DeleteOracle::preflight(PreflightContext const& ctx) TER DeleteOracle::preclaim(PreclaimContext const& ctx) { - if (!ctx.view.exists(keylet::account(ctx.account))) + if (!ctx.view.exists(keylet::account(ctx.tx.getAccountID(sfAccount)))) return terNO_ACCOUNT; // LCOV_EXCL_LINE - if (auto const sle = ctx.view.read( - keylet::oracle(ctx.account, ctx.tx[sfOracleDocumentID])); + if (auto const sle = ctx.view.read(keylet::oracle( + ctx.tx.getAccountID(sfAccount), ctx.tx[sfOracleDocumentID])); !sle) { JLOG(ctx.j.debug()) << "Oracle Delete: Oracle does not exist."; return tecNO_ENTRY; } - else if (ctx.account != sle->getAccountID(sfOwner)) + else if (ctx.tx.getAccountID(sfAccount) != sle->getAccountID(sfOwner)) { // this can't happen because of the above check // LCOV_EXCL_START diff --git a/src/xrpld/app/tx/detail/DepositPreauth.cpp b/src/xrpld/app/tx/detail/DepositPreauth.cpp index 57bef6db4dd..73cd19e4120 100644 --- a/src/xrpld/app/tx/detail/DepositPreauth.cpp +++ b/src/xrpld/app/tx/detail/DepositPreauth.cpp @@ -85,7 +85,7 @@ DepositPreauth::preflight(PreflightContext const& ctx) } // An account may not preauthorize itself. - if (optAuth && (target == ctx.account)) + if (optAuth && (target == ctx.tx[sfAccount])) { JLOG(ctx.j.trace()) << "Malformed transaction: Attempting to DepositPreauth self."; @@ -141,7 +141,7 @@ DepositPreauth::preflight(PreflightContext const& ctx) TER DepositPreauth::preclaim(PreclaimContext const& ctx) { - AccountID const account(ctx.account); + AccountID const account(ctx.tx[sfAccount]); // Determine which operation we're performing: authorizing or unauthorizing. if (ctx.tx.isFieldPresent(sfAuthorize)) diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index f855188fd08..2f942e352c9 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -94,7 +94,7 @@ after(NetClock::time_point now, std::uint32_t mark) TxConsequences EscrowCreate::makeTxConsequences(PreflightContext const& ctx) { - return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()}; + return TxConsequences{ctx.tx.getTx(), ctx.tx[sfAmount].xrp()}; } NotTEC @@ -206,7 +206,8 @@ EscrowCreate::doApply() } } - auto const sle = ctx_.view().peek(keylet::account(account_)); + auto const account = ctx_.tx[sfAccount]; + auto const sle = ctx_.view().peek(keylet::account(account)); if (!sle) return tefINTERNAL; @@ -243,10 +244,10 @@ EscrowCreate::doApply() // Create escrow in ledger. Note that we we use the value from the // sequence or ticket. For more explanation see comments in SeqProxy.h. Keylet const escrowKeylet = - keylet::escrow(account_, ctx_.tx.getSeqProxy().value()); + keylet::escrow(account, ctx_.tx.getSeqProxy().value()); auto const slep = std::make_shared(escrowKeylet); (*slep)[sfAmount] = ctx_.tx[sfAmount]; - (*slep)[sfAccount] = account_; + (*slep)[sfAccount] = account; (*slep)[~sfCondition] = ctx_.tx[~sfCondition]; (*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag]; (*slep)[sfDestination] = ctx_.tx[sfDestination]; @@ -259,16 +260,14 @@ EscrowCreate::doApply() // Add escrow to sender's owner directory { auto page = ctx_.view().dirInsert( - keylet::ownerDir(account_), - escrowKeylet, - describeOwnerDir(account_)); + keylet::ownerDir(account), escrowKeylet, describeOwnerDir(account)); if (!page) return tecDIR_FULL; (*slep)[sfOwnerNode] = *page; } // If it's not a self-send, add escrow to recipient's owner directory. - if (auto const dest = ctx_.tx[sfDestination]; dest != account_) + if (auto const dest = ctx_.tx[sfDestination]; dest != ctx_.tx[sfAccount]) { auto page = ctx_.view().dirInsert( keylet::ownerDir(dest), escrowKeylet, describeOwnerDir(dest)); @@ -378,7 +377,7 @@ EscrowFinish::preclaim(PreclaimContext const& ctx) if (!ctx.view.rules().enabled(featureCredentials)) return Transactor::preclaim(ctx); - if (auto const err = credentials::valid(ctx, ctx.account); + if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); !isTesSuccess(err)) return err; diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index bc982bb12b0..3757481c4af 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -43,7 +43,7 @@ TransactionFeeCheck::visitEntry( bool TransactionFeeCheck::finalize( - STTx const& tx, + STTxWr const& tx, TER const, XRPAmount const fee, ReadView const&, @@ -137,7 +137,7 @@ XRPNotCreated::visitEntry( bool XRPNotCreated::finalize( - STTx const& tx, + STTxWr const& tx, TER const, XRPAmount const fee, ReadView const&, @@ -198,7 +198,7 @@ XRPBalanceChecks::visitEntry( bool XRPBalanceChecks::finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -242,7 +242,7 @@ NoBadOffers::visitEntry( bool NoBadOffers::finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -287,7 +287,7 @@ NoZeroEscrow::visitEntry( bool NoZeroEscrow::finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -316,7 +316,7 @@ AccountRootsNotDeleted::visitEntry( bool AccountRootsNotDeleted::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const, ReadView const&, @@ -371,7 +371,7 @@ AccountRootsDeletedClean::visitEntry( bool AccountRootsDeletedClean::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const, ReadView const& view, @@ -493,7 +493,7 @@ LedgerEntryTypesMatch::visitEntry( bool LedgerEntryTypesMatch::finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -536,7 +536,7 @@ NoXRPTrustLines::visitEntry( bool NoXRPTrustLines::finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -566,7 +566,7 @@ ValidNewAccountRoot::visitEntry( bool ValidNewAccountRoot::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const, ReadView const& view, @@ -717,7 +717,7 @@ ValidNFTokenPage::visitEntry( bool ValidNFTokenPage::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const, ReadView const& view, @@ -793,7 +793,7 @@ NFTokenCountTracking::visitEntry( bool NFTokenCountTracking::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const, ReadView const& view, @@ -894,7 +894,7 @@ ValidClawback::visitEntry( bool ValidClawback::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const, ReadView const& view, @@ -982,7 +982,7 @@ ValidMPTIssuance::visitEntry( bool ValidMPTIssuance::finalize( - STTx const& tx, + STTxWr const& tx, TER const result, XRPAmount const _fee, ReadView const& _view, diff --git a/src/xrpld/app/tx/detail/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h index 23ec8005556..563b6c5aaad 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -76,7 +76,7 @@ class InvariantChecker_PROTOTYPE */ bool finalize( - STTx const& tx, + STTxWr const& tx, TER const tec, XRPAmount const fee, ReadView const& view, @@ -101,7 +101,7 @@ class TransactionFeeCheck bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -129,7 +129,7 @@ class XRPNotCreated bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -157,7 +157,7 @@ class AccountRootsNotDeleted bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -187,7 +187,7 @@ class AccountRootsDeletedClean bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -214,7 +214,7 @@ class XRPBalanceChecks bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -239,7 +239,7 @@ class LedgerEntryTypesMatch bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -265,7 +265,7 @@ class NoXRPTrustLines bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -292,7 +292,7 @@ class NoBadOffers bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -316,7 +316,7 @@ class NoZeroEscrow bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -342,7 +342,7 @@ class ValidNewAccountRoot bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -379,7 +379,7 @@ class ValidNFTokenPage bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -415,7 +415,7 @@ class NFTokenCountTracking bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -444,7 +444,7 @@ class ValidClawback bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, @@ -468,7 +468,7 @@ class ValidMPTIssuance bool finalize( - STTx const&, + STTxWr const&, TER const, XRPAmount const, ReadView const&, diff --git a/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp b/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp index a7f96d6f028..8042c9c6982 100644 --- a/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp +++ b/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp @@ -37,7 +37,7 @@ MPTokenAuthorize::preflight(PreflightContext const& ctx) if (ctx.tx.getFlags() & tfMPTokenAuthorizeMask) return temINVALID_FLAG; - if (ctx.account == ctx.tx[~sfHolder]) + if (ctx.tx[sfAccount] == ctx.tx[~sfHolder]) return temMALFORMED; return preflight2(ctx); @@ -46,7 +46,7 @@ MPTokenAuthorize::preflight(PreflightContext const& ctx) TER MPTokenAuthorize::preclaim(PreclaimContext const& ctx) { - auto const accountID = ctx.account; + auto const accountID = ctx.tx[sfAccount]; auto const holderID = ctx.tx[~sfHolder]; // if non-issuer account submits this tx, then they are trying either: diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp index 49d3a2f1f80..a0f0b9d8602 100644 --- a/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp @@ -52,7 +52,7 @@ MPTokenIssuanceDestroy::preclaim(PreclaimContext const& ctx) return tecOBJECT_NOT_FOUND; // ensure it is issued by the tx submitter - if ((*sleMPT)[sfIssuer] != ctx.account) + if ((*sleMPT)[sfIssuer] != ctx.tx[sfAccount]) return tecNO_PERMISSION; // ensure it has no outstanding balances diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp index 1cf0a6cc67c..93bd66c329d 100644 --- a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp @@ -43,7 +43,7 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx) else if ((txFlags & tfMPTLock) && (txFlags & tfMPTUnlock)) return temINVALID_FLAG; - auto const accountID = ctx.account; + auto const accountID = ctx.tx[sfAccount]; auto const holderID = ctx.tx[~sfHolder]; if (holderID && accountID == holderID) return temMALFORMED; @@ -65,7 +65,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) return tecNO_PERMISSION; // ensure it is issued by the tx submitter - if ((*sleMptIssuance)[sfIssuer] != ctx.account) + if ((*sleMptIssuance)[sfIssuer] != ctx.tx[sfAccount]) return tecNO_PERMISSION; if (auto const holderID = ctx.tx[~sfHolder]) @@ -104,13 +104,13 @@ MPTokenIssuanceSet::doApply() bool bLock = txFlags & tfMPTLock; bool bUnlock = txFlags & tfMPTUnlock; - if (ctx_.isDelegated && !ctx_.gpSet.empty()) + + if (ctx_.tx.isDelegated() && !ctx_.permissions.empty()) { - // if gpSet is not empty, granular delegation is happening. - if (bLock && ctx_.gpSet.find(gpMPTokenIssuanceLock) == ctx_.gpSet.end()) + // if permissions is not empty, granular delegation is happening. + if (bLock && !ctx_.permissions.contains(MPTokenIssuanceLock)) return terNO_AUTH; - if (bUnlock && - ctx_.gpSet.find(gpMPTokenIssuanceUnlock) == ctx_.gpSet.end()) + if (bUnlock && !ctx_.permissions.contains(MPTokenIssuanceUnlock)) return terNO_AUTH; } diff --git a/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp index c22411348ad..b884a791e78 100644 --- a/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp +++ b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp @@ -125,10 +125,10 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // a broker. After, it must be whoever is submitting the tx. if (ctx.view.rules().enabled(fixNonFungibleTokensV1_2)) { - if (*dest != ctx.account) + if (*dest != ctx.tx[sfAccount]) return tecNO_PERMISSION; } - else if (*dest != so->at(sfOwner) && *dest != ctx.account) + else if (*dest != so->at(sfOwner) && *dest != ctx.tx[sfAccount]) return tecNFTOKEN_BUY_SELL_MISMATCH; } @@ -139,10 +139,10 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // a broker. After, it must be whoever is submitting the tx. if (ctx.view.rules().enabled(fixNonFungibleTokensV1_2)) { - if (*dest != ctx.account) + if (*dest != ctx.tx[sfAccount]) return tecNO_PERMISSION; } - else if (*dest != bo->at(sfOwner) && *dest != ctx.account) + else if (*dest != bo->at(sfOwner) && *dest != ctx.tx[sfAccount]) return tecNFTOKEN_BUY_SELL_MISMATCH; } @@ -169,11 +169,12 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) return tecNFTOKEN_OFFER_TYPE_MISMATCH; // An account can't accept an offer it placed: - if ((*bo)[sfOwner] == ctx.account) + if ((*bo)[sfOwner] == ctx.tx[sfAccount]) return tecCANT_ACCEPT_OWN_NFTOKEN_OFFER; // If not in bridged mode, the account must own the token: - if (!so && !nft::findToken(ctx.view, ctx.account, (*bo)[sfNFTokenID])) + if (!so && + !nft::findToken(ctx.view, ctx.tx[sfAccount], (*bo)[sfNFTokenID])) return tecNO_PERMISSION; // If not in bridged mode... @@ -182,7 +183,7 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // If the offer has a Destination field, the acceptor must be the // Destination. if (auto const dest = bo->at(~sfDestination); - dest.has_value() && *dest != ctx.account) + dest.has_value() && *dest != ctx.tx[sfAccount]) return tecNO_PERMISSION; } @@ -215,7 +216,7 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) return tecNFTOKEN_OFFER_TYPE_MISMATCH; // An account can't accept an offer it placed: - if ((*so)[sfOwner] == ctx.account) + if ((*so)[sfOwner] == ctx.tx[sfAccount]) return tecCANT_ACCEPT_OWN_NFTOKEN_OFFER; // The seller must own the token. @@ -228,7 +229,7 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // If the offer has a Destination field, the acceptor must be the // Destination. if (auto const dest = so->at(~sfDestination); - dest.has_value() && *dest != ctx.account) + dest.has_value() && *dest != ctx.tx[sfAccount]) return tecNO_PERMISSION; } @@ -238,7 +239,7 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) { if (accountHolds( ctx.view, - ctx.account, + ctx.tx[sfAccount], needed.getCurrency(), needed.getIssuer(), fhZERO_IF_FROZEN, @@ -260,8 +261,11 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) // cover what the buyer will pay, which doesn't make sense, causes // an unnecessary tec, and is also resolved with this amendment. if (accountFunds( - ctx.view, ctx.account, needed, fhZERO_IF_FROZEN, ctx.j) < - needed) + ctx.view, + ctx.tx[sfAccount], + needed, + fhZERO_IF_FROZEN, + ctx.j) < needed) return tecINSUFFICIENT_FUNDS; } } diff --git a/src/xrpld/app/tx/detail/NFTokenBurn.cpp b/src/xrpld/app/tx/detail/NFTokenBurn.cpp index e5d795a8e87..725e35791f9 100644 --- a/src/xrpld/app/tx/detail/NFTokenBurn.cpp +++ b/src/xrpld/app/tx/detail/NFTokenBurn.cpp @@ -51,7 +51,7 @@ NFTokenBurn::preclaim(PreclaimContext const& ctx) if (ctx.tx.isFieldPresent(sfOwner)) return ctx.tx.getAccountID(sfOwner); - return ctx.account; + return ctx.tx[sfAccount]; }(); if (!nft::findToken(ctx.view, owner, ctx.tx[sfNFTokenID])) @@ -59,7 +59,7 @@ NFTokenBurn::preclaim(PreclaimContext const& ctx) // The owner of a token can always burn it, but the issuer can only // do so if the token is marked as burnable. - if (auto const account = ctx.account; owner != account) + if (auto const account = ctx.tx[sfAccount]; owner != account) { if (!(nft::getFlags(ctx.tx[sfNFTokenID]) & nft::flagBurnable)) return tecNO_PERMISSION; @@ -93,7 +93,7 @@ NFTokenBurn::doApply() auto const ret = nft::removeToken( view(), ctx_.tx.isFieldPresent(sfOwner) ? ctx_.tx.getAccountID(sfOwner) - : account_, + : ctx_.tx.getAccountID(sfAccount), ctx_.tx[sfNFTokenID]); // Should never happen since preclaim() verified the token is present. diff --git a/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp b/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp index 85b2e7f6188..ef66ceecd0c 100644 --- a/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp +++ b/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp @@ -56,7 +56,7 @@ NFTokenCancelOffer::preflight(PreflightContext const& ctx) TER NFTokenCancelOffer::preclaim(PreclaimContext const& ctx) { - auto const account = ctx.account; + auto const account = ctx.tx[sfAccount]; auto const& ids = ctx.tx[sfNFTokenOffers]; diff --git a/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp b/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp index 860c2c0a3ec..43178d31b4a 100644 --- a/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp +++ b/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp @@ -45,7 +45,7 @@ NFTokenCreateOffer::preflight(PreflightContext const& ctx) // Use implementation shared with NFTokenMint if (NotTEC notTec = nft::tokenOfferCreatePreflight( - ctx.account, + ctx.tx[sfAccount], ctx.tx[sfAmount], ctx.tx[~sfDestination], ctx.tx[~sfExpiration], @@ -70,14 +70,14 @@ NFTokenCreateOffer::preclaim(PreclaimContext const& ctx) if (!nft::findToken( ctx.view, - (txFlags & tfSellNFToken) ? ctx.account : ctx.tx[sfOwner], + ctx.tx[(txFlags & tfSellNFToken) ? sfAccount : sfOwner], nftokenID)) return tecNO_ENTRY; // Use implementation shared with NFTokenMint return nft::tokenOfferCreatePreclaim( ctx.view, - ctx.account, + ctx.tx[sfAccount], nft::getIssuer(nftokenID), ctx.tx[sfAmount], ctx.tx[~sfDestination], @@ -94,7 +94,7 @@ NFTokenCreateOffer::doApply() // Use implementation shared with NFTokenMint return nft::tokenOfferCreateApply( view(), - account_, + ctx_.tx[sfAccount], ctx_.tx[sfAmount], ctx_.tx[~sfDestination], ctx_.tx[~sfExpiration], diff --git a/src/xrpld/app/tx/detail/NFTokenMint.cpp b/src/xrpld/app/tx/detail/NFTokenMint.cpp index a7c952290ae..d5c3a8707c2 100644 --- a/src/xrpld/app/tx/detail/NFTokenMint.cpp +++ b/src/xrpld/app/tx/detail/NFTokenMint.cpp @@ -84,7 +84,7 @@ NFTokenMint::preflight(PreflightContext const& ctx) } // An issuer must only be set if the tx is executed by the minter - if (auto iss = ctx.tx[~sfIssuer]; iss == ctx.account) + if (auto iss = ctx.tx[~sfIssuer]; iss == ctx.tx[sfAccount]) return temMALFORMED; if (auto uri = ctx.tx[~sfURI]) @@ -104,7 +104,7 @@ NFTokenMint::preflight(PreflightContext const& ctx) // do the validation. We pass tfSellNFToken as the transaction flags // because a Mint is only allowed to create a sell offer. if (NotTEC notTec = nft::tokenOfferCreatePreflight( - ctx.account, + ctx.tx[sfAccount], ctx.tx[sfAmount], ctx.tx[~sfDestination], ctx.tx[~sfExpiration], @@ -177,7 +177,8 @@ NFTokenMint::preclaim(PreclaimContext const& ctx) if (!sle) return tecNO_ISSUER; - if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != ctx.account) + if (auto const minter = (*sle)[~sfNFTokenMinter]; + minter != ctx.tx[sfAccount]) return tecNO_PERMISSION; } @@ -192,8 +193,8 @@ NFTokenMint::preclaim(PreclaimContext const& ctx) // because a Mint is only allowed to create a sell offer. if (TER const ter = nft::tokenOfferCreatePreclaim( ctx.view, - ctx.account, - ctx.tx[~sfIssuer].value_or(ctx.account), + ctx.tx[sfAccount], + ctx.tx[~sfIssuer].value_or(ctx.tx[sfAccount]), ctx.tx[sfAmount], ctx.tx[~sfDestination], extractNFTokenFlagsFromTxFlags(ctx.tx.getFlags()), @@ -321,7 +322,7 @@ NFTokenMint::doApply() // because a Mint is only allowed to create a sell offer. if (TER const ter = nft::tokenOfferCreateApply( view(), - account_, + ctx_.tx[sfAccount], ctx_.tx[sfAmount], ctx_.tx[~sfDestination], ctx_.tx[~sfExpiration], diff --git a/src/xrpld/app/tx/detail/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp index 8dcb74094e0..9177aa04a75 100644 --- a/src/xrpld/app/tx/detail/PayChan.cpp +++ b/src/xrpld/app/tx/detail/PayChan.cpp @@ -166,7 +166,7 @@ closeChannel( TxConsequences PayChanCreate::makeTxConsequences(PreflightContext const& ctx) { - return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()}; + return TxConsequences{ctx.tx.getTx(), ctx.tx[sfAmount].xrp()}; } NotTEC @@ -181,7 +181,7 @@ PayChanCreate::preflight(PreflightContext const& ctx) if (!isXRP(ctx.tx[sfAmount]) || (ctx.tx[sfAmount] <= beast::zero)) return temBAD_AMOUNT; - if (ctx.account == ctx.tx[sfDestination]) + if (ctx.tx[sfAccount] == ctx.tx[sfDestination]) return temDST_IS_SRC; if (!publicKeyType(ctx.tx[sfPublicKey])) @@ -193,7 +193,7 @@ PayChanCreate::preflight(PreflightContext const& ctx) TER PayChanCreate::preclaim(PreclaimContext const& ctx) { - auto const account = ctx.account; + auto const account = ctx.tx[sfAccount]; auto const sle = ctx.view.read(keylet::account(account)); if (!sle) return terNO_ACCOUNT; @@ -245,7 +245,8 @@ PayChanCreate::preclaim(PreclaimContext const& ctx) TER PayChanCreate::doApply() { - auto const sle = ctx_.view().peek(keylet::account(account_)); + auto const account = ctx_.tx[sfAccount]; + auto const sle = ctx_.view().peek(keylet::account(account)); if (!sle) return tefINTERNAL; @@ -256,14 +257,14 @@ PayChanCreate::doApply() // Note that we we use the value from the sequence or ticket as the // payChan sequence. For more explanation see comments in SeqProxy.h. Keylet const payChanKeylet = - keylet::payChan(account_, dst, ctx_.tx.getSeqProxy().value()); + keylet::payChan(account, dst, ctx_.tx.getSeqProxy().value()); auto const slep = std::make_shared(payChanKeylet); // Funds held in this channel (*slep)[sfAmount] = ctx_.tx[sfAmount]; // Amount channel has already paid (*slep)[sfBalance] = ctx_.tx[sfAmount].zeroed(); - (*slep)[sfAccount] = account_; + (*slep)[sfAccount] = account; (*slep)[sfDestination] = dst; (*slep)[sfSettleDelay] = ctx_.tx[sfSettleDelay]; (*slep)[sfPublicKey] = ctx_.tx[sfPublicKey]; @@ -276,9 +277,9 @@ PayChanCreate::doApply() // Add PayChan to owner directory { auto const page = ctx_.view().dirInsert( - keylet::ownerDir(account_), + keylet::ownerDir(account), payChanKeylet, - describeOwnerDir(account_)); + describeOwnerDir(account)); if (!page) return tecDIR_FULL; (*slep)[sfOwnerNode] = *page; @@ -307,7 +308,7 @@ PayChanCreate::doApply() TxConsequences PayChanFund::makeTxConsequences(PreflightContext const& ctx) { - return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()}; + return TxConsequences{ctx.tx.getTx(), ctx.tx[sfAmount].xrp()}; } NotTEC @@ -334,6 +335,7 @@ PayChanFund::doApply() return tecNO_ENTRY; AccountID const src = (*slep)[sfAccount]; + auto const txAccount = ctx_.tx[sfAccount]; auto const expiration = (*slep)[~sfExpiration]; { @@ -346,7 +348,7 @@ PayChanFund::doApply() slep, ctx_.view(), k.key, ctx_.app.journal("View")); } - if (src != account_) + if (src != txAccount) // only the owner can add funds or extend return tecNO_PERMISSION; @@ -364,7 +366,7 @@ PayChanFund::doApply() ctx_.view().update(slep); } - auto const sle = ctx_.view().peek(keylet::account(account_)); + auto const sle = ctx_.view().peek(keylet::account(txAccount)); if (!sle) return tefINTERNAL; @@ -468,7 +470,7 @@ PayChanClaim::preclaim(PreclaimContext const& ctx) if (!ctx.view.rules().enabled(featureCredentials)) return Transactor::preclaim(ctx); - if (auto const err = credentials::valid(ctx, ctx.account); + if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); !isTesSuccess(err)) return err; @@ -485,6 +487,7 @@ PayChanClaim::doApply() AccountID const src = (*slep)[sfAccount]; AccountID const dst = (*slep)[sfDestination]; + AccountID const txAccount = ctx_.tx[sfAccount]; auto const curExpiration = (*slep)[~sfExpiration]; { @@ -497,7 +500,7 @@ PayChanClaim::doApply() slep, ctx_.view(), k.key, ctx_.app.journal("View")); } - if (account_ != src && account_ != dst) + if (txAccount != src && txAccount != dst) return tecNO_PERMISSION; if (ctx_.tx[~sfBalance]) @@ -506,7 +509,7 @@ PayChanClaim::doApply() auto const chanFunds = slep->getFieldAmount(sfAmount).xrp(); auto const reqBalance = ctx_.tx[sfBalance].xrp(); - if (account_ == dst && !ctx_.tx[~sfSignature]) + if (txAccount == dst && !ctx_.tx[~sfSignature]) return temBAD_SIGNATURE; if (ctx_.tx[~sfSignature]) @@ -531,12 +534,12 @@ PayChanClaim::doApply() // featureDepositAuth to remove the bug. bool const depositAuth{ctx_.view().rules().enabled(featureDepositAuth)}; if (!depositAuth && - (account_ == src && (sled->getFlags() & lsfDisallowXRP))) + (txAccount == src && (sled->getFlags() & lsfDisallowXRP))) return tecNO_TARGET; if (depositAuth) { - if (auto err = verifyDepositPreauth(ctx_, account_, dst, sled); + if (auto err = verifyDepositPreauth(ctx_, txAccount, dst, sled); !isTesSuccess(err)) return err; } @@ -551,7 +554,7 @@ PayChanClaim::doApply() if (ctx_.tx.getFlags() & tfRenew) { - if (src != account_) + if (src != txAccount) return tecNO_PERMISSION; (*slep)[~sfExpiration] = std::nullopt; ctx_.view().update(slep); @@ -560,7 +563,7 @@ PayChanClaim::doApply() if (ctx_.tx.getFlags() & tfClose) { // Channel will close immediately if dry or the receiver closes - if (dst == account_ || (*slep)[sfBalance] == (*slep)[sfAmount]) + if (dst == txAccount || (*slep)[sfBalance] == (*slep)[sfAmount]) return closeChannel( slep, ctx_.view(), k.key, ctx_.app.journal("View")); diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 39e68f891e1..8ee08ada82d 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -42,7 +42,7 @@ Payment::makeTxConsequences(PreflightContext const& ctx) return maxAmount.native() ? maxAmount.xrp() : beast::zero; }; - return TxConsequences{ctx.tx, calculateMaxXRPSpend(ctx.tx)}; + return TxConsequences{ctx.tx.getTx(), calculateMaxXRPSpend(ctx.tx.getTx())}; } STAmount @@ -105,7 +105,7 @@ Payment::preflight(PreflightContext const& ctx) auto const account = tx.getAccountID(sfAccount); STAmount const maxSourceAmount = - getMaxSourceAmount(ctx.account, dstAmount, tx[~sfSendMax]); + getMaxSourceAmount(account, dstAmount, tx[~sfSendMax]); if ((mptDirect && dstAmount.asset() != maxSourceAmount.asset()) || (!mptDirect && maxSourceAmount.holds())) @@ -319,7 +319,7 @@ Payment::preclaim(PreclaimContext const& ctx) } } - if (auto const err = credentials::valid(ctx, ctx.account); + if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); !isTesSuccess(err)) return err; @@ -342,9 +342,9 @@ Payment::doApply() AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination)); STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount)); - if (ctx_.isDelegated && !ctx_.gpSet.empty()) + if (ctx_.tx.isDelegated() && !ctx_.permissions.empty()) { - // If gpSet is not empty, granular delegation is happening. + // If permissions is not empty, granular delegation is happening. // Currently we only support PaymentMint and PaymentBurn granular // permission. PaymentMint means the sender is the issuer. PaymentBurn // means the destination is the issuer. @@ -353,10 +353,10 @@ Payment::doApply() if (isXRP(amountIssue)) return tecNO_AUTH; if (amountIssue.account == account_ && - ctx_.gpSet.find(gpPaymentMint) != ctx_.gpSet.end()) + ctx_.permissions.contains(PaymentMint)) authorized = true; if (amountIssue.account == dstAccountID && - ctx_.gpSet.find(gpPaymentBurn) != ctx_.gpSet.end()) + ctx_.permissions.contains(PaymentBurn)) authorized = true; if (!authorized) diff --git a/src/xrpld/app/tx/detail/SetAccount.cpp b/src/xrpld/app/tx/detail/SetAccount.cpp index d1d2496747b..5acf0221c20 100644 --- a/src/xrpld/app/tx/detail/SetAccount.cpp +++ b/src/xrpld/app/tx/detail/SetAccount.cpp @@ -52,7 +52,8 @@ SetAccount::makeTxConsequences(PreflightContext const& ctx) return TxConsequences::normal; }; - return TxConsequences{ctx.tx, getTxConsequencesCategory(ctx.tx)}; + return TxConsequences{ + ctx.tx.getTx(), getTxConsequencesCategory(ctx.tx.getTx())}; } NotTEC @@ -262,7 +263,7 @@ SetAccount::doApply() std::uint32_t const uFlagsIn = sle->getFieldU32(sfFlags); std::uint32_t uFlagsOut = uFlagsIn; - STTx const& tx{ctx_.tx}; + STTx const& tx{ctx_.tx.getTx()}; std::uint32_t const uSetFlag{tx.getFieldU32(sfSetFlag)}; std::uint32_t const uClearFlag{tx.getFieldU32(sfClearFlag)}; @@ -270,9 +271,9 @@ SetAccount::doApply() std::uint32_t const uTxFlags{tx.getFlags()}; bool granularDelegated = false; - if (ctx_.isDelegated && !ctx_.gpSet.empty()) + if (ctx_.tx.isDelegated() && !ctx_.permissions.empty()) { - // if gpSet is not empty, granular delegation is happening. + // if permissions is not empty, granular delegation is happening. granularDelegated = true; // We don't support any flag based granular permission under AccountSet @@ -465,7 +466,8 @@ SetAccount::doApply() if (tx.isFieldPresent(sfEmailHash)) { if (granularDelegated && - ctx_.gpSet.find(gpAccountEmailHashSet) == ctx_.gpSet.end()) + ctx_.permissions.find(AccountEmailHashSet) == + ctx_.permissions.end()) return tecNO_AUTH; uint128 const uHash = tx.getFieldH128(sfEmailHash); @@ -510,7 +512,8 @@ SetAccount::doApply() if (tx.isFieldPresent(sfMessageKey)) { if (granularDelegated && - ctx_.gpSet.find(gpAccountMessageKeySet) == ctx_.gpSet.end()) + ctx_.permissions.find(AccountMessageKeySet) == + ctx_.permissions.end()) return tecNO_AUTH; Blob const messageKey = tx.getFieldVL(sfMessageKey); @@ -533,7 +536,7 @@ SetAccount::doApply() if (tx.isFieldPresent(sfDomain)) { if (granularDelegated && - ctx_.gpSet.find(gpAccountDomainSet) == ctx_.gpSet.end()) + ctx_.permissions.find(AccountDomainSet) == ctx_.permissions.end()) return tecNO_AUTH; Blob const domain = tx.getFieldVL(sfDomain); @@ -556,7 +559,8 @@ SetAccount::doApply() if (tx.isFieldPresent(sfTransferRate)) { if (granularDelegated && - ctx_.gpSet.find(gpAccountTransferRateSet) == ctx_.gpSet.end()) + ctx_.permissions.find(AccountTransferRateSet) == + ctx_.permissions.end()) return tecNO_AUTH; std::uint32_t uRate = tx.getFieldU32(sfTransferRate); @@ -579,7 +583,7 @@ SetAccount::doApply() if (tx.isFieldPresent(sfTickSize)) { if (granularDelegated && - ctx_.gpSet.find(gpAccountTickSizeSet) == ctx_.gpSet.end()) + ctx_.permissions.find(AccountTickSizeSet) == ctx_.permissions.end()) return tecNO_AUTH; auto uTickSize = tx[sfTickSize]; diff --git a/src/xrpld/app/tx/detail/SetOracle.cpp b/src/xrpld/app/tx/detail/SetOracle.cpp index 9d62a8b7c55..055143cc6fd 100644 --- a/src/xrpld/app/tx/detail/SetOracle.cpp +++ b/src/xrpld/app/tx/detail/SetOracle.cpp @@ -70,7 +70,8 @@ SetOracle::preflight(PreflightContext const& ctx) TER SetOracle::preclaim(PreclaimContext const& ctx) { - auto const sleSetter = ctx.view.read(keylet::account(ctx.account)); + auto const sleSetter = + ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount))); if (!sleSetter) return terNO_ACCOUNT; // LCOV_EXCL_LINE @@ -91,8 +92,8 @@ SetOracle::preclaim(PreclaimContext const& ctx) lastUpdateTimeEpoch > (closeTime + maxLastUpdateTimeDelta)) return tecINVALID_UPDATE_TIME; - auto const sle = - ctx.view.read(keylet::oracle(ctx.account, ctx.tx[sfOracleDocumentID])); + auto const sle = ctx.view.read(keylet::oracle( + ctx.tx.getAccountID(sfAccount), ctx.tx[sfOracleDocumentID])); // token pairs to add/update std::set> pairs; @@ -184,7 +185,8 @@ SetOracle::preclaim(PreclaimContext const& ctx) static bool adjustOwnerCount(ApplyContext& ctx, int count) { - if (auto const sleAccount = ctx.view().peek(keylet::account(ctx.account))) + if (auto const sleAccount = + ctx.view().peek(keylet::account(ctx.tx[sfAccount]))) { adjustOwnerCount(ctx.view(), sleAccount, count, ctx.journal); return true; @@ -279,7 +281,7 @@ SetOracle::doApply() // create sle = std::make_shared(oracleID); - sle->setAccountID(sfOwner, account_); + sle->setAccountID(sfOwner, ctx_.tx.getAccountID(sfAccount)); sle->setFieldVL(sfProvider, ctx_.tx[sfProvider]); if (ctx_.tx.isFieldPresent(sfURI)) sle->setFieldVL(sfURI, ctx_.tx[sfURI]); diff --git a/src/xrpld/app/tx/detail/SetRegularKey.cpp b/src/xrpld/app/tx/detail/SetRegularKey.cpp index 39a556fb0e2..9f165612f3a 100644 --- a/src/xrpld/app/tx/detail/SetRegularKey.cpp +++ b/src/xrpld/app/tx/detail/SetRegularKey.cpp @@ -64,7 +64,7 @@ SetRegularKey::preflight(PreflightContext const& ctx) if (ctx.rules.enabled(fixMasterKeyAsRegularKey) && ctx.tx.isFieldPresent(sfRegularKey) && - (ctx.tx.getAccountID(sfRegularKey) == ctx.account)) + (ctx.tx.getAccountID(sfRegularKey) == ctx.tx.getAccountID(sfAccount))) { return temBAD_REGKEY; } diff --git a/src/xrpld/app/tx/detail/SetSignerList.cpp b/src/xrpld/app/tx/detail/SetSignerList.cpp index 6093c798392..740390c1c4c 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.cpp +++ b/src/xrpld/app/tx/detail/SetSignerList.cpp @@ -81,7 +81,7 @@ SetSignerList::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; - auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j); + auto const result = determineOperation(ctx.tx.getTx(), ctx.flags, ctx.j); if (std::get<0>(result) != tesSUCCESS) return std::get<0>(result); @@ -97,7 +97,7 @@ SetSignerList::preflight(PreflightContext const& ctx) if (std::get<3>(result) == set) { // Validate our settings. - auto const account = ctx.account; + auto const account = ctx.tx.getAccountID(sfAccount); NotTEC const ter = validateQuorumAndSignerEntries( std::get<1>(result), std::get<2>(result), @@ -136,7 +136,7 @@ void SetSignerList::preCompute() { // Get the quorum and operation info. - auto result = determineOperation(ctx_.tx, view().flags(), j_); + auto result = determineOperation(ctx_.tx.getTx(), view().flags(), j_); assert(std::get<0>(result) == tesSUCCESS); assert(std::get<3>(result) != unknown); diff --git a/src/xrpld/app/tx/detail/SetTrust.cpp b/src/xrpld/app/tx/detail/SetTrust.cpp index ba45fbefb15..6d29efc3bcd 100644 --- a/src/xrpld/app/tx/detail/SetTrust.cpp +++ b/src/xrpld/app/tx/detail/SetTrust.cpp @@ -84,7 +84,7 @@ SetTrust::preflight(PreflightContext const& ctx) TER SetTrust::preclaim(PreclaimContext const& ctx) { - auto const id = ctx.account; + auto const id = ctx.tx[sfAccount]; auto const sle = ctx.view.read(keylet::account(id)); if (!sle) @@ -244,7 +244,7 @@ SetTrust::doApply() bool const bClearFreeze = (uTxFlags & tfClearFreeze); bool granularDelegated = false; - if (ctx_.isDelegated && !ctx_.gpSet.empty()) + if (ctx_.tx.isDelegated() && !ctx_.permissions.empty()) { granularDelegated = true; // If granular permission is delegated under the TrustSet transaction. @@ -252,14 +252,11 @@ SetTrust::doApply() // TrustlineUnfreeze granular permission. if (bSetNoRipple || bClearNoRipple || bQualityIn || bQualityOut) return terNO_AUTH; - if (bSetAuth && - ctx_.gpSet.find(gpTrustlineAuthorize) == ctx_.gpSet.end()) + if (bSetAuth && !ctx_.permissions.contains(TrustlineAuthorize)) return terNO_AUTH; - if (bSetFreeze && - ctx_.gpSet.find(gpTrustlineFreeze) == ctx_.gpSet.end()) + if (bSetFreeze && !ctx_.permissions.contains(TrustlineFreeze)) return terNO_AUTH; - if (bClearFreeze && - ctx_.gpSet.find(gpTrustlineUnfreeze) == ctx_.gpSet.end()) + if (bClearFreeze && !ctx_.permissions.contains(TrustlineUnfreeze)) return terNO_AUTH; } diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 3c0cd359b3e..c674dd7898f 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -41,7 +41,7 @@ namespace ripple { NotTEC preflight0(PreflightContext const& ctx) { - if (!isPseudoTx(ctx.tx) || ctx.tx.isFieldPresent(sfNetworkID)) + if (!isPseudoTx(ctx.tx.getTx()) || ctx.tx.isFieldPresent(sfNetworkID)) { uint32_t nodeNID = ctx.app.config().NETWORK_ID; std::optional txNID = ctx.tx[~sfNetworkID]; @@ -81,6 +81,10 @@ preflight0(PreflightContext const& ctx) NotTEC preflight1(PreflightContext const& ctx) { + if (!ctx.rules.enabled(featureAccountPermission) && + ctx.tx.isFieldPresent(sfOnBehalfOf)) + return temDISABLED; + // This is inappropriate in preflight0, because only Change transactions // skip this function, and those do not allow an sfTicketSequence field. if (ctx.tx.isFieldPresent(sfTicketSequence) && @@ -126,6 +130,10 @@ preflight1(PreflightContext const& ctx) ctx.tx.isFieldPresent(sfAccountTxnID)) return temINVALID; + if (!ctx.rules.enabled(featureAccountPermission) && + ctx.tx.isFieldPresent(sfOnBehalfOf)) + return temDISABLED; + return tesSUCCESS; } @@ -134,7 +142,7 @@ NotTEC preflight2(PreflightContext const& ctx) { auto const sigValid = checkValidity( - ctx.app.getHashRouter(), ctx.tx, ctx.rules, ctx.app.config()); + ctx.app.getHashRouter(), ctx.tx.getTx(), ctx.rules, ctx.app.config()); if (sigValid.first == Validity::SigBad) { JLOG(ctx.j.debug()) << "preflight2: bad signature. " << sigValid.second; @@ -147,19 +155,18 @@ preflight2(PreflightContext const& ctx) PreflightContext::PreflightContext( Application& app_, - STTx const& tx_, + STTxWr const& tx_, Rules const& rules_, ApplyFlags flags_, - AccountID const account_, beast::Journal j_) - : app(app_), tx(tx_), rules(rules_), flags(flags_), account(account_), j(j_) + : app(app_), tx(tx_), rules(rules_), flags(flags_), j(j_) { } //------------------------------------------------------------------------------ Transactor::Transactor(ApplyContext& ctx) - : ctx_(ctx), j_(ctx.journal), account_(ctx.account) + : ctx_(ctx), j_(ctx.journal), account_(ctx.tx.getAccountID(sfAccount)) { } @@ -182,13 +189,12 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx) } TER -Transactor::checkAuthorization( +Transactor::checkPermissions( ReadView const& view, STTx const& tx, - std::unordered_set& gpSet) + std::unordered_set& permissions) { - auto const onBehalfOfAccount = view.read(keylet::account(tx[sfOnBehalfOf])); - if (!onBehalfOfAccount) + if (!view.read(keylet::account(tx[sfOnBehalfOf]))) return terNO_ACCOUNT; auto const accountPermissionKey = @@ -197,17 +203,17 @@ Transactor::checkAuthorization( if (!sle) return temMALFORMED; // todo: change error code - auto const permissions = sle->getFieldArray(sfPermissions); + auto const permissionArray = sle->getFieldArray(sfPermissions); auto const transactionType = tx.getTxnType(); - for (auto const& permission : permissions) + for (auto const& permission : permissionArray) { auto const permissionValue = permission[sfPermissionValue]; if (permissionValue == transactionType + 1) { // if the transaction permission is authorized, do not need to check // granular permission. - gpSet.clear(); + permissions.clear(); return tesSUCCESS; } @@ -215,15 +221,15 @@ Transactor::checkAuthorization( static_cast(permissionValue); auto const& type = Permission::getInstance().getGranularTxType(gpType); if (type && *type == transactionType) - gpSet.insert(gpType); + permissions.insert(gpType); } - if (gpSet.empty()) + if (permissions.empty()) return terNO_AUTH; // When the code reaches here, the transaction permission is not authorized. // But one or more of its granular permission under this transaction type is - // authorized. And the granular types are stored in gpSet. + // authorized. And the granular types are stored in permissions. return tesSUCCESS; } @@ -294,11 +300,11 @@ TER Transactor::payFee() { auto const feePaid = ctx_.tx[sfFee].xrp(); - if (ctx_.isDelegated) + if (ctx_.tx.isDelegated()) { // if the transaction is being delegated to another account, // the sender account will pay the fee. - auto const sender = ctx_.tx.getAccountID(sfAccount); + auto const sender = ctx_.tx.getTx().getAccountID(sfAccount); auto const sleSender = view().peek(keylet::account(sender)); if (!sleSender) return tefINTERNAL; @@ -564,7 +570,7 @@ Transactor::checkSingleSign(PreclaimContext const& ctx) // Look up the account. auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner))); - auto const idAccount = ctx.tx.getAccountID(sfAccount); + auto const idAccount = ctx.tx.getTx().getAccountID(sfAccount); auto const sleAccount = ctx.view.read(keylet::account(idAccount)); if (!sleAccount) return terNO_ACCOUNT; @@ -928,7 +934,7 @@ Transactor::operator()() SerialIter sit(ser.slice()); STTx s2(sit); - if (!s2.isEquivalent(ctx_.tx)) + if (!s2.isEquivalent(ctx_.tx.getTx())) { JLOG(j_.fatal()) << "Transaction serdes mismatch"; JLOG(j_.info()) << to_string(ctx_.tx.getJson(JsonOptions::none)); diff --git a/src/xrpld/app/tx/detail/Transactor.h b/src/xrpld/app/tx/detail/Transactor.h index b6718ef16e1..23368da3f47 100644 --- a/src/xrpld/app/tx/detail/Transactor.h +++ b/src/xrpld/app/tx/detail/Transactor.h @@ -33,18 +33,16 @@ struct PreflightContext { public: Application& app; - STTx const& tx; + STTxWr const& tx; Rules const rules; ApplyFlags flags; - AccountID const account; beast::Journal const j; PreflightContext( Application& app_, - STTx const& tx_, + STTxWr const& tx_, Rules const& rules_, ApplyFlags flags_, - AccountID const account_, beast::Journal j_); PreflightContext& @@ -58,28 +56,22 @@ struct PreclaimContext Application& app; ReadView const& view; TER preflightResult; - STTx const& tx; + STTxWr const& tx; ApplyFlags flags; - bool isDelegated; - AccountID const account; beast::Journal const j; PreclaimContext( Application& app_, ReadView const& view_, TER preflightResult_, - STTx const& tx_, + STTxWr const& tx_, ApplyFlags flags_, - bool isDelegated, - AccountID const account, beast::Journal j_ = beast::Journal{beast::Journal::getNullSink()}) : app(app_) , view(view_) , preflightResult(preflightResult_) , tx(tx_) , flags(flags_) - , isDelegated(isDelegated) - , account(account) , j(j_) { } @@ -151,10 +143,10 @@ class Transactor calculateBaseFee(ReadView const& view, STTx const& tx); static TER - checkAuthorization( + checkPermissions( ReadView const& view, STTx const& tx, - std::unordered_set& gpSet); + std::unordered_set& permissions); static TER preclaim(PreclaimContext const& ctx) diff --git a/src/xrpld/app/tx/detail/XChainBridge.cpp b/src/xrpld/app/tx/detail/XChainBridge.cpp index e94941cd583..69c5c89c52a 100644 --- a/src/xrpld/app/tx/detail/XChainBridge.cpp +++ b/src/xrpld/app/tx/detail/XChainBridge.cpp @@ -1220,7 +1220,7 @@ attestationPreflight(PreflightContext const& ctx) if (!publicKeyType(ctx.tx[sfPublicKey])) return temMALFORMED; - auto const att = toClaim(ctx.tx); + auto const att = toClaim(ctx.tx.getTx()); if (!att) return temMALFORMED; @@ -1244,7 +1244,7 @@ template TER attestationPreclaim(PreclaimContext const& ctx) { - auto const att = toClaim(ctx.tx); + auto const att = toClaim(ctx.tx.getTx()); if (!att) return tecINTERNAL; // checked in preflight @@ -1274,7 +1274,7 @@ template TER attestationDoApply(ApplyContext& ctx) { - auto const att = toClaim(ctx.tx); + auto const att = toClaim(ctx.tx.getTx()); if (!att) // Should already be checked in preflight return tecINTERNAL; @@ -1384,7 +1384,7 @@ XChainCreateBridge::preflight(PreflightContext const& ctx) if (ctx.tx.getFlags() & tfUniversalMask) return temINVALID_FLAG; - auto const account = ctx.account; + auto const account = ctx.tx[sfAccount]; auto const reward = ctx.tx[sfSignatureReward]; auto const minAccountCreate = ctx.tx[~sfMinAccountCreateAmount]; auto const bridgeSpec = ctx.tx[sfXChainBridge]; @@ -1459,7 +1459,7 @@ XChainCreateBridge::preflight(PreflightContext const& ctx) TER XChainCreateBridge::preclaim(PreclaimContext const& ctx) { - auto const account = ctx.account; + auto const account = ctx.tx[sfAccount]; auto const bridgeSpec = ctx.tx[sfXChainBridge]; STXChainBridge::ChainType const chainType = STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); @@ -1510,21 +1510,22 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx) TER XChainCreateBridge::doApply() { + auto const account = ctx_.tx[sfAccount]; auto const bridgeSpec = ctx_.tx[sfXChainBridge]; auto const reward = ctx_.tx[sfSignatureReward]; auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount]; - auto const sleAcct = ctx_.view().peek(keylet::account(account_)); + auto const sleAcct = ctx_.view().peek(keylet::account(account)); if (!sleAcct) return tecINTERNAL; STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account_ == bridgeSpec.lockingChainDoor()); + STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); Keylet const bridgeKeylet = keylet::bridge(bridgeSpec, chainType); auto const sleBridge = std::make_shared(bridgeKeylet); - (*sleBridge)[sfAccount] = account_; + (*sleBridge)[sfAccount] = account; (*sleBridge)[sfSignatureReward] = reward; if (minAccountCreate) (*sleBridge)[sfMinAccountCreateAmount] = *minAccountCreate; @@ -1536,9 +1537,7 @@ XChainCreateBridge::doApply() // Add to owner directory { auto const page = ctx_.view().dirInsert( - keylet::ownerDir(account_), - bridgeKeylet, - describeOwnerDir(account_)); + keylet::ownerDir(account), bridgeKeylet, describeOwnerDir(account)); if (!page) return tecDIR_FULL; (*sleBridge)[sfOwnerNode] = *page; @@ -1566,7 +1565,7 @@ BridgeModify::preflight(PreflightContext const& ctx) if (ctx.tx.getFlags() & tfBridgeModifyMask) return temINVALID_FLAG; - auto const account = ctx.account; + auto const account = ctx.tx[sfAccount]; auto const reward = ctx.tx[~sfSignatureReward]; auto const minAccountCreate = ctx.tx[~sfMinAccountCreateAmount]; auto const bridgeSpec = ctx.tx[sfXChainBridge]; @@ -1610,10 +1609,11 @@ BridgeModify::preflight(PreflightContext const& ctx) TER BridgeModify::preclaim(PreclaimContext const& ctx) { + auto const account = ctx.tx[sfAccount]; auto const bridgeSpec = ctx.tx[sfXChainBridge]; STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(ctx.account == bridgeSpec.lockingChainDoor()); + STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); if (!ctx.view.read(keylet::bridge(bridgeSpec, chainType))) { @@ -1626,18 +1626,19 @@ BridgeModify::preclaim(PreclaimContext const& ctx) TER BridgeModify::doApply() { + auto const account = ctx_.tx[sfAccount]; auto const bridgeSpec = ctx_.tx[sfXChainBridge]; auto const reward = ctx_.tx[~sfSignatureReward]; auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount]; bool const clearAccountCreate = ctx_.tx.getFlags() & tfClearAccountCreateAmount; - auto const sleAcct = ctx_.view().peek(keylet::account(account_)); + auto const sleAcct = ctx_.view().peek(keylet::account(account)); if (!sleAcct) return tecINTERNAL; STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain(account_ == bridgeSpec.lockingChainDoor()); + STXChainBridge::srcChain(account == bridgeSpec.lockingChainDoor()); auto const sleBridge = ctx_.view().peek(keylet::bridge(bridgeSpec, chainType)); @@ -1690,6 +1691,7 @@ XChainClaim::preflight(PreflightContext const& ctx) TER XChainClaim::preclaim(PreclaimContext const& ctx) { + AccountID const account = ctx.tx[sfAccount]; STXChainBridge const bridgeSpec = ctx.tx[sfXChainBridge]; STAmount const& thisChainAmount = ctx.tx[sfAmount]; auto const claimID = ctx.tx[sfXChainClaimID]; @@ -1759,7 +1761,7 @@ XChainClaim::preclaim(PreclaimContext const& ctx) return tecXCHAIN_NO_CLAIM_ID; } - if ((*sleClaimID)[sfAccount] != ctx.account) + if ((*sleClaimID)[sfAccount] != account) { // Sequence number isn't owned by the sender of this transaction return tecXCHAIN_BAD_CLAIM_ID; @@ -1775,6 +1777,7 @@ XChainClaim::doApply() { PaymentSandbox psb(&ctx_.view()); + AccountID const account = ctx_.tx[sfAccount]; auto const dst = ctx_.tx[sfDestination]; STXChainBridge const bridgeSpec = ctx_.tx[sfXChainBridge]; STAmount const& thisChainAmount = ctx_.tx[sfAmount]; @@ -1796,7 +1799,7 @@ XChainClaim::doApply() // `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child // views, it's important that the sle's lifetime doesn't overlap. - auto const sleAcct = psb.peek(keylet::account(account_)); + auto const sleAcct = psb.peek(keylet::account(account)); auto const sleBridge = peekBridge(psb, bridgeSpec); auto const sleClaimID = psb.peek(claimIDKeylet); @@ -1865,7 +1868,7 @@ XChainClaim::doApply() bridgeSpec, dst, dstTag, - /*claimOwner*/ account_, + /*claimOwner*/ account, sendingAmount, rewardPoolSrc, signatureReward, @@ -1895,7 +1898,7 @@ XChainCommit::makeTxConsequences(PreflightContext const& ctx) return XRPAmount{beast::zero}; }(); - return TxConsequences{ctx.tx, maxSpend}; + return TxConsequences{ctx.tx.getTx(), maxSpend}; } NotTEC @@ -1936,8 +1939,9 @@ XChainCommit::preclaim(PreclaimContext const& ctx) } AccountID const thisDoor = (*sleBridge)[sfAccount]; + AccountID const account = ctx.tx[sfAccount]; - if (thisDoor == ctx.account) + if (thisDoor == account) { // Door account can't lock funds onto itself return tecXCHAIN_SELF_COMMIT; @@ -1972,10 +1976,11 @@ XChainCommit::doApply() { PaymentSandbox psb(&ctx_.view()); + auto const account = ctx_.tx[sfAccount]; auto const amount = ctx_.tx[sfAmount]; auto const bridgeSpec = ctx_.tx[sfXChainBridge]; - if (!psb.read(keylet::account(account_))) + if (!psb.read(keylet::account(account))) return tecINTERNAL; auto const sleBridge = readBridge(psb, bridgeSpec); @@ -1990,7 +1995,7 @@ XChainCommit::doApply() auto const thTer = transferHelper( psb, - account_, + account, dst, /*dstTag*/ std::nullopt, /*claimOwner*/ std::nullopt, @@ -2033,6 +2038,7 @@ XChainCreateClaimID::preflight(PreflightContext const& ctx) TER XChainCreateClaimID::preclaim(PreclaimContext const& ctx) { + auto const account = ctx.tx[sfAccount]; auto const bridgeSpec = ctx.tx[sfXChainBridge]; auto const sleBridge = readBridge(ctx.view, bridgeSpec); @@ -2051,7 +2057,7 @@ XChainCreateClaimID::preclaim(PreclaimContext const& ctx) { // Check reserve - auto const sleAcc = ctx.view.read(keylet::account(ctx.account)); + auto const sleAcc = ctx.view.read(keylet::account(account)); if (!sleAcc) return terNO_ACCOUNT; @@ -2069,11 +2075,12 @@ XChainCreateClaimID::preclaim(PreclaimContext const& ctx) TER XChainCreateClaimID::doApply() { + auto const account = ctx_.tx[sfAccount]; auto const bridgeSpec = ctx_.tx[sfXChainBridge]; auto const reward = ctx_.tx[sfSignatureReward]; auto const otherChainSrc = ctx_.tx[sfOtherChainSource]; - auto const sleAcct = ctx_.view().peek(keylet::account(account_)); + auto const sleAcct = ctx_.view().peek(keylet::account(account)); if (!sleAcct) return tecINTERNAL; @@ -2093,7 +2100,7 @@ XChainCreateClaimID::doApply() auto const sleClaimID = std::make_shared(claimIDKeylet); - (*sleClaimID)[sfAccount] = account_; + (*sleClaimID)[sfAccount] = account; (*sleClaimID)[sfXChainBridge] = bridgeSpec; (*sleClaimID)[sfXChainClaimID] = claimID; (*sleClaimID)[sfOtherChainSource] = otherChainSrc; @@ -2104,9 +2111,9 @@ XChainCreateClaimID::doApply() // Add to owner directory { auto const page = ctx_.view().dirInsert( - keylet::ownerDir(account_), + keylet::ownerDir(account), claimIDKeylet, - describeOwnerDir(account_)); + describeOwnerDir(account)); if (!page) return tecDIR_FULL; (*sleClaimID)[sfOwnerNode] = *page; @@ -2221,7 +2228,8 @@ XChainCreateAccountCommit::preclaim(PreclaimContext const& ctx) return tecXCHAIN_BAD_TRANSFER_ISSUE; AccountID const thisDoor = (*sleBridge)[sfAccount]; - if (thisDoor == ctx.account) + AccountID const account = ctx.tx[sfAccount]; + if (thisDoor == account) { // Door account can't lock funds onto itself return tecXCHAIN_SELF_COMMIT; @@ -2253,11 +2261,12 @@ XChainCreateAccountCommit::doApply() { PaymentSandbox psb(&ctx_.view()); + AccountID const account = ctx_.tx[sfAccount]; STAmount const amount = ctx_.tx[sfAmount]; STAmount const reward = ctx_.tx[sfSignatureReward]; STXChainBridge const bridge = ctx_.tx[sfXChainBridge]; - auto const sle = psb.peek(keylet::account(account_)); + auto const sle = psb.peek(keylet::account(account)); if (!sle) return tecINTERNAL; @@ -2273,7 +2282,7 @@ XChainCreateAccountCommit::doApply() STAmount const toTransfer = amount + reward; auto const thTer = transferHelper( psb, - account_, + account, dst, /*dstTag*/ std::nullopt, /*claimOwner*/ std::nullopt, diff --git a/src/xrpld/app/tx/detail/apply.cpp b/src/xrpld/app/tx/detail/apply.cpp index 103ec041074..bad97f9bc85 100644 --- a/src/xrpld/app/tx/detail/apply.cpp +++ b/src/xrpld/app/tx/detail/apply.cpp @@ -116,7 +116,11 @@ apply( STAmountSO stAmountSO{view.rules().enabled(fixSTAmountCanonicalize)}; NumberSO stNumberSO{view.rules().enabled(fixUniversalNumber)}; - auto pfresult = preflight(app, view.rules(), tx, flags, j); + bool const isDelegated = view.rules().enabled(featureAccountPermission) && + tx.isFieldPresent(sfOnBehalfOf); + STTxWr txWr(tx, isDelegated); + + auto pfresult = preflight(app, view.rules(), txWr, flags, j); auto pcresult = preclaim(pfresult, app, view); return doApply(pcresult, app, view); } diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index 17f6c2b658c..340df3155d5 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -118,7 +118,7 @@ requires(T::ConsequencesFactory == Transactor::Normal) TxConsequences consequences_helper(PreflightContext const& ctx) { - return TxConsequences(ctx.tx); + return TxConsequences(ctx.tx.getTx()); }; // For Transactor::Blocker @@ -127,7 +127,7 @@ requires(T::ConsequencesFactory == Transactor::Blocker) TxConsequences consequences_helper(PreflightContext const& ctx) { - return TxConsequences(ctx.tx, TxConsequences::blocker); + return TxConsequences(ctx.tx.getTx(), TxConsequences::blocker); }; // For Transactor::Custom @@ -175,40 +175,42 @@ invoke_preclaim(PreclaimContext const& ctx) // doesn't list one, preflight will have already a flagged a // failure. auto const id = ctx.tx.getAccountID(sfAccount); - std::unordered_set gpSet; + std::unordered_set permissions; if (id != beast::zero) { - TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j); + TER result = T::checkSeqProxy(ctx.view, ctx.tx.getTx(), ctx.j); if (result != tesSUCCESS) - return std::make_pair(result, gpSet); + return std::make_pair(result, permissions); result = T::checkPriorTxAndLastLedger(ctx); if (result != tesSUCCESS) - return std::make_pair(result, gpSet); + return std::make_pair(result, permissions); - result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx)); + result = T::checkFee( + ctx, calculateBaseFee(ctx.view, ctx.tx.getTx())); if (result != tesSUCCESS) - return std::make_pair(result, gpSet); + return std::make_pair(result, permissions); result = T::checkSign(ctx); if (result != tesSUCCESS) - return std::make_pair(result, gpSet); + return std::make_pair(result, permissions); - if (ctx.isDelegated) + if (ctx.tx.isDelegated()) // if this is a delegated transaction, check if the account // has authorization. - result = T::checkAuthorization(ctx.view, ctx.tx, gpSet); + result = T::checkPermissions( + ctx.view, ctx.tx.getTx(), permissions); if (result != tesSUCCESS) - return std::make_pair(result, gpSet); + return std::make_pair(result, permissions); } - return std::make_pair(T::preclaim(ctx), gpSet); + return std::make_pair(T::preclaim(ctx), permissions); }); } catch (UnknownTxnType const& e) @@ -300,26 +302,19 @@ PreflightResult preflight( Application& app, Rules const& rules, - STTx const& tx, + STTxWr const& tx, ApplyFlags flags, beast::Journal j) { - bool const isDelegated = - rules.enabled(featureAccountPermission) && tx[~sfOnBehalfOf]; - AccountID const account = isDelegated ? *tx[~sfOnBehalfOf] : tx[sfAccount]; - PreflightContext const pfctx(app, tx, rules, flags, account, j); + PreflightContext const pfctx(app, tx, rules, flags, j); try { - // if AccountPermission is not enabled, do not use OnBehalfOf field. - if (!rules.enabled(featureAccountPermission) && tx[~sfOnBehalfOf]) - throw std::runtime_error("invalid field"); - - return {pfctx, isDelegated, account, invoke_preflight(pfctx)}; + return {pfctx, invoke_preflight(pfctx)}; } catch (std::exception const& e) { JLOG(j.fatal()) << "apply: " << e.what(); - return {pfctx, false, AccountID(0), {tefEXCEPTION, TxConsequences{tx}}}; + return {pfctx, {tefEXCEPTION, TxConsequences{tx.getTx()}}}; } } @@ -344,8 +339,6 @@ preclaim( secondFlight.ter, secondFlight.tx, secondFlight.flags, - secondFlight.isDelegated, - secondFlight.account, secondFlight.j); } else @@ -356,8 +349,6 @@ preclaim( preflightResult.ter, preflightResult.tx, preflightResult.flags, - preflightResult.isDelegated, - preflightResult.account, preflightResult.j); } try @@ -409,11 +400,9 @@ doApply(PreclaimResult const& preclaimResult, Application& app, OpenView& view) view, preclaimResult.tx, preclaimResult.ter, - calculateBaseFee(view, preclaimResult.tx), + calculateBaseFee(view, preclaimResult.tx.getTx()), preclaimResult.flags, - preclaimResult.isDelegated, - preclaimResult.account, - preclaimResult.gpSet, + preclaimResult.permissions, preclaimResult.j); return invoke_apply(ctx); } diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 7f52582b73b..4ef9660bb59 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -809,7 +809,37 @@ doLedgerEntry(RPC::JsonContext& context) } else if (context.params.isMember(jss::account_permission)) { - // to be implemented + expectedType = ltACCOUNT_PERMISSION; + auto const& permission = context.params[jss::account_permission]; + + if (!permission.isObject()) + { + if (!uNodeIndex.parseHex(permission.asString())) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + } + else if ( + !permission.isMember(jss::account) || + !permission.isMember(jss::authorize)) + { + jvResult[jss::error] = "malformedRequest"; + } + else + { + auto const account = + parseBase58(permission[jss::account].asString()); + auto const authorize = parseBase58( + permission[jss::authorize].asString()); + if (!account) + jvResult[jss::error] = "malformedAccount"; + else if (!authorize) + jvResult[jss::error] = "malformedAuthorize"; + else + uNodeIndex = + keylet::accountPermission(*account, *authorize).key; + } } else {