From bd7150e2c56b2d192c23aedfab19a772b27e116f Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Wed, 23 Oct 2024 12:41:56 -0400 Subject: [PATCH] add AccountPermission --- include/xrpl/protocol/Feature.h | 2 +- include/xrpl/protocol/Indexes.h | 11 ++ include/xrpl/protocol/Permissions.h | 82 ++++++++++ include/xrpl/protocol/detail/features.macro | 1 + .../xrpl/protocol/detail/ledger_entries.macro | 13 ++ include/xrpl/protocol/detail/sfields.macro | 3 + .../xrpl/protocol/detail/transactions.macro | 6 + include/xrpl/protocol/jss.h | 2 + src/libxrpl/protocol/Indexes.cpp | 18 +++ src/libxrpl/protocol/InnerObjectFormats.cpp | 4 + src/libxrpl/protocol/Permissions.cpp | 73 +++++++++ src/libxrpl/protocol/STParsedJSON.cpp | 43 ++++- .../app/tx/detail/AccountPermissionSet.cpp | 152 ++++++++++++++++++ .../app/tx/detail/AccountPermissionSet.h | 56 +++++++ src/xrpld/app/tx/detail/DeleteAccount.cpp | 16 ++ src/xrpld/app/tx/detail/InvariantCheck.cpp | 1 + src/xrpld/app/tx/detail/applySteps.cpp | 1 + src/xrpld/rpc/detail/RPCHelpers.cpp | 3 +- src/xrpld/rpc/handlers/LedgerEntry.cpp | 4 + 19 files changed, 485 insertions(+), 6 deletions(-) create mode 100644 include/xrpl/protocol/Permissions.h create mode 100644 src/libxrpl/protocol/Permissions.cpp create mode 100644 src/xrpld/app/tx/detail/AccountPermissionSet.cpp create mode 100644 src/xrpld/app/tx/detail/AccountPermissionSet.h diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 5537c543d6f..eb975f39ae0 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 79; +static constexpr std::size_t numFeatures = 80; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index f179bbacfab..17a7ded1d00 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -272,6 +272,17 @@ amm(Issue const& issue1, Issue const& issue2) noexcept; Keylet amm(uint256 const& amm) noexcept; +/** An AccountPermission */ +/** @{ */ +Keylet +accountPermission( + AccountID const& account, + AccountID const& authorizedAccount) noexcept; + +Keylet +accountPermission(uint256 const& key) noexcept; +/** @} */ + Keylet bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType); diff --git a/include/xrpl/protocol/Permissions.h b/include/xrpl/protocol/Permissions.h new file mode 100644 index 00000000000..9d14b6b1dd3 --- /dev/null +++ b/include/xrpl/protocol/Permissions.h @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +/* + 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_PERMISSION_H_INCLUDED +#define RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +/** + * We have transaction type permissions and granular type + * permissions. Since we will reuse the TransactionFormats to parse the + * Transaction Permissions, we only define the GranularPermissionType here. + */ + +enum GranularPermissionType : std::uint32_t { + gpTrustlineAuthorize = 65537, + + gpTrustlineFreeze = 65538, + + gpTrustlineUnfreeze = 65539, + + gpAccountDomainSet = 65540, + + gpAccountEmailHashSet = 65541, + + gpAccountMessageKeySet = 65542, + + gpAccountTransferRateSet = 65543, + + gpAccountTickSizeSet = 65544, + + gpPaymentMint = 65545, + + gpPaymentBurn = 65546, + + gpMPTokenIssuanceLock = 65547, + + gpMPTokenIssuanceUnlock = 65548, +}; + +class Permission +{ +private: + Permission(); + + std::unordered_map + granularPermissionMap; + +public: + static Permission const& + getInstance(); + + std::optional + getGranularValue(const std::string& name) const; + + bool + isProhibited(const std::string& name) const; +}; + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 159bc3720b7..141533e1e52 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -94,6 +94,7 @@ XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYe XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo) +XRPL_FEATURE(AccountPermission, Supported::yes, VoteBehavior::DefaultYes) // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index 359000cbbf3..8a91fe54ef1 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -392,3 +392,16 @@ LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, ({ {sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED}, })) + +/** A ledger object representing permissions an account has delegated to another account. + + \sa keylet::accountPermission + */ +LEDGER_ENTRY(ltACCOUNT_PERMISSION, 0x0081, AccountPermission, ({ + {sfAccount, soeREQUIRED}, + {sfAuthorize, soeREQUIRED}, + {sfPermissions, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) \ No newline at end of file diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index bdfcf5dfafd..5c80549859d 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -111,6 +111,7 @@ TYPED_SFIELD(sfEmitGeneration, UINT32, 46) TYPED_SFIELD(sfVoteWeight, UINT32, 48) TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50) TYPED_SFIELD(sfOracleDocumentID, UINT32, 51) +TYPED_SFIELD(sfPermissionValue, UINT32, 52) // 64-bit integers (common) TYPED_SFIELD(sfIndexNext, UINT64, 1) @@ -309,6 +310,7 @@ UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11) UNTYPED_SFIELD(sfNFToken, OBJECT, 12) UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13) UNTYPED_SFIELD(sfHook, OBJECT, 14) +UNTYPED_SFIELD(sfPermission, OBJECT, 15) // inner object (uncommon) UNTYPED_SFIELD(sfSigner, OBJECT, 16) @@ -355,3 +357,4 @@ UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22) // 23 unused UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24) UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25) +UNTYPED_SFIELD(sfPermissions, ARRAY, 26) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 98678e9d509..db8e168b9f7 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -386,6 +386,12 @@ TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, ({ {sfOwner, soeOPTIONAL}, })) +/** This transaction type delegates authorized account specified permissions */ +TRANSACTION(ttACCOUNT_PERMISSION_SET, 54, AccountPermissionSet, ({ + {sfAuthorize, soeREQUIRED}, + {sfPermissions, soeREQUIRED}, +})) + /** This system-generated transaction type is used to update the status of the various amendments. For details, see: https://xrpl.org/amendments.html diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 1e4e22cd73a..66056cd7634 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -45,6 +45,7 @@ namespace jss { JSS(AL_size); // out: GetCounts JSS(AL_hit_rate); // out: GetCounts JSS(Account); // in: TransactionSign; field. +JSS(AccountPermission); // ledger type. JSS(AccountRoot); // ledger type. JSS(AMM); // ledger type JSS(AMMID); // field @@ -126,6 +127,7 @@ JSS(account_hash); // out: LedgerToJson JSS(account_id); // out: WalletPropose JSS(account_nfts); // out: AccountNFTs JSS(account_objects); // out: AccountObjects +JSS(account_permission); // in: AccountPermission JSS(account_root); // in: LedgerEntry JSS(account_sequence_next); // out: SubmitTransaction JSS(account_sequence_available); // out: SubmitTransaction diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 30d97416cfa..649ef44b852 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -73,6 +73,7 @@ enum class LedgerNameSpace : std::uint16_t { XCHAIN_CREATE_ACCOUNT_CLAIM_ID = 'K', DID = 'I', ORACLE = 'R', + ACCOUNT_PERMISSION = 'P', // No longer used or supported. Left here to reserve the space // to avoid accidental reuse. @@ -398,6 +399,23 @@ amm(uint256 const& id) noexcept return {ltAMM, id}; } +Keylet +accountPermission( + AccountID const& account, + AccountID const& authorizedAccount) noexcept +{ + return { + ltACCOUNT_PERMISSION, + indexHash( + LedgerNameSpace::ACCOUNT_PERMISSION, account, authorizedAccount)}; +} + +Keylet +accountPermission(uint256 const& key) noexcept +{ + return {ltACCOUNT_PERMISSION, key}; +} + Keylet bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType) { diff --git a/src/libxrpl/protocol/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp index 6d7b855d199..c6fc787f2a3 100644 --- a/src/libxrpl/protocol/InnerObjectFormats.cpp +++ b/src/libxrpl/protocol/InnerObjectFormats.cpp @@ -147,6 +147,10 @@ InnerObjectFormats::InnerObjectFormats() {sfAssetPrice, soeOPTIONAL}, {sfScale, soeDEFAULT}, }); + + add(sfPermission.jsonName.c_str(), + sfPermission.getCode(), + {{sfPermissionValue, soeREQUIRED}}); } InnerObjectFormats const& diff --git a/src/libxrpl/protocol/Permissions.cpp b/src/libxrpl/protocol/Permissions.cpp new file mode 100644 index 00000000000..74182b77ff8 --- /dev/null +++ b/src/libxrpl/protocol/Permissions.cpp @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#include +#include +#include +#include + +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}}; +} + +Permission const& +Permission::getInstance() +{ + static Permission const instance; + return instance; +} + +std::optional +Permission::getGranularValue(const std::string& name) const +{ + auto const it = granularPermissionMap.find(name); + if (it != granularPermissionMap.end()) + return static_cast(it->second); + + return std::nullopt; +} + +bool +Permission::isProhibited(const std::string& name) const +{ + // We do not allow delegating the following transaction permissions to other + // accounts for security reason. + if (name == "AccountSet" || name == "SetRegularKey" || + name == "SignerListSet") + return true; + + return false; +} + +} // namespace ripple diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 327b9ee31c4..167c1663f13 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -360,10 +361,44 @@ parseLeaf( { if (value.isString()) { - ret = detail::make_stvar( - field, - beast::lexicalCastThrow( - value.asString())); + if (field == sfPermissionValue) + { + std::string const strValue = value.asString(); + auto const granularPermission = + Permission::getInstance().getGranularValue( + strValue); + if (!granularPermission) + { + // if it's not granular permission, parse as + // transaction type permission. + if (Permission::getInstance().isProhibited( + strValue)) + { + // we do not allow delegating some transaction + // type permissions to other accounts for + // security reason. + error = invalid_data(json_name, fieldName); + return ret; + } + else + ret = detail::make_stvar( + field, + static_cast( + TxFormats::getInstance().findTypeByName( + strValue) + + 1)); + } + else + ret = detail::make_stvar( + field, *granularPermission); + } + else + { + ret = detail::make_stvar( + field, + beast::lexicalCastThrow( + value.asString())); + } } else if (value.isInt()) { diff --git a/src/xrpld/app/tx/detail/AccountPermissionSet.cpp b/src/xrpld/app/tx/detail/AccountPermissionSet.cpp new file mode 100644 index 00000000000..bacb2c96878 --- /dev/null +++ b/src/xrpld/app/tx/detail/AccountPermissionSet.cpp @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +constexpr std::size_t permissionMaxSize = 10; + +NotTEC +AccountPermissionSet::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureAccountPermission)) + return temDISABLED; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + auto const& permissions = ctx.tx.getFieldArray(sfPermissions); + if (permissions.size() > permissionMaxSize) + return temARRAY_TOO_LARGE; + + std::unordered_set permissionSet; + + 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()) + return temMALFORMED; + + permissionSet.insert(permissionValue); + } + + return preflight2(ctx); +} + +TER +AccountPermissionSet::preclaim(PreclaimContext const& ctx) +{ + auto const account = ctx.view.read(keylet::account(ctx.tx[sfAccount])); + if (!account) + return terNO_ACCOUNT; // LCOV_EXCL_LINE + + auto const authAccount = + ctx.view.read(keylet::account(ctx.tx[sfAuthorize])); + if (!authAccount) + return terNO_ACCOUNT; + + return tesSUCCESS; +} + +TER +AccountPermissionSet::doApply() +{ + auto const sleOwner = ctx_.view().peek(keylet::account(account_)); + if (!sleOwner) + return tefINTERNAL; // LCOV_EXCL_LINE + + auto const accountPermissionKey = + keylet::accountPermission(account_, ctx_.tx[sfAuthorize]); + + auto sle = ctx_.view().peek(accountPermissionKey); + if (sle) + { + auto const& permissions = ctx_.tx.getFieldArray(sfPermissions); + sle->setFieldArray(sfPermissions, permissions); + ctx_.view().update(sle); + return tesSUCCESS; + } + + STAmount const reserve{ctx_.view().fees().accountReserve( + sleOwner->getFieldU32(sfOwnerCount) + 1)}; + + if (mPriorBalance < reserve) + return tecINSUFFICIENT_RESERVE; + + sle = std::make_shared(accountPermissionKey); + auto const& permissions = ctx_.tx.getFieldArray(sfPermissions); + sle->setFieldArray(sfPermissions, permissions); + auto const page = ctx_.view().dirInsert( + keylet::ownerDir(account_), + accountPermissionKey, + describeOwnerDir(account_)); + + if (!page) + return tecDIR_FULL; // LCOV_EXCL_LINE + + (*sle)[sfOwnerNode] = *page; + ctx_.view().insert(sle); + adjustOwnerCount(ctx_.view(), sleOwner, 1, ctx_.journal); + return tesSUCCESS; +} + +TER +AccountPermissionSet::deleteAccountPermission( + ApplyView& view, + std::shared_ptr const& sle, + AccountID const& account, + beast::Journal j) +{ + if (!sle) + return tecINTERNAL; // LCOV_EXCL_LINE + + if (!view.dirRemove( + keylet::ownerDir(account), (*sle)[sfOwnerNode], sle->key(), false)) + { + // LCOV_EXCL_START + JLOG(j.fatal()) << "Unable to delete AccountPermission from owner."; + return tefBAD_LEDGER; + // LCOV_EXCL_STOP + } + + auto const sleOwner = view.peek(keylet::account(account)); + if (!sleOwner) + return tecINTERNAL; // LCOV_EXCL_LINE + + adjustOwnerCount(view, sleOwner, -1, j); + + view.erase(sle); + + return tesSUCCESS; +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/AccountPermissionSet.h b/src/xrpld/app/tx/detail/AccountPermissionSet.h new file mode 100644 index 00000000000..d6096dc794d --- /dev/null +++ b/src/xrpld/app/tx/detail/AccountPermissionSet.h @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +/* + 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_TX_ACCOUNTPERMISSIONSET_H_INCLUDED +#define RIPPLE_TX_ACCOUNTPERMISSIONSET_H_INCLUDED + +#include + +namespace ripple { + +class AccountPermissionSet : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit AccountPermissionSet(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; + + // Interface used by DeleteAccount + static TER + deleteAccountPermission( + ApplyView& view, + std::shared_ptr const& sle, + AccountID const& account, + beast::Journal j); +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index fb2f3fc507f..50e59e6537d 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include #include @@ -159,6 +160,19 @@ removeOracleFromLedger( return DeleteOracle::deleteOracle(view, sleDel, account, j); } +TER +removeAccountPermissionFromLedger( + Application& app, + ApplyView& view, + AccountID const& account, + uint256 const& delIndex, + std::shared_ptr const& sleDel, + beast::Journal j) +{ + return AccountPermissionSet::deleteAccountPermission( + view, sleDel, account, j); +} + // Return nullptr if the LedgerEntryType represents an obligation that can't // be deleted. Otherwise return the pointer to the function that can delete // the non-obligation @@ -181,6 +195,8 @@ nonObligationDeleter(LedgerEntryType t) return removeDIDFromLedger; case ltORACLE: return removeOracleFromLedger; + case ltACCOUNT_PERMISSION: + return removeAccountPermissionFromLedger; default: return nullptr; } diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index f855ad8578c..453e14a2aa6 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -457,6 +457,7 @@ LedgerEntryTypesMatch::visitEntry( switch (after->getType()) { case ltACCOUNT_ROOT: + case ltACCOUNT_PERMISSION: case ltDIR_NODE: case ltRIPPLE_STATE: case ltTICKET: diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index f39c61abeac..5d83d3db4db 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index fa66fecfbba..f707d2d9266 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -915,9 +915,10 @@ chooseLedgerEntryType(Json::Value const& params) std::pair result{RPC::Status::OK, ltANY}; if (params.isMember(jss::type)) { - static constexpr std::array, 22> + static constexpr std::array, 23> types{ {{jss::account, ltACCOUNT_ROOT}, + {jss::account_permission, ltACCOUNT_PERMISSION}, {jss::amendments, ltAMENDMENTS}, {jss::amm, ltAMM}, {jss::bridge, ltBRIDGE}, diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index f461cd3100b..37a1033f046 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -644,6 +644,10 @@ doLedgerEntry(RPC::JsonContext& context) uNodeIndex = keylet::oracle(*account, *documentID).key; } } + else if (context.params.isMember(jss::account_permission)) + { + // to be implemented + } else { if (context.params.isMember("params") &&