WIP support adding domainID in VaultSet

This commit is contained in:
Bronek Kozicki
2025-01-20 16:08:10 +00:00
parent dbaa12aa1c
commit 580a85f2c8
7 changed files with 73 additions and 13 deletions

View File

@@ -347,6 +347,7 @@ enum TECcodes : TERUnderlyingType {
tecBAD_CREDENTIALS = 193, tecBAD_CREDENTIALS = 193,
tecWRONG_ASSET = 194, tecWRONG_ASSET = 194,
tecLIMIT_EXCEEDED = 195, tecLIMIT_EXCEEDED = 195,
tecREMOVING_PERMISSIONS = 196,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -479,6 +479,7 @@ TRANSACTION(ttVAULT_CREATE, 64, VaultCreate, ({
TRANSACTION(ttVAULT_SET, 65, VaultSet, ({ TRANSACTION(ttVAULT_SET, 65, VaultSet, ({
{sfVaultID, soeREQUIRED}, {sfVaultID, soeREQUIRED},
{sfAssetMaximum, soeOPTIONAL}, {sfAssetMaximum, soeOPTIONAL},
{sfDomainID, soeOPTIONAL}, // PermissionedDomainID
// no WithdrawalPolicy yet // no WithdrawalPolicy yet
{sfData, soeOPTIONAL}, {sfData, soeOPTIONAL},
})) }))

View File

@@ -119,6 +119,7 @@ transResults()
MAKE_ERROR(tecBAD_CREDENTIALS, "Bad credentials."), MAKE_ERROR(tecBAD_CREDENTIALS, "Bad credentials."),
MAKE_ERROR(tecWRONG_ASSET, "Wrong asset given."), MAKE_ERROR(tecWRONG_ASSET, "Wrong asset given."),
MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."), MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."),
MAKE_ERROR(tecREMOVING_PERMISSIONS, "Would remove permissions previously granted."),
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."), MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."), MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),

View File

@@ -23,6 +23,7 @@
#include <xrpl/protocol/Feature.h> #include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/STNumber.h> #include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h> #include <xrpl/protocol/TxFlags.h>
namespace ripple { namespace ripple {
@@ -45,16 +46,19 @@ VaultCreate::preflight(PreflightContext const& ctx)
return temSTRING_TOO_LARGE; return temSTRING_TOO_LARGE;
} }
auto const domain = ctx.tx[~sfDomainID]; if (auto const domain = ctx.tx[~sfDomainID])
if (domain && *domain == beast::zero) {
return temMALFORMED; if (*domain == beast::zero)
return temMALFORMED;
else if ((ctx.tx.getFlags() & tfVaultPrivate) == 0)
return temMALFORMED; // DomainID only allowed on private vaults
}
// This block is copied from `MPTokenIssuanceCreate::preflight`.
if (auto const metadata = ctx.tx[~sfMPTokenMetadata]) if (auto const metadata = ctx.tx[~sfMPTokenMetadata])
{ {
if (metadata->length() == 0 || if (metadata->length() == 0 ||
metadata->length() > maxMPTokenMetadataLength) metadata->length() > maxMPTokenMetadataLength)
return temSTRING_TOO_LARGE; return temMALFORMED;
} }
return preflight2(ctx); return preflight2(ctx);
@@ -83,8 +87,7 @@ VaultCreate::preclaim(PreclaimContext const& ctx)
return tecLOCKED; return tecLOCKED;
} }
auto const domain = ctx.tx[~sfDomainID]; if (auto const domain = ctx.tx[~sfDomainID])
if (domain)
{ {
auto const sleDomain = auto const sleDomain =
ctx.view.read(keylet::permissionedDomain(*domain)); ctx.view.read(keylet::permissionedDomain(*domain));
@@ -129,7 +132,7 @@ VaultCreate::doApply()
auto txFlags = tx.getFlags(); auto txFlags = tx.getFlags();
std::uint32_t mptFlags = 0; std::uint32_t mptFlags = 0;
if (!(txFlags & tfVaultShareNonTransferable)) if ((txFlags & tfVaultShareNonTransferable) == 0)
mptFlags |= (lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer); mptFlags |= (lsfMPTCanEscrow | lsfMPTCanTrade | lsfMPTCanTransfer);
if (txFlags & tfVaultPrivate) if (txFlags & tfVaultPrivate)
mptFlags |= lsfMPTRequireAuth; mptFlags |= lsfMPTRequireAuth;

View File

@@ -19,6 +19,7 @@
#include <xrpld/app/tx/detail/VaultDeposit.h> #include <xrpld/app/tx/detail/VaultDeposit.h>
#include <xrpld/app/misc/CredentialHelpers.h>
#include <xrpld/app/tx/detail/MPTokenAuthorize.h> #include <xrpld/app/tx/detail/MPTokenAuthorize.h>
#include <xrpld/ledger/View.h> #include <xrpld/ledger/View.h>
#include <xrpl/protocol/Feature.h> #include <xrpl/protocol/Feature.h>
@@ -49,6 +50,19 @@ VaultDeposit::preclaim(PreclaimContext const& ctx)
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID])); auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
if (!vault) if (!vault)
return tecOBJECT_NOT_FOUND; return tecOBJECT_NOT_FOUND;
// Only the VaultDeposit transaction is subject to this permission check.
if (vault->getFlags() == tfVaultPrivate &&
ctx.tx[sfAccount] != vault->at(sfOwner))
{
if (auto const domain = vault->at(~sfVaultID))
{
if (!credentials::authorizedDomain(
ctx.view, *domain, ctx.tx[sfAccount]))
return tecNO_PERMISSION;
}
}
return tesSUCCESS; return tesSUCCESS;
} }

View File

@@ -20,7 +20,9 @@
#include <xrpld/app/tx/detail/VaultSet.h> #include <xrpld/app/tx/detail/VaultSet.h>
#include <xrpld/ledger/View.h> #include <xrpld/ledger/View.h>
#include <xrpl/protocol/Feature.h> #include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/STNumber.h> #include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h> #include <xrpl/protocol/TxFlags.h>
namespace ripple { namespace ripple {
@@ -41,12 +43,40 @@ VaultSet::preflight(PreflightContext const& ctx)
return temSTRING_TOO_LARGE; return temSTRING_TOO_LARGE;
} }
auto const domain = ctx.tx[~sfDomainID];
if (domain && *domain == beast::zero)
return temMALFORMED;
return preflight2(ctx); return preflight2(ctx);
} }
TER TER
VaultSet::preclaim(PreclaimContext const& ctx) VaultSet::preclaim(PreclaimContext const& ctx)
{ {
auto const id = ctx.tx[sfVaultID];
auto const sle = ctx.view.read(keylet::vault(id));
if (!sle)
return tecOBJECT_NOT_FOUND;
// Assert that submitter is the Owner.
if (ctx.tx[sfAccount] != sle->at(sfOwner))
return tecNO_PERMISSION;
// We can only set domain if private flag was originally set and
// domain was not set
if (auto const domain = ctx.tx[~sfDomainID])
{
if ((sle->getFlags() & tfVaultPrivate) == 0)
return tecREMOVING_PERMISSIONS;
if (auto const oldDomain = sle->at(~sfDomainID))
{
if (*oldDomain != *domain)
return tecREMOVING_PERMISSIONS;
// else no change
}
// else domain wasn't set previously, we allow setting it now
}
return tesSUCCESS; return tesSUCCESS;
} }
@@ -58,17 +88,12 @@ VaultSet::doApply()
// we can consider downgrading them to `tef` or `tem`. // we can consider downgrading them to `tef` or `tem`.
auto const& tx = ctx_.tx; auto const& tx = ctx_.tx;
auto const& owner = account_;
// Update existing object. // Update existing object.
auto vault = view().peek({ltVAULT, tx[sfVaultID]}); auto vault = view().peek({ltVAULT, tx[sfVaultID]});
if (!vault) if (!vault)
return tecOBJECT_NOT_FOUND; return tecOBJECT_NOT_FOUND;
// Assert that submitter is the Owner.
if (owner != vault->at(sfOwner))
return tecNO_PERMISSION;
// Update mutable flags and fields if given. // Update mutable flags and fields if given.
if (tx.isFieldPresent(sfData)) if (tx.isFieldPresent(sfData))
vault->at(sfData) = tx[sfData]; vault->at(sfData) = tx[sfData];
@@ -78,6 +103,17 @@ VaultSet::doApply()
return tecLIMIT_EXCEEDED; return tecLIMIT_EXCEEDED;
vault->at(sfAssetMaximum) = tx[sfAssetMaximum]; vault->at(sfAssetMaximum) = tx[sfAssetMaximum];
} }
if (tx.isFieldPresent(sfDomainID))
{
// In VaultSet::preclaim we enforce that either DomainID wasn't present
// in the vault, or was the same value as the one supplied. We also
// enforce that tfVaultPrivate must have been set in the vault. By
// adding DomainID to an existing private vault, we are allowing
// permissioned users to interract with a vault which was previously
// accessible to its owner only. We currently do not support making
// such a vault public (i.e. removal of tfVaultPrivate flag)
vault->setFieldH256(sfDomainID, tx.getFieldH256(sfDomainID));
}
view().update(vault); view().update(vault);

View File

@@ -19,9 +19,12 @@
#include <xrpld/app/tx/detail/VaultWithdraw.h> #include <xrpld/app/tx/detail/VaultWithdraw.h>
#include <xrpld/app/misc/CredentialHelpers.h>
#include <xrpld/ledger/View.h> #include <xrpld/ledger/View.h>
#include <xrpl/protocol/Feature.h> #include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STNumber.h> #include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/TxFlags.h> #include <xrpl/protocol/TxFlags.h>
namespace ripple { namespace ripple {
@@ -47,6 +50,7 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID])); auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
if (!vault) if (!vault)
return tecOBJECT_NOT_FOUND; return tecOBJECT_NOT_FOUND;
return tesSUCCESS; return tesSUCCESS;
} }