mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
refactor: Decouple ledger from xrpld/app (#5492)
This change decouples `ledger` from `xrpld/app`, and therefore fully clears the path to the modularisation of the ledger component. Before this change, `View.cpp` relied on `MPTokenAuthorize::authorize; this change moves `MPTokenAuthorize::authorize` to `View.cpp` to invert the dependency, making ledger a standalone module.
This commit is contained in:
@@ -175,126 +175,18 @@ MPTokenAuthorize::createMPToken(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
MPTokenAuthorize::authorize(
|
||||
ApplyView& view,
|
||||
beast::Journal journal,
|
||||
MPTAuthorizeArgs const& args)
|
||||
{
|
||||
auto const sleAcct = view.peek(keylet::account(args.account));
|
||||
if (!sleAcct)
|
||||
return tecINTERNAL;
|
||||
|
||||
// If the account that submitted the tx is a holder
|
||||
// Note: `account_` is holder's account
|
||||
// `holderID` is NOT used
|
||||
if (!args.holderID)
|
||||
{
|
||||
// When a holder wants to unauthorize/delete a MPT, the ledger must
|
||||
// - delete mptokenKey from owner directory
|
||||
// - delete the MPToken
|
||||
if (args.flags & tfMPTUnauthorize)
|
||||
{
|
||||
auto const mptokenKey =
|
||||
keylet::mptoken(args.mptIssuanceID, args.account);
|
||||
auto const sleMpt = view.peek(mptokenKey);
|
||||
if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!view.dirRemove(
|
||||
keylet::ownerDir(args.account),
|
||||
(*sleMpt)[sfOwnerNode],
|
||||
sleMpt->key(),
|
||||
false))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, sleAcct, -1, journal);
|
||||
|
||||
view.erase(sleMpt);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
// A potential holder wants to authorize/hold a mpt, the ledger must:
|
||||
// - add the new mptokenKey to the owner directory
|
||||
// - create the MPToken object for the holder
|
||||
|
||||
// The reserve that is required to create the MPToken. Note
|
||||
// that although the reserve increases with every item
|
||||
// an account owns, in the case of MPTokens we only
|
||||
// *enforce* a reserve if the user owns more than two
|
||||
// items. This is similar to the reserve requirements of trust lines.
|
||||
std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount);
|
||||
XRPAmount const reserveCreate(
|
||||
(uOwnerCount < 2) ? XRPAmount(beast::zero)
|
||||
: view.fees().accountReserve(uOwnerCount + 1));
|
||||
|
||||
if (args.priorBalance < reserveCreate)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
auto const mptokenKey =
|
||||
keylet::mptoken(args.mptIssuanceID, args.account);
|
||||
auto mptoken = std::make_shared<SLE>(mptokenKey);
|
||||
if (auto ter = dirLink(view, args.account, mptoken))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
|
||||
(*mptoken)[sfAccount] = args.account;
|
||||
(*mptoken)[sfMPTokenIssuanceID] = args.mptIssuanceID;
|
||||
(*mptoken)[sfFlags] = 0;
|
||||
view.insert(mptoken);
|
||||
|
||||
// Update owner count.
|
||||
adjustOwnerCount(view, sleAcct, 1, journal);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const sleMptIssuance =
|
||||
view.read(keylet::mptIssuance(args.mptIssuanceID));
|
||||
if (!sleMptIssuance)
|
||||
return tecINTERNAL;
|
||||
|
||||
// If the account that submitted this tx is the issuer of the MPT
|
||||
// Note: `account_` is issuer's account
|
||||
// `holderID` is holder's account
|
||||
if (args.account != (*sleMptIssuance)[sfIssuer])
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const sleMpt =
|
||||
view.peek(keylet::mptoken(args.mptIssuanceID, *args.holderID));
|
||||
if (!sleMpt)
|
||||
return tecINTERNAL;
|
||||
|
||||
std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags);
|
||||
std::uint32_t flagsOut = flagsIn;
|
||||
|
||||
// Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on
|
||||
// their MPToken
|
||||
if (args.flags & tfMPTUnauthorize)
|
||||
flagsOut &= ~lsfMPTAuthorized;
|
||||
// Issuer wants to authorize a holder, set lsfMPTAuthorized on their
|
||||
// MPToken
|
||||
else
|
||||
flagsOut |= lsfMPTAuthorized;
|
||||
|
||||
if (flagsIn != flagsOut)
|
||||
sleMpt->setFieldU32(sfFlags, flagsOut);
|
||||
|
||||
view.update(sleMpt);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
MPTokenAuthorize::doApply()
|
||||
{
|
||||
auto const& tx = ctx_.tx;
|
||||
return authorize(
|
||||
return authorizeMPToken(
|
||||
ctx_.view(),
|
||||
mPriorBalance,
|
||||
tx[sfMPTokenIssuanceID],
|
||||
account_,
|
||||
ctx_.journal,
|
||||
{.priorBalance = mPriorBalance,
|
||||
.mptIssuanceID = tx[sfMPTokenIssuanceID],
|
||||
.account = account_,
|
||||
.flags = tx.getFlags(),
|
||||
.holderID = tx[~sfHolder]});
|
||||
tx.getFlags(),
|
||||
tx[~sfHolder]);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -48,12 +48,6 @@ public:
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
static TER
|
||||
authorize(
|
||||
ApplyView& view,
|
||||
beast::Journal journal,
|
||||
MPTAuthorizeArgs const& args);
|
||||
|
||||
static TER
|
||||
createMPToken(
|
||||
ApplyView& view,
|
||||
|
||||
@@ -210,12 +210,12 @@ VaultDeposit::doApply()
|
||||
auto sleMpt = view().read(keylet::mptoken(mptIssuanceID, account_));
|
||||
if (!sleMpt)
|
||||
{
|
||||
if (auto const err = MPTokenAuthorize::authorize(
|
||||
if (auto const err = authorizeMPToken(
|
||||
view(),
|
||||
ctx_.journal,
|
||||
{.priorBalance = mPriorBalance,
|
||||
.mptIssuanceID = mptIssuanceID->value(),
|
||||
.account = account_});
|
||||
mPriorBalance,
|
||||
mptIssuanceID->value(),
|
||||
account_,
|
||||
ctx_.journal);
|
||||
!isTesSuccess(err))
|
||||
return err;
|
||||
}
|
||||
@@ -223,15 +223,15 @@ VaultDeposit::doApply()
|
||||
// If the vault is private, set the authorized flag for the vault owner
|
||||
if (vault->isFlag(tfVaultPrivate))
|
||||
{
|
||||
if (auto const err = MPTokenAuthorize::authorize(
|
||||
if (auto const err = authorizeMPToken(
|
||||
view(),
|
||||
mPriorBalance, // priorBalance
|
||||
mptIssuanceID->value(), // mptIssuanceID
|
||||
sleIssuance->at(sfIssuer), // account
|
||||
ctx_.journal,
|
||||
{
|
||||
.priorBalance = mPriorBalance,
|
||||
.mptIssuanceID = mptIssuanceID->value(),
|
||||
.account = sleIssuance->at(sfIssuer),
|
||||
.holderID = account_,
|
||||
});
|
||||
{}, // flags
|
||||
account_ // holderID
|
||||
);
|
||||
!isTesSuccess(err))
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -600,6 +600,16 @@ addEmptyHolding(
|
||||
asset.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
authorizeMPToken(
|
||||
ApplyView& view,
|
||||
XRPAmount const& priorBalance,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
beast::Journal journal,
|
||||
std::uint32_t flags = 0,
|
||||
std::optional<AccountID> holderID = std::nullopt);
|
||||
|
||||
// VFALCO NOTE Both STAmount parameters should just
|
||||
// be "Amount", a unit-less number.
|
||||
//
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/app/misc/CredentialHelpers.h>
|
||||
#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
|
||||
#include <xrpld/ledger/ReadView.h>
|
||||
#include <xrpld/ledger/View.h>
|
||||
|
||||
@@ -1215,12 +1214,115 @@ addEmptyHolding(
|
||||
if (view.peek(keylet::mptoken(mptID, accountID)))
|
||||
return tecDUPLICATE;
|
||||
|
||||
return MPTokenAuthorize::authorize(
|
||||
view,
|
||||
journal,
|
||||
{.priorBalance = priorBalance,
|
||||
.mptIssuanceID = mptID,
|
||||
.account = accountID});
|
||||
return authorizeMPToken(view, priorBalance, mptID, accountID, journal);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
authorizeMPToken(
|
||||
ApplyView& view,
|
||||
XRPAmount const& priorBalance,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
beast::Journal journal,
|
||||
std::uint32_t flags,
|
||||
std::optional<AccountID> holderID)
|
||||
{
|
||||
auto const sleAcct = view.peek(keylet::account(account));
|
||||
if (!sleAcct)
|
||||
return tecINTERNAL;
|
||||
|
||||
// If the account that submitted the tx is a holder
|
||||
// Note: `account_` is holder's account
|
||||
// `holderID` is NOT used
|
||||
if (!holderID)
|
||||
{
|
||||
// When a holder wants to unauthorize/delete a MPT, the ledger must
|
||||
// - delete mptokenKey from owner directory
|
||||
// - delete the MPToken
|
||||
if (flags & tfMPTUnauthorize)
|
||||
{
|
||||
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
|
||||
auto const sleMpt = view.peek(mptokenKey);
|
||||
if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!view.dirRemove(
|
||||
keylet::ownerDir(account),
|
||||
(*sleMpt)[sfOwnerNode],
|
||||
sleMpt->key(),
|
||||
false))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, sleAcct, -1, journal);
|
||||
|
||||
view.erase(sleMpt);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
// A potential holder wants to authorize/hold a mpt, the ledger must:
|
||||
// - add the new mptokenKey to the owner directory
|
||||
// - create the MPToken object for the holder
|
||||
|
||||
// The reserve that is required to create the MPToken. Note
|
||||
// that although the reserve increases with every item
|
||||
// an account owns, in the case of MPTokens we only
|
||||
// *enforce* a reserve if the user owns more than two
|
||||
// items. This is similar to the reserve requirements of trust lines.
|
||||
std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount);
|
||||
XRPAmount const reserveCreate(
|
||||
(uOwnerCount < 2) ? XRPAmount(beast::zero)
|
||||
: view.fees().accountReserve(uOwnerCount + 1));
|
||||
|
||||
if (priorBalance < reserveCreate)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
|
||||
auto mptoken = std::make_shared<SLE>(mptokenKey);
|
||||
if (auto ter = dirLink(view, account, mptoken))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
|
||||
(*mptoken)[sfAccount] = account;
|
||||
(*mptoken)[sfMPTokenIssuanceID] = mptIssuanceID;
|
||||
(*mptoken)[sfFlags] = 0;
|
||||
view.insert(mptoken);
|
||||
|
||||
// Update owner count.
|
||||
adjustOwnerCount(view, sleAcct, 1, journal);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const sleMptIssuance = view.read(keylet::mptIssuance(mptIssuanceID));
|
||||
if (!sleMptIssuance)
|
||||
return tecINTERNAL;
|
||||
|
||||
// If the account that submitted this tx is the issuer of the MPT
|
||||
// Note: `account_` is issuer's account
|
||||
// `holderID` is holder's account
|
||||
if (account != (*sleMptIssuance)[sfIssuer])
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const sleMpt = view.peek(keylet::mptoken(mptIssuanceID, *holderID));
|
||||
if (!sleMpt)
|
||||
return tecINTERNAL;
|
||||
|
||||
std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags);
|
||||
std::uint32_t flagsOut = flagsIn;
|
||||
|
||||
// Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on
|
||||
// their MPToken
|
||||
if (flags & tfMPTUnauthorize)
|
||||
flagsOut &= ~lsfMPTAuthorized;
|
||||
// Issuer wants to authorize a holder, set lsfMPTAuthorized on their
|
||||
// MPToken
|
||||
else
|
||||
flagsOut |= lsfMPTAuthorized;
|
||||
|
||||
if (flagsIn != flagsOut)
|
||||
sleMpt->setFieldU32(sfFlags, flagsOut);
|
||||
|
||||
view.update(sleMpt);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -1418,13 +1520,14 @@ removeEmptyHolding(
|
||||
if (mptoken->at(sfMPTAmount) != 0)
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
return MPTokenAuthorize::authorize(
|
||||
return authorizeMPToken(
|
||||
view,
|
||||
{}, // priorBalance
|
||||
mptID,
|
||||
accountID,
|
||||
journal,
|
||||
{.priorBalance = {},
|
||||
.mptIssuanceID = mptID,
|
||||
.account = accountID,
|
||||
.flags = tfMPTUnauthorize});
|
||||
tfMPTUnauthorize // flags
|
||||
);
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -2497,15 +2600,12 @@ enforceMPTokenAuthorization(
|
||||
XRPL_ASSERT(
|
||||
maybeDomainID.has_value() && sleToken == nullptr,
|
||||
"ripple::enforceMPTokenAuthorization : new MPToken for domain");
|
||||
if (auto const err = MPTokenAuthorize::authorize(
|
||||
if (auto const err = authorizeMPToken(
|
||||
view,
|
||||
j,
|
||||
{
|
||||
.priorBalance = priorBalance,
|
||||
.mptIssuanceID = mptIssuanceID,
|
||||
.account = account,
|
||||
.flags = 0,
|
||||
});
|
||||
priorBalance, // priorBalance
|
||||
mptIssuanceID, // mptIssuanceID
|
||||
account, // account
|
||||
j);
|
||||
!isTesSuccess(err))
|
||||
return err;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user