From dbaa12aa1cec8fdf451bf5b33a4feb286aee5e11 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 17 Jan 2025 18:54:13 +0000 Subject: [PATCH] WIP permissioned domain support --- .../xrpl/protocol/detail/ledger_entries.macro | 2 +- .../xrpl/protocol/detail/transactions.macro | 3 +- src/xrpld/app/misc/CredentialHelpers.cpp | 48 +++++++++++++++---- src/xrpld/app/misc/CredentialHelpers.h | 16 +++++-- src/xrpld/app/tx/detail/VaultCreate.cpp | 18 +++++++ 5 files changed, 72 insertions(+), 15 deletions(-) diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index fad7bc6979..9dfed3ae59 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -478,9 +478,9 @@ LEDGER_ENTRY(ltVAULT, 0x0083, Vault, vault, ({ {sfAssetMaximum, soeDEFAULT}, {sfLossUnrealized, soeDEFAULT}, {sfMPTokenIssuanceID, soeREQUIRED}, // sfShare + {sfDomainID, soeOPTIONAL}, // PermissionedDomainID // no ShareTotal ever (use MPTIssuance.sfOutstandingAmount) // no WithdrawalPolicy yet - // no PermissionedDomainID yet })) #undef EXPAND diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index ef121fc4f1..66d0391b9f 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -470,7 +470,7 @@ TRANSACTION(ttVAULT_CREATE, 64, VaultCreate, ({ {sfAsset, soeREQUIRED, soeMPTSupported}, {sfAssetMaximum, soeOPTIONAL}, {sfMPTokenMetadata, soeOPTIONAL}, - // no PermissionedDomainID yet + {sfDomainID, soeOPTIONAL}, // PermissionedDomainID // no WithdrawalPolicy yet {sfData, soeOPTIONAL}, })) @@ -479,7 +479,6 @@ TRANSACTION(ttVAULT_CREATE, 64, VaultCreate, ({ TRANSACTION(ttVAULT_SET, 65, VaultSet, ({ {sfVaultID, soeREQUIRED}, {sfAssetMaximum, soeOPTIONAL}, - // no PermissionedDomainID yet // no WithdrawalPolicy yet {sfData, soeOPTIONAL}, })) diff --git a/src/xrpld/app/misc/CredentialHelpers.cpp b/src/xrpld/app/misc/CredentialHelpers.cpp index a18cd40336..a8ec360744 100644 --- a/src/xrpld/app/misc/CredentialHelpers.cpp +++ b/src/xrpld/app/misc/CredentialHelpers.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include +#include #include #include @@ -185,15 +188,41 @@ valid(PreclaimContext const& ctx, AccountID const& src) } TER -authorized(ApplyContext const& ctx, AccountID const& dst) +authorizedDomain( + ReadView const& view, + uint256 domainID, + AccountID const& subject) +{ + auto const sle = view.read(keylet::permissionedDomain(domainID)); + if (!sle || !sle->isFieldPresent(sfAcceptedCredentials)) + return tefINTERNAL; + + for (auto const& h : sle->getFieldArray(sfAcceptedCredentials)) + { + if (!h.isFieldPresent(sfIssuer) || !h.isFieldPresent(sfCredentialType)) + return tefINTERNAL; + + auto const issuer = h.getAccountID(sfIssuer); + auto const type = makeSlice(h.getFieldVL(sfCredentialType)); + if (view.exists(keylet::credential(subject, issuer, type))) + return tesSUCCESS; + } + + return tecNO_PERMISSION; +} + +TER +authorizedDepositPreauth( + ApplyView const& view, + STVector256 const& credIDs, + AccountID const& dst) { - auto const& credIDs(ctx.tx.getFieldV256(sfCredentialIDs)); std::set> sorted; std::vector> lifeExtender; lifeExtender.reserve(credIDs.size()); for (auto const& h : credIDs) { - auto sleCred = ctx.view().read(keylet::credential(h)); + auto sleCred = view.read(keylet::credential(h)); if (!sleCred) // already checked in preclaim return tefINTERNAL; @@ -204,11 +233,8 @@ authorized(ApplyContext const& ctx, AccountID const& dst) lifeExtender.push_back(std::move(sleCred)); } - if (!ctx.view().exists(keylet::depositPreauth(dst, sorted))) - { - JLOG(ctx.journal.trace()) << "DepositPreauth doesn't exist"; + if (!view.exists(keylet::depositPreauth(dst, sorted))) return tecNO_PERMISSION; - } return tesSUCCESS; } @@ -296,8 +322,12 @@ verifyDepositPreauth( if (src != dst) { if (!ctx.view().exists(keylet::depositPreauth(dst, src))) - return !credentialsPresent ? tecNO_PERMISSION - : credentials::authorized(ctx, dst); + return !credentialsPresent + ? tecNO_PERMISSION + : credentials::authorizedDepositPreauth( + ctx.view(), + ctx.tx.getFieldV256(sfCredentialIDs), + dst); } } diff --git a/src/xrpld/app/misc/CredentialHelpers.h b/src/xrpld/app/misc/CredentialHelpers.h index acc4f2621d..fcfb3b28a0 100644 --- a/src/xrpld/app/misc/CredentialHelpers.h +++ b/src/xrpld/app/misc/CredentialHelpers.h @@ -53,10 +53,20 @@ checkFields(PreflightContext const& ctx); TER valid(PreclaimContext const& ctx, AccountID const& src); -// This function is only called when we about to return tecNO_PERMISSION because -// all the checks for the DepositPreauth authorization failed. +// Check if subject has any credentials maching given credential domain TER -authorized(ApplyContext const& ctx, AccountID const& dst); +authorizedDomain( + ReadView const& view, + uint256 domainID, + AccountID const& subject); + +// This function is only called when we about to return tecNO_PERMISSION +// because all the checks for the DepositPreauth authorization failed. +TER +authorizedDepositPreauth( + ApplyView const& view, + STVector256 const& ctx, + AccountID const& dst); // Sort credentials array, return empty set if there are duplicates std::set> diff --git a/src/xrpld/app/tx/detail/VaultCreate.cpp b/src/xrpld/app/tx/detail/VaultCreate.cpp index aced64d8ed..98b5fc7a79 100644 --- a/src/xrpld/app/tx/detail/VaultCreate.cpp +++ b/src/xrpld/app/tx/detail/VaultCreate.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,10 @@ VaultCreate::preflight(PreflightContext const& ctx) return temSTRING_TOO_LARGE; } + auto const domain = ctx.tx[~sfDomainID]; + if (domain && *domain == beast::zero) + return temMALFORMED; + // This block is copied from `MPTokenIssuanceCreate::preflight`. if (auto const metadata = ctx.tx[~sfMPTokenMetadata]) { @@ -70,12 +75,23 @@ VaultCreate::preclaim(PreclaimContext const& ctx) { auto mptID = asset.get().getMptID(); auto issuance = ctx.view.read(keylet::mptIssuance(mptID)); + if (!issuance) + return tecNO_ENTRY; if (issuance->getFlags() & lsfMPTLocked) return tecLOCKED; if ((issuance->getFlags() & lsfMPTCanTransfer) == 0) return tecLOCKED; } + auto const domain = ctx.tx[~sfDomainID]; + if (domain) + { + auto const sleDomain = + ctx.view.read(keylet::permissionedDomain(*domain)); + if (!sleDomain) + return tecNO_ENTRY; + } + return tesSUCCESS; } @@ -136,6 +152,8 @@ VaultCreate::doApply() vault->at(sfOwner) = ownerId; vault->at(sfAccount) = pseudoId; vault->at(sfAsset) = tx[sfAsset]; + if (tx.isFieldPresent(sfDomainID)) + vault->setFieldH256(sfDomainID, tx.getFieldH256(sfDomainID)); // Leave default values for AssetTotal and AssetAvailable, both zero. if (auto value = tx[~sfAssetMaximum]) vault->at(sfAssetMaximum) = *value;