mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 19:15:54 +00:00
WIP permissioned domain support
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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},
|
||||
}))
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
#include <xrpld/app/misc/CredentialHelpers.h>
|
||||
#include <xrpld/ledger/View.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
|
||||
#include <unordered_set>
|
||||
@@ -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<std::pair<AccountID, Slice>> sorted;
|
||||
std::vector<std::shared_ptr<SLE const>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::pair<AccountID, Slice>>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <xrpld/app/tx/detail/VaultCreate.h>
|
||||
#include <xrpld/ledger/View.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
|
||||
@@ -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<MPTIssue>().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;
|
||||
|
||||
Reference in New Issue
Block a user