Code cleanup

This commit is contained in:
Bronek Kozicki
2025-04-23 11:14:31 +01:00
parent 20ce0e79ab
commit 0ab792263a
13 changed files with 85 additions and 81 deletions

View File

@@ -124,7 +124,7 @@ std::uint8_t constexpr vaultStrategyFirstComeFirstServe = 1;
/** Maximum recursion depth for vault shares being put as an asset inside /** Maximum recursion depth for vault shares being put as an asset inside
* another vault; counted from 0 */ * another vault; counted from 0 */
std::uint8_t constexpr maxFreezeCheckDepth = 5; std::uint8_t constexpr maxAssetCheckDepth = 5;
/** A ledger index. */ /** A ledger index. */
using LedgerIndex = std::uint32_t; using LedgerIndex = std::uint32_t;

View File

@@ -93,7 +93,9 @@ struct JsonOptions
}; };
template <typename T> template <typename T>
requires requires(T const& t) { t.getJson(JsonOptions::none); } requires requires(T const& t) {
{ t.getJson(JsonOptions::none) } -> std::convertible_to<Json::Value>;
}
Json::Value Json::Value
to_json(T const& t) to_json(T const& t)
{ {

View File

@@ -61,8 +61,7 @@ using NodeID = base_uint<160, detail::NodeIDTag>;
/** MPTID is a 192-bit value representing MPT Issuance ID, /** MPTID is a 192-bit value representing MPT Issuance ID,
* which is a concatenation of a 32-bit sequence (big endian) * which is a concatenation of a 32-bit sequence (big endian)
* and a 160-bit account */ * and a 160-bit account */
// TODO - edhennis - Add a tag using MPTID = base_uint<192>;
using MPTID = uint192;
/** XRP currency. */ /** XRP currency. */
Currency const& Currency const&

View File

@@ -197,9 +197,9 @@ TYPED_SFIELD(sfVaultID, UINT256, 35)
// number (common) // number (common)
TYPED_SFIELD(sfNumber, NUMBER, 1) TYPED_SFIELD(sfNumber, NUMBER, 1)
TYPED_SFIELD(sfAssetsAvailable, NUMBER, 2) TYPED_SFIELD(sfAssetsAvailable, NUMBER, 2)
TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3) TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3)
TYPED_SFIELD(sfAssetsTotal, NUMBER, 4) TYPED_SFIELD(sfAssetsTotal, NUMBER, 4)
TYPED_SFIELD(sfLossUnrealized, NUMBER, 5) TYPED_SFIELD(sfLossUnrealized, NUMBER, 5)
// currency amount (common) // currency amount (common)

View File

@@ -89,7 +89,6 @@ JSS(SettleDelay); // in: TransactionSign
JSS(SendMax); // in: TransactionSign JSS(SendMax); // in: TransactionSign
JSS(Sequence); // in/out: TransactionSign; field. JSS(Sequence); // in/out: TransactionSign; field.
JSS(SetFlag); // field. JSS(SetFlag); // field.
JSS(SharesTotal); // out: Vault
JSS(Signer); // field. JSS(Signer); // field.
JSS(Signers); // field. JSS(Signers); // field.
JSS(SigningPubKey); // field. JSS(SigningPubKey); // field.
@@ -101,7 +100,6 @@ JSS(TransactionType); // in: TransactionSign.
JSS(TransferRate); // in: TransferRate. JSS(TransferRate); // in: TransferRate.
JSS(TxnSignature); // field. JSS(TxnSignature); // field.
JSS(URI); // field. JSS(URI); // field.
JSS(VaultID); // field.
JSS(VoteSlots); // out: AMM Vote JSS(VoteSlots); // out: AMM Vote
JSS(aborted); // out: InboundLedger JSS(aborted); // out: InboundLedger
JSS(accepted); // out: LedgerToJson, OwnerInfo, SubmitTransaction JSS(accepted); // out: LedgerToJson, OwnerInfo, SubmitTransaction

View File

@@ -31,7 +31,6 @@
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h> #include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/STLedgerEntry.h> #include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STNumber.h>
#include <xrpl/protocol/STObject.h> #include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/Serializer.h> #include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/jss.h> #include <xrpl/protocol/jss.h>

View File

@@ -50,7 +50,7 @@ Vault::set(SetArgs const& args)
Json::Value jv; Json::Value jv;
jv[jss::TransactionType] = jss::VaultSet; jv[jss::TransactionType] = jss::VaultSet;
jv[jss::Account] = args.owner.human(); jv[jss::Account] = args.owner.human();
jv[jss::VaultID] = to_string(args.id); jv[sfVaultID] = to_string(args.id);
return jv; return jv;
} }
@@ -60,7 +60,7 @@ Vault::del(DeleteArgs const& args)
Json::Value jv; Json::Value jv;
jv[jss::TransactionType] = jss::VaultDelete; jv[jss::TransactionType] = jss::VaultDelete;
jv[jss::Account] = args.owner.human(); jv[jss::Account] = args.owner.human();
jv[jss::VaultID] = to_string(args.id); jv[sfVaultID] = to_string(args.id);
return jv; return jv;
} }
@@ -70,7 +70,7 @@ Vault::deposit(DepositArgs const& args)
Json::Value jv; Json::Value jv;
jv[jss::TransactionType] = jss::VaultDeposit; jv[jss::TransactionType] = jss::VaultDeposit;
jv[jss::Account] = args.depositor.human(); jv[jss::Account] = args.depositor.human();
jv[jss::VaultID] = to_string(args.id); jv[sfVaultID] = to_string(args.id);
jv[jss::Amount] = to_json(args.amount); jv[jss::Amount] = to_json(args.amount);
return jv; return jv;
} }
@@ -81,7 +81,7 @@ Vault::withdraw(WithdrawArgs const& args)
Json::Value jv; Json::Value jv;
jv[jss::TransactionType] = jss::VaultWithdraw; jv[jss::TransactionType] = jss::VaultWithdraw;
jv[jss::Account] = args.depositor.human(); jv[jss::Account] = args.depositor.human();
jv[jss::VaultID] = to_string(args.id); jv[sfVaultID] = to_string(args.id);
jv[jss::Amount] = to_json(args.amount); jv[jss::Amount] = to_json(args.amount);
return jv; return jv;
} }
@@ -92,7 +92,7 @@ Vault::clawback(ClawbackArgs const& args)
Json::Value jv; Json::Value jv;
jv[jss::TransactionType] = jss::VaultClawback; jv[jss::TransactionType] = jss::VaultClawback;
jv[jss::Account] = args.issuer.human(); jv[jss::Account] = args.issuer.human();
jv[jss::VaultID] = to_string(args.id); jv[sfVaultID] = to_string(args.id);
jv[jss::Holder] = args.holder.human(); jv[jss::Holder] = args.holder.human();
if (args.amount) if (args.amount)
jv[jss::Amount] = to_json(*args.amount); jv[jss::Amount] = to_json(*args.amount);

View File

@@ -227,8 +227,7 @@ applyCreate(
auto const ammKeylet = keylet::amm(amount.issue(), amount2.issue()); auto const ammKeylet = keylet::amm(amount.issue(), amount2.issue());
// Mitigate same account exists possibility // Mitigate same account exists possibility
auto const maybeAccount = auto const maybeAccount = createPseudoAccount(sb, ammKeylet.key, sfAMMID);
createPseudoAccount(sb, ammKeylet.key, PseudoAccountOwnerType::AMM);
// AMM account already exists (should not happen) // AMM account already exists (should not happen)
if (!maybeAccount) if (!maybeAccount)
{ {

View File

@@ -97,7 +97,7 @@ VaultClawback::preclaim(PreclaimContext const& ctx)
return tecWRONG_ASSET; return tecWRONG_ASSET;
std::uint32_t const issueFlags = mptIssue->getFieldU32(sfFlags); std::uint32_t const issueFlags = mptIssue->getFieldU32(sfFlags);
if (!(issueFlags & lsfMPTCanClawback) || !(issueFlags & lsfMPTCanLock)) if (!(issueFlags & lsfMPTCanClawback))
return tecNO_PERMISSION; return tecNO_PERMISSION;
} }
else if (asset.holds<Issue>()) else if (asset.holds<Issue>())

View File

@@ -56,10 +56,10 @@ VaultCreate::preflight(PreflightContext const& ctx)
return temMALFORMED; return temMALFORMED;
} }
if (auto const data = ctx.tx[~sfWithdrawalPolicy]) if (auto const withdrawalPolicy = ctx.tx[~sfWithdrawalPolicy])
{ {
// Enforce valid withdrawal policy // Enforce valid withdrawal policy
if (*data != vaultStrategyFirstComeFirstServe) if (*withdrawalPolicy != vaultStrategyFirstComeFirstServe)
return temMALFORMED; return temMALFORMED;
} }
@@ -151,22 +151,21 @@ VaultCreate::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& ownerId = account_;
auto sequence = tx.getSeqValue(); auto sequence = tx.getSeqValue();
auto owner = view().peek(keylet::account(account_));
if (owner == nullptr)
return tefINTERNAL;
auto owner = view().peek(keylet::account(ownerId)); auto vault = std::make_shared<SLE>(keylet::vault(account_, sequence));
auto vault = std::make_shared<SLE>(keylet::vault(ownerId, sequence));
if (auto ter = dirLink(view(), ownerId, vault)) if (auto ter = dirLink(view(), account_, vault))
return ter; return ter;
// Should the next 3 lines be folded into `dirLink`?
adjustOwnerCount(view(), owner, 1, j_); adjustOwnerCount(view(), owner, 1, j_);
auto ownerCount = owner->at(sfOwnerCount); auto ownerCount = owner->at(sfOwnerCount);
if (mPriorBalance < view().fees().accountReserve(ownerCount)) if (mPriorBalance < view().fees().accountReserve(ownerCount))
return tecINSUFFICIENT_RESERVE; return tecINSUFFICIENT_RESERVE;
auto maybePseudo = createPseudoAccount( auto maybePseudo = createPseudoAccount(view(), vault->key(), sfVaultID);
view(), vault->key(), PseudoAccountOwnerType::Vault);
if (!maybePseudo) if (!maybePseudo)
return maybePseudo.error(); return maybePseudo.error();
auto& pseudo = *maybePseudo; auto& pseudo = *maybePseudo;
@@ -206,7 +205,7 @@ VaultCreate::doApply()
vault->at(sfFlags) = txFlags & tfVaultPrivate; vault->at(sfFlags) = txFlags & tfVaultPrivate;
vault->at(sfSequence) = sequence; vault->at(sfSequence) = sequence;
vault->at(sfOwner) = ownerId; vault->at(sfOwner) = account_;
vault->at(sfAccount) = pseudoId; vault->at(sfAccount) = pseudoId;
vault->at(sfAsset) = asset; vault->at(sfAsset) = asset;
vault->at(sfAssetsTotal) = Number(0); vault->at(sfAssetsTotal) = Number(0);

View File

@@ -83,7 +83,7 @@ VaultDeposit::preclaim(PreclaimContext const& ctx)
if (isFrozen(ctx.view, account, share)) if (isFrozen(ctx.view, account, share))
return tecLOCKED; return tecLOCKED;
if ((vault->getFlags() & tfVaultPrivate) && account != vault->at(sfOwner)) if (vault->isFlag(tfVaultPrivate) && account != vault->at(sfOwner))
{ {
auto const maybeDomainID = sleIssuance->at(~sfDomainID); auto const maybeDomainID = sleIssuance->at(~sfDomainID);
// Since this is a private vault and the account is not its owner, we // Since this is a private vault and the account is not its owner, we
@@ -176,7 +176,7 @@ VaultDeposit::doApply()
} }
// If the vault is private, set the authorized flag for the vault owner // If the vault is private, set the authorized flag for the vault owner
if (vault->getFlags() & tfVaultPrivate) if (vault->isFlag(tfVaultPrivate))
{ {
if (auto const err = MPTokenAuthorize::authorize( if (auto const err = MPTokenAuthorize::authorize(
view(), view(),

View File

@@ -155,6 +155,12 @@ isFrozen(
MPTIssue const& mptIssue, MPTIssue const& mptIssue,
int depth = 0); int depth = 0);
/**
* isFrozen check is recursive for MPT shares in a vault, descending to assets
* in the vault. These assets could be themselves MPT shares in another vault.
* For this reason we limit depth of check, up to maxAssetCheckDepth. If this
* depth is exceeded, we return true (i.e. the asset is considered frozen).
*/
[[nodiscard]] inline bool [[nodiscard]] inline bool
isFrozen( isFrozen(
ReadView const& view, ReadView const& view,
@@ -502,14 +508,19 @@ dirLink(ApplyView& view, AccountID const& owner, std::shared_ptr<SLE>& object);
AccountID AccountID
pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey); pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey);
// Which of the owner-object fields should we set: sfAMMID, sfVaultID /**
enum class PseudoAccountOwnerType : int { AMM, Vault }; *
* Create pseudo-account, storing pseudoOwnerKey into ownerField.
*
* The list of valid ownerField is maintained in View.cpp and the caller to
* this function must perform necessary amendment check(s) before using a
* field. The amendment check is **not** performed in createPseudoAccount.
*/
[[nodiscard]] Expected<std::shared_ptr<SLE>, TER> [[nodiscard]] Expected<std::shared_ptr<SLE>, TER>
createPseudoAccount( createPseudoAccount(
ApplyView& view, ApplyView& view,
uint256 const& pseudoOwnerKey, uint256 const& pseudoOwnerKey,
PseudoAccountOwnerType type); SField const& ownerField);
// Returns true iff sleAcct is a pseudo-account. // Returns true iff sleAcct is a pseudo-account.
// //
@@ -691,12 +702,6 @@ transferXRP(
STAmount const& amount, STAmount const& amount,
beast::Journal j); beast::Journal j);
struct TokenDescriptor
{
std::shared_ptr<SLE const> token;
std::shared_ptr<SLE const> issuance;
};
/** Check if the account lacks required authorization. /** Check if the account lacks required authorization.
* *
* Return tecNO_AUTH or tecNO_LINE if it does * Return tecNO_AUTH or tecNO_LINE if it does
@@ -711,6 +716,13 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account);
* from preclaim, the user should convert result tecEXPIRED to tesSUCCESS and * from preclaim, the user should convert result tecEXPIRED to tesSUCCESS and
* proceed to also check permissions with enforceMPTokenAuthorization inside * proceed to also check permissions with enforceMPTokenAuthorization inside
* doApply. This will ensure that any expired credentials are deleted. * doApply. This will ensure that any expired credentials are deleted.
*
* requireAuth check is recursive for MPT shares in a vault, descending to
* assets in the vault. These assets could be themselves MPT shares in another
* vault. For this reason we limit depth of check, up to maxAssetCheckDepth.
* This function will return tecKILLED if maximum depth is exceeded.
* Transaction VaultCreate checks for tecKILLED to prevent such vaults being
* created.
*/ */
[[nodiscard]] TER [[nodiscard]] TER
requireAuth( requireAuth(
@@ -728,7 +740,7 @@ requireAuth(
* in order for the transactor to proceed to doApply. * in order for the transactor to proceed to doApply.
* *
* This function will create MPToken (if needed) on the basis of any * This function will create MPToken (if needed) on the basis of any
* non-expired credentals and will delete any expired credentials, indirectly * non-expired credentials and will delete any expired credentials, indirectly
* via verifyValidDomain, as per DomainID (if set in MPTokenIssuance). * via verifyValidDomain, as per DomainID (if set in MPTokenIssuance).
* *
* The caller does NOT need to ensure that DomainID is actually set - this * The caller does NOT need to ensure that DomainID is actually set - this

View File

@@ -17,10 +17,9 @@
*/ */
//============================================================================== //==============================================================================
#include <xrpld/ledger/ReadView.h>
// TODO: Move the helper out of the `app` module.
#include <xrpld/app/misc/CredentialHelpers.h> #include <xrpld/app/misc/CredentialHelpers.h>
#include <xrpld/app/tx/detail/MPTokenAuthorize.h> #include <xrpld/app/tx/detail/MPTokenAuthorize.h>
#include <xrpld/ledger/ReadView.h>
#include <xrpld/ledger/View.h> #include <xrpld/ledger/View.h>
#include <xrpl/basics/Expected.h> #include <xrpl/basics/Expected.h>
@@ -328,8 +327,8 @@ isVaultPseudoAccountFrozen(
if (!mptIssuer->isFieldPresent(sfVaultID)) if (!mptIssuer->isFieldPresent(sfVaultID))
return false; // not a Vault pseudo-account, common case return false; // not a Vault pseudo-account, common case
if (depth >= maxFreezeCheckDepth) if (depth >= maxAssetCheckDepth)
return true; // fail at maximum 2^maxFreezeCheckDepth checks return true; // fail at maximum 2^maxAssetCheckDepth checks
auto const vault = auto const vault =
view.read(keylet::vault(mptIssuer->getFieldH256(sfVaultID))); view.read(keylet::vault(mptIssuer->getFieldH256(sfVaultID)));
@@ -1063,12 +1062,31 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
return beast::zero; return beast::zero;
} }
// Note, the list of the pseudo-account designator fields below MUST be
// maintained but it does NOT need to be amendment-gated, since a
// non-active amendment will not set any field, by definition. Specific
// properties of a pseudo-account are NOT checked here, that's what
// InvariantCheck is for.
static std::array<SField const*, 2> const pseudoAccountOwnerFields = {
&sfAMMID, //
&sfVaultID, //
};
Expected<std::shared_ptr<SLE>, TER> Expected<std::shared_ptr<SLE>, TER>
createPseudoAccount( createPseudoAccount(
ApplyView& view, ApplyView& view,
uint256 const& pseudoOwnerKey, uint256 const& pseudoOwnerKey,
PseudoAccountOwnerType type) SField const& ownerField)
{ {
XRPL_ASSERT(
std::count_if(
pseudoAccountOwnerFields.begin(),
pseudoAccountOwnerFields.end(),
[&ownerField](SField const* sf) -> bool {
return *sf == ownerField;
}) == 1,
"ripple::createPseudoAccount : valid owner field");
auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey); auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey);
if (accountId == beast::zero) if (accountId == beast::zero)
return Unexpected(tecDUPLICATE); return Unexpected(tecDUPLICATE);
@@ -1081,12 +1099,10 @@ createPseudoAccount(
// Pseudo-accounts can't submit transactions, so set the sequence number // Pseudo-accounts can't submit transactions, so set the sequence number
// to 0 to make them easier to spot and verify, and add an extra level // to 0 to make them easier to spot and verify, and add an extra level
// of protection. // of protection.
std::uint32_t const seqno = // std::uint32_t const seqno = //
view.rules().enabled(featureSingleAssetVault) // view.rules().enabled(featureSingleAssetVault) //
? 0 // ? 0 //
: view.rules().enabled(featureDeletableAccounts) // : view.seq();
? view.seq() //
: 1;
account->setFieldU32(sfSequence, seqno); account->setFieldU32(sfSequence, seqno);
// Ignore reserves requirement, disable the master key, allow default // Ignore reserves requirement, disable the master key, allow default
// rippling, and enable deposit authorization to prevent payments into // rippling, and enable deposit authorization to prevent payments into
@@ -1094,19 +1110,7 @@ createPseudoAccount(
account->setFieldU32( account->setFieldU32(
sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth); sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
// Link the pseudo-account with its owner object. // Link the pseudo-account with its owner object.
switch (type) account->setFieldH256(ownerField, pseudoOwnerKey);
{
case PseudoAccountOwnerType::AMM:
account->setFieldH256(sfAMMID, pseudoOwnerKey);
break;
case PseudoAccountOwnerType::Vault:
account->setFieldH256(sfVaultID, pseudoOwnerKey);
break;
default:
UNREACHABLE( // LCOV_EXCL_LINE
"ripple::createPseudoAccount : unknown owner key type"); // LCOV_EXCL_LINE
return Unexpected(tecINTERNAL); // LCOV_EXCL_LINE
}
view.insert(account); view.insert(account);
@@ -1116,21 +1120,13 @@ createPseudoAccount(
[[nodiscard]] bool [[nodiscard]] bool
isPseudoAccount(std::shared_ptr<SLE const> sleAcct) isPseudoAccount(std::shared_ptr<SLE const> sleAcct)
{ {
// Note, the list of the pseudo-account designator fields below MUST be
// maintained but it does NOT need to be amendment-gated, since a non-active
// amendment will not set any field, by definition. Specific properties of a
// pseudo-account are NOT checked here, that's what InvariantCheck is for.
static std::array<SField const*, 2> const fields = //
{
&sfAMMID, //
&sfVaultID, //
};
// Intentionally use defensive coding here because it's cheap and makes the // Intentionally use defensive coding here because it's cheap and makes the
// semantics of true return value clean. // semantics of true return value clean.
return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT && return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
std::count_if( std::count_if(
fields.begin(), fields.end(), [&sleAcct](SField const* sf) -> bool { pseudoAccountOwnerFields.begin(),
pseudoAccountOwnerFields.end(),
[&sleAcct](SField const* sf) -> bool {
return sleAcct->isFieldPresent(*sf); return sleAcct->isFieldPresent(*sf);
}) > 0; }) > 0;
} }
@@ -2301,7 +2297,7 @@ requireAuth(
if (!sleVault) if (!sleVault)
return tefINTERNAL; // LCOV_EXCL_LINE return tefINTERNAL; // LCOV_EXCL_LINE
if (depth >= maxFreezeCheckDepth) if (depth >= maxAssetCheckDepth)
return tecKILLED; // VaultCreate looks for this error code return tecKILLED; // VaultCreate looks for this error code
auto const asset = sleVault->at(sfAsset); auto const asset = sleVault->at(sfAsset);
@@ -2342,8 +2338,8 @@ requireAuth(
return tecNO_AUTH; return tecNO_AUTH;
// mptoken must be authorized if issuance enabled requireAuth // mptoken must be authorized if issuance enabled requireAuth
if (sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth && if (sleIssuance->isFlag(lsfMPTRequireAuth) &&
!(sleToken->getFlags() & lsfMPTAuthorized)) !(sleToken->isFlag(lsfMPTAuthorized)))
return tecNO_AUTH; return tecNO_AUTH;
// We are authorized by permissioned domain. // We are authorized by permissioned domain.
@@ -2364,7 +2360,7 @@ enforceMPTokenAuthorization(
return tefINTERNAL; return tefINTERNAL;
XRPL_ASSERT( XRPL_ASSERT(
sleIssuance->getFlags() & lsfMPTRequireAuth, sleIssuance->isFlag(lsfMPTRequireAuth),
"ripple::enforceMPTokenAuthorization : authorization required"); "ripple::enforceMPTokenAuthorization : authorization required");
if (account == sleIssuance->at(sfIssuer)) if (account == sleIssuance->at(sfIssuer))
@@ -2401,7 +2397,7 @@ enforceMPTokenAuthorization(
XRPL_ASSERT( XRPL_ASSERT(
sleToken != nullptr && !maybeDomainID.has_value(), sleToken != nullptr && !maybeDomainID.has_value(),
"ripple::enforceMPTokenAuthorization : found MPToken"); "ripple::enforceMPTokenAuthorization : found MPToken");
if (sleToken->getFlags() & lsfMPTAuthorized) if (sleToken->isFlag(lsfMPTAuthorized))
return tesSUCCESS; return tesSUCCESS;
return tecNO_AUTH; return tecNO_AUTH;