mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-22 11:37:07 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16389dcb2e | ||
|
|
97a780b29f | ||
|
|
654edc9a08 | ||
|
|
658d04f694 | ||
|
|
93498952b1 | ||
|
|
269f79e568 | ||
|
|
e7a8e0336a | ||
|
|
1d7e40777a | ||
|
|
7bb43a243b | ||
|
|
d697b7843c | ||
|
|
2de5140f20 | ||
|
|
edf085a697 | ||
|
|
c35ac1339b | ||
|
|
dc1cfbc474 | ||
|
|
3044073401 | ||
|
|
651bb207b4 | ||
|
|
c45363fd8b | ||
|
|
f1744cb76e |
No files matched your search
@@ -255,6 +255,7 @@ words:
|
|||||||
- queuable
|
- queuable
|
||||||
- Raphson
|
- Raphson
|
||||||
- rcflags
|
- rcflags
|
||||||
|
- reencrypted
|
||||||
- replayer
|
- replayer
|
||||||
- repodata
|
- repodata
|
||||||
- repomd
|
- repomd
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Asset.h>
|
#include <xrpl/protocol/Asset.h>
|
||||||
#include <xrpl/protocol/Keylet.h>
|
#include <xrpl/protocol/Keylet.h>
|
||||||
@@ -211,7 +212,7 @@ canWithdraw(
|
|||||||
ReadView const& view,
|
ReadView const& view,
|
||||||
AccountID const& from,
|
AccountID const& from,
|
||||||
AccountID const& to,
|
AccountID const& to,
|
||||||
SLE::ConstRef toSle,
|
AccountRootEntryR const& toSle,
|
||||||
STAmount const& amount,
|
STAmount const& amount,
|
||||||
bool hasDestinationTag,
|
bool hasDestinationTag,
|
||||||
std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt);
|
std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt);
|
||||||
|
|||||||
@@ -7,9 +7,20 @@
|
|||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/LedgerFormats.h>
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
|
#include <xrpl/protocol/TER.h>
|
||||||
|
#include <xrpl/protocol/XRPAmount.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
|
struct Adjustment
|
||||||
|
{
|
||||||
|
std::int32_t ownerCountDelta = 0;
|
||||||
|
std::int32_t accountCountDelta = 0;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename ViewT>
|
template <typename ViewT>
|
||||||
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
|
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
|
||||||
{
|
{
|
||||||
@@ -27,6 +38,123 @@ public:
|
|||||||
: Base(keylet::account(id), view, j)
|
: Base(keylet::account(id), view, j)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the account reserve, in drops.
|
||||||
|
*
|
||||||
|
* Actual owner count can be adjusted by delta in ownerCountAdj
|
||||||
|
* Actual reserve count can be adjusted by delta in accountCountAdj
|
||||||
|
* The reserve is calculated as:
|
||||||
|
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
||||||
|
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
||||||
|
*
|
||||||
|
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
|
||||||
|
* to subtract.
|
||||||
|
* @return The account reserve amount in drops
|
||||||
|
*/
|
||||||
|
[[nodiscard]] XRPAmount
|
||||||
|
reserve(Adjustment adj = {}) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return number of the objects which reserve is covered by the account (so called "owner
|
||||||
|
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
|
||||||
|
*
|
||||||
|
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||||
|
* @return The adjusted owner count
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::uint32_t
|
||||||
|
ownerCount(std::int32_t ownerCountAdj = 0) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this account has sufficient reserve.
|
||||||
|
*
|
||||||
|
* @param ctx The apply-view context (view + tx)
|
||||||
|
* @param accBalance The account's balance
|
||||||
|
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||||
|
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
|
||||||
|
* to subtract.
|
||||||
|
* @param insufReserveCode The transaction result code to return if the reserve is
|
||||||
|
* insufficient (default: tecINSUFFICIENT_RESERVE).
|
||||||
|
* @return Transaction result code
|
||||||
|
*/
|
||||||
|
[[nodiscard]] TER
|
||||||
|
checkReserve(
|
||||||
|
ApplyViewContext ctx,
|
||||||
|
XRPAmount accBalance,
|
||||||
|
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
|
||||||
|
Adjustment adj,
|
||||||
|
TER insufReserveCode = tecINSUFFICIENT_RESERVE) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this account has sufficient reserve, deriving the sponsor internally.
|
||||||
|
*
|
||||||
|
* Equivalent to the overload above, but resolves the sponsor via
|
||||||
|
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use this
|
||||||
|
* in the common case where the sponsor is simply the transaction's reserve
|
||||||
|
* sponsor for this account. Callers that must force the account's-own-reserve branch
|
||||||
|
* (passing a null sponsor) or supply a different sponsor should use the
|
||||||
|
* explicit overload above.
|
||||||
|
*
|
||||||
|
* @param ctx The apply-view context (view + tx)
|
||||||
|
* @param accBalance The account's balance
|
||||||
|
* @param adj Reserve adjustments (owner/account count deltas)
|
||||||
|
* @return Transaction result code
|
||||||
|
*/
|
||||||
|
[[nodiscard]] TER
|
||||||
|
checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase owner-count fields when the caller supplies the sponsor.
|
||||||
|
*
|
||||||
|
* This helper does not create a ledger object. It updates reserve accounting
|
||||||
|
* after the caller has created/updated an object.
|
||||||
|
* If sponsorSle is provided, this also adjusts the account's sponsored count
|
||||||
|
* and the sponsor's sponsoring count.
|
||||||
|
*
|
||||||
|
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||||
|
* @param count Amount to add to the owner count
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
increaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
|
||||||
|
requires Base::kIsWritable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increase owner-count fields, deriving the tx reserve sponsor internally.
|
||||||
|
*
|
||||||
|
* Equivalent to the overload above, but resolves the sponsor via
|
||||||
|
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use
|
||||||
|
* this when the sponsor is the transaction's reserve sponsor for this account
|
||||||
|
* (the common create path). Deletion paths, which derive the sponsor from an
|
||||||
|
* object's sfSponsor field, should keep using the explicit overload.
|
||||||
|
*
|
||||||
|
* @param ctx The apply-view context (view + tx)
|
||||||
|
* @param count Amount to add to the owner count
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
|
||||||
|
requires Base::kIsWritable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrease owner-count fields when the caller supplies the sponsor.
|
||||||
|
*
|
||||||
|
* This helper does not delete a ledger object. It updates reserve accounting
|
||||||
|
* after the caller has removed an owner-counted reserve, or for special
|
||||||
|
* owner-count changes whose sponsor cannot be derived from an object's
|
||||||
|
* sfSponsor field.
|
||||||
|
*
|
||||||
|
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||||
|
* @param count Amount to remove from the owner count
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
decreaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
|
||||||
|
requires Base::kIsWritable;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void
|
||||||
|
adjustOwnerCountSigned(
|
||||||
|
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
|
||||||
|
std::int32_t adjustment)
|
||||||
|
requires Base::kIsWritable;
|
||||||
};
|
};
|
||||||
|
|
||||||
using AccountRootEntryR = AccountRootEntry<ReadView>;
|
using AccountRootEntryR = AccountRootEntry<ReadView>;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
|
||||||
#include <xrpl/protocol/Rate.h>
|
#include <xrpl/protocol/Rate.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
#include <xrpl/protocol/STLedgerEntry.h>
|
#include <xrpl/protocol/STLedgerEntry.h>
|
||||||
@@ -46,30 +46,55 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer);
|
|||||||
[[nodiscard]] XRPAmount
|
[[nodiscard]] XRPAmount
|
||||||
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
|
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
|
||||||
|
|
||||||
struct Adjustment
|
namespace detail {
|
||||||
{
|
|
||||||
std::int32_t ownerCountDelta = 0;
|
|
||||||
std::int32_t accountCountDelta = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the account reserve, in drops.
|
* An owner count cannot be negative. If adjustment would cause a negative
|
||||||
|
* owner count, clamp the owner count at 0. Similarly for overflow. This
|
||||||
|
* adjustment allows the ownerCount to be adjusted up or down in multiple steps.
|
||||||
|
* If id != std::nullopt, then do error reporting.
|
||||||
*
|
*
|
||||||
* Actual owner count can be adjusted by delta in ownerCountAdj
|
* Shared by AccountRootEntry::ownerCount() and the owner-count helpers.
|
||||||
* Actual reserve count can be adjusted by delta in accountCountAdj
|
|
||||||
* The reserve is calculated as:
|
|
||||||
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
|
||||||
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
|
||||||
*
|
*
|
||||||
* @param view The ledger view to read from
|
* @param currentOwnerCount The owner count before adjustment
|
||||||
* @param sle The ledger entry for the account
|
* @param ownerCountAdj Positive to add to count, negative to reduce count
|
||||||
|
* @param id The account ID to use for error reporting, or std::nullopt to
|
||||||
|
* skip error reporting
|
||||||
* @param j Journal for logging
|
* @param j Journal for logging
|
||||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
* @return The adjusted owner count
|
||||||
* subtract.
|
|
||||||
* @return The account reserve amount in drops
|
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] XRPAmount
|
std::uint32_t
|
||||||
accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj = {});
|
confineOwnerCount(
|
||||||
|
std::uint32_t currentOwnerCount,
|
||||||
|
std::int32_t ownerCountAdj,
|
||||||
|
std::optional<AccountID> const& id = std::nullopt,
|
||||||
|
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamps and writes an owner-count field of sle, then updates sle in view.
|
||||||
|
*
|
||||||
|
* Shared by AccountRootEntry and adjustLoanBrokerOwnerCount().
|
||||||
|
*
|
||||||
|
* @return The adjusted owner count
|
||||||
|
*/
|
||||||
|
std::uint32_t
|
||||||
|
adjustOwnerCountImpl(
|
||||||
|
ApplyView& view,
|
||||||
|
SLE::Ref sle,
|
||||||
|
SF_UINT32 const& sfield,
|
||||||
|
AccountID const& accID,
|
||||||
|
std::int32_t ownerCountAdj,
|
||||||
|
beast::Journal j);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of account reserves funded by this account: 1 for itself
|
||||||
|
* (0 if sponsored by another account) plus the count of accounts it sponsors.
|
||||||
|
* Shared by AccountRootEntry::reserve() and xrpLiquid().
|
||||||
|
*/
|
||||||
|
std::uint32_t
|
||||||
|
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience overload that accepts AccountID instead of SLE.
|
* Convenience overload that accepts AccountID instead of SLE.
|
||||||
@@ -84,114 +109,9 @@ accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjust
|
|||||||
[[nodiscard]] inline XRPAmount
|
[[nodiscard]] inline XRPAmount
|
||||||
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
|
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
|
||||||
{
|
{
|
||||||
return accountReserve(view, view.read(keylet::account(id)), j, adj);
|
return AccountRootEntryR(id, view, j).reserve(adj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an account has sufficient reserve.
|
|
||||||
*
|
|
||||||
* @param view The ledger view to read from
|
|
||||||
* @param tx The transaction being processed
|
|
||||||
* @param accSle The account's ledger entry
|
|
||||||
* @param accBalance The account's balance
|
|
||||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
|
||||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
|
||||||
* subtract.
|
|
||||||
* @param j Journal for logging (default: null sink)
|
|
||||||
* @param insufReserveCode The transaction result code to return if the reserve is insufficient
|
|
||||||
* (default: tecINSUFFICIENT_RESERVE).
|
|
||||||
* @return Transaction result code
|
|
||||||
*/
|
|
||||||
[[nodiscard]] TER
|
|
||||||
checkReserve(
|
|
||||||
ApplyViewContext ctx,
|
|
||||||
SLE::ConstRef accSle,
|
|
||||||
XRPAmount accBalance,
|
|
||||||
SLE::ConstRef sponsorSle,
|
|
||||||
Adjustment adj,
|
|
||||||
beast::Journal j,
|
|
||||||
TER insufReserveCode = tecINSUFFICIENT_RESERVE);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an account has sufficient reserve, deriving the sponsor internally.
|
|
||||||
*
|
|
||||||
* Equivalent to the overload above, but resolves the sponsor via
|
|
||||||
* getEffectiveTxReserveSponsor(ctx, accSle) instead of taking it explicitly. Use this
|
|
||||||
* in the common case where the sponsor is simply the transaction's reserve
|
|
||||||
* sponsor for accSle. Callers that must force the account's-own-reserve branch
|
|
||||||
* (passing a null sponsor) or supply a different sponsor should use the
|
|
||||||
* explicit overload above.
|
|
||||||
*
|
|
||||||
* @param ctx The apply-view context (view + tx)
|
|
||||||
* @param accSle The account's ledger entry
|
|
||||||
* @param accBalance The account's balance
|
|
||||||
* @param adj Reserve adjustments (owner/account count deltas)
|
|
||||||
* @param j Journal for logging (default: null sink)
|
|
||||||
* @return Transaction result code
|
|
||||||
*/
|
|
||||||
[[nodiscard]] TER
|
|
||||||
checkReserve(
|
|
||||||
ApplyViewContext ctx,
|
|
||||||
SLE::ConstRef accSle,
|
|
||||||
XRPAmount accBalance,
|
|
||||||
Adjustment adj,
|
|
||||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return number of the objects which reserve is covered by the account(sle) (so called "owner
|
|
||||||
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
|
|
||||||
*
|
|
||||||
* @param sle The account's ledger entry
|
|
||||||
* @param j Journal for logging
|
|
||||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
|
||||||
* @return The adjusted owner count
|
|
||||||
*/
|
|
||||||
std::uint32_t
|
|
||||||
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increase owner-count fields when the caller supplies the sponsor.
|
|
||||||
*
|
|
||||||
* This helper does not create a ledger object. It updates reserve accounting
|
|
||||||
* after the caller has created/updated an object.
|
|
||||||
* If sponsorSle is provided, this also adjusts the account's sponsored count
|
|
||||||
* and the sponsor's sponsoring count.
|
|
||||||
*
|
|
||||||
* @param view The apply view for making changes
|
|
||||||
* @param accountSle The account's ledger entry
|
|
||||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
|
||||||
* @param count Amount to add to the owner count
|
|
||||||
* @param j Journal for logging
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
increaseOwnerCount(
|
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref accountSle,
|
|
||||||
SLE::Ref sponsorSle,
|
|
||||||
std::uint32_t count,
|
|
||||||
beast::Journal j);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increase owner-count fields, deriving the tx reserve sponsor internally.
|
|
||||||
*
|
|
||||||
* Equivalent to the overload above, but resolves the sponsor via
|
|
||||||
* getEffectiveTxReserveSponsor(ctx, accountSle) instead of taking it explicitly. Use
|
|
||||||
* this when the sponsor is the transaction's reserve sponsor for accountSle
|
|
||||||
* (the common create path). Deletion paths, which derive the sponsor from an
|
|
||||||
* object's sfSponsor field, should keep using the explicit overload.
|
|
||||||
*
|
|
||||||
* @param ctx The apply-view context (view + tx)
|
|
||||||
* @param accountSle The account's ledger entry
|
|
||||||
* @param count Amount to add to the owner count
|
|
||||||
* @param j Journal for logging
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
increaseOwnerCount(
|
|
||||||
ApplyViewContext ctx,
|
|
||||||
SLE::Ref accountSle,
|
|
||||||
std::uint32_t count,
|
|
||||||
beast::Journal j);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience overload that accepts AccountID instead of SLE references.
|
* Convenience overload that accepts AccountID instead of SLE references.
|
||||||
*
|
*
|
||||||
@@ -209,36 +129,13 @@ increaseOwnerCount(
|
|||||||
std::uint32_t count,
|
std::uint32_t count,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
{
|
{
|
||||||
increaseOwnerCount(
|
AccountRootEntryW accountSle(account, view, j);
|
||||||
view,
|
std::optional<AccountRootEntryW> sponsorSle;
|
||||||
view.peek(keylet::account(account)),
|
if (sponsor)
|
||||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
sponsorSle.emplace(*sponsor, view);
|
||||||
count,
|
accountSle.increaseOwnerCount(sponsorSle, count);
|
||||||
j);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrease owner-count fields when the caller supplies the sponsor.
|
|
||||||
*
|
|
||||||
* This helper does not delete a ledger object. It updates reserve accounting
|
|
||||||
* after the caller has removed an owner-counted reserve, or for special
|
|
||||||
* owner-count changes whose sponsor cannot be derived from an object's
|
|
||||||
* sfSponsor field.
|
|
||||||
*
|
|
||||||
* @param view The apply view for making changes
|
|
||||||
* @param accountSle The account's ledger entry
|
|
||||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
|
||||||
* @param count Amount to remove from the owner count
|
|
||||||
* @param j Journal for logging
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
decreaseOwnerCount(
|
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref accountSle,
|
|
||||||
SLE::Ref sponsorSle,
|
|
||||||
std::uint32_t count,
|
|
||||||
beast::Journal j);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience overload that accepts AccountID instead of SLE references.
|
* Convenience overload that accepts AccountID instead of SLE references.
|
||||||
*
|
*
|
||||||
@@ -256,12 +153,11 @@ decreaseOwnerCount(
|
|||||||
std::uint32_t count,
|
std::uint32_t count,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
{
|
{
|
||||||
decreaseOwnerCount(
|
AccountRootEntryW accountSle(account, view, j);
|
||||||
view,
|
std::optional<AccountRootEntryW> sponsorSle;
|
||||||
view.peek(keylet::account(account)),
|
if (sponsor)
|
||||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
sponsorSle.emplace(*sponsor, view);
|
||||||
count,
|
accountSle.decreaseOwnerCount(sponsorSle, count);
|
||||||
j);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -281,7 +177,7 @@ decreaseOwnerCount(
|
|||||||
void
|
void
|
||||||
decreaseOwnerCountForObject(
|
decreaseOwnerCountForObject(
|
||||||
ApplyView& view,
|
ApplyView& view,
|
||||||
SLE::Ref accountSle,
|
AccountRootEntryW& accountSle,
|
||||||
SLE::Ref objectSle,
|
SLE::Ref objectSle,
|
||||||
std::uint32_t count,
|
std::uint32_t count,
|
||||||
beast::Journal j);
|
beast::Journal j);
|
||||||
@@ -303,7 +199,7 @@ decreaseOwnerCountForObject(
|
|||||||
std::uint32_t count,
|
std::uint32_t count,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
{
|
{
|
||||||
SLE::Ref accountSle = view.peek(keylet::account(account));
|
AccountRootEntryW accountSle(account, view);
|
||||||
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
|
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +263,7 @@ getPseudoAccountFields();
|
|||||||
* - null pointer
|
* - null pointer
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] bool
|
[[nodiscard]] bool
|
||||||
isPseudoAccount(SLE::const_pointer sleAcct);
|
isPseudoAccount(AccountRootEntryR const& sleAcct);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience overload that reads the account from the view.
|
* Convenience overload that reads the account from the view.
|
||||||
@@ -375,7 +271,7 @@ isPseudoAccount(SLE::const_pointer sleAcct);
|
|||||||
[[nodiscard]] inline bool
|
[[nodiscard]] inline bool
|
||||||
isPseudoAccount(ReadView const& view, AccountID const& accountId)
|
isPseudoAccount(ReadView const& view, AccountID const& accountId)
|
||||||
{
|
{
|
||||||
return isPseudoAccount(view.read(keylet::account(accountId)));
|
return isPseudoAccount(AccountRootEntryR(accountId, view));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -396,6 +292,6 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
|
|||||||
* - If the SLE requires a destination tag, checks that there is a tag.
|
* - If the SLE requires a destination tag, checks that there is a tag.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] TER
|
[[nodiscard]] TER
|
||||||
checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag);
|
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag);
|
||||||
|
|
||||||
} // namespace xrpl
|
} // namespace xrpl
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -27,6 +27,32 @@
|
|||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before fixCleanup3_2_0, EscrowCancel passes the escrow SLE as sleDest.
|
||||||
|
* Return what the old reserve check returned for it, without adopting a
|
||||||
|
* non-AccountRoot SLE into an AccountRootEntry: the tx reserve sponsor's
|
||||||
|
* error if the escrow owner submitted the tx, else tefINTERNAL.
|
||||||
|
*
|
||||||
|
* @param ctx the apply view context for the escrow transaction.
|
||||||
|
* @param sleDest the non-AccountRoot SLE that was passed as the destination.
|
||||||
|
* @return the tx reserve sponsor's error code if the escrow owner submitted
|
||||||
|
* the tx, else tefINTERNAL.
|
||||||
|
*/
|
||||||
|
inline TER
|
||||||
|
escrowDestNotAccountResult(ApplyViewContext ctx, SLE::ConstRef sleDest)
|
||||||
|
{
|
||||||
|
if (sleDest->getAccountID(sfAccount) == ctx.tx[sfAccount])
|
||||||
|
{
|
||||||
|
if (auto const sponsor = getTxReserveSponsor(ctx); !sponsor)
|
||||||
|
return sponsor.error(); // LCOV_EXCL_LINE
|
||||||
|
}
|
||||||
|
return tefINTERNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template <ValidIssueType T>
|
template <ValidIssueType T>
|
||||||
TER
|
TER
|
||||||
escrowUnlockApplyHelper(
|
escrowUnlockApplyHelper(
|
||||||
@@ -70,18 +96,17 @@ escrowUnlockApplyHelper<Issue>(
|
|||||||
if (!ctx.view.exists(trustLineKey) && createAsset)
|
if (!ctx.view.exists(trustLineKey) && createAsset)
|
||||||
{
|
{
|
||||||
// Can the account cover the trust line's reserve?
|
// Can the account cover the trust line's reserve?
|
||||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
|
if (sleDest->getType() != ltACCOUNT_ROOT)
|
||||||
|
return detail::escrowDestNotAccountResult(ctx, sleDest);
|
||||||
|
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
|
||||||
|
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
|
||||||
if (!sponsorSle)
|
if (!sponsorSle)
|
||||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
auto& sponsor = *sponsorSle;
|
||||||
ctx,
|
|
||||||
sleDest,
|
if (auto const ret = destSle.checkReserve(
|
||||||
xrpBalance,
|
ctx, xrpBalance, sponsor, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE);
|
||||||
*sponsorSle,
|
|
||||||
{.ownerCountDelta = 1},
|
|
||||||
journal,
|
|
||||||
tecNO_LINE_INSUF_RESERVE);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
{
|
{
|
||||||
JLOG(journal.trace()) << "Trust line does not exist. "
|
JLOG(journal.trace()) << "Trust line does not exist. "
|
||||||
@@ -94,22 +119,22 @@ escrowUnlockApplyHelper<Issue>(
|
|||||||
initialBalance.get<Issue>().account = noAccount();
|
initialBalance.get<Issue>().account = noAccount();
|
||||||
|
|
||||||
if (TER const ter = trustCreate(
|
if (TER const ter = trustCreate(
|
||||||
ctx.view, // payment sandbox
|
ctx.view, // payment sandbox
|
||||||
recvLow, // is dest low?
|
recvLow, // is dest low?
|
||||||
issuer, // source
|
issuer, // source
|
||||||
receiver, // destination
|
receiver, // destination
|
||||||
trustLineKey.key, // ledger index
|
trustLineKey.key, // ledger index
|
||||||
sleDest, // Account to add to
|
sleDest, // Account to add to
|
||||||
false, // authorize account
|
false, // authorize account
|
||||||
!sleDest->isFlag(lsfDefaultRipple), //
|
!sleDest->isFlag(lsfDefaultRipple), //
|
||||||
false, // freeze trust line
|
false, // freeze trust line
|
||||||
false, // deep freeze trust line
|
false, // deep freeze trust line
|
||||||
initialBalance, // zero initial balance
|
initialBalance, // zero initial balance
|
||||||
Issue(currency, receiver), // limit of zero
|
Issue(currency, receiver), // limit of zero
|
||||||
0, // quality in
|
0, // quality in
|
||||||
0, // quality out
|
0, // quality out
|
||||||
*sponsorSle, // sponsor
|
sponsor ? sponsor->mutableRawSle() : SLE::pointer(), // sponsor
|
||||||
journal); // journal
|
journal); // journal
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
{
|
{
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
@@ -204,23 +229,29 @@ escrowUnlockApplyHelper<MPTIssue>(
|
|||||||
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
|
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
|
||||||
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
|
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
|
||||||
{
|
{
|
||||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
|
if (sleDest->getType() != ltACCOUNT_ROOT)
|
||||||
|
return detail::escrowDestNotAccountResult(ctx, sleDest);
|
||||||
|
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
|
||||||
|
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
|
||||||
if (!sponsorSle)
|
if (!sponsorSle)
|
||||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
auto& sponsor = *sponsorSle;
|
||||||
ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal);
|
|
||||||
|
if (auto const ret = destSle.checkReserve(ctx, xrpBalance, sponsor, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0);
|
if (auto const ter = createMPToken(
|
||||||
|
ctx.view, mptID, receiver, sponsor ? sponsor->mutableRawSle() : SLE::pointer(), 0);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
{
|
{
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
// update owner count.
|
// update owner count.
|
||||||
increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal);
|
AccountRootEntryW receiverSle(receiver, ctx.view, journal);
|
||||||
|
receiverSle.increaseOwnerCount(sponsor, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.view.exists(mptKeylet) && !receiverIssuer)
|
if (!ctx.view.exists(mptKeylet) && !receiverIssuer)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
#include <xrpl/protocol/STLedgerEntry.h>
|
#include <xrpl/protocol/STLedgerEntry.h>
|
||||||
@@ -54,11 +55,11 @@ getTxReserveSponsorID(STTx const& tx);
|
|||||||
* Return a mutable SLE for the transaction's reserve sponsor account.
|
* Return a mutable SLE for the transaction's reserve sponsor account.
|
||||||
*
|
*
|
||||||
* @param ctx The apply-view context (view + tx)
|
* @param ctx The apply-view context (view + tx)
|
||||||
* @return The sponsor account SLE, a null pointer if the tx is not
|
* @return The sponsor account entry, nullopt if the tx is not
|
||||||
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
||||||
* be loaded (an already-checked invariant).
|
* be loaded (an already-checked invariant).
|
||||||
*/
|
*/
|
||||||
std::expected<SLE::pointer, TER>
|
std::expected<std::optional<AccountRootEntryW>, TER>
|
||||||
getTxReserveSponsor(ApplyViewContext ctx);
|
getTxReserveSponsor(ApplyViewContext ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,29 +67,29 @@ getTxReserveSponsor(ApplyViewContext ctx);
|
|||||||
*
|
*
|
||||||
* @param view The ledger read view
|
* @param view The ledger read view
|
||||||
* @param tx The transaction to inspect
|
* @param tx The transaction to inspect
|
||||||
* @return The sponsor account SLE, a null pointer if the tx is not
|
* @return The sponsor account entry, nullopt if the tx is not
|
||||||
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
||||||
* be loaded (an already-checked invariant).
|
* be loaded (an already-checked invariant).
|
||||||
*/
|
*/
|
||||||
std::expected<SLE::const_pointer, TER>
|
std::expected<std::optional<AccountRootEntryR>, TER>
|
||||||
getTxReserveSponsor(ReadView const& view, STTx const& tx);
|
getTxReserveSponsor(ReadView const& view, STTx const& tx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The transaction's reserve sponsor for the given account, if applicable.
|
* The transaction's reserve sponsor for the given account, if applicable.
|
||||||
*
|
*
|
||||||
* A reserve sponsor only covers the transaction submitter's own objects, so
|
* A reserve sponsor only covers the transaction submitter's own objects, so
|
||||||
* this returns the tx reserve sponsor SLE only when accountSle is the tx's own
|
* this returns the tx reserve sponsor entry only when accountSle is the tx's
|
||||||
* (non-pseudo) account; otherwise it returns a null sponsor pointer. This is
|
* own (non-pseudo) account; otherwise it returns nullopt. This is
|
||||||
* the single source of truth for the "sponsor applies to tx.Account only" rule
|
* the single source of truth for the "sponsor applies to tx.Account only" rule
|
||||||
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
|
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
|
||||||
*
|
*
|
||||||
* @param ctx The apply-view context (view + tx)
|
* @param ctx The apply-view context (view + tx)
|
||||||
* @param accountSle The account whose sponsor is being resolved
|
* @param accountSle The account whose sponsor is being resolved
|
||||||
* @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the
|
* @return The sponsor entry (nullopt if unsponsored), or tecINTERNAL if the
|
||||||
* sponsor account cannot be loaded (an already-checked invariant)
|
* sponsor account cannot be loaded (an already-checked invariant)
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::expected<SLE::pointer, TER>
|
[[nodiscard]] std::expected<std::optional<AccountRootEntryW>, TER>
|
||||||
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle);
|
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
|
* Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
|
||||||
@@ -105,9 +106,9 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field = sfSp
|
|||||||
* @param view The mutable apply view
|
* @param view The mutable apply view
|
||||||
* @param sle The ledger entry whose sponsor field is inspected
|
* @param sle The ledger entry whose sponsor field is inspected
|
||||||
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
|
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
|
||||||
* @return The sponsor account SLE, or a null pointer if the entry is unsponsored.
|
* @return The sponsor account entry, or nullopt if the entry is unsponsored.
|
||||||
*/
|
*/
|
||||||
SLE::pointer
|
std::optional<AccountRootEntryW>
|
||||||
getLedgerEntryReserveSponsor(
|
getLedgerEntryReserveSponsor(
|
||||||
ApplyView& view,
|
ApplyView& view,
|
||||||
SLE::ConstRef sle,
|
SLE::ConstRef sle,
|
||||||
|
|||||||
@@ -238,6 +238,12 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
|||||||
TF_FLAG(tfSponsorshipEnd, 0x00010000) \
|
TF_FLAG(tfSponsorshipEnd, 0x00010000) \
|
||||||
TF_FLAG(tfSponsorshipCreate, 0x00020000) \
|
TF_FLAG(tfSponsorshipCreate, 0x00020000) \
|
||||||
TF_FLAG(tfSponsorshipReassign, 0x00040000), \
|
TF_FLAG(tfSponsorshipReassign, 0x00040000), \
|
||||||
|
MASK_ADJ(0)) \
|
||||||
|
\
|
||||||
|
TRANSACTION(ConfidentialMPTHolderKeyUpdate, \
|
||||||
|
TF_FLAG(tfHolderKeyRotation, 0x00010000) \
|
||||||
|
TF_FLAG(tfHolderKeyRecovery, 0x00020000) \
|
||||||
|
TF_FLAG(tfCancelRecovery, 0x00040000), \
|
||||||
MASK_ADJ(0))
|
MASK_ADJ(0))
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|||||||
@@ -439,6 +439,7 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
|
|||||||
{sfIssuerKeyMirrorEpoch, SoeOptional},
|
{sfIssuerKeyMirrorEpoch, SoeOptional},
|
||||||
{sfAuditorKeyMirrorEpoch, SoeOptional},
|
{sfAuditorKeyMirrorEpoch, SoeOptional},
|
||||||
{sfHolderEncryptionKey, SoeOptional},
|
{sfHolderEncryptionKey, SoeOptional},
|
||||||
|
{sfRecoveryKey, SoeOptional},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
/** A ledger object which tracks Oracle
|
/** A ledger object which tracks Oracle
|
||||||
|
|||||||
@@ -330,6 +330,7 @@ TYPED_SFIELD(sfAuditorEncryptionKey, VL, 44)
|
|||||||
TYPED_SFIELD(sfAmountCommitment, VL, 45)
|
TYPED_SFIELD(sfAmountCommitment, VL, 45)
|
||||||
TYPED_SFIELD(sfBalanceCommitment, VL, 46)
|
TYPED_SFIELD(sfBalanceCommitment, VL, 46)
|
||||||
TYPED_SFIELD(sfBytecode, VL, 47)
|
TYPED_SFIELD(sfBytecode, VL, 47)
|
||||||
|
TYPED_SFIELD(sfRecoveryKey, VL, 48)
|
||||||
|
|
||||||
// account (common)
|
// account (common)
|
||||||
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
|
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
|
||||||
|
|||||||
@@ -1147,12 +1147,27 @@ TRANSACTION(ttCONFIDENTIAL_MPT_MIRROR_UPDATE, 92, ConfidentialMPTMirrorUpdate,
|
|||||||
{sfZKProof, SoeRequired},
|
{sfZKProof, SoeRequired},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
/** This transaction rotates or recovers a confidential MPT holder's ElGamal encryption key,
|
||||||
|
or cancels a recovery. */
|
||||||
|
#if TRANSACTION_INCLUDE
|
||||||
|
# include <xrpl/tx/transactors/token/ConfidentialMPTHolderKeyUpdate.h>
|
||||||
|
#endif
|
||||||
|
TRANSACTION(ttCONFIDENTIAL_MPT_HOLDER_KEY_UPDATE, 93, ConfidentialMPTHolderKeyUpdate,
|
||||||
|
({.amendment = featureConfidentialMPTKeyRotation}),
|
||||||
|
({
|
||||||
|
{sfMPTokenIssuanceID, SoeRequired},
|
||||||
|
{sfHolderEncryptionKey, SoeOptional},
|
||||||
|
{sfConfidentialBalanceSpending, SoeOptional},
|
||||||
|
{sfConfidentialBalanceInbox, SoeOptional},
|
||||||
|
{sfZKProof, SoeOptional},
|
||||||
|
}))
|
||||||
|
|
||||||
/** This transaction posts an unsigned transaction on-ledger as a
|
/** This transaction posts an unsigned transaction on-ledger as a
|
||||||
TransactionProposal, pending multi-signature collection. */
|
TransactionProposal, pending multi-signature collection. */
|
||||||
#if TRANSACTION_INCLUDE
|
#if TRANSACTION_INCLUDE
|
||||||
# include <xrpl/tx/transactors/proposal/TransactionProposalCreate.h>
|
# include <xrpl/tx/transactors/proposal/TransactionProposalCreate.h>
|
||||||
#endif
|
#endif
|
||||||
TRANSACTION(ttTRANSACTION_PROPOSAL_CREATE, 93, TransactionProposalCreate,
|
TRANSACTION(ttTRANSACTION_PROPOSAL_CREATE, 95, TransactionProposalCreate,
|
||||||
({.amendment = featureCosign}),
|
({.amendment = featureCosign}),
|
||||||
({
|
({
|
||||||
{sfProposedTransaction, SoeRequired},
|
{sfProposedTransaction, SoeRequired},
|
||||||
|
|||||||
@@ -339,6 +339,30 @@ public:
|
|||||||
{
|
{
|
||||||
return this->sle_->isFieldPresent(sfHolderEncryptionKey);
|
return this->sle_->isFieldPresent(sfHolderEncryptionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sfRecoveryKey (SoeOptional)
|
||||||
|
* @return The field value, or std::nullopt if not present.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||||
|
getRecoveryKey() const
|
||||||
|
{
|
||||||
|
if (hasRecoveryKey())
|
||||||
|
return this->sle_->at(sfRecoveryKey);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if sfRecoveryKey is present.
|
||||||
|
* @return True if the field is present, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool
|
||||||
|
hasRecoveryKey() const
|
||||||
|
{
|
||||||
|
return this->sle_->isFieldPresent(sfRecoveryKey);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -552,6 +576,17 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set sfRecoveryKey (SoeOptional)
|
||||||
|
* @return Reference to this builder for method chaining.
|
||||||
|
*/
|
||||||
|
MPTokenBuilder&
|
||||||
|
setRecoveryKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||||
|
{
|
||||||
|
object_[sfRecoveryKey] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Build and return the completed MPToken wrapper.
|
* @brief Build and return the completed MPToken wrapper.
|
||||||
* @param index The ledger entry index.
|
* @param index The ledger entry index.
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
// This file is auto-generated. Do not edit.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpl/protocol/STTx.h>
|
||||||
|
#include <xrpl/protocol/STParsedJSON.h>
|
||||||
|
#include <xrpl/protocol/jss.h>
|
||||||
|
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||||
|
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||||
|
#include <xrpl/json/json_value.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace xrpl::transactions {
|
||||||
|
|
||||||
|
class ConfidentialMPTHolderKeyUpdateBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transaction: ConfidentialMPTHolderKeyUpdate
|
||||||
|
*
|
||||||
|
* Type: ttCONFIDENTIAL_MPT_HOLDER_KEY_UPDATE (93)
|
||||||
|
* Delegable: Delegation::NotDelegable
|
||||||
|
* Amendment: featureConfidentialMPTKeyRotation
|
||||||
|
* Privileges: Privilege::NoPriv
|
||||||
|
*
|
||||||
|
* Immutable wrapper around STTx providing type-safe field access.
|
||||||
|
* Use ConfidentialMPTHolderKeyUpdateBuilder to construct new transactions.
|
||||||
|
*/
|
||||||
|
class ConfidentialMPTHolderKeyUpdate : public TransactionBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr xrpl::TxType txType = ttCONFIDENTIAL_MPT_HOLDER_KEY_UPDATE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a ConfidentialMPTHolderKeyUpdate transaction wrapper from an existing STTx object.
|
||||||
|
* @throws std::runtime_error if the transaction type doesn't match.
|
||||||
|
*/
|
||||||
|
explicit ConfidentialMPTHolderKeyUpdate(std::shared_ptr<STTx const> tx)
|
||||||
|
: TransactionBase(std::move(tx))
|
||||||
|
{
|
||||||
|
// Verify transaction type
|
||||||
|
if (tx_->getTxnType() != txType)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid transaction type for ConfidentialMPTHolderKeyUpdate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction-specific field getters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sfMPTokenIssuanceID (SoeRequired)
|
||||||
|
* @return The field value.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
SF_UINT192::type::value_type
|
||||||
|
getMPTokenIssuanceID() const
|
||||||
|
{
|
||||||
|
return this->tx_->at(sfMPTokenIssuanceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sfHolderEncryptionKey (SoeOptional)
|
||||||
|
* @return The field value, or std::nullopt if not present.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||||
|
getHolderEncryptionKey() const
|
||||||
|
{
|
||||||
|
if (hasHolderEncryptionKey())
|
||||||
|
{
|
||||||
|
return this->tx_->at(sfHolderEncryptionKey);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if sfHolderEncryptionKey is present.
|
||||||
|
* @return True if the field is present, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool
|
||||||
|
hasHolderEncryptionKey() const
|
||||||
|
{
|
||||||
|
return this->tx_->isFieldPresent(sfHolderEncryptionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sfConfidentialBalanceSpending (SoeOptional)
|
||||||
|
* @return The field value, or std::nullopt if not present.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||||
|
getConfidentialBalanceSpending() const
|
||||||
|
{
|
||||||
|
if (hasConfidentialBalanceSpending())
|
||||||
|
{
|
||||||
|
return this->tx_->at(sfConfidentialBalanceSpending);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if sfConfidentialBalanceSpending is present.
|
||||||
|
* @return True if the field is present, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool
|
||||||
|
hasConfidentialBalanceSpending() const
|
||||||
|
{
|
||||||
|
return this->tx_->isFieldPresent(sfConfidentialBalanceSpending);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sfConfidentialBalanceInbox (SoeOptional)
|
||||||
|
* @return The field value, or std::nullopt if not present.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||||
|
getConfidentialBalanceInbox() const
|
||||||
|
{
|
||||||
|
if (hasConfidentialBalanceInbox())
|
||||||
|
{
|
||||||
|
return this->tx_->at(sfConfidentialBalanceInbox);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if sfConfidentialBalanceInbox is present.
|
||||||
|
* @return True if the field is present, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool
|
||||||
|
hasConfidentialBalanceInbox() const
|
||||||
|
{
|
||||||
|
return this->tx_->isFieldPresent(sfConfidentialBalanceInbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get sfZKProof (SoeOptional)
|
||||||
|
* @return The field value, or std::nullopt if not present.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||||
|
getZKProof() const
|
||||||
|
{
|
||||||
|
if (hasZKProof())
|
||||||
|
{
|
||||||
|
return this->tx_->at(sfZKProof);
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if sfZKProof is present.
|
||||||
|
* @return True if the field is present, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
bool
|
||||||
|
hasZKProof() const
|
||||||
|
{
|
||||||
|
return this->tx_->isFieldPresent(sfZKProof);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Builder for ConfidentialMPTHolderKeyUpdate transactions.
|
||||||
|
*
|
||||||
|
* Provides a fluent interface for constructing transactions with method chaining.
|
||||||
|
* Uses STObject internally for flexible transaction construction.
|
||||||
|
* Inherits common field setters from TransactionBuilderBase.
|
||||||
|
*/
|
||||||
|
class ConfidentialMPTHolderKeyUpdateBuilder : public TransactionBuilderBase<ConfidentialMPTHolderKeyUpdateBuilder>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new ConfidentialMPTHolderKeyUpdateBuilder with required fields.
|
||||||
|
* @param account The account initiating the transaction.
|
||||||
|
* @param mPTokenIssuanceID The sfMPTokenIssuanceID field value.
|
||||||
|
* @param sequence Optional sequence number for the transaction.
|
||||||
|
* @param fee Optional fee for the transaction.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder(SF_ACCOUNT::type::value_type account,
|
||||||
|
std::decay_t<typename SF_UINT192::type::value_type> const& mPTokenIssuanceID, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||||
|
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||||
|
)
|
||||||
|
: TransactionBuilderBase<ConfidentialMPTHolderKeyUpdateBuilder>(ttCONFIDENTIAL_MPT_HOLDER_KEY_UPDATE, account, sequence, fee)
|
||||||
|
{
|
||||||
|
setMPTokenIssuanceID(mPTokenIssuanceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a ConfidentialMPTHolderKeyUpdateBuilder from an existing STTx object.
|
||||||
|
* @param tx The existing transaction to copy from.
|
||||||
|
* @throws std::runtime_error if the transaction type doesn't match.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder(std::shared_ptr<STTx const> tx)
|
||||||
|
{
|
||||||
|
if (tx->getTxnType() != ttCONFIDENTIAL_MPT_HOLDER_KEY_UPDATE)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid transaction type for ConfidentialMPTHolderKeyUpdateBuilder");
|
||||||
|
}
|
||||||
|
object_ = *tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transaction-specific field setters
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set sfMPTokenIssuanceID (SoeRequired)
|
||||||
|
* @return Reference to this builder for method chaining.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder&
|
||||||
|
setMPTokenIssuanceID(std::decay_t<typename SF_UINT192::type::value_type> const& value)
|
||||||
|
{
|
||||||
|
object_[sfMPTokenIssuanceID] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set sfHolderEncryptionKey (SoeOptional)
|
||||||
|
* @return Reference to this builder for method chaining.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder&
|
||||||
|
setHolderEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||||
|
{
|
||||||
|
object_[sfHolderEncryptionKey] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set sfConfidentialBalanceSpending (SoeOptional)
|
||||||
|
* @return Reference to this builder for method chaining.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder&
|
||||||
|
setConfidentialBalanceSpending(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||||
|
{
|
||||||
|
object_[sfConfidentialBalanceSpending] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set sfConfidentialBalanceInbox (SoeOptional)
|
||||||
|
* @return Reference to this builder for method chaining.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder&
|
||||||
|
setConfidentialBalanceInbox(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||||
|
{
|
||||||
|
object_[sfConfidentialBalanceInbox] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set sfZKProof (SoeOptional)
|
||||||
|
* @return Reference to this builder for method chaining.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdateBuilder&
|
||||||
|
setZKProof(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||||
|
{
|
||||||
|
object_[sfZKProof] = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Build and return the ConfidentialMPTHolderKeyUpdate wrapper.
|
||||||
|
* @param publicKey The public key for signing.
|
||||||
|
* @param secretKey The secret key for signing.
|
||||||
|
* @return The constructed transaction wrapper.
|
||||||
|
*/
|
||||||
|
ConfidentialMPTHolderKeyUpdate
|
||||||
|
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||||
|
{
|
||||||
|
sign(publicKey, secretKey);
|
||||||
|
return ConfidentialMPTHolderKeyUpdate{std::make_shared<STTx>(std::move(object_))};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xrpl::transactions
|
||||||
@@ -18,7 +18,7 @@ class TransactionProposalCreateBuilder;
|
|||||||
/**
|
/**
|
||||||
* @brief Transaction: TransactionProposalCreate
|
* @brief Transaction: TransactionProposalCreate
|
||||||
*
|
*
|
||||||
* Type: ttTRANSACTION_PROPOSAL_CREATE (93)
|
* Type: ttTRANSACTION_PROPOSAL_CREATE (95)
|
||||||
* Delegable: Delegation::NotDelegable
|
* Delegable: Delegation::NotDelegable
|
||||||
* Amendment: featureCosign
|
* Amendment: featureCosign
|
||||||
* Privileges: Privilege::NoPriv
|
* Privileges: Privilege::NoPriv
|
||||||
|
|||||||
@@ -27,6 +27,18 @@
|
|||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if sleAcct is an AccountRoot carrying a pseudo-account field.
|
||||||
|
*
|
||||||
|
* isPseudoAccount() takes a view-bound AccountRootEntry, which is not
|
||||||
|
* available while visiting entries, so invariant checks use this instead.
|
||||||
|
*
|
||||||
|
* @param sleAcct the SLE to check.
|
||||||
|
* @return true if sleAcct is an AccountRoot carrying a pseudo-account field.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] bool
|
||||||
|
isPseudoAccountSle(SLE::ConstRef sleAcct);
|
||||||
|
|
||||||
#if GENERATING_DOCS
|
#if GENERATING_DOCS
|
||||||
/**
|
/**
|
||||||
* @brief Prototype for invariant check implementations.
|
* @brief Prototype for invariant check implementations.
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ class ValidMPTIssuance
|
|||||||
* MPTokens and RippleStates deleted during apply. finalize() checks each
|
* MPTokens and RippleStates deleted during apply. finalize() checks each
|
||||||
* holder's AccountRoot to detect vault pseudo-account holdings deleted
|
* holder's AccountRoot to detect vault pseudo-account holdings deleted
|
||||||
* outside VaultDelete. All these checks are gated on fixCleanup3_2_0.
|
* outside VaultDelete. All these checks are gated on fixCleanup3_2_0.
|
||||||
|
*
|
||||||
|
* Under fixCleanup3_5_0, finalize() also rejects any MPToken erased with
|
||||||
|
* a non-zero sfMPTAmount.
|
||||||
*/
|
*/
|
||||||
std::vector<std::shared_ptr<SLE const>> deletedHoldings_;
|
std::vector<std::shared_ptr<SLE const>> deletedHoldings_;
|
||||||
|
|
||||||
@@ -138,8 +141,9 @@ public:
|
|||||||
* - Convert/ConvertBack symmetry:
|
* - Convert/ConvertBack symmetry:
|
||||||
* Regular MPToken balance change (±X) == COA (Confidential Outstanding Amount) change (∓X)
|
* Regular MPToken balance change (±X) == COA (Confidential Outstanding Amount) change (∓X)
|
||||||
* - Cannot delete MPToken with non-zero confidential state:
|
* - Cannot delete MPToken with non-zero confidential state:
|
||||||
* Cannot delete if sfIssuerEncryptedBalance exists
|
* Cannot delete if any of sfConfidentialBalanceSpending, sfConfidentialBalanceInbox,
|
||||||
* Cannot delete if sfConfidentialBalanceInbox and sfConfidentialBalanceSpending exist
|
* sfIssuerEncryptedBalance or sfAuditorEncryptedBalance is present, and the issuance's
|
||||||
|
* sfConfidentialOutstandingAmount is non-zero. Mirrors MPTokenAuthorize::preclaim.
|
||||||
* - Privacy flag consistency:
|
* - Privacy flag consistency:
|
||||||
* MPToken confidential balance fields can only be created or changed if
|
* MPToken confidential balance fields can only be created or changed if
|
||||||
* lsfMPTCanHoldConfidentialBalance is set on the issuance.
|
* lsfMPTCanHoldConfidentialBalance is set on the issuance.
|
||||||
@@ -162,6 +166,8 @@ class ValidConfidentialMPToken
|
|||||||
std::int64_t outstandingDelta = 0;
|
std::int64_t outstandingDelta = 0;
|
||||||
SLE::const_pointer issuance;
|
SLE::const_pointer issuance;
|
||||||
bool deletedWithEncrypted = false;
|
bool deletedWithEncrypted = false;
|
||||||
|
// True when an erased MPToken had a non-zero pre-tx public balance.
|
||||||
|
bool deletedWithBalanceBefore = false;
|
||||||
bool badConsistency = false;
|
bool badConsistency = false;
|
||||||
bool badCOA = false;
|
bool badCOA = false;
|
||||||
bool changesConfidentialFields = false;
|
bool changesConfidentialFields = false;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
@@ -25,7 +26,7 @@ checkFreeze(
|
|||||||
XRPL_ASSERT(src != dst, "xrpl::checkFreeze : unequal input accounts");
|
XRPL_ASSERT(src != dst, "xrpl::checkFreeze : unequal input accounts");
|
||||||
|
|
||||||
// check freeze
|
// check freeze
|
||||||
if (auto sle = view.read(keylet::account(dst)))
|
if (auto sle = AccountRootEntryR(dst, view))
|
||||||
{
|
{
|
||||||
if (sle->isFlag(lsfGlobalFreeze))
|
if (sle->isFlag(lsfGlobalFreeze))
|
||||||
{
|
{
|
||||||
@@ -49,7 +50,7 @@ checkFreeze(
|
|||||||
|
|
||||||
if (view.rules().enabled(fixFrozenLPTokenTransfer))
|
if (view.rules().enabled(fixFrozenLPTokenTransfer))
|
||||||
{
|
{
|
||||||
if (auto const sleDst = view.read(keylet::account(dst));
|
if (auto const sleDst = AccountRootEntryR(dst, view);
|
||||||
sleDst && sleDst->isFieldPresent(sfAMMID))
|
sleDst && sleDst->isFieldPresent(sfAMMID))
|
||||||
{
|
{
|
||||||
auto const sleAmm = view.read(keylet::amm((*sleDst)[sfAMMID]));
|
auto const sleAmm = view.read(keylet::amm((*sleDst)[sfAMMID]));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Keylet.h>
|
#include <xrpl/protocol/Keylet.h>
|
||||||
#include <xrpl/protocol/STLedgerEntry.h>
|
#include <xrpl/protocol/STLedgerEntry.h>
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
#include <xrpl/tx/Transactor.h>
|
#include <xrpl/tx/Transactor.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
@@ -56,8 +58,8 @@ private:
|
|||||||
Keylet const& sponsorshipKeylet,
|
Keylet const& sponsorshipKeylet,
|
||||||
AccountID const& sponsorID,
|
AccountID const& sponsorID,
|
||||||
AccountID const& sponseeID,
|
AccountID const& sponseeID,
|
||||||
SLE::Ref sponsorAccSle,
|
AccountRootEntryW& sponsorAccSle,
|
||||||
SLE::Ref reserveSponsorAccSle);
|
std::optional<AccountRootEntryW>& reserveSponsorAccSle);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xrpl
|
} // namespace xrpl
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/protocol/STTx.h>
|
||||||
|
#include <xrpl/protocol/TER.h>
|
||||||
|
#include <xrpl/protocol/XRPAmount.h>
|
||||||
|
#include <xrpl/tx/ApplyContext.h>
|
||||||
|
#include <xrpl/tx/Transactor.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace xrpl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allows a confidential MPT holder to rotate or recover their ElGamal
|
||||||
|
* encryption key, or to cancel a pending recovery.
|
||||||
|
*
|
||||||
|
* Submitted by the holder. Exactly one of three modes must be selected via
|
||||||
|
* the transaction flags:
|
||||||
|
*
|
||||||
|
* - Rotation (tfHolderKeyRotation): the holder still has their current
|
||||||
|
* ElGamal private key. They provide a new public key along with their
|
||||||
|
* current spending/inbox balances re-encrypted under that new key. The
|
||||||
|
* holder's encryption key and confidential balances are updated
|
||||||
|
* immediately.
|
||||||
|
*
|
||||||
|
* - Recovery (tfHolderKeyRecovery): the holder has lost their current
|
||||||
|
* private key. They provide a new public key but cannot provide
|
||||||
|
* re-encrypted balances. The new key is recorded as a pending
|
||||||
|
* sfRecoveryKey; the confidential balances are left untouched. Completing
|
||||||
|
* the recovery (rewriting the balances) is done separately by the issuer
|
||||||
|
* via ConfidentialMPTRecoverBalance.
|
||||||
|
*
|
||||||
|
* - Cancel (tfCancelRecovery): the holder revokes a pending recovery
|
||||||
|
* authorization created by a prior Recovery-mode transaction. No key,
|
||||||
|
* balances, or proof are carried; authorization is via the holder's
|
||||||
|
* ordinary XRPL signature. sfRecoveryKey is removed and everything else
|
||||||
|
* is left untouched. Fails if no recovery is pending.
|
||||||
|
*
|
||||||
|
* @note Zero-knowledge proof verification for Rotation and Recovery is
|
||||||
|
* deferred to a follow-up once the mpt-crypto constructions are finalized.
|
||||||
|
*/
|
||||||
|
class ConfidentialMPTHolderKeyUpdate : public Transactor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||||
|
|
||||||
|
explicit ConfidentialMPTHolderKeyUpdate(ApplyContext& ctx) : Transactor(ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
checkExtraFeatures(PreflightContext const& ctx);
|
||||||
|
|
||||||
|
static std::uint32_t
|
||||||
|
getFlagsMask(PreflightContext const& ctx);
|
||||||
|
|
||||||
|
static NotTEC
|
||||||
|
preflight(PreflightContext const& ctx);
|
||||||
|
|
||||||
|
static XRPAmount
|
||||||
|
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||||
|
|
||||||
|
static TER
|
||||||
|
preclaim(PreclaimContext const& ctx);
|
||||||
|
|
||||||
|
TER
|
||||||
|
doApply() override;
|
||||||
|
|
||||||
|
void
|
||||||
|
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool
|
||||||
|
finalizeInvariants(
|
||||||
|
STTx const& tx,
|
||||||
|
TER result,
|
||||||
|
XRPAmount fee,
|
||||||
|
ReadView const& view,
|
||||||
|
beast::Journal const& j) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xrpl
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
@@ -99,12 +100,13 @@ uniqueRandomPath(
|
|||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
"Unable to check path '" + candidate.string() + "': " + ec.message());
|
std::format("Unable to check path '{}': {}", candidate.string(), ec.message()));
|
||||||
}
|
}
|
||||||
if (!exists)
|
if (!exists)
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
Throw<std::runtime_error>("Unable to generate a unique path under '" + base.string() + "'");
|
Throw<std::runtime_error>(
|
||||||
|
std::format("Unable to generate a unique path under '{}'", base.string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TempDir::TempDir() : path_(uniqueRandomPath(std::filesystem::temp_directory_path()))
|
TempDir::TempDir() : path_(uniqueRandomPath(std::filesystem::temp_directory_path()))
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
|
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <format>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -264,7 +265,7 @@ OpenView::rawTxInsert(
|
|||||||
auto const result = txs_.emplace(
|
auto const result = txs_.emplace(
|
||||||
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(txn, metaData));
|
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(txn, metaData));
|
||||||
if (!result.second)
|
if (!result.second)
|
||||||
Throw<std::logic_error>("rawTxInsert: duplicate TX id: " + to_string(key));
|
Throw<std::logic_error>(std::format("rawTxInsert: duplicate TX id: {}", to_string(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xrpl
|
} // namespace xrpl
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
@@ -115,8 +116,8 @@ isVaultPseudoAccountFrozenForIssuance(
|
|||||||
view, {issuer, account}, assetOfHolding(issuanceSle, *sleHolding), depth + 1);
|
view, {issuer, account}, assetOfHolding(issuanceSle, *sleHolding), depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const mptIssuer = view.read(keylet::account(issuer));
|
auto const mptIssuer = AccountRootEntryR(issuer, view);
|
||||||
if (mptIssuer == nullptr)
|
if (!mptIssuer.exists())
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null MPToken issuer");
|
UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null MPToken issuer");
|
||||||
@@ -189,7 +190,7 @@ canTransferLPToken(
|
|||||||
{
|
{
|
||||||
// Only AMM-issued LPTokens are subject to this check. The LPToken's issuer
|
// Only AMM-issued LPTokens are subject to this check. The LPToken's issuer
|
||||||
// is the AMM account; if it is not an AMM, this is not an LPToken.
|
// is the AMM account; if it is not an AMM, this is not an LPToken.
|
||||||
auto const sleIssuer = view.read(keylet::account(lpTokenIssuer));
|
auto const sleIssuer = AccountRootEntryR(lpTokenIssuer, view);
|
||||||
if (!sleIssuer || !sleIssuer->isFieldPresent(sfAMMID))
|
if (!sleIssuer || !sleIssuer->isFieldPresent(sfAMMID))
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|
||||||
@@ -466,7 +467,7 @@ canWithdraw(
|
|||||||
ReadView const& view,
|
ReadView const& view,
|
||||||
AccountID const& from,
|
AccountID const& from,
|
||||||
AccountID const& to,
|
AccountID const& to,
|
||||||
SLE::ConstRef toSle,
|
AccountRootEntryR const& toSle,
|
||||||
STAmount const& amount,
|
STAmount const& amount,
|
||||||
bool hasDestinationTag,
|
bool hasDestinationTag,
|
||||||
std::optional<std::vector<UInt256>> const& credentialIDs)
|
std::optional<std::vector<UInt256>> const& credentialIDs)
|
||||||
@@ -516,7 +517,7 @@ canWithdraw(
|
|||||||
bool hasDestinationTag,
|
bool hasDestinationTag,
|
||||||
std::optional<std::vector<UInt256>> const& credentialIDs)
|
std::optional<std::vector<UInt256>> const& credentialIDs)
|
||||||
{
|
{
|
||||||
auto const toSle = view.read(keylet::account(to));
|
auto const toSle = AccountRootEntryR(to, view);
|
||||||
|
|
||||||
return canWithdraw(view, from, to, toSle, amount, hasDestinationTag, credentialIDs);
|
return canWithdraw(view, from, to, toSle, amount, hasDestinationTag, credentialIDs);
|
||||||
}
|
}
|
||||||
@@ -541,7 +542,7 @@ doWithdraw(
|
|||||||
STAmount const& amount,
|
STAmount const& amount,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
{
|
{
|
||||||
auto const dstSle = ctx.view.read(keylet::account(dstAcct));
|
auto dstSle = AccountRootEntryW(dstAcct, ctx.view);
|
||||||
|
|
||||||
// Create a trust line or MPToken for a self-destination only when there
|
// Create a trust line or MPToken for a self-destination only when there
|
||||||
// is a payout to credit. Post-fixCleanup3_4_0, a zero-value withdraw
|
// is a payout to credit. Post-fixCleanup3_4_0, a zero-value withdraw
|
||||||
@@ -559,7 +560,8 @@ doWithdraw(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (auto err = verifyDepositPreauth(ctx.tx, ctx.view, senderAcct, dstAcct, dstSle, j))
|
if (auto err =
|
||||||
|
verifyDepositPreauth(ctx.tx, ctx.view, senderAcct, dstAcct, dstSle.rawSle(), j))
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,14 +584,21 @@ doWithdraw(
|
|||||||
// sponsor against the destination. accountSend can auto-create a holding
|
// sponsor against the destination. accountSend can auto-create a holding
|
||||||
// for dstAcct; keying on the destination ensures a third-party destination's
|
// for dstAcct; keying on the destination ensures a third-party destination's
|
||||||
// holding is never stamped with the tx's reserve sponsor.
|
// holding is never stamped with the tx's reserve sponsor.
|
||||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, dstSle);
|
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, dstSle);
|
||||||
if (!sponsorSle)
|
if (!sponsorSle)
|
||||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Move the funds directly from the broker's pseudo-account to the
|
// Move the funds directly from the broker's pseudo-account to the
|
||||||
// dstAcct
|
// dstAcct
|
||||||
|
auto& sponsor = *sponsorSle;
|
||||||
return accountSend(
|
return accountSend(
|
||||||
ctx.view, sourceAcct, dstAcct, amount, j, *sponsorSle, WaiveTransferFee::Yes);
|
ctx.view,
|
||||||
|
sourceAcct,
|
||||||
|
dstAcct,
|
||||||
|
amount,
|
||||||
|
j,
|
||||||
|
sponsor ? sponsor->mutableRawSle() : SLE::pointer{},
|
||||||
|
WaiveTransferFee::Yes);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
TER
|
||||||
|
|||||||
@@ -0,0 +1,322 @@
|
|||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
|
|
||||||
|
#include <xrpl/basics/Log.h>
|
||||||
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
|
#include <xrpl/ledger/OwnerCounts.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
|
#include <xrpl/protocol/AccountID.h>
|
||||||
|
#include <xrpl/protocol/Feature.h>
|
||||||
|
#include <xrpl/protocol/Indexes.h>
|
||||||
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
|
#include <xrpl/protocol/SField.h>
|
||||||
|
#include <xrpl/protocol/STTx.h>
|
||||||
|
#include <xrpl/protocol/TER.h>
|
||||||
|
#include <xrpl/protocol/XRPAmount.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace xrpl {
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
XRPAmount
|
||||||
|
AccountRootEntry<ViewT>::reserve(Adjustment adj) const
|
||||||
|
{
|
||||||
|
auto const& view = this->readView();
|
||||||
|
auto const j = this->journal();
|
||||||
|
|
||||||
|
XRPL_ASSERT(
|
||||||
|
this->exists() && (*this)->getType() == ltACCOUNT_ROOT, "xrpl::accountReserve : valid sle");
|
||||||
|
|
||||||
|
if (!view.rules().enabled(featureSponsor))
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::accountReserve : no account count delta");
|
||||||
|
return view.fees().accountReserve(
|
||||||
|
(*this)->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
|
||||||
|
}
|
||||||
|
std::uint32_t const currentOwnerCount = ownerCount(adj.ownerCountDelta);
|
||||||
|
std::uint32_t const currentAccountCount =
|
||||||
|
detail::accountCountImpl(*this, adj.accountCountDelta, j);
|
||||||
|
|
||||||
|
return view.fees().accountReserve(currentOwnerCount, currentAccountCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
std::uint32_t
|
||||||
|
AccountRootEntry<ViewT>::ownerCount(std::int32_t ownerCountAdj) const
|
||||||
|
{
|
||||||
|
auto const j = this->journal();
|
||||||
|
|
||||||
|
XRPL_ASSERT(
|
||||||
|
this->exists() && (*this)->getType() == ltACCOUNT_ROOT,
|
||||||
|
"xrpl::ownerCount : sle is account root");
|
||||||
|
|
||||||
|
AccountID const id = (*this)->getAccountID(sfAccount);
|
||||||
|
std::uint32_t const currentOwnerCount = (*this)->at(sfOwnerCount);
|
||||||
|
std::uint32_t const sponsoredOwnerCount = (*this)->at(sfSponsoredOwnerCount);
|
||||||
|
std::uint32_t const sponsoringOwnerCount = (*this)->at(sfSponsoringOwnerCount);
|
||||||
|
|
||||||
|
XRPL_ASSERT(
|
||||||
|
currentOwnerCount >= sponsoredOwnerCount,
|
||||||
|
"xrpl::ownerCount : OwnerCount must be greater than or equal to SponsoredOwnerCount");
|
||||||
|
|
||||||
|
std::int64_t deltaCount =
|
||||||
|
static_cast<std::int64_t>(ownerCountAdj) - sponsoredOwnerCount + sponsoringOwnerCount;
|
||||||
|
|
||||||
|
if (deltaCount > std::numeric_limits<std::int32_t>::max())
|
||||||
|
{
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
deltaCount = std::numeric_limits<std::int32_t>::max();
|
||||||
|
JLOG(j.fatal()) << "Account " << id << " delta count exceeds max, "
|
||||||
|
<< "adjustment: " << ownerCountAdj
|
||||||
|
<< ", sponsoredCount: " << sponsoredOwnerCount
|
||||||
|
<< ", sponsoringOwnerCount: " << sponsoringOwnerCount;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
else if (deltaCount < std::numeric_limits<std::int32_t>::min())
|
||||||
|
{
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
deltaCount = std::numeric_limits<std::int32_t>::min();
|
||||||
|
JLOG(j.fatal()) << "Account " << id << " delta count is below min, "
|
||||||
|
<< "adjustment: " << ownerCountAdj
|
||||||
|
<< ", sponsoredCount: " << sponsoredOwnerCount
|
||||||
|
<< ", sponsoringCount: " << sponsoringOwnerCount;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
return detail::confineOwnerCount(currentOwnerCount, deltaCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
TER
|
||||||
|
AccountRootEntry<ViewT>::checkReserve(
|
||||||
|
ApplyViewContext ctx,
|
||||||
|
XRPAmount accBalance,
|
||||||
|
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
|
||||||
|
Adjustment adj,
|
||||||
|
TER insufReserveCode) const
|
||||||
|
{
|
||||||
|
// TODO: swap to assert after fixCleanup3_2_0 is retired
|
||||||
|
if (!this->exists() || (*this)->getType() != ltACCOUNT_ROOT)
|
||||||
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
XRPL_ASSERT(
|
||||||
|
!isTesSuccess(insufReserveCode), "xrpl::checkReserve : insufReserveCode is not tesSUCCESS");
|
||||||
|
if (ctx.view.rules().enabled(featureSponsor))
|
||||||
|
{
|
||||||
|
if (sponsorSle)
|
||||||
|
{
|
||||||
|
if ((*sponsorSle)->getType() != ltACCOUNT_ROOT)
|
||||||
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
auto const sle = ctx.view.read(
|
||||||
|
keylet::sponsorship(
|
||||||
|
(*sponsorSle)->getAccountID(sfAccount), (*this)->getAccountID(sfAccount)));
|
||||||
|
|
||||||
|
// A reserve-sponsored tx must carry a sponsor signature
|
||||||
|
// (cosigning path) and/or have a pre-existing sponsorship SLE
|
||||||
|
// (prefunded path). Absence of both is an internal invariant break.
|
||||||
|
if (isReserveSponsored(ctx.tx) && !sle && !ctx.tx.isFieldPresent(sfSponsorSignature))
|
||||||
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
if (sle)
|
||||||
|
{
|
||||||
|
auto const ownerCountAllowed = sle->getFieldU32(sfRemainingOwnerCount);
|
||||||
|
if (adj.ownerCountDelta > 0 &&
|
||||||
|
ownerCountAllowed < static_cast<std::uint32_t>(adj.ownerCountDelta))
|
||||||
|
return insufReserveCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const sponsorBalance = (*sponsorSle)->getFieldAmount(sfBalance).xrp();
|
||||||
|
XRPAmount const sponsorReserve = sponsorSle->reserve(adj);
|
||||||
|
|
||||||
|
if (sponsorBalance < sponsorReserve)
|
||||||
|
return insufReserveCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XRPAmount const reserve = this->reserve(adj);
|
||||||
|
if (accBalance < reserve)
|
||||||
|
return insufReserveCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
!sponsorSle,
|
||||||
|
"xrpl::checkReserve : featureSponsor disabled and sponsorSle not provided");
|
||||||
|
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::checkReserve : accountCountDelta is 0");
|
||||||
|
auto const reserve = ctx.view.fees().accountReserve(
|
||||||
|
(*this)->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
|
||||||
|
if (accBalance < reserve)
|
||||||
|
return insufReserveCode;
|
||||||
|
}
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
TER
|
||||||
|
AccountRootEntry<ViewT>::checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, *this);
|
||||||
|
if (!sponsorExp)
|
||||||
|
return sponsorExp.error(); // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
std::optional<AccountRootEntry<ReadView>> sponsorSle;
|
||||||
|
if (*sponsorExp)
|
||||||
|
sponsorSle.emplace(**sponsorExp);
|
||||||
|
return checkReserve(ctx, accBalance, sponsorSle, adj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
void
|
||||||
|
AccountRootEntry<ViewT>::adjustOwnerCountSigned(
|
||||||
|
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
|
||||||
|
std::int32_t adjustment)
|
||||||
|
requires Base::kIsWritable
|
||||||
|
{
|
||||||
|
auto& view = this->applyView();
|
||||||
|
auto const j = this->journal();
|
||||||
|
|
||||||
|
if (view.rules().enabled(featureSponsor))
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(this->exists(), "xrpl::adjustOwnerCountSigned : valid account sle");
|
||||||
|
if (!this->exists())
|
||||||
|
return; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
auto const accountID = (*this)->getAccountID(sfAccount);
|
||||||
|
bool const validType = (*this)->getType() == ltACCOUNT_ROOT;
|
||||||
|
XRPL_ASSERT(validType, "xrpl::adjustOwnerCountSigned : valid account sle type");
|
||||||
|
if (!validType)
|
||||||
|
return; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCountSigned : nonzero adjustment input");
|
||||||
|
|
||||||
|
OwnerCounts const currentOwnerCount(this->rawSle());
|
||||||
|
OwnerCounts totalOwnerCount(currentOwnerCount);
|
||||||
|
|
||||||
|
if (sponsorSle)
|
||||||
|
{
|
||||||
|
bool const validSponsorType = (*sponsorSle)->getType() == ltACCOUNT_ROOT;
|
||||||
|
XRPL_ASSERT(validSponsorType, "xrpl::adjustOwnerCountSigned : valid sponsor sle type");
|
||||||
|
if (!validSponsorType)
|
||||||
|
return; // LCOV_EXCL_LINE
|
||||||
|
auto const sponsorID = (*sponsorSle)->getAccountID(sfAccount);
|
||||||
|
|
||||||
|
totalOwnerCount.sponsored = detail::adjustOwnerCountImpl(
|
||||||
|
view, this->mutableRawSle(), sfSponsoredOwnerCount, accountID, adjustment, j);
|
||||||
|
|
||||||
|
{
|
||||||
|
OwnerCounts const sponsorCurrent(sponsorSle->rawSle());
|
||||||
|
OwnerCounts sponsorAdjustment(sponsorCurrent);
|
||||||
|
sponsorAdjustment.sponsoring = detail::adjustOwnerCountImpl(
|
||||||
|
view,
|
||||||
|
sponsorSle->mutableRawSle(),
|
||||||
|
sfSponsoringOwnerCount,
|
||||||
|
sponsorID,
|
||||||
|
adjustment,
|
||||||
|
j);
|
||||||
|
view.adjustOwnerCountHook(sponsorID, sponsorCurrent, sponsorAdjustment);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
|
||||||
|
if (sponsorshipSle && adjustment > 0)
|
||||||
|
{
|
||||||
|
// Only decrease the pre-funded ReserveCount on Sponsorship if we assign new
|
||||||
|
// objects. Removing/reassigning ownership of the object doesn't increase
|
||||||
|
// RemainingOwnerCount back. Don't call hook because this counter is not something
|
||||||
|
// that requires reserve (like other sf...OwnerCounts do).
|
||||||
|
detail::adjustOwnerCountImpl(
|
||||||
|
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
totalOwnerCount.owner = detail::adjustOwnerCountImpl(
|
||||||
|
view, this->mutableRawSle(), sfOwnerCount, accountID, adjustment, j);
|
||||||
|
view.adjustOwnerCountHook(accountID, currentOwnerCount, totalOwnerCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(this->exists(), "xrpl::adjustOwnerCountSigned : valid account sle");
|
||||||
|
if (!this->exists())
|
||||||
|
return;
|
||||||
|
// the remaining are only asserts to preserve existing behavior
|
||||||
|
XRPL_ASSERT(!sponsorSle, "xrpl::adjustOwnerCountSigned : sponsor not enabled");
|
||||||
|
XRPL_ASSERT(
|
||||||
|
(*this)->getType() == ltACCOUNT_ROOT,
|
||||||
|
"xrpl::adjustOwnerCountSigned : valid account sle type");
|
||||||
|
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCount : nonzero adjustment input");
|
||||||
|
std::uint32_t const current{(*this)->getFieldU32(sfOwnerCount)};
|
||||||
|
AccountID const id = (**this)[sfAccount];
|
||||||
|
std::uint32_t const adjusted = detail::confineOwnerCount(current, adjustment, id, j);
|
||||||
|
|
||||||
|
OwnerCounts const currentOwnerCount(this->rawSle());
|
||||||
|
OwnerCounts finalOwnerCount(currentOwnerCount);
|
||||||
|
finalOwnerCount.owner = adjusted;
|
||||||
|
|
||||||
|
view.adjustOwnerCountHook(id, currentOwnerCount, finalOwnerCount);
|
||||||
|
(*this)->at(sfOwnerCount) = adjusted;
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
void
|
||||||
|
AccountRootEntry<ViewT>::increaseOwnerCount(
|
||||||
|
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
|
||||||
|
std::uint32_t count)
|
||||||
|
requires Base::kIsWritable
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
|
||||||
|
"xrpl::increaseOwnerCount : count in signed delta range");
|
||||||
|
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
|
||||||
|
return; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
adjustOwnerCountSigned(sponsorSle, static_cast<std::int32_t>(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
void
|
||||||
|
AccountRootEntry<ViewT>::increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
|
||||||
|
requires Base::kIsWritable
|
||||||
|
{
|
||||||
|
auto sponsorExp = getEffectiveTxReserveSponsor(ctx, *this);
|
||||||
|
|
||||||
|
// The sponsor's existence is validated by checkReserve/checkSponsor before
|
||||||
|
// any owner-count mutation, so loading it here cannot fail.
|
||||||
|
XRPL_ASSERT(
|
||||||
|
sponsorExp.has_value(), "xrpl::increaseOwnerCount : sponsor validated before mutation");
|
||||||
|
|
||||||
|
std::optional<AccountRootEntry<ApplyView>> sponsorSle;
|
||||||
|
if (sponsorExp && *sponsorExp)
|
||||||
|
sponsorSle.emplace(std::move(**sponsorExp));
|
||||||
|
|
||||||
|
increaseOwnerCount(sponsorSle, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ViewT>
|
||||||
|
void
|
||||||
|
AccountRootEntry<ViewT>::decreaseOwnerCount(
|
||||||
|
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
|
||||||
|
std::uint32_t count)
|
||||||
|
requires Base::kIsWritable
|
||||||
|
{
|
||||||
|
XRPL_ASSERT(
|
||||||
|
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
|
||||||
|
"xrpl::decreaseOwnerCount : count in signed delta range");
|
||||||
|
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
|
||||||
|
return; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
adjustOwnerCountSigned(sponsorSle, -static_cast<std::int32_t>(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
template class AccountRootEntry<ReadView>;
|
||||||
|
template class AccountRootEntry<ApplyView>;
|
||||||
|
|
||||||
|
} // namespace xrpl
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/Sandbox.h>
|
#include <xrpl/ledger/Sandbox.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
@@ -641,7 +642,7 @@ ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Asset const
|
|||||||
[&](Issue const& issue) {
|
[&](Issue const& issue) {
|
||||||
if (isXRP(issue))
|
if (isXRP(issue))
|
||||||
{
|
{
|
||||||
if (auto const sle = view.read(keylet::account(ammAccountID)))
|
if (auto const sle = AccountRootEntryR(ammAccountID, view))
|
||||||
return (*sle)[sfBalance];
|
return (*sle)[sfBalance];
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
@@ -757,7 +758,7 @@ deleteAMMAccount(Sandbox& sb, Asset const& asset, Asset const& asset2, beast::Jo
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const ammAccountID = (*ammSle)[sfAccount];
|
auto const ammAccountID = (*ammSle)[sfAccount];
|
||||||
auto sleAMMRoot = sb.peek(keylet::account(ammAccountID));
|
auto sleAMMRoot = AccountRootEntryW(ammAccountID, sb);
|
||||||
if (!sleAMMRoot)
|
if (!sleAMMRoot)
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
@@ -795,7 +796,7 @@ deleteAMMAccount(Sandbox& sb, Asset const& asset, Asset const& asset2, beast::Jo
|
|||||||
}
|
}
|
||||||
|
|
||||||
sb.erase(ammSle);
|
sb.erase(ammSle);
|
||||||
sb.erase(sleAMMRoot);
|
sleAMMRoot.erase();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/OwnerCounts.h>
|
#include <xrpl/ledger/OwnerCounts.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -17,7 +18,6 @@
|
|||||||
#include <xrpl/protocol/Rate.h>
|
#include <xrpl/protocol/Rate.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
#include <xrpl/protocol/STLedgerEntry.h>
|
#include <xrpl/protocol/STLedgerEntry.h>
|
||||||
#include <xrpl/protocol/STTx.h>
|
|
||||||
#include <xrpl/protocol/TER.h>
|
#include <xrpl/protocol/TER.h>
|
||||||
#include <xrpl/protocol/XRPAmount.h>
|
#include <xrpl/protocol/XRPAmount.h>
|
||||||
#include <xrpl/protocol/digest.h>
|
#include <xrpl/protocol/digest.h>
|
||||||
@@ -38,25 +38,19 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer)
|
|||||||
{
|
{
|
||||||
if (isXRP(issuer))
|
if (isXRP(issuer))
|
||||||
return false;
|
return false;
|
||||||
if (auto const sle = view.read(keylet::account(issuer)))
|
if (auto const sle = AccountRootEntryR(issuer, view))
|
||||||
return sle->isFlag(lsfGlobalFreeze);
|
return sle->isFlag(lsfGlobalFreeze);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace detail {
|
||||||
|
|
||||||
// An owner count cannot be negative. If adjustment would cause a negative
|
|
||||||
// owner count, clamp the owner count at 0. Similarly for overflow. This
|
|
||||||
// adjustment allows the ownerCount to be adjusted up or down in multiple steps.
|
|
||||||
// If id != std::nullopt, then do error reporting.
|
|
||||||
//
|
|
||||||
// Returns adjusted owner count.
|
|
||||||
std::uint32_t
|
std::uint32_t
|
||||||
confineOwnerCount(
|
confineOwnerCount(
|
||||||
std::uint32_t currentOwnerCount,
|
std::uint32_t currentOwnerCount,
|
||||||
std::int32_t ownerCountAdj,
|
std::int32_t ownerCountAdj,
|
||||||
std::optional<AccountID> const& id = std::nullopt,
|
std::optional<AccountID> const& id,
|
||||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
beast::Journal j)
|
||||||
{
|
{
|
||||||
std::uint32_t totalOwnerCount{currentOwnerCount + ownerCountAdj};
|
std::uint32_t totalOwnerCount{currentOwnerCount + ownerCountAdj};
|
||||||
if (ownerCountAdj > 0)
|
if (ownerCountAdj > 0)
|
||||||
@@ -91,10 +85,8 @@ confineOwnerCount(
|
|||||||
return totalOwnerCount;
|
return totalOwnerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of account reserves funded by this account: 1 for itself (0 if sponsored by
|
|
||||||
// another account) plus the count of accounts it sponsors.
|
|
||||||
std::uint32_t
|
std::uint32_t
|
||||||
accountCountImpl(SLE::ConstRef sle, std::int32_t accountCountAdj, beast::Journal j)
|
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j)
|
||||||
{
|
{
|
||||||
bool const isSponsored = sle->isFieldPresent(sfSponsor);
|
bool const isSponsored = sle->isFieldPresent(sfSponsor);
|
||||||
std::int64_t const sponsoringAccountCount = sle->getFieldU32(sfSponsoringAccountCount);
|
std::int64_t const sponsoringAccountCount = sle->getFieldU32(sfSponsoringAccountCount);
|
||||||
@@ -131,151 +123,25 @@ adjustOwnerCountImpl(
|
|||||||
{
|
{
|
||||||
std::uint32_t const currentOwnerCount = sle->at(sfield);
|
std::uint32_t const currentOwnerCount = sle->at(sfield);
|
||||||
std::uint32_t const totalOwnerCount =
|
std::uint32_t const totalOwnerCount =
|
||||||
confineOwnerCount(currentOwnerCount, ownerCountAdj, accID, j);
|
detail::confineOwnerCount(currentOwnerCount, ownerCountAdj, accID, j);
|
||||||
sle->at(sfield) = totalOwnerCount;
|
sle->at(sfield) = totalOwnerCount;
|
||||||
view.update(sle);
|
view.update(sle);
|
||||||
return totalOwnerCount;
|
return totalOwnerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
} // namespace detail
|
||||||
adjustOwnerCountSigned(
|
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref accountSle,
|
|
||||||
SLE::Ref sponsorSle,
|
|
||||||
std::int32_t adjustment,
|
|
||||||
beast::Journal j)
|
|
||||||
{
|
|
||||||
if (view.rules().enabled(featureSponsor))
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(accountSle, "xrpl::adjustOwnerCountSigned : valid account sle");
|
|
||||||
if (!accountSle)
|
|
||||||
return; // LCOV_EXCL_LINE
|
|
||||||
|
|
||||||
auto const accountID = accountSle->getAccountID(sfAccount);
|
|
||||||
bool const validType = accountSle->getType() == ltACCOUNT_ROOT;
|
|
||||||
XRPL_ASSERT(validType, "xrpl::adjustOwnerCountSigned : valid account sle type");
|
|
||||||
if (!validType)
|
|
||||||
return; // LCOV_EXCL_LINE
|
|
||||||
|
|
||||||
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCountSigned : nonzero adjustment input");
|
|
||||||
|
|
||||||
OwnerCounts const currentOwnerCount(accountSle);
|
|
||||||
OwnerCounts totalOwnerCount(currentOwnerCount);
|
|
||||||
|
|
||||||
if (sponsorSle)
|
|
||||||
{
|
|
||||||
bool const validSponsorType = sponsorSle->getType() == ltACCOUNT_ROOT;
|
|
||||||
XRPL_ASSERT(validSponsorType, "xrpl::adjustOwnerCountSigned : valid sponsor sle type");
|
|
||||||
if (!validSponsorType)
|
|
||||||
return; // LCOV_EXCL_LINE
|
|
||||||
auto const sponsorID = sponsorSle->getAccountID(sfAccount);
|
|
||||||
|
|
||||||
totalOwnerCount.sponsored = adjustOwnerCountImpl(
|
|
||||||
view, accountSle, sfSponsoredOwnerCount, accountID, adjustment, j);
|
|
||||||
|
|
||||||
{
|
|
||||||
OwnerCounts const sponsorCurrent(sponsorSle);
|
|
||||||
OwnerCounts sponsorAdjustment(sponsorCurrent);
|
|
||||||
sponsorAdjustment.sponsoring = adjustOwnerCountImpl(
|
|
||||||
view, sponsorSle, sfSponsoringOwnerCount, sponsorID, adjustment, j);
|
|
||||||
view.adjustOwnerCountHook(sponsorID, sponsorCurrent, sponsorAdjustment);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sponsorshipSle = view.peek(keylet::sponsorship(sponsorID, accountID));
|
|
||||||
if (sponsorshipSle && adjustment > 0)
|
|
||||||
{
|
|
||||||
// Only decrease the pre-funded ReserveCount on Sponsorship if we assign new
|
|
||||||
// objects. Removing/reassigning ownership of the object doesn't increase
|
|
||||||
// RemainingOwnerCount back. Don't call hook because this counter is not something
|
|
||||||
// that requires reserve (like other sf...OwnerCounts do).
|
|
||||||
adjustOwnerCountImpl(
|
|
||||||
view, sponsorshipSle, sfRemainingOwnerCount, sponsorID, -adjustment, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalOwnerCount.owner =
|
|
||||||
adjustOwnerCountImpl(view, accountSle, sfOwnerCount, accountID, adjustment, j);
|
|
||||||
view.adjustOwnerCountHook(accountID, currentOwnerCount, totalOwnerCount);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(accountSle, "xrpl::adjustOwnerCountSigned : valid account sle");
|
|
||||||
if (!accountSle)
|
|
||||||
return;
|
|
||||||
// the remaining are only asserts to preserve existing behavior
|
|
||||||
XRPL_ASSERT(sponsorSle == nullptr, "xrpl::adjustOwnerCountSigned : sponsor not enabled");
|
|
||||||
XRPL_ASSERT(
|
|
||||||
accountSle->getType() == ltACCOUNT_ROOT,
|
|
||||||
"xrpl::adjustOwnerCountSigned : valid account sle type");
|
|
||||||
XRPL_ASSERT(adjustment, "xrpl::adjustOwnerCount : nonzero adjustment input");
|
|
||||||
std::uint32_t const current{accountSle->getFieldU32(sfOwnerCount)};
|
|
||||||
AccountID const id = (*accountSle)[sfAccount];
|
|
||||||
std::uint32_t const adjusted = confineOwnerCount(current, adjustment, id, j);
|
|
||||||
|
|
||||||
OwnerCounts const currentOwnerCount(accountSle);
|
|
||||||
OwnerCounts finalOwnerCount(currentOwnerCount);
|
|
||||||
finalOwnerCount.owner = adjusted;
|
|
||||||
|
|
||||||
view.adjustOwnerCountHook(id, currentOwnerCount, finalOwnerCount);
|
|
||||||
accountSle->at(sfOwnerCount) = adjusted;
|
|
||||||
view.update(accountSle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
std::uint32_t
|
|
||||||
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj)
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::ownerCount : sle is account root");
|
|
||||||
|
|
||||||
AccountID const id = sle->getAccountID(sfAccount);
|
|
||||||
std::uint32_t const currentOwnerCount = sle->at(sfOwnerCount);
|
|
||||||
std::uint32_t const sponsoredOwnerCount = sle->at(sfSponsoredOwnerCount);
|
|
||||||
std::uint32_t const sponsoringOwnerCount = sle->at(sfSponsoringOwnerCount);
|
|
||||||
|
|
||||||
XRPL_ASSERT(
|
|
||||||
currentOwnerCount >= sponsoredOwnerCount,
|
|
||||||
"xrpl::ownerCount : OwnerCount must be greater than or equal to SponsoredOwnerCount");
|
|
||||||
|
|
||||||
std::int64_t deltaCount =
|
|
||||||
static_cast<std::int64_t>(ownerCountAdj) - sponsoredOwnerCount + sponsoringOwnerCount;
|
|
||||||
|
|
||||||
if (deltaCount > std::numeric_limits<std::int32_t>::max())
|
|
||||||
{
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
deltaCount = std::numeric_limits<std::int32_t>::max();
|
|
||||||
JLOG(j.fatal()) << "Account " << id << " delta count exceeds max, "
|
|
||||||
<< "adjustment: " << ownerCountAdj
|
|
||||||
<< ", sponsoredCount: " << sponsoredOwnerCount
|
|
||||||
<< ", sponsoringOwnerCount: " << sponsoringOwnerCount;
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
}
|
|
||||||
else if (deltaCount < std::numeric_limits<std::int32_t>::min())
|
|
||||||
{
|
|
||||||
// LCOV_EXCL_START
|
|
||||||
deltaCount = std::numeric_limits<std::int32_t>::min();
|
|
||||||
JLOG(j.fatal()) << "Account " << id << " delta count is below min, "
|
|
||||||
<< "adjustment: " << ownerCountAdj
|
|
||||||
<< ", sponsoredCount: " << sponsoredOwnerCount
|
|
||||||
<< ", sponsoringCount: " << sponsoringOwnerCount;
|
|
||||||
// LCOV_EXCL_STOP
|
|
||||||
}
|
|
||||||
|
|
||||||
return confineOwnerCount(currentOwnerCount, deltaCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
XRPAmount
|
XRPAmount
|
||||||
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j)
|
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j)
|
||||||
{
|
{
|
||||||
auto const sle = view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, view);
|
||||||
if (sle == nullptr)
|
if (!sle.exists())
|
||||||
return beast::kZero;
|
return beast::kZero;
|
||||||
|
|
||||||
// Return balance minus reserve
|
// Return balance minus reserve
|
||||||
std::uint32_t const currentOwnerCount =
|
std::uint32_t const currentOwnerCount = detail::confineOwnerCount(
|
||||||
confineOwnerCount(view.ownerCountHook(id, OwnerCounts(sle)).count(), ownerCountAdj);
|
view.ownerCountHook(id, OwnerCounts(sle.rawSle())).count(), ownerCountAdj);
|
||||||
std::uint32_t const currentAccountCount = accountCountImpl(sle, 0, j);
|
std::uint32_t const currentAccountCount = detail::accountCountImpl(sle, 0, j);
|
||||||
|
|
||||||
// Pseudo-accounts have no reserve requirement
|
// Pseudo-accounts have no reserve requirement
|
||||||
auto const reserve = isPseudoAccount(sle)
|
auto const reserve = isPseudoAccount(sle)
|
||||||
@@ -300,7 +166,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
|
|||||||
Rate
|
Rate
|
||||||
transferRate(ReadView const& view, AccountID const& issuer)
|
transferRate(ReadView const& view, AccountID const& issuer)
|
||||||
{
|
{
|
||||||
auto const sle = view.read(keylet::account(issuer));
|
auto const sle = AccountRootEntryR(issuer, view);
|
||||||
|
|
||||||
if (sle && sle->isFieldPresent(sfTransferRate))
|
if (sle && sle->isFieldPresent(sfTransferRate))
|
||||||
return Rate{sle->getFieldU32(sfTransferRate)};
|
return Rate{sle->getFieldU32(sfTransferRate)};
|
||||||
@@ -308,57 +174,10 @@ transferRate(ReadView const& view, AccountID const& issuer)
|
|||||||
return kParityRate;
|
return kParityRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
increaseOwnerCount(
|
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref accountSle,
|
|
||||||
SLE::Ref sponsorSle,
|
|
||||||
std::uint32_t count,
|
|
||||||
beast::Journal j)
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(
|
|
||||||
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
|
|
||||||
"xrpl::increaseOwnerCount : count in signed delta range");
|
|
||||||
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
|
|
||||||
return; // LCOV_EXCL_LINE
|
|
||||||
|
|
||||||
adjustOwnerCountSigned(view, accountSle, sponsorSle, static_cast<std::int32_t>(count), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
increaseOwnerCount(ApplyViewContext ctx, SLE::Ref accountSle, std::uint32_t count, beast::Journal j)
|
|
||||||
{
|
|
||||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, accountSle);
|
|
||||||
|
|
||||||
// The sponsor's existence is validated by checkReserve/checkSponsor before
|
|
||||||
// any owner-count mutation, so loading it here cannot fail.
|
|
||||||
XRPL_ASSERT(
|
|
||||||
sponsorExp.has_value(), "xrpl::increaseOwnerCount : sponsor validated before mutation");
|
|
||||||
|
|
||||||
increaseOwnerCount(ctx.view, accountSle, sponsorExp ? *sponsorExp : SLE::pointer(), count, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
decreaseOwnerCount(
|
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref accountSle,
|
|
||||||
SLE::Ref sponsorSle,
|
|
||||||
std::uint32_t count,
|
|
||||||
beast::Journal j)
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(
|
|
||||||
count != 0 && count <= std::numeric_limits<std::int32_t>::max(),
|
|
||||||
"xrpl::decreaseOwnerCount : count in signed delta range");
|
|
||||||
if (count == 0 || count > std::numeric_limits<std::int32_t>::max())
|
|
||||||
return; // LCOV_EXCL_LINE
|
|
||||||
|
|
||||||
adjustOwnerCountSigned(view, accountSle, sponsorSle, -static_cast<std::int32_t>(count), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
decreaseOwnerCountForObject(
|
decreaseOwnerCountForObject(
|
||||||
ApplyView& view,
|
ApplyView& view,
|
||||||
SLE::Ref accountSle,
|
AccountRootEntryW& accountSle,
|
||||||
SLE::Ref objectSle,
|
SLE::Ref objectSle,
|
||||||
std::uint32_t count,
|
std::uint32_t count,
|
||||||
beast::Journal j)
|
beast::Journal j)
|
||||||
@@ -372,8 +191,8 @@ decreaseOwnerCountForObject(
|
|||||||
if (!validObjectType)
|
if (!validObjectType)
|
||||||
return; // LCOV_EXCL_LINE
|
return; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
SLE::Ref sponsorSle = getLedgerEntryReserveSponsor(view, objectSle);
|
auto sponsorSle = getLedgerEntryReserveSponsor(view, objectSle);
|
||||||
decreaseOwnerCount(view, accountSle, sponsorSle, count, j);
|
accountSle.decreaseOwnerCount(sponsorSle, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -393,107 +212,10 @@ adjustLoanBrokerOwnerCount(
|
|||||||
if (delta == 0)
|
if (delta == 0)
|
||||||
return; // LCOV_EXCL_LINE
|
return; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
adjustOwnerCountImpl(
|
detail::adjustOwnerCountImpl(
|
||||||
view, brokerSle, sfOwnerCount, brokerSle->getAccountID(sfAccount), delta, j);
|
view, brokerSle, sfOwnerCount, brokerSle->getAccountID(sfAccount), delta, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
XRPAmount
|
|
||||||
accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj)
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(sle && sle->getType() == ltACCOUNT_ROOT, "xrpl::accountReserve : valid sle");
|
|
||||||
|
|
||||||
if (!view.rules().enabled(featureSponsor))
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::accountReserve : no account count delta");
|
|
||||||
return view.fees().accountReserve(sle->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
|
|
||||||
}
|
|
||||||
std::uint32_t const currentOwnerCount = ownerCount(sle, j, adj.ownerCountDelta);
|
|
||||||
std::uint32_t const currentAccountCount = accountCountImpl(sle, adj.accountCountDelta, j);
|
|
||||||
|
|
||||||
return view.fees().accountReserve(currentOwnerCount, currentAccountCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
TER
|
|
||||||
checkReserve(
|
|
||||||
ApplyViewContext ctx,
|
|
||||||
SLE::ConstRef accSle,
|
|
||||||
XRPAmount accBalance,
|
|
||||||
SLE::ConstRef sponsorSle,
|
|
||||||
Adjustment adj,
|
|
||||||
beast::Journal j,
|
|
||||||
TER insufReserveCode)
|
|
||||||
{
|
|
||||||
// TODO: swap to assert after fixCleanup3_2_0 is retired
|
|
||||||
if (!accSle || accSle->getType() != ltACCOUNT_ROOT)
|
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
|
||||||
XRPL_ASSERT(
|
|
||||||
!isTesSuccess(insufReserveCode), "xrpl::checkReserve : insufReserveCode is not tesSUCCESS");
|
|
||||||
if (ctx.view.rules().enabled(featureSponsor))
|
|
||||||
{
|
|
||||||
if (sponsorSle)
|
|
||||||
{
|
|
||||||
if (sponsorSle->getType() != ltACCOUNT_ROOT)
|
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
|
||||||
|
|
||||||
auto const sle = ctx.view.read(
|
|
||||||
keylet::sponsorship(
|
|
||||||
sponsorSle->getAccountID(sfAccount), accSle->getAccountID(sfAccount)));
|
|
||||||
|
|
||||||
// A reserve-sponsored tx must carry a sponsor signature
|
|
||||||
// (cosigning path) and/or have a pre-existing sponsorship SLE
|
|
||||||
// (prefunded path). Absence of both is an internal invariant break.
|
|
||||||
if (isReserveSponsored(ctx.tx) && !sle && !ctx.tx.isFieldPresent(sfSponsorSignature))
|
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
|
||||||
|
|
||||||
if (sle)
|
|
||||||
{
|
|
||||||
auto const ownerCountAllowed = sle->getFieldU32(sfRemainingOwnerCount);
|
|
||||||
if (adj.ownerCountDelta > 0 &&
|
|
||||||
ownerCountAllowed < static_cast<std::uint32_t>(adj.ownerCountDelta))
|
|
||||||
return insufReserveCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const sponsorBalance = sponsorSle->getFieldAmount(sfBalance).xrp();
|
|
||||||
XRPAmount const sponsorReserve = accountReserve(ctx.view, sponsorSle, j, adj);
|
|
||||||
|
|
||||||
if (sponsorBalance < sponsorReserve)
|
|
||||||
return insufReserveCode;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XRPAmount const reserve = accountReserve(ctx.view, accSle, j, adj);
|
|
||||||
if (accBalance < reserve)
|
|
||||||
return insufReserveCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
XRPL_ASSERT(
|
|
||||||
!sponsorSle,
|
|
||||||
"xrpl::checkReserve : featureSponsor disabled and sponsorSle not provided");
|
|
||||||
XRPL_ASSERT(adj.accountCountDelta == 0, "xrpl::checkReserve : accountCountDelta is 0");
|
|
||||||
auto const reserve = ctx.view.fees().accountReserve(
|
|
||||||
accSle->getFieldU32(sfOwnerCount) + adj.ownerCountDelta, 1);
|
|
||||||
if (accBalance < reserve)
|
|
||||||
return insufReserveCode;
|
|
||||||
}
|
|
||||||
return tesSUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
TER
|
|
||||||
checkReserve(
|
|
||||||
ApplyViewContext ctx,
|
|
||||||
SLE::ConstRef accSle,
|
|
||||||
XRPAmount accBalance,
|
|
||||||
Adjustment adj,
|
|
||||||
beast::Journal j)
|
|
||||||
{
|
|
||||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, accSle);
|
|
||||||
if (!sponsorExp)
|
|
||||||
return sponsorExp.error(); // LCOV_EXCL_LINE
|
|
||||||
return checkReserve(ctx, accSle, accBalance, *sponsorExp, adj, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
AccountID
|
AccountID
|
||||||
@@ -507,7 +229,7 @@ pseudoAccountAddress(ReadView const& view, UInt256 const& pseudoOwnerKey)
|
|||||||
auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey);
|
auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey);
|
||||||
rsh(hash.data(), hash.size());
|
rsh(hash.data(), hash.size());
|
||||||
AccountID const ret = AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
|
AccountID const ret = AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
|
||||||
if (!view.read(keylet::account(ret)))
|
if (!AccountRootEntryR(ret, view).exists())
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return beast::kZero;
|
return beast::kZero;
|
||||||
@@ -546,7 +268,7 @@ getPseudoAccountFields()
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool
|
[[nodiscard]] bool
|
||||||
isPseudoAccount(SLE::const_pointer sleAcct)
|
isPseudoAccount(AccountRootEntryR const& sleAcct)
|
||||||
{
|
{
|
||||||
// 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.
|
||||||
@@ -599,9 +321,9 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] TER
|
[[nodiscard]] TER
|
||||||
checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag)
|
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag)
|
||||||
{
|
{
|
||||||
if (toSle == nullptr)
|
if (!toSle.exists())
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
// The tag is basically account-specific information we don't
|
// The tag is basically account-specific information we don't
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -81,7 +82,7 @@ deleteSLE(ApplyView& view, SLE::Ref sleCredential, beast::Journal j)
|
|||||||
|
|
||||||
auto delSLE = [&view, &sleCredential, j](
|
auto delSLE = [&view, &sleCredential, j](
|
||||||
AccountID const& account, SField const& node, bool isOwner) -> TER {
|
AccountID const& account, SField const& node, bool isOwner) -> TER {
|
||||||
auto const sleAccount = view.peek(keylet::account(account));
|
auto sleAccount = AccountRootEntryW(account, view);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
@@ -206,7 +207,7 @@ authorizeMPToken(
|
|||||||
std::uint32_t flags,
|
std::uint32_t flags,
|
||||||
std::optional<AccountID> holderID)
|
std::optional<AccountID> holderID)
|
||||||
{
|
{
|
||||||
auto const sleAcct = ctx.view.peek(keylet::account(account));
|
auto sleAcct = AccountRootEntryW(account, ctx.view, journal);
|
||||||
if (!sleAcct)
|
if (!sleAcct)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -242,10 +243,10 @@ authorizeMPToken(
|
|||||||
// - create the MPToken object for the holder
|
// - create the MPToken object for the holder
|
||||||
|
|
||||||
// A reserve sponsor only covers tx.Account's own objects.
|
// A reserve sponsor only covers tx.Account's own objects.
|
||||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, sleAcct);
|
auto sponsorExp = getEffectiveTxReserveSponsor(ctx, sleAcct);
|
||||||
if (!sponsorExp)
|
if (!sponsorExp)
|
||||||
return sponsorExp.error(); // LCOV_EXCL_LINE
|
return sponsorExp.error(); // LCOV_EXCL_LINE
|
||||||
auto const sponsorSle = *sponsorExp;
|
auto& sponsorSle = *sponsorExp;
|
||||||
|
|
||||||
// The reserve that is required to create the MPToken. Note
|
// The reserve that is required to create the MPToken. Note
|
||||||
// that although the reserve increases with every item
|
// that although the reserve increases with every item
|
||||||
@@ -255,10 +256,10 @@ authorizeMPToken(
|
|||||||
// The "free-tier" shortcut (ownerCount < 2) does not apply once a sponsor is on
|
// The "free-tier" shortcut (ownerCount < 2) does not apply once a sponsor is on
|
||||||
// the tx — the sponsor must always cover the reserve (via balance or prefunded
|
// the tx — the sponsor must always cover the reserve (via balance or prefunded
|
||||||
// budget), so this check always runs for sponsored transactions.
|
// budget), so this check always runs for sponsored transactions.
|
||||||
if (sponsorSle || ownerCount(sleAcct, journal) >= 2)
|
if (sponsorSle || sleAcct.ownerCount() >= 2)
|
||||||
{
|
{
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret =
|
||||||
ctx, sleAcct, priorBalance, sponsorSle, {.ownerCountDelta = 1}, journal);
|
sleAcct.checkReserve(ctx, priorBalance, sponsorSle, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -285,8 +286,8 @@ authorizeMPToken(
|
|||||||
ctx.view.insert(mptoken);
|
ctx.view.insert(mptoken);
|
||||||
|
|
||||||
// Update owner count.
|
// Update owner count.
|
||||||
increaseOwnerCount(ctx.view, sleAcct, sponsorSle, 1, journal);
|
sleAcct.increaseOwnerCount(sponsorSle, 1);
|
||||||
addSponsorToLedgerEntry(mptoken, sponsorSle);
|
addSponsorToLedgerEntry(mptoken, sponsorSle ? sponsorSle->rawSle() : SLE::const_pointer{});
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
@@ -415,7 +416,7 @@ requireAuth(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// requireAuth is recursive if the issuer is a vault pseudo-account
|
// requireAuth is recursive if the issuer is a vault pseudo-account
|
||||||
auto const sleIssuer = view.read(keylet::account(mptIssuer));
|
auto const sleIssuer = AccountRootEntryR(mptIssuer, view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -1020,13 +1021,16 @@ checkCreateMPT(
|
|||||||
{
|
{
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
auto const sleAcct = view.peek(keylet::account(holder));
|
auto sleAcct = AccountRootEntryW(holder, view, j);
|
||||||
if (!sleAcct)
|
if (!sleAcct)
|
||||||
{
|
{
|
||||||
return tecINTERNAL;
|
return tecINTERNAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
increaseOwnerCount(view, sleAcct, sponsorSle, 1, j);
|
std::optional<AccountRootEntryW> sponsorAccSle;
|
||||||
|
if (sponsorSle)
|
||||||
|
sponsorAccSle.emplace(sponsorSle->getAccountID(sfAccount), view);
|
||||||
|
sleAcct.increaseOwnerCount(sponsorAccSle, 1);
|
||||||
}
|
}
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -394,9 +396,11 @@ removeToken(ApplyView& view, AccountID const& owner, UInt256 const& nftokenID, S
|
|||||||
|
|
||||||
if (!page2)
|
if (!page2)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"page " + to_string(page1->key()) + " has a broken " + field.getName() +
|
"page {} has a broken {} field pointing to {}",
|
||||||
" field pointing to " + to_string(*id));
|
to_string(page1->key()),
|
||||||
|
field.getName(),
|
||||||
|
to_string(*id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,7 +601,7 @@ removeTokenOffersWithLimit(ApplyView& view, Keylet const& directory, std::size_t
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
"Offer " + to_string(offerIndexes[i]) + " cannot be deleted!");
|
std::format("Offer {} cannot be deleted!", to_string(offerIndexes[i])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,9 +738,9 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner)
|
|||||||
if (!newPrev)
|
if (!newPrev)
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"NFTokenPage directory for " + to_string(owner) +
|
"NFTokenPage directory for {} cannot be repaired. Unexpected link problem.",
|
||||||
" cannot be repaired. Unexpected link problem.");
|
to_string(owner)));
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
newPrev->at(sfNextPageMin) = nextPage->key();
|
newPrev->at(sfNextPageMin) = nextPage->key();
|
||||||
@@ -852,7 +856,7 @@ tokenOfferCreatePreclaim(
|
|||||||
|
|
||||||
if (nftIssuer != acctID && ((nftFlags & nft::kFlagTransferable) == 0))
|
if (nftIssuer != acctID && ((nftFlags & nft::kFlagTransferable) == 0))
|
||||||
{
|
{
|
||||||
auto const root = view.read(keylet::account(nftIssuer));
|
auto const root = AccountRootEntryR(nftIssuer, view);
|
||||||
XRPL_ASSERT(root, "xrpl::nft::tokenOfferCreatePreclaim : non-null account");
|
XRPL_ASSERT(root, "xrpl::nft::tokenOfferCreatePreclaim : non-null account");
|
||||||
|
|
||||||
if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID)
|
if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID)
|
||||||
@@ -883,7 +887,7 @@ tokenOfferCreatePreclaim(
|
|||||||
{
|
{
|
||||||
// If a destination is specified, the destination must already be in
|
// If a destination is specified, the destination must already be in
|
||||||
// the ledger.
|
// the ledger.
|
||||||
auto const sleDst = view.read(keylet::account(*dest));
|
auto const sleDst = AccountRootEntryR(*dest, view);
|
||||||
|
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
@@ -895,7 +899,7 @@ tokenOfferCreatePreclaim(
|
|||||||
|
|
||||||
if (owner)
|
if (owner)
|
||||||
{
|
{
|
||||||
auto const sleOwner = view.read(keylet::account(*owner));
|
auto const sleOwner = AccountRootEntryR(*owner, view);
|
||||||
|
|
||||||
// defensively check
|
// defensively check
|
||||||
// it should not be possible to specify owner that doesn't exist
|
// it should not be possible to specify owner that doesn't exist
|
||||||
@@ -934,9 +938,8 @@ tokenOfferCreateApply(
|
|||||||
beast::Journal j,
|
beast::Journal j,
|
||||||
std::uint32_t txFlags)
|
std::uint32_t txFlags)
|
||||||
{
|
{
|
||||||
Keylet const acctKeylet = keylet::account(acctID);
|
if (auto const acct = AccountRootEntryW(acctID, view, j);
|
||||||
if (auto const acct = view.read(acctKeylet);
|
priorBalance < acct.reserve({.ownerCountDelta = 1}))
|
||||||
priorBalance < accountReserve(view, acct, j, {.ownerCountDelta = 1}))
|
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
|
|
||||||
auto const offerID = keylet::nftokenOffer(acctID, seqProxy);
|
auto const offerID = keylet::nftokenOffer(acctID, seqProxy);
|
||||||
@@ -1005,7 +1008,7 @@ checkTrustlineAuthorized(
|
|||||||
|
|
||||||
if (view.rules().enabled(fixEnforceNFTokenTrustlineV2))
|
if (view.rules().enabled(fixEnforceNFTokenTrustlineV2))
|
||||||
{
|
{
|
||||||
auto const issuerAccount = view.read(keylet::account(issue.account));
|
auto const issuerAccount = AccountRootEntryR(issue.account, view);
|
||||||
if (!issuerAccount)
|
if (!issuerAccount)
|
||||||
{
|
{
|
||||||
JLOG(j.debug()) << "xrpl::nft::checkTrustlineAuthorized: can't "
|
JLOG(j.debug()) << "xrpl::nft::checkTrustlineAuthorized: can't "
|
||||||
@@ -1057,7 +1060,7 @@ checkTrustlineDeepFrozen(
|
|||||||
|
|
||||||
if (view.rules().enabled(featureDeepFreeze))
|
if (view.rules().enabled(featureDeepFreeze))
|
||||||
{
|
{
|
||||||
auto const issuerAccount = view.read(keylet::account(issue.account));
|
auto const issuerAccount = AccountRootEntryR(issue.account, view);
|
||||||
if (!issuerAccount)
|
if (!issuerAccount)
|
||||||
{
|
{
|
||||||
JLOG(j.debug()) << "xrpl::nft::checkTrustlineDeepFrozen: can't "
|
JLOG(j.debug()) << "xrpl::nft::checkTrustlineDeepFrozen: can't "
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -51,7 +52,7 @@ closeChannel(SLE::Ref slep, ApplyView& view, UInt256 const& key, beast::Journal
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transfer amount back to owner, decrement owner count
|
// Transfer amount back to owner, decrement owner count
|
||||||
auto const sle = view.peek(keylet::account(src));
|
auto sle = AccountRootEntryW(src, view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ closeChannel(SLE::Ref slep, ApplyView& view, UInt256 const& key, beast::Journal
|
|||||||
(*slep)[sfAmount] >= (*slep)[sfBalance], "xrpl::closeChannel : minimum channel amount");
|
(*slep)[sfAmount] >= (*slep)[sfBalance], "xrpl::closeChannel : minimum channel amount");
|
||||||
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
|
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
|
||||||
decreaseOwnerCountForObject(view, sle, slep, 1, j);
|
decreaseOwnerCountForObject(view, sle, slep, 1, j);
|
||||||
view.update(sle);
|
sle.update();
|
||||||
|
|
||||||
// Remove PayChan from ledger
|
// Remove PayChan from ledger
|
||||||
view.erase(slep);
|
view.erase(slep);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -133,14 +134,14 @@ isFrozen(
|
|||||||
{
|
{
|
||||||
if (isXRP(currency))
|
if (isXRP(currency))
|
||||||
return false;
|
return false;
|
||||||
auto sle = view.read(keylet::account(issuer));
|
auto const sleIssuer = AccountRootEntryR(issuer, view);
|
||||||
if (sle && sle->isFlag(lsfGlobalFreeze))
|
if (sleIssuer && sleIssuer->isFlag(lsfGlobalFreeze))
|
||||||
return true;
|
return true;
|
||||||
if (issuer != account)
|
if (issuer != account)
|
||||||
{
|
{
|
||||||
// Check if the issuer froze the line
|
// Check if the issuer froze the line
|
||||||
sle = view.read(keylet::trustLine(account, issuer, currency));
|
auto const sleLine = view.read(keylet::trustLine(account, issuer, currency));
|
||||||
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
|
if (sleLine && sleLine->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -238,7 +239,7 @@ trustCreate(
|
|||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
|
sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
|
||||||
"xrpl::trustCreate : matching account ID");
|
"xrpl::trustCreate : matching account ID");
|
||||||
auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
|
auto const slePeer = AccountRootEntryW(bSetHigh ? uLowAccountID : uHighAccountID, view);
|
||||||
if (!slePeer)
|
if (!slePeer)
|
||||||
return tecNO_TARGET;
|
return tecNO_TARGET;
|
||||||
|
|
||||||
@@ -283,7 +284,11 @@ trustCreate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sleRippleState->setFieldU32(sfFlags, uFlags);
|
sleRippleState->setFieldU32(sfFlags, uFlags);
|
||||||
increaseOwnerCount(view, sleAccount, sponsorSle, 1, j);
|
AccountRootEntryW accountSle(bSetHigh ? uHighAccountID : uLowAccountID, view, j);
|
||||||
|
std::optional<AccountRootEntryW> sponsorAccSle;
|
||||||
|
if (sponsorSle)
|
||||||
|
sponsorAccSle.emplace(sponsorSle->getAccountID(sfAccount), view);
|
||||||
|
accountSle.increaseOwnerCount(sponsorAccSle, 1);
|
||||||
|
|
||||||
addSponsorToLedgerEntry(sleRippleState, sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
|
addSponsorToLedgerEntry(sleRippleState, sponsorSle, bSetHigh ? sfHighSponsor : sfLowSponsor);
|
||||||
|
|
||||||
@@ -349,7 +354,7 @@ updateTrustLine(
|
|||||||
if (!state)
|
if (!state)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto sle = view.peek(keylet::account(sender));
|
auto sle = AccountRootEntryW(sender, view, j);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -376,9 +381,9 @@ updateTrustLine(
|
|||||||
{
|
{
|
||||||
// VFALCO Where is the line being deleted?
|
// VFALCO Where is the line being deleted?
|
||||||
// Clear the reserve of the sender, possibly delete the line!
|
// Clear the reserve of the sender, possibly delete the line!
|
||||||
auto const currentSponsor =
|
auto currentSponsor =
|
||||||
getLedgerEntryReserveSponsor(view, state, bSenderHigh ? sfHighSponsor : sfLowSponsor);
|
getLedgerEntryReserveSponsor(view, state, bSenderHigh ? sfHighSponsor : sfLowSponsor);
|
||||||
decreaseOwnerCount(view, sle, currentSponsor, 1, j);
|
sle.decreaseOwnerCount(currentSponsor, 1);
|
||||||
|
|
||||||
// Clear reserve flag.
|
// Clear reserve flag.
|
||||||
state->clearFlag(senderReserveFlag);
|
state->clearFlag(senderReserveFlag);
|
||||||
@@ -464,7 +469,7 @@ issueIOU(
|
|||||||
|
|
||||||
finalBalance.get<Issue>().account = noAccount();
|
finalBalance.get<Issue>().account = noAccount();
|
||||||
|
|
||||||
auto const receiverAccount = view.peek(keylet::account(account));
|
auto receiverAccount = AccountRootEntryW(account, view);
|
||||||
if (!receiverAccount)
|
if (!receiverAccount)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -476,7 +481,7 @@ issueIOU(
|
|||||||
issue.account,
|
issue.account,
|
||||||
account,
|
account,
|
||||||
index.key,
|
index.key,
|
||||||
receiverAccount,
|
receiverAccount.mutableRawSle(),
|
||||||
false,
|
false,
|
||||||
noRipple,
|
noRipple,
|
||||||
false,
|
false,
|
||||||
@@ -579,7 +584,7 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
|
|||||||
|
|
||||||
// If this is a weak or legacy check, or if the account has a line, fail if
|
// If this is a weak or legacy check, or if the account has a line, fail if
|
||||||
// auth is required and not set on the line
|
// auth is required and not set on the line
|
||||||
if (auto const issuerAccount = view.read(keylet::account(issue.account));
|
if (auto const issuerAccount = AccountRootEntryR(issue.account, view);
|
||||||
issuerAccount && issuerAccount->isFlag(lsfRequireAuth))
|
issuerAccount && issuerAccount->isFlag(lsfRequireAuth))
|
||||||
{
|
{
|
||||||
if (trustLine)
|
if (trustLine)
|
||||||
@@ -609,8 +614,8 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
|
|||||||
auto const& issuerId = issue.getIssuer();
|
auto const& issuerId = issue.getIssuer();
|
||||||
if (issuerId == from || issuerId == to)
|
if (issuerId == from || issuerId == to)
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
auto const sleIssuer = view.read(keylet::account(issuerId));
|
auto const sleIssuer = AccountRootEntryR(issuerId, view);
|
||||||
if (sleIssuer == nullptr)
|
if (!sleIssuer.exists())
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const isRippleDisabled = [&](AccountID account) -> bool {
|
auto const isRippleDisabled = [&](AccountID account) -> bool {
|
||||||
@@ -665,8 +670,8 @@ addEmptyHolding(
|
|||||||
if (isGlobalFrozen(ctx.view, issuerId))
|
if (isGlobalFrozen(ctx.view, issuerId))
|
||||||
return tecFROZEN; // LCOV_EXCL_LINE
|
return tecFROZEN; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const sleSrc = ctx.view.peek(keylet::account(srcId));
|
auto const sleSrc = AccountRootEntryW(srcId, ctx.view);
|
||||||
auto const sleDst = ctx.view.peek(keylet::account(dstId));
|
auto sleDst = AccountRootEntryW(dstId, ctx.view, journal);
|
||||||
if (!sleDst || !sleSrc)
|
if (!sleDst || !sleSrc)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
// Create path: DefaultRipple is still required. terNO_RIPPLE is
|
// Create path: DefaultRipple is still required. terNO_RIPPLE is
|
||||||
@@ -681,20 +686,14 @@ addEmptyHolding(
|
|||||||
return tecDUPLICATE;
|
return tecDUPLICATE;
|
||||||
|
|
||||||
// A reserve sponsor only covers tx.Account's own objects.
|
// A reserve sponsor only covers tx.Account's own objects.
|
||||||
auto const sponsorExp = getEffectiveTxReserveSponsor(ctx, sleDst);
|
auto sponsorExp = getEffectiveTxReserveSponsor(ctx, sleDst);
|
||||||
if (!sponsorExp)
|
if (!sponsorExp)
|
||||||
return sponsorExp.error(); // LCOV_EXCL_LINE
|
return sponsorExp.error(); // LCOV_EXCL_LINE
|
||||||
auto const sponsorSle = *sponsorExp;
|
auto& sponsorSle = *sponsorExp;
|
||||||
|
|
||||||
// Can the account cover the trust line reserve ?
|
// Can the account cover the trust line reserve ?
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sleDst.checkReserve(
|
||||||
ctx,
|
ctx, priorBalance, sponsorSle, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE);
|
||||||
sleDst,
|
|
||||||
priorBalance,
|
|
||||||
sponsorSle,
|
|
||||||
{.ownerCountDelta = 1},
|
|
||||||
journal,
|
|
||||||
tecNO_LINE_INSUF_RESERVE);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
{
|
{
|
||||||
return ret;
|
return ret;
|
||||||
@@ -706,7 +705,7 @@ addEmptyHolding(
|
|||||||
srcId,
|
srcId,
|
||||||
dstId,
|
dstId,
|
||||||
index.key,
|
index.key,
|
||||||
sleDst,
|
sleDst.mutableRawSle(),
|
||||||
/*bAuth=*/false,
|
/*bAuth=*/false,
|
||||||
/*bNoRipple=*/true,
|
/*bNoRipple=*/true,
|
||||||
/*bFreeze=*/false,
|
/*bFreeze=*/false,
|
||||||
@@ -715,7 +714,7 @@ addEmptyHolding(
|
|||||||
/*saLimit=*/STAmount{Issue{currency, dstId}},
|
/*saLimit=*/STAmount{Issue{currency, dstId}},
|
||||||
/*uQualityIn=*/0,
|
/*uQualityIn=*/0,
|
||||||
/*uQualityOut=*/0,
|
/*uQualityOut=*/0,
|
||||||
sponsorSle,
|
sponsorSle ? sponsorSle->mutableRawSle() : SLE::pointer{},
|
||||||
journal);
|
journal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,7 +727,7 @@ removeEmptyHolding(
|
|||||||
{
|
{
|
||||||
if (issue.native())
|
if (issue.native())
|
||||||
{
|
{
|
||||||
auto const sle = ctx.view.read(keylet::account(accountID));
|
auto const sle = AccountRootEntryW(accountID, ctx.view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -753,13 +752,14 @@ removeEmptyHolding(
|
|||||||
if (line->isFlag(lsfLowReserve))
|
if (line->isFlag(lsfLowReserve))
|
||||||
{
|
{
|
||||||
// Clear reserve for low account.
|
// Clear reserve for low account.
|
||||||
auto sleLowAccount = ctx.view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
|
auto sleLowAccount =
|
||||||
|
AccountRootEntryW(line->at(sfLowLimit)->getIssuer(), ctx.view, journal);
|
||||||
if (!sleLowAccount)
|
if (!sleLowAccount)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfLowSponsor);
|
auto currentLowSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfLowSponsor);
|
||||||
|
|
||||||
decreaseOwnerCount(ctx.view, sleLowAccount, currentLowSponsor, 1, journal);
|
sleLowAccount.decreaseOwnerCount(currentLowSponsor, 1);
|
||||||
// It's not really necessary to clear the reserve flag, since the line
|
// It's not really necessary to clear the reserve flag, since the line
|
||||||
// is about to be deleted, but this will make the metadata reflect an
|
// is about to be deleted, but this will make the metadata reflect an
|
||||||
// accurate state at the time of deletion.
|
// accurate state at the time of deletion.
|
||||||
@@ -770,13 +770,14 @@ removeEmptyHolding(
|
|||||||
if (line->isFlag(lsfHighReserve))
|
if (line->isFlag(lsfHighReserve))
|
||||||
{
|
{
|
||||||
// Clear reserve for high account.
|
// Clear reserve for high account.
|
||||||
auto sleHighAccount = ctx.view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
|
auto sleHighAccount =
|
||||||
|
AccountRootEntryW(line->at(sfHighLimit)->getIssuer(), ctx.view, journal);
|
||||||
if (!sleHighAccount)
|
if (!sleHighAccount)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfHighSponsor);
|
auto currentHighSponsor = getLedgerEntryReserveSponsor(ctx.view, line, sfHighSponsor);
|
||||||
|
|
||||||
decreaseOwnerCount(ctx.view, sleHighAccount, currentHighSponsor, 1, journal);
|
sleHighAccount.decreaseOwnerCount(currentHighSponsor, 1);
|
||||||
// It's not really necessary to clear the reserve flag, since the line
|
// It's not really necessary to clear the reserve flag, since the line
|
||||||
// is about to be deleted, but this will make the metadata reflect an
|
// is about to be deleted, but this will make the metadata reflect an
|
||||||
// accurate state at the time of deletion.
|
// accurate state at the time of deletion.
|
||||||
@@ -805,8 +806,8 @@ deleteAMMTrustLine(
|
|||||||
auto const& [low, high] = std::minmax(
|
auto const& [low, high] = std::minmax(
|
||||||
sleState->getFieldAmount(sfLowLimit).getIssuer(),
|
sleState->getFieldAmount(sfLowLimit).getIssuer(),
|
||||||
sleState->getFieldAmount(sfHighLimit).getIssuer());
|
sleState->getFieldAmount(sfHighLimit).getIssuer());
|
||||||
auto sleLow = view.peek(keylet::account(low));
|
auto sleLow = AccountRootEntryW(low, view, j);
|
||||||
auto sleHigh = view.peek(keylet::account(high));
|
auto sleHigh = AccountRootEntryW(high, view, j);
|
||||||
if (!sleLow || !sleHigh)
|
if (!sleLow || !sleHigh)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -825,7 +826,7 @@ deleteAMMTrustLine(
|
|||||||
if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
|
if (ammAccountID && (low != *ammAccountID && high != *ammAccountID))
|
||||||
return terNO_AMM;
|
return terNO_AMM;
|
||||||
|
|
||||||
auto const sponsorSle =
|
auto sponsorSle =
|
||||||
getLedgerEntryReserveSponsor(view, sleState, !ammLow ? sfLowSponsor : sfHighSponsor);
|
getLedgerEntryReserveSponsor(view, sleState, !ammLow ? sfLowSponsor : sfHighSponsor);
|
||||||
|
|
||||||
if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter))
|
if (auto const ter = trustDelete(view, sleState, low, high, j); !isTesSuccess(ter))
|
||||||
@@ -838,7 +839,7 @@ deleteAMMTrustLine(
|
|||||||
if (!sleState->isFlag(uFlags))
|
if (!sleState->isFlag(uFlags))
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
decreaseOwnerCount(view, !ammLow ? sleLow : sleHigh, sponsorSle, 1, j);
|
(!ammLow ? sleLow : sleHigh).decreaseOwnerCount(sponsorSle, 1);
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/ProposalHelpers.h>
|
#include <xrpl/ledger/helpers/ProposalHelpers.h>
|
||||||
@@ -76,7 +77,7 @@ getTxReserveSponsorID(STTx const& tx)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::expected<SLE::pointer, TER>
|
std::expected<std::optional<AccountRootEntryW>, TER>
|
||||||
getTxReserveSponsor(ApplyViewContext ctx)
|
getTxReserveSponsor(ApplyViewContext ctx)
|
||||||
{
|
{
|
||||||
auto const sponsorID = getTxReserveSponsorID(ctx.tx);
|
auto const sponsorID = getTxReserveSponsorID(ctx.tx);
|
||||||
@@ -85,17 +86,17 @@ getTxReserveSponsor(ApplyViewContext ctx)
|
|||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
ctx.view.rules().enabled(featureSponsor),
|
ctx.view.rules().enabled(featureSponsor),
|
||||||
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
|
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
|
||||||
auto sle = ctx.view.peek(keylet::account(*sponsorID));
|
auto sle = AccountRootEntryW(*sponsorID, ctx.view);
|
||||||
|
|
||||||
// already checked in Transactor::checkSponsor
|
// already checked in Transactor::checkSponsor
|
||||||
if (!sle)
|
if (!sle.exists())
|
||||||
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
||||||
return sle;
|
return sle;
|
||||||
}
|
}
|
||||||
return SLE::pointer();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::expected<SLE::const_pointer, TER>
|
std::expected<std::optional<AccountRootEntryR>, TER>
|
||||||
getTxReserveSponsor(ReadView const& view, STTx const& tx)
|
getTxReserveSponsor(ReadView const& view, STTx const& tx)
|
||||||
{
|
{
|
||||||
auto const sponsorID = getTxReserveSponsorID(tx);
|
auto const sponsorID = getTxReserveSponsorID(tx);
|
||||||
@@ -104,18 +105,18 @@ getTxReserveSponsor(ReadView const& view, STTx const& tx)
|
|||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
view.rules().enabled(featureSponsor),
|
view.rules().enabled(featureSponsor),
|
||||||
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
|
"xrpl::getTxReserveSponsor : sponsor exists + Sponsor enabled");
|
||||||
auto sle = view.read(keylet::account(*sponsorID));
|
auto sle = AccountRootEntryR(*sponsorID, view);
|
||||||
|
|
||||||
// already checked in Transactor::checkSponsor
|
// already checked in Transactor::checkSponsor
|
||||||
if (!sle)
|
if (!sle.exists())
|
||||||
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
return std::unexpected(tecINTERNAL); // LCOV_EXCL_LINE
|
||||||
return sle;
|
return sle;
|
||||||
}
|
}
|
||||||
return SLE::pointer();
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::expected<SLE::pointer, TER>
|
std::expected<std::optional<AccountRootEntryW>, TER>
|
||||||
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle)
|
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle)
|
||||||
{
|
{
|
||||||
// A reserve sponsor only covers tx.Account's own objects.
|
// A reserve sponsor only covers tx.Account's own objects.
|
||||||
if (ctx.view.rules().enabled(fixCleanup3_2_0))
|
if (ctx.view.rules().enabled(fixCleanup3_2_0))
|
||||||
@@ -133,7 +134,7 @@ getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPseudoAccount(accountSle) || accountSle->getAccountID(sfAccount) != ctx.tx[sfAccount])
|
if (isPseudoAccount(accountSle) || accountSle->getAccountID(sfAccount) != ctx.tx[sfAccount])
|
||||||
return SLE::pointer();
|
return std::nullopt;
|
||||||
return getTxReserveSponsor(ctx);
|
return getTxReserveSponsor(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +152,7 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
SLE::pointer
|
std::optional<AccountRootEntryW>
|
||||||
getLedgerEntryReserveSponsor(ApplyView& view, SLE::ConstRef sle, SF_ACCOUNT const& field)
|
getLedgerEntryReserveSponsor(ApplyView& view, SLE::ConstRef sle, SF_ACCOUNT const& field)
|
||||||
{
|
{
|
||||||
auto const sponsorID = getLedgerEntryReserveSponsorID(sle, field);
|
auto const sponsorID = getLedgerEntryReserveSponsorID(sle, field);
|
||||||
@@ -160,9 +161,9 @@ getLedgerEntryReserveSponsor(ApplyView& view, SLE::ConstRef sle, SF_ACCOUNT cons
|
|||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
view.rules().enabled(featureSponsor),
|
view.rules().enabled(featureSponsor),
|
||||||
"xrpl::getLedgerEntryReserveSponsor : sponsor exists + Sponsor enabled");
|
"xrpl::getLedgerEntryReserveSponsor : sponsor exists + Sponsor enabled");
|
||||||
return view.peek(keylet::account(*sponsorID));
|
return AccountRootEntryW(*sponsorID, view);
|
||||||
}
|
}
|
||||||
return {};
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -185,16 +186,16 @@ addSponsorToLedgerEntry(SLE::Ref sle, SLE::ConstRef sponsorSle, SF_ACCOUNT const
|
|||||||
void
|
void
|
||||||
addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::Ref sle, SF_ACCOUNT const& field)
|
addSponsorToLedgerEntry(ApplyViewContext ctx, SLE::Ref sle, SF_ACCOUNT const& field)
|
||||||
{
|
{
|
||||||
// getTxReserveSponsor yields a null pointer when the tx is not
|
// getTxReserveSponsor yields nullopt when the tx is not reserve-sponsored,
|
||||||
// reserve-sponsored, so addSponsorToLedgerEntry becomes a no-op then. The
|
// so addSponsorToLedgerEntry becomes a no-op then. The error case
|
||||||
// error case (tecINTERNAL) is an already-checked invariant; skip stamping.
|
// (tecINTERNAL) is an already-checked invariant; skip stamping.
|
||||||
auto const sponsorSle = getTxReserveSponsor(ctx);
|
auto const sponsorSle = getTxReserveSponsor(ctx);
|
||||||
if (sponsorSle && *sponsorSle)
|
if (sponsorSle && *sponsorSle)
|
||||||
{
|
{
|
||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
ctx.view.rules().enabled(featureSponsor),
|
ctx.view.rules().enabled(featureSponsor),
|
||||||
"xrpl::addSponsorToLedgerEntry : sponsor exists + Sponsor enabled");
|
"xrpl::addSponsorToLedgerEntry : sponsor exists + Sponsor enabled");
|
||||||
addSponsorToLedgerEntry(sle, *sponsorSle, field);
|
addSponsorToLedgerEntry(sle, (**sponsorSle).rawSle(), field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
@@ -293,7 +294,7 @@ getLineIfUsable(
|
|||||||
// we need to check if the associated assets have been frozen
|
// we need to check if the associated assets have been frozen
|
||||||
if (view.rules().enabled(fixFrozenLPTokenTransfer))
|
if (view.rules().enabled(fixFrozenLPTokenTransfer))
|
||||||
{
|
{
|
||||||
auto const sleIssuer = view.read(keylet::account(issuer));
|
auto const sleIssuer = AccountRootEntryR(issuer, view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
{
|
{
|
||||||
return nullptr; // LCOV_EXCL_LINE
|
return nullptr; // LCOV_EXCL_LINE
|
||||||
@@ -562,7 +563,7 @@ canAddHolding(ReadView const& view, Issue const& issue)
|
|||||||
return tesSUCCESS; // No special checks for XRP
|
return tesSUCCESS; // No special checks for XRP
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const issuer = view.read(keylet::account(issue.getIssuer()));
|
auto const issuer = AccountRootEntryR(issue.getIssuer(), view);
|
||||||
if (!issuer)
|
if (!issuer)
|
||||||
{
|
{
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
@@ -738,6 +739,8 @@ directSendNoFeeIOU(
|
|||||||
auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
|
auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
|
||||||
auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
|
auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
|
||||||
|
|
||||||
|
AccountRootEntryW senderSle(uSenderID, view, j);
|
||||||
|
|
||||||
// FIXME This NEEDS to be cleaned up and simplified. It's impossible
|
// FIXME This NEEDS to be cleaned up and simplified. It's impossible
|
||||||
// for anyone to understand.
|
// for anyone to understand.
|
||||||
if (saBefore > beast::kZero
|
if (saBefore > beast::kZero
|
||||||
@@ -746,8 +749,7 @@ directSendNoFeeIOU(
|
|||||||
// Sender is zero or negative.
|
// Sender is zero or negative.
|
||||||
&& sleRippleState->isFlag(senderReserveFlag)
|
&& sleRippleState->isFlag(senderReserveFlag)
|
||||||
// Sender reserve is set.
|
// Sender reserve is set.
|
||||||
&& sleRippleState->isFlag(senderNoRippleFlag) !=
|
&& sleRippleState->isFlag(senderNoRippleFlag) != senderSle->isFlag(lsfDefaultRipple) &&
|
||||||
view.read(keylet::account(uSenderID))->isFlag(lsfDefaultRipple) &&
|
|
||||||
!sleRippleState->isFlag(senderFreezeFlag) &&
|
!sleRippleState->isFlag(senderFreezeFlag) &&
|
||||||
!sleRippleState->getFieldAmount(bSenderHigh ? sfHighLimit : sfLowLimit)
|
!sleRippleState->getFieldAmount(bSenderHigh ? sfHighLimit : sfLowLimit)
|
||||||
// Sender trust limit is 0.
|
// Sender trust limit is 0.
|
||||||
@@ -758,9 +760,9 @@ directSendNoFeeIOU(
|
|||||||
// Sender quality out is 0.
|
// Sender quality out is 0.
|
||||||
{
|
{
|
||||||
// Clear the reserve of the sender, possibly delete the line!
|
// Clear the reserve of the sender, possibly delete the line!
|
||||||
auto const currentSponsor = getLedgerEntryReserveSponsor(
|
auto currentSponsor = getLedgerEntryReserveSponsor(
|
||||||
view, sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
view, sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
||||||
decreaseOwnerCount(view, view.peek(keylet::account(uSenderID)), currentSponsor, 1, j);
|
senderSle.decreaseOwnerCount(currentSponsor, 1);
|
||||||
|
|
||||||
removeSponsorFromLedgerEntry(
|
removeSponsorFromLedgerEntry(
|
||||||
sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
sleRippleState, !bSenderHigh ? sfLowSponsor : sfHighSponsor);
|
||||||
@@ -805,7 +807,7 @@ directSendNoFeeIOU(
|
|||||||
<< to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : "
|
<< to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : "
|
||||||
<< saAmount.getFullText();
|
<< saAmount.getFullText();
|
||||||
|
|
||||||
auto const sleAccount = view.peek(keylet::account(uReceiverID));
|
auto sleAccount = AccountRootEntryW(uReceiverID, view);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -817,7 +819,7 @@ directSendNoFeeIOU(
|
|||||||
uSenderID,
|
uSenderID,
|
||||||
uReceiverID,
|
uReceiverID,
|
||||||
index.key,
|
index.key,
|
||||||
sleAccount,
|
sleAccount.mutableRawSle(),
|
||||||
false,
|
false,
|
||||||
noRipple,
|
noRipple,
|
||||||
false,
|
false,
|
||||||
@@ -1010,10 +1012,12 @@ accountSendIOU(
|
|||||||
*/
|
*/
|
||||||
TER terResult(tesSUCCESS);
|
TER terResult(tesSUCCESS);
|
||||||
|
|
||||||
SLE::pointer const sender =
|
SLE::pointer const sender = uSenderID != beast::kZero
|
||||||
uSenderID != beast::kZero ? view.peek(keylet::account(uSenderID)) : SLE::pointer();
|
? AccountRootEntryW(uSenderID, view).mutableRawSle()
|
||||||
SLE::pointer const receiver =
|
: SLE::pointer();
|
||||||
uReceiverID != beast::kZero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer();
|
SLE::pointer const receiver = uReceiverID != beast::kZero
|
||||||
|
? AccountRootEntryW(uReceiverID, view).mutableRawSle()
|
||||||
|
: SLE::pointer();
|
||||||
|
|
||||||
if (auto stream = j.trace())
|
if (auto stream = j.trace())
|
||||||
{
|
{
|
||||||
@@ -1106,8 +1110,9 @@ accountSendMultiIOU(
|
|||||||
* ensure that transfers are balanced.
|
* ensure that transfers are balanced.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SLE::pointer const sender =
|
SLE::pointer const sender = senderID != beast::kZero
|
||||||
senderID != beast::kZero ? view.peek(keylet::account(senderID)) : SLE::pointer();
|
? AccountRootEntryW(senderID, view).mutableRawSle()
|
||||||
|
: SLE::pointer();
|
||||||
|
|
||||||
if (auto stream = j.trace())
|
if (auto stream = j.trace())
|
||||||
{
|
{
|
||||||
@@ -1138,8 +1143,9 @@ accountSendMultiIOU(
|
|||||||
if (!amount || (senderID == receiverID))
|
if (!amount || (senderID == receiverID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SLE::pointer const receiver =
|
SLE::pointer const receiver = receiverID != beast::kZero
|
||||||
receiverID != beast::kZero ? view.peek(keylet::account(receiverID)) : SLE::pointer();
|
? AccountRootEntryW(receiverID, view).mutableRawSle()
|
||||||
|
: SLE::pointer();
|
||||||
|
|
||||||
if (auto stream = j.trace())
|
if (auto stream = j.trace())
|
||||||
{
|
{
|
||||||
@@ -1591,8 +1597,8 @@ transferXRP(
|
|||||||
XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver");
|
XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver");
|
||||||
XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP");
|
XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP");
|
||||||
|
|
||||||
SLE::pointer const sender = view.peek(keylet::account(from));
|
SLE::pointer const sender = AccountRootEntryW(from, view).mutableRawSle();
|
||||||
SLE::pointer const receiver = view.peek(keylet::account(to));
|
SLE::pointer const receiver = AccountRootEntryW(to, view).mutableRawSle();
|
||||||
if (!sender || !receiver)
|
if (!sender || !receiver)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -193,7 +194,7 @@ public:
|
|||||||
if (!s.ok())
|
if (!s.ok())
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
std::string("Unable to set RocksDB bbt_options: ") + s.ToString());
|
std::format("Unable to set RocksDB bbt_options: {}", s.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +207,7 @@ public:
|
|||||||
if (!s.ok())
|
if (!s.ok())
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
std::string("Unable to set RocksDB options: ") + s.ToString());
|
std::format("Unable to set RocksDB options: {}", s.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +242,7 @@ public:
|
|||||||
if (!status.ok() || (localDb == nullptr))
|
if (!status.ok() || (localDb == nullptr))
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
std::string("Unable to open/create RocksDB: ") + status.ToString());
|
std::format("Unable to open/create RocksDB: {}", status.ToString()));
|
||||||
}
|
}
|
||||||
db.reset(localDb);
|
db.reset(localDb);
|
||||||
}
|
}
|
||||||
@@ -356,7 +357,7 @@ public:
|
|||||||
auto ret = db->Write(options, &wb);
|
auto ret = db->Write(options, &wb);
|
||||||
|
|
||||||
if (!ret.ok())
|
if (!ret.ok())
|
||||||
Throw<std::runtime_error>("storeBatch failed: " + ret.ToString());
|
Throw<std::runtime_error>(std::format("storeBatch failed: {}", ret.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -105,8 +106,8 @@ Permission::Permission()
|
|||||||
if (type <= UINT16_MAX)
|
if (type <= UINT16_MAX)
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
Throw<std::logic_error>(
|
Throw<std::logic_error>(std::format(
|
||||||
"Granular permission value must exceed the maximum uint16_t value: " + name);
|
"Granular permission value must exceed the maximum uint16_t value: {}", name));
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <format>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -1193,8 +1194,7 @@ muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divis
|
|||||||
if (ret > std::numeric_limits<std::uint64_t>::max())
|
if (ret > std::numeric_limits<std::uint64_t>::max())
|
||||||
{
|
{
|
||||||
Throw<std::overflow_error>(
|
Throw<std::overflow_error>(
|
||||||
"overflow: (" + std::to_string(multiplier) + " * " + std::to_string(multiplicand) +
|
std::format("overflow: ({} * {}) / {}", multiplier, multiplicand, divisor));
|
||||||
") / " + std::to_string(divisor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<uint64_t>(ret);
|
return static_cast<uint64_t>(ret);
|
||||||
@@ -1215,9 +1215,8 @@ muldivRound(
|
|||||||
|
|
||||||
if (ret > std::numeric_limits<std::uint64_t>::max())
|
if (ret > std::numeric_limits<std::uint64_t>::max())
|
||||||
{
|
{
|
||||||
Throw<std::overflow_error>(
|
Throw<std::overflow_error>(std::format(
|
||||||
"overflow: ((" + std::to_string(multiplier) + " * " + std::to_string(multiplicand) +
|
"overflow: (({} * {}) + {}) / {}", multiplier, multiplicand, rounding, divisor));
|
||||||
") + " + std::to_string(rounding) + ") / " + std::to_string(divisor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<uint64_t>(ret);
|
return static_cast<uint64_t>(ret);
|
||||||
|
|||||||
@@ -35,9 +35,8 @@ STLedgerEntry::STLedgerEntry(Keylet const& k) : STObject(sfLedgerEntry), key_(k.
|
|||||||
|
|
||||||
if (format == nullptr)
|
if (format == nullptr)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Attempt to create a SLE of unknown type " +
|
"Attempt to create a SLE of unknown type {}", safeCast<std::uint16_t>(k.type)));
|
||||||
std::to_string(safeCast<std::uint16_t>(k.type)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set(format->getSOTemplate());
|
set(format->getSOTemplate());
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <format>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -170,7 +171,7 @@ partsFromString(std::string const& number)
|
|||||||
boost::smatch match;
|
boost::smatch match;
|
||||||
|
|
||||||
if (!boost::regex_match(number, match, kReNumber))
|
if (!boost::regex_match(number, match, kReNumber))
|
||||||
Throw<std::runtime_error>("'" + number + "' is not a number");
|
Throw<std::runtime_error>(std::format("'{}' is not a number", number));
|
||||||
|
|
||||||
// Match fields:
|
// Match fields:
|
||||||
// 0 = whole input
|
// 0 = whole input
|
||||||
|
|||||||
@@ -59,9 +59,8 @@ getTxFormat(TxType type)
|
|||||||
|
|
||||||
if (format == nullptr)
|
if (format == nullptr)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Invalid transaction type " +
|
"Invalid transaction type {}", safeCast<std::underlying_type_t<TxType>>(type)));
|
||||||
std::to_string(safeCast<std::underlying_type_t<TxType>>(type)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return format;
|
return format;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
#include <xrpl/protocol/Serializer.h>
|
#include <xrpl/protocol/Serializer.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
@@ -22,7 +22,7 @@ STVector256::STVector256(SerialIter& sit, SField const& name) : STBase(name)
|
|||||||
if (slice.size() % UInt256::size() != 0)
|
if (slice.size() % UInt256::size() != 0)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(
|
||||||
"Bad serialization for STVector256: " + std::to_string(slice.size()));
|
std::format("Bad serialization for STVector256: {}", slice.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const cnt = slice.size() / UInt256::size();
|
auto const cnt = slice.size() / UInt256::size();
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ STXChainBridge::STXChainBridge(SField const& name, json::Value const& v) : STBas
|
|||||||
std::string const name = it.memberName();
|
std::string const name = it.memberName();
|
||||||
if (!kBridgeJson.isMember(name))
|
if (!kBridgeJson.isMember(name))
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>("STXChainBridge extra field detected: " + name);
|
Throw<std::runtime_error>(
|
||||||
|
std::format("STXChainBridge extra field detected: {}", name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
@@ -456,7 +456,7 @@ SerialIter::getFieldID(int& type, int& name)
|
|||||||
// uncommon type
|
// uncommon type
|
||||||
type = get8();
|
type = get8();
|
||||||
if (type < 16)
|
if (type < 16)
|
||||||
Throw<std::runtime_error>("gFID: uncommon type out of range " + std::to_string(type));
|
Throw<std::runtime_error>(std::format("gFID: uncommon type out of range {}", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name == 0)
|
if (name == 0)
|
||||||
@@ -464,7 +464,7 @@ SerialIter::getFieldID(int& type, int& name)
|
|||||||
// uncommon name
|
// uncommon name
|
||||||
name = get8();
|
name = get8();
|
||||||
if (name < 16)
|
if (name < 16)
|
||||||
Throw<std::runtime_error>("gFID: uncommon name out of range " + std::to_string(name));
|
Throw<std::runtime_error>(std::format("gFID: uncommon name out of range {}", name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <soci/sqlite3/soci-sqlite3.h> // IWYU pragma: keep
|
#include <soci/sqlite3/soci-sqlite3.h> // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include <format>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
@@ -40,8 +41,8 @@ getSociSqliteInit(std::string const& name, std::string const& dir, std::string c
|
|||||||
{
|
{
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Sqlite databases must specify a dir and a name. Name: " + name + " Dir: " + dir);
|
"Sqlite databases must specify a dir and a name. Name: {} Dir: {}", name, dir));
|
||||||
}
|
}
|
||||||
std::filesystem::path file(dir);
|
std::filesystem::path file(dir);
|
||||||
if (std::filesystem::is_directory(file))
|
if (std::filesystem::is_directory(file))
|
||||||
@@ -56,7 +57,7 @@ getSociInit(BasicConfig const& config, std::string const& dbName)
|
|||||||
auto const backendName = get(section, Keys::kBackend, "sqlite");
|
auto const backendName = get(section, Keys::kBackend, "sqlite");
|
||||||
|
|
||||||
if (backendName != "sqlite")
|
if (backendName != "sqlite")
|
||||||
Throw<std::runtime_error>("Unsupported soci backend: " + backendName);
|
Throw<std::runtime_error>(std::format("Unsupported soci backend: {}", backendName));
|
||||||
|
|
||||||
auto const path = config.legacy(Sections::kDatabasePath);
|
auto const path = config.legacy(Sections::kDatabasePath);
|
||||||
auto const ext = dbName == "validators" || dbName == "peerfinder" ? ".sqlite" : ".db";
|
auto const ext = dbName == "validators" || dbName == "peerfinder" ? ".sqlite" : ".db";
|
||||||
@@ -101,7 +102,7 @@ open(soci::session& s, std::string const& beName, std::string const& connectionS
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>("Unsupported soci backend: " + beName);
|
Throw<std::runtime_error>(std::format("Unsupported soci backend: {}", beName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <format>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -48,7 +49,7 @@ to_string(Manifest const& m)
|
|||||||
return "Revocation Manifest " + mk;
|
return "Revocation Manifest " + mk;
|
||||||
|
|
||||||
if (!m.signingKey)
|
if (!m.signingKey)
|
||||||
Throw<std::runtime_error>("No SigningKey in manifest " + mk);
|
Throw<std::runtime_error>(std::format("No SigningKey in manifest {}", mk));
|
||||||
|
|
||||||
return "Manifest " + mk + " (" + std::to_string(m.sequence) + ": " +
|
return "Manifest " + mk + " (" + std::to_string(m.sequence) + ": " +
|
||||||
toBase58(TokenType::NodePublic, *m.signingKey) + ")";
|
toBase58(TokenType::NodePublic, *m.signingKey) + ")";
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <format>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -107,10 +108,10 @@ SHAMapNodeID::getChildNodeID(unsigned int branch) const
|
|||||||
depth_ <= SHAMap::kLeafDepth, "xrpl::SHAMapNodeID::getChildNodeID : maximum leaf depth");
|
depth_ <= SHAMap::kLeafDepth, "xrpl::SHAMapNodeID::getChildNodeID : maximum leaf depth");
|
||||||
|
|
||||||
if (depth_ >= SHAMap::kLeafDepth)
|
if (depth_ >= SHAMap::kLeafDepth)
|
||||||
Throw<std::logic_error>("Request for child node ID of " + to_string(*this));
|
Throw<std::logic_error>(std::format("Request for child node ID of {}", to_string(*this)));
|
||||||
|
|
||||||
if (!isPrefixOf(id_))
|
if (!isPrefixOf(id_))
|
||||||
Throw<std::logic_error>("Incorrect mask for " + to_string(*this));
|
Throw<std::logic_error>(std::format("Incorrect mask for {}", to_string(*this)));
|
||||||
|
|
||||||
SHAMapNodeID node{depth_ + 1, id_};
|
SHAMapNodeID node{depth_ + 1, id_};
|
||||||
node.id_.begin()[depth_ / 2] |= ((depth_ & 1) != 0u) ? branch : (branch << 4);
|
node.id_.begin()[depth_ / 2] |= ((depth_ & 1) != 0u) ? branch : (branch << 4);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <xrpl/shamap/SHAMapTxPlusMetaLeafNode.h>
|
#include <xrpl/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <format>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -30,9 +31,8 @@ SHAMapTreeNode::makeTransaction(Slice data, SHAMapHash const& hash, bool hashVal
|
|||||||
{
|
{
|
||||||
if (data.size() < kMinShaMapItemBytes)
|
if (data.size() < kMinShaMapItemBytes)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Short TXN node: " + std::to_string(data.size()) + " bytes (minimum " +
|
"Short TXN node: {} bytes (minimum {} required)", data.size(), kMinShaMapItemBytes));
|
||||||
std::to_string(kMinShaMapItemBytes) + " required)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item = makeShamapitem(sha512Half(HashPrefix::TransactionId, data), data);
|
auto item = makeShamapitem(sha512Half(HashPrefix::TransactionId, data), data);
|
||||||
@@ -52,27 +52,25 @@ SHAMapTreeNode::makeTransactionWithMeta(Slice data, SHAMapHash const& hash, bool
|
|||||||
|
|
||||||
if (s.size() < tag.kBytes)
|
if (s.size() < tag.kBytes)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Short TXN+MD node: " + std::to_string(s.size()) + " bytes (minimum " +
|
"Short TXN+MD node: {} bytes (minimum {} required for tag)", s.size(), tag.kBytes));
|
||||||
std::to_string(tag.kBytes) + " required for tag)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: improve this interface so that the above check isn't needed
|
// FIXME: improve this interface so that the above check isn't needed
|
||||||
if (!s.getBitString(tag, s.size() - tag.kBytes))
|
if (!s.getBitString(tag, s.size() - tag.kBytes))
|
||||||
{
|
{
|
||||||
Throw<std::out_of_range>(
|
Throw<std::out_of_range>(std::format(
|
||||||
"Short TXN+MD node: failed to read tag at offset " +
|
"Short TXN+MD node: failed to read tag at offset {}", s.size() - tag.kBytes));
|
||||||
std::to_string(s.size() - tag.kBytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.chop(tag.kBytes);
|
s.chop(tag.kBytes);
|
||||||
|
|
||||||
if (s.size() < kMinShaMapItemBytes)
|
if (s.size() < kMinShaMapItemBytes)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Short TXN+MD node: " + std::to_string(s.size()) +
|
"Short TXN+MD node: {} bytes after tag removal (minimum {} required)",
|
||||||
" bytes after tag removal (minimum " + std::to_string(kMinShaMapItemBytes) +
|
s.size(),
|
||||||
" required)");
|
kMinShaMapItemBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item = makeShamapitem(tag, s.slice());
|
auto item = makeShamapitem(tag, s.slice());
|
||||||
@@ -92,16 +90,15 @@ SHAMapTreeNode::makeAccountState(Slice data, SHAMapHash const& hash, bool hashVa
|
|||||||
|
|
||||||
if (s.size() < tag.kBytes)
|
if (s.size() < tag.kBytes)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Short AS node: " + std::to_string(s.size()) + " bytes (minimum " +
|
"Short AS node: {} bytes (minimum {} required for tag)", s.size(), tag.kBytes));
|
||||||
std::to_string(tag.kBytes) + " required for tag)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: improve this interface so that the above check isn't needed
|
// FIXME: improve this interface so that the above check isn't needed
|
||||||
if (!s.getBitString(tag, s.size() - tag.kBytes))
|
if (!s.getBitString(tag, s.size() - tag.kBytes))
|
||||||
{
|
{
|
||||||
Throw<std::out_of_range>(
|
Throw<std::out_of_range>(
|
||||||
"Short AS node: failed to read tag at offset " + std::to_string(s.size() - tag.kBytes));
|
std::format("Short AS node: failed to read tag at offset {}", s.size() - tag.kBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
s.chop(tag.kBytes);
|
s.chop(tag.kBytes);
|
||||||
@@ -111,9 +108,10 @@ SHAMapTreeNode::makeAccountState(Slice data, SHAMapHash const& hash, bool hashVa
|
|||||||
|
|
||||||
if (s.size() < kMinShaMapItemBytes)
|
if (s.size() < kMinShaMapItemBytes)
|
||||||
{
|
{
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"Short AS node: " + std::to_string(s.size()) + " bytes after tag removal (minimum " +
|
"Short AS node: {} bytes after tag removal (minimum {} required)",
|
||||||
std::to_string(kMinShaMapItemBytes) + " required)");
|
s.size(),
|
||||||
|
kMinShaMapItemBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item = makeShamapitem(tag, s.slice());
|
auto item = makeShamapitem(tag, s.slice());
|
||||||
@@ -152,7 +150,7 @@ SHAMapTreeNode::makeFromWire(Slice rawNode)
|
|||||||
if (type == kWireTypeTransactionWithMeta)
|
if (type == kWireTypeTransactionWithMeta)
|
||||||
return makeTransactionWithMeta(rawNode, hash, hashValid);
|
return makeTransactionWithMeta(rawNode, hash, hashValid);
|
||||||
|
|
||||||
Throw<std::runtime_error>("wire: Unknown type (" + std::to_string(type) + ")");
|
Throw<std::runtime_error>(std::format("wire: Unknown type ({})", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAMapTreeNodePtr
|
SHAMapTreeNodePtr
|
||||||
@@ -183,9 +181,8 @@ SHAMapTreeNode::makeFromPrefix(Slice rawNode, SHAMapHash const& hash)
|
|||||||
if (type == HashPrefix::TxNode)
|
if (type == HashPrefix::TxNode)
|
||||||
return makeTransactionWithMeta(rawNode, hash, hashValid);
|
return makeTransactionWithMeta(rawNode, hash, hashValid);
|
||||||
|
|
||||||
Throw<std::runtime_error>(
|
Throw<std::runtime_error>(std::format(
|
||||||
"prefix: unknown type (" +
|
"prefix: unknown type ({})", safeCast<std::underlying_type_t<HashPrefix>>(type)));
|
||||||
std::to_string(safeCast<std::underlying_type_t<HashPrefix>>(type)) + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <xrpl/json/to_string.h> // IWYU pragma: keep
|
#include <xrpl/json/to_string.h> // IWYU pragma: keep
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DelegateHelpers.h>
|
#include <xrpl/ledger/helpers/DelegateHelpers.h>
|
||||||
@@ -586,7 +587,7 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
|
|||||||
|
|
||||||
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
||||||
{
|
{
|
||||||
auto const sponsorReserve = accountReserve(ctx.view, payerSle, ctx.j);
|
auto const sponsorReserve = accountReserve(ctx.view, feePayer.id, ctx.j);
|
||||||
maxSpendable = payerSle->getFieldAmount(sfBalance).xrp() - sponsorReserve;
|
maxSpendable = payerSle->getFieldAmount(sfBalance).xrp() - sponsorReserve;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -652,7 +653,7 @@ Transactor::payFee()
|
|||||||
XRPAmount spendable = balance;
|
XRPAmount spendable = balance;
|
||||||
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
||||||
{
|
{
|
||||||
auto const sponsorReserve = accountReserve(view(), sle, j_);
|
auto const sponsorReserve = accountReserve(view(), feePayer.id, j_);
|
||||||
// max(balance - reserve, 0) with overflow handling
|
// max(balance - reserve, 0) with overflow handling
|
||||||
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
|
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
|
||||||
}
|
}
|
||||||
@@ -700,7 +701,7 @@ Transactor::checkSeqProxy(ReadView const& view, STTx const& tx, beast::Journal j
|
|||||||
{
|
{
|
||||||
auto const id = tx.getAccountID(sfAccount);
|
auto const id = tx.getAccountID(sfAccount);
|
||||||
|
|
||||||
auto const sle = view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, view);
|
||||||
|
|
||||||
if (!sle)
|
if (!sle)
|
||||||
{
|
{
|
||||||
@@ -765,7 +766,7 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx)
|
|||||||
{
|
{
|
||||||
auto const id = ctx.tx.getAccountID(sfAccount);
|
auto const id = ctx.tx.getAccountID(sfAccount);
|
||||||
|
|
||||||
auto const sle = ctx.view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, ctx.view);
|
||||||
|
|
||||||
if (!sle)
|
if (!sle)
|
||||||
{
|
{
|
||||||
@@ -835,7 +836,7 @@ Transactor::ticketDelete(
|
|||||||
|
|
||||||
// Update the account root's TicketCount. If the ticket count drops to
|
// Update the account root's TicketCount. If the ticket count drops to
|
||||||
// zero remove the (optional) field.
|
// zero remove the (optional) field.
|
||||||
auto sleAccount = view.peek(keylet::account(account));
|
auto sleAccount = AccountRootEntryW(account, view);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
@@ -885,19 +886,19 @@ Transactor::apply()
|
|||||||
|
|
||||||
// If the transactor requires a valid account and the transaction doesn't
|
// If the transactor requires a valid account and the transaction doesn't
|
||||||
// list one, preflight will have already a flagged a failure.
|
// list one, preflight will have already a flagged a failure.
|
||||||
auto const sle = view().peek(keylet::account(accountID_));
|
auto sle = AccountRootEntryW(accountID_, view());
|
||||||
|
|
||||||
// sle must exist except for transactions
|
// sle must exist except for transactions
|
||||||
// that allow zero account.
|
// that allow zero account.
|
||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
sle != nullptr || accountID_ == beast::kZero,
|
sle.exists() || accountID_ == beast::kZero,
|
||||||
"xrpl::Transactor::apply : non-null SLE or zero account");
|
"xrpl::Transactor::apply : non-null SLE or zero account");
|
||||||
|
|
||||||
if (sle)
|
if (sle)
|
||||||
{
|
{
|
||||||
preFeeBalance_ = STAmount{(*sle)[sfBalance]}.xrp();
|
preFeeBalance_ = STAmount{(*sle)[sfBalance]}.xrp();
|
||||||
|
|
||||||
TER result = consumeSeqProxy(sle);
|
TER result = consumeSeqProxy(sle.mutableRawSle());
|
||||||
if (!isTesSuccess(result))
|
if (!isTesSuccess(result))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -908,7 +909,7 @@ Transactor::apply()
|
|||||||
if (sle->isFieldPresent(sfAccountTxnID))
|
if (sle->isFieldPresent(sfAccountTxnID))
|
||||||
sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
|
sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
|
||||||
|
|
||||||
view().update(sle);
|
sle.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
return doApply();
|
return doApply();
|
||||||
@@ -925,7 +926,7 @@ Transactor::checkSign(
|
|||||||
bool permitUncreatedAccount)
|
bool permitUncreatedAccount)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto const sle = view.read(keylet::account(idAccount));
|
auto const sle = AccountRootEntryR(idAccount, view);
|
||||||
|
|
||||||
if ((view.rules().enabled(featureLendingProtocol) ||
|
if ((view.rules().enabled(featureLendingProtocol) ||
|
||||||
view.rules().enabled(featureBatchV1_1) || view.rules().enabled(fixCleanup3_3_0)) &&
|
view.rules().enabled(featureBatchV1_1) || view.rules().enabled(fixCleanup3_3_0)) &&
|
||||||
@@ -991,7 +992,7 @@ Transactor::checkSign(
|
|||||||
|
|
||||||
// Look up the account.
|
// Look up the account.
|
||||||
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
|
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
|
||||||
auto const sleAccount = view.read(keylet::account(idAccount));
|
auto const sleAccount = AccountRootEntryR(idAccount, view);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
{
|
{
|
||||||
// An account that does not exist yet can only be authorized by its own
|
// An account that does not exist yet can only be authorized by its own
|
||||||
@@ -1004,7 +1005,7 @@ Transactor::checkSign(
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return checkSingleSign(view, idSigner, idAccount, sleAccount, j);
|
return checkSingleSign(view, idSigner, idAccount, sleAccount.rawSle(), j);
|
||||||
}
|
}
|
||||||
|
|
||||||
NotTEC
|
NotTEC
|
||||||
@@ -1153,7 +1154,7 @@ Transactor::checkMultiSign(
|
|||||||
|
|
||||||
// In any of these cases we need to know whether the account is in
|
// In any of these cases we need to know whether the account is in
|
||||||
// the ledger. Determine that now.
|
// the ledger. Determine that now.
|
||||||
auto const sleTxSignerRoot = view.read(keylet::account(txSignerAcctID));
|
auto const sleTxSignerRoot = AccountRootEntryR(txSignerAcctID, view);
|
||||||
|
|
||||||
if (signingAcctIDFromPubKey == txSignerAcctID)
|
if (signingAcctIDFromPubKey == txSignerAcctID)
|
||||||
{
|
{
|
||||||
@@ -1296,7 +1297,7 @@ Transactor::reset(XRPAmount fee)
|
|||||||
{
|
{
|
||||||
ctx_.discard();
|
ctx_.discard();
|
||||||
|
|
||||||
auto const txnAcct = view().peek(keylet::account(ctx_.tx.getAccountID(sfAccount)));
|
auto txnAcct = AccountRootEntryW(ctx_.tx.getAccountID(sfAccount), view());
|
||||||
|
|
||||||
// The account should never be missing from the ledger. But if it
|
// The account should never be missing from the ledger. But if it
|
||||||
// is missing then we can't very well charge it a fee, can we?
|
// is missing then we can't very well charge it a fee, can we?
|
||||||
@@ -1331,7 +1332,7 @@ Transactor::reset(XRPAmount fee)
|
|||||||
XRPAmount spendable = balance;
|
XRPAmount spendable = balance;
|
||||||
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
if (feePayer.type == FeePayerType::SponsorCoSigned)
|
||||||
{
|
{
|
||||||
auto const sponsorReserve = accountReserve(view(), payerSle, j_);
|
auto const sponsorReserve = accountReserve(view(), feePayer.id, j_);
|
||||||
// max(balance - reserve, 0) with overflow handling
|
// max(balance - reserve, 0) with overflow handling
|
||||||
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
|
spendable = balance > sponsorReserve ? balance - sponsorReserve : beast::kZero;
|
||||||
}
|
}
|
||||||
@@ -1364,13 +1365,13 @@ Transactor::reset(XRPAmount fee)
|
|||||||
payerSle->setFieldAmount(feePayer.balanceField, feeAmountAfter);
|
payerSle->setFieldAmount(feePayer.balanceField, feeAmountAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER const ter{consumeSeqProxy(txnAcct)};
|
TER const ter{consumeSeqProxy(txnAcct.mutableRawSle())};
|
||||||
XRPL_ASSERT(isTesSuccess(ter), "xrpl::Transactor::reset : result is tesSUCCESS");
|
XRPL_ASSERT(isTesSuccess(ter), "xrpl::Transactor::reset : result is tesSUCCESS");
|
||||||
|
|
||||||
if (isTesSuccess(ter))
|
if (isTesSuccess(ter))
|
||||||
{
|
{
|
||||||
view().update(txnAcct);
|
txnAcct.update();
|
||||||
if (payerSle != txnAcct)
|
if (payerSle != txnAcct.mutableRawSle())
|
||||||
view().update(payerSle);
|
view().update(payerSle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -735,6 +735,15 @@ NoDeepFreezeTrustLinesWithoutFreeze::finalize(
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool
|
||||||
|
isPseudoAccountSle(SLE::ConstRef sleAcct)
|
||||||
|
{
|
||||||
|
auto const& fields = getPseudoAccountFields();
|
||||||
|
return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
|
||||||
|
std::ranges::any_of(
|
||||||
|
fields, [&sleAcct](SField const* sf) { return sleAcct->isFieldPresent(*sf); });
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ValidNewAccountRoot::visitEntry(bool, SLE::ConstRef before, SLE::ConstRef after)
|
ValidNewAccountRoot::visitEntry(bool, SLE::ConstRef before, SLE::ConstRef after)
|
||||||
{
|
{
|
||||||
@@ -742,7 +751,7 @@ ValidNewAccountRoot::visitEntry(bool, SLE::ConstRef before, SLE::ConstRef after)
|
|||||||
{
|
{
|
||||||
accountsCreated_++;
|
accountsCreated_++;
|
||||||
accountSeq_ = (*after)[sfSequence];
|
accountSeq_ = (*after)[sfSequence];
|
||||||
pseudoAccount_ = isPseudoAccount(after);
|
pseudoAccount_ = isPseudoAccountSle(after);
|
||||||
flags_ = after->getFlags();
|
flags_ = after->getFlags();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1020,9 +1029,9 @@ ValidPseudoAccounts::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstR
|
|||||||
if (after && after->getType() == ltACCOUNT_ROOT)
|
if (after && after->getType() == ltACCOUNT_ROOT)
|
||||||
{
|
{
|
||||||
bool const isPseudo = [&]() {
|
bool const isPseudo = [&]() {
|
||||||
// isPseudoAccount checks that any of the pseudo-account fields are
|
// isPseudoAccountSle checks that any of the pseudo-account fields
|
||||||
// set.
|
// are set.
|
||||||
if (isPseudoAccount(after))
|
if (isPseudoAccountSle(after))
|
||||||
return true;
|
return true;
|
||||||
// Not all pseudo-accounts have a zero sequence, but all accounts
|
// Not all pseudo-accounts have a zero sequence, but all accounts
|
||||||
// with a zero sequence had better be pseudo-accounts.
|
// with a zero sequence had better be pseudo-accounts.
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include <xrpl/protocol/TxFormats.h>
|
#include <xrpl/protocol/TxFormats.h>
|
||||||
#include <xrpl/protocol/UintTypes.h>
|
#include <xrpl/protocol/UintTypes.h>
|
||||||
#include <xrpl/protocol/XRPAmount.h>
|
#include <xrpl/protocol/XRPAmount.h>
|
||||||
|
#include <xrpl/tx/invariants/InvariantCheck.h>
|
||||||
#include <xrpl/tx/invariants/InvariantCheckPrivilege.h>
|
#include <xrpl/tx/invariants/InvariantCheckPrivilege.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -41,6 +42,7 @@ constexpr auto kConfidentialMptTxTypes = std::to_array<TxType>({
|
|||||||
ttCONFIDENTIAL_MPT_MERGE_INBOX,
|
ttCONFIDENTIAL_MPT_MERGE_INBOX,
|
||||||
ttCONFIDENTIAL_MPT_CLAWBACK,
|
ttCONFIDENTIAL_MPT_CLAWBACK,
|
||||||
ttCONFIDENTIAL_MPT_MIRROR_UPDATE,
|
ttCONFIDENTIAL_MPT_MIRROR_UPDATE,
|
||||||
|
ttCONFIDENTIAL_MPT_HOLDER_KEY_UPDATE,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clamp to the cap (== INT64_MAX) before the signed conversion. Invariant
|
// Clamp to the cap (== INT64_MAX) before the signed conversion. Invariant
|
||||||
@@ -73,7 +75,7 @@ ValidMPTIssuance::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef
|
|||||||
// only meaningful post-fixCleanup3_2_0 (the field is never set
|
// only meaningful post-fixCleanup3_2_0 (the field is never set
|
||||||
// pre-amendment, and the holding-deletion rule does not apply).
|
// pre-amendment, and the holding-deletion rule does not apply).
|
||||||
// Skip both blocks when the amendment is off so we avoid wasted work
|
// Skip both blocks when the amendment is off so we avoid wasted work
|
||||||
// on the hot path.
|
// on the hot path, except where noted for fixCleanup3_5_0 below.
|
||||||
bool const fix320Enabled = isFeatureEnabled(fixCleanup3_2_0);
|
bool const fix320Enabled = isFeatureEnabled(fixCleanup3_2_0);
|
||||||
|
|
||||||
if (after && after->getType() == ltMPTOKEN_ISSUANCE)
|
if (after && after->getType() == ltMPTOKEN_ISSUANCE)
|
||||||
@@ -108,7 +110,10 @@ ValidMPTIssuance::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef
|
|||||||
if (isDelete)
|
if (isDelete)
|
||||||
{
|
{
|
||||||
mptokensDeleted_++;
|
mptokensDeleted_++;
|
||||||
if (fix320Enabled)
|
// deletedHoldings_ also feeds finalize()'s erase-time public
|
||||||
|
// balance check, gated on fixCleanup3_5_0 independently of
|
||||||
|
// fixCleanup3_2_0.
|
||||||
|
if (fix320Enabled || isFeatureEnabled(fixCleanup3_5_0))
|
||||||
deletedHoldings_.push_back(after);
|
deletedHoldings_.push_back(after);
|
||||||
}
|
}
|
||||||
else if (!before)
|
else if (!before)
|
||||||
@@ -195,6 +200,19 @@ ValidMPTIssuance::finalize(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deleting an MPToken with a non-zero MPTAmount is rejected.
|
||||||
|
if (rules.enabled(fixCleanup3_5_0))
|
||||||
|
{
|
||||||
|
for (auto const& sleHolding : deletedHoldings_)
|
||||||
|
{
|
||||||
|
if (sleHolding->getType() == ltMPTOKEN && sleHolding->getFieldU64(sfMPTAmount) > 0)
|
||||||
|
{
|
||||||
|
JLOG(j.fatal()) << "Invariant failed: MPToken deleted with non-zero balance";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isTesSuccess(result) || (mptV2Enabled && result == tecINCOMPLETE))
|
if (isTesSuccess(result) || (mptV2Enabled && result == tecINCOMPLETE))
|
||||||
{
|
{
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
@@ -579,16 +597,27 @@ ValidConfidentialMPToken::visitEntry(
|
|||||||
change.mptAmountDelta =
|
change.mptAmountDelta =
|
||||||
subtractMPTAmountDelta(change.mptAmountDelta, before->getFieldU64(sfMPTAmount));
|
subtractMPTAmountDelta(change.mptAmountDelta, before->getFieldU64(sfMPTAmount));
|
||||||
|
|
||||||
// Cannot delete MPToken with non-zero confidential state or non-zero public amount
|
// Cannot delete MPToken with non-zero confidential state.
|
||||||
if (isDelete)
|
if (isDelete)
|
||||||
{
|
{
|
||||||
bool const hasPublicBalance = before->getFieldU64(sfMPTAmount) > 0;
|
// changes_ is keyed by issuance, so sibling holders erased by the
|
||||||
bool const hasEncryptedFields = before->isFieldPresent(sfConfidentialBalanceSpending) ||
|
// same transaction share this entry. Only ever set these flags,
|
||||||
|
// never clear them, or an empty sibling visited later would mask
|
||||||
|
// a funded MPToken.
|
||||||
|
|
||||||
|
// Retired by fixCleanup3_5_0, which moved the public balance
|
||||||
|
// check to ValidMPTIssuance::finalize. Kept pre-amendment for
|
||||||
|
// consensus safety: a non-zero public balance used to feed the
|
||||||
|
// confidential gate below, rejecting the erase whenever the
|
||||||
|
// issuance's COA was non-zero, and already-validated ledgers
|
||||||
|
// depend on that.
|
||||||
|
if (!isFeatureEnabled(fixCleanup3_5_0) && before->getFieldU64(sfMPTAmount) > 0)
|
||||||
|
changes_[id].deletedWithBalanceBefore = true;
|
||||||
|
|
||||||
|
if (before->isFieldPresent(sfConfidentialBalanceSpending) ||
|
||||||
before->isFieldPresent(sfConfidentialBalanceInbox) ||
|
before->isFieldPresent(sfConfidentialBalanceInbox) ||
|
||||||
before->isFieldPresent(sfIssuerEncryptedBalance) ||
|
before->isFieldPresent(sfIssuerEncryptedBalance) ||
|
||||||
before->isFieldPresent(sfAuditorEncryptedBalance);
|
before->isFieldPresent(sfAuditorEncryptedBalance))
|
||||||
|
|
||||||
if (hasPublicBalance || hasEncryptedFields)
|
|
||||||
changes_[id].deletedWithEncrypted = true;
|
changes_[id].deletedWithEncrypted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -694,6 +723,8 @@ ValidConfidentialMPToken::finalize(
|
|||||||
if (result != tesSUCCESS)
|
if (result != tesSUCCESS)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
bool const fix350Enabled = view.rules().enabled(fixCleanup3_5_0);
|
||||||
|
|
||||||
for (auto const& [id, checks] : changes_)
|
for (auto const& [id, checks] : changes_)
|
||||||
{
|
{
|
||||||
// Find the MPTokenIssuance
|
// Find the MPTokenIssuance
|
||||||
@@ -708,8 +739,20 @@ ValidConfidentialMPToken::finalize(
|
|||||||
if (!issuance)
|
if (!issuance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Cannot delete MPToken with non-zero confidential state
|
// Cannot delete MPToken with non-zero confidential state.
|
||||||
if (checks.deletedWithEncrypted)
|
//
|
||||||
|
// Before fixCleanup3_5_0 this gate also absorbed the pre-transaction
|
||||||
|
// public balance, so any drain-then-erase of an MPToken -- an
|
||||||
|
// AMMWithdraw of the whole pool, a LoanBrokerDelete returning cover --
|
||||||
|
// was rejected whenever some unrelated holder of the same issuance
|
||||||
|
// held a confidential balance. The COA gate itself is correct for
|
||||||
|
// ciphertext and mirrors MPTokenAuthorize::preclaim; only the public
|
||||||
|
// balance leg was misplaced.
|
||||||
|
bool const deletedWithEncrypted = fix350Enabled
|
||||||
|
? checks.deletedWithEncrypted
|
||||||
|
: (checks.deletedWithEncrypted || checks.deletedWithBalanceBefore);
|
||||||
|
|
||||||
|
if (deletedWithEncrypted)
|
||||||
{
|
{
|
||||||
if ((*issuance)[~sfConfidentialOutstandingAmount].value_or(0) > 0)
|
if ((*issuance)[~sfConfidentialOutstandingAmount].value_or(0) > 0)
|
||||||
{
|
{
|
||||||
@@ -784,10 +827,10 @@ ValidConfidentialMPToken::finalize(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Among confidential MPT transactions, only ConfidentialMPTSend and
|
// Reaching here means this confidential MPT transaction left coaDelta
|
||||||
// ConfidentialMPTMergeInbox leave coaDelta unmodified. Therefore, if a confidential MPT
|
// unmodified (e.g. ConfidentialMPTSend, ConfidentialMPTMergeInbox, or
|
||||||
// transaction reaches here, it must be one of these two types, neither of which will
|
// ConfidentialMPTHolderKeyUpdate/ConfidentialMPTMirrorUpdate, none of which touch
|
||||||
// modify sfOutstandingAmount
|
// sfConfidentialOutstandingAmount), so it must not modify sfOutstandingAmount either.
|
||||||
if (checks.outstandingDelta != 0)
|
if (checks.outstandingDelta != 0)
|
||||||
{
|
{
|
||||||
JLOG(j.fatal()) << "Invariant failed: OutstandingAmount changed "
|
JLOG(j.fatal()) << "Invariant failed: OutstandingAmount changed "
|
||||||
@@ -851,7 +894,7 @@ ValidMPTTransfer::visitEntry(
|
|||||||
// no trace of its pseudo-account status in the post-transaction view
|
// no trace of its pseudo-account status in the post-transaction view
|
||||||
// isAuthorized() sees at finalize() time.
|
// isAuthorized() sees at finalize() time.
|
||||||
if (before && before->getType() == ltACCOUNT_ROOT)
|
if (before && before->getType() == ltACCOUNT_ROOT)
|
||||||
pseudoAccountsBefore_[before->at(sfAccount)] = isPseudoAccount(before);
|
pseudoAccountsBefore_[before->at(sfAccount)] = isPseudoAccountSle(before);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|||||||
@@ -740,7 +740,7 @@ ValidVault::finalize(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isPseudoAccount(sleSharesIssuer))
|
if (!isPseudoAccount(AccountRootEntryR(sleSharesIssuer, view)))
|
||||||
{
|
{
|
||||||
JLOG(j.fatal()) //
|
JLOG(j.fatal()) //
|
||||||
<< "Invariant failed: shares issuer must be a "
|
<< "Invariant failed: shares issuer must be a "
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
@@ -836,7 +837,7 @@ DirectStepI<TDerived>::check(StrandContext const& ctx) const
|
|||||||
return temBAD_PATH;
|
return temBAD_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleSrc = ctx.view.read(keylet::account(src_));
|
auto const sleSrc = AccountRootEntryR(src_, ctx.view);
|
||||||
if (!sleSrc)
|
if (!sleSrc)
|
||||||
{
|
{
|
||||||
JLOG(j_.warn()) << "DirectStepI: can't receive IOUs from non-existent issuer: " << src_;
|
JLOG(j_.warn()) << "DirectStepI: can't receive IOUs from non-existent issuer: " << src_;
|
||||||
@@ -902,7 +903,7 @@ DirectStepI<TDerived>::check(StrandContext const& ctx) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<TDerived const*>(this)->check(ctx, sleSrc);
|
return static_cast<TDerived const*>(this)->check(ctx, sleSrc.rawSle());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -865,7 +866,7 @@ MPTEndpointStep<TDerived>::check(StrandContext const& ctx) const
|
|||||||
return temBAD_PATH;
|
return temBAD_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleSrc = ctx.view.read(keylet::account(src_));
|
auto const sleSrc = AccountRootEntryR(src_, ctx.view);
|
||||||
if (!sleSrc)
|
if (!sleSrc)
|
||||||
{
|
{
|
||||||
JLOG(j_.warn()) << "MPTEndpointStep: can't receive MPT from non-existent issuer: " << src_;
|
JLOG(j_.warn()) << "MPTEndpointStep: can't receive MPT from non-existent issuer: " << src_;
|
||||||
@@ -928,7 +929,7 @@ MPTEndpointStep<TDerived>::check(StrandContext const& ctx) const
|
|||||||
return temBAD_PATH;
|
return temBAD_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<TDerived const*>(this)->check(ctx, sleSrc);
|
return static_cast<TDerived const*>(this)->check(ctx, sleSrc.rawSle());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class TDerived>
|
template <class TDerived>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -342,7 +343,7 @@ XRPEndpointStep<TDerived>::check(StrandContext const& ctx) const
|
|||||||
return temBAD_PATH;
|
return temBAD_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sleAcc = ctx.view.read(keylet::account(acc_));
|
auto sleAcc = AccountRootEntryR(acc_, ctx.view);
|
||||||
if (!sleAcc)
|
if (!sleAcc)
|
||||||
{
|
{
|
||||||
JLOG(j_.warn()) << "XRPEndpointStep: can't send or receive XRP from "
|
JLOG(j_.warn()) << "XRPEndpointStep: can't send or receive XRP from "
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||||
@@ -224,7 +225,7 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
|
|||||||
AccountID const account{ctx.tx[sfAccount]};
|
AccountID const account{ctx.tx[sfAccount]};
|
||||||
AccountID const dst{ctx.tx[sfDestination]};
|
AccountID const dst{ctx.tx[sfDestination]};
|
||||||
|
|
||||||
auto sleDst = ctx.view.read(keylet::account(dst));
|
auto sleDst = AccountRootEntryR(dst, ctx.view);
|
||||||
|
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
@@ -250,7 +251,7 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sleAccount = ctx.view.read(keylet::account(account));
|
auto sleAccount = AccountRootEntryR(account, ctx.view);
|
||||||
XRPL_ASSERT(sleAccount, "xrpl::AccountDelete::preclaim : non-null account");
|
XRPL_ASSERT(sleAccount, "xrpl::AccountDelete::preclaim : non-null account");
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
@@ -353,11 +354,11 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
AccountDelete::doApply()
|
AccountDelete::doApply()
|
||||||
{
|
{
|
||||||
auto src = view().peek(keylet::account(accountID_));
|
auto src = AccountRootEntryW(accountID_, view());
|
||||||
XRPL_ASSERT(src, "xrpl::AccountDelete::doApply : non-null source account");
|
XRPL_ASSERT(src, "xrpl::AccountDelete::doApply : non-null source account");
|
||||||
|
|
||||||
auto const dstID = ctx_.tx[sfDestination];
|
auto const dstID = ctx_.tx[sfDestination];
|
||||||
auto dst = view().peek(keylet::account(dstID));
|
auto dst = AccountRootEntryW(dstID, view());
|
||||||
XRPL_ASSERT(dst, "xrpl::AccountDelete::doApply : non-null destination account");
|
XRPL_ASSERT(dst, "xrpl::AccountDelete::doApply : non-null destination account");
|
||||||
|
|
||||||
if (!src || !dst)
|
if (!src || !dst)
|
||||||
@@ -365,8 +366,8 @@ AccountDelete::doApply()
|
|||||||
|
|
||||||
if (ctx_.tx.isFieldPresent(sfCredentialIDs))
|
if (ctx_.tx.isFieldPresent(sfCredentialIDs))
|
||||||
{
|
{
|
||||||
if (auto err =
|
if (auto err = verifyDepositPreauth(
|
||||||
verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dstID, dst, ctx_.journal);
|
ctx_.tx, ctx_.view(), accountID_, dstID, dst.rawSle(), ctx_.journal);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -407,7 +408,7 @@ AccountDelete::doApply()
|
|||||||
if (src->isFieldPresent(sfSponsor))
|
if (src->isFieldPresent(sfSponsor))
|
||||||
{
|
{
|
||||||
auto const sponsorID = src->getAccountID(sfSponsor);
|
auto const sponsorID = src->getAccountID(sfSponsor);
|
||||||
auto sponsorSle = view().peek(keylet::account(sponsorID));
|
auto sponsorSle = AccountRootEntryW(sponsorID, view());
|
||||||
|
|
||||||
if (!sponsorSle)
|
if (!sponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
@@ -425,7 +426,7 @@ AccountDelete::doApply()
|
|||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
sponsorSle->at(sfSponsoringAccountCount) = sponsoringAccountCount - 1;
|
sponsorSle->at(sfSponsoringAccountCount) = sponsoringAccountCount - 1;
|
||||||
view().update(sponsorSle);
|
sponsorSle.update();
|
||||||
|
|
||||||
// Following line might look redundant, but without it, sfSponsor
|
// Following line might look redundant, but without it, sfSponsor
|
||||||
// would end up remaining in after-ltAccountRoot during the
|
// would end up remaining in after-ltAccountRoot during the
|
||||||
@@ -448,8 +449,8 @@ AccountDelete::doApply()
|
|||||||
if (remainingBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent))
|
if (remainingBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent))
|
||||||
dst->clearFlag(lsfPasswordSpent);
|
dst->clearFlag(lsfPasswordSpent);
|
||||||
|
|
||||||
view().update(dst);
|
dst.update();
|
||||||
view().erase(src);
|
src.erase();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
@@ -170,7 +171,7 @@ AccountSet::preclaim(PreclaimContext const& ctx)
|
|||||||
{
|
{
|
||||||
auto const id = ctx.tx[sfAccount];
|
auto const id = ctx.tx[sfAccount];
|
||||||
|
|
||||||
auto const sle = ctx.view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, ctx.view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
@@ -224,7 +225,7 @@ AccountSet::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
AccountSet::doApply()
|
AccountSet::doApply()
|
||||||
{
|
{
|
||||||
auto const sle = view().peek(keylet::account(accountID_));
|
auto sle = AccountRootEntryW(accountID_, view());
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -582,7 +583,7 @@ AccountSet::doApply()
|
|||||||
if (uFlagsIn != uFlagsOut)
|
if (uFlagsIn != uFlagsOut)
|
||||||
sle->setFieldU32(sfFlags, uFlagsOut);
|
sle->setFieldU32(sfFlags, uFlagsOut);
|
||||||
|
|
||||||
ctx_.view().update(sle);
|
sle.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/basics/Slice.h>
|
#include <xrpl/basics/Slice.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/LedgerFormats.h>
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
#include <xrpl/protocol/PublicKey.h>
|
#include <xrpl/protocol/PublicKey.h>
|
||||||
@@ -25,7 +26,7 @@ SetRegularKey::calculateBaseFee(ReadView const& view, STTx const& tx)
|
|||||||
{
|
{
|
||||||
if (calcAccountID(PublicKey(makeSlice(spk))) == id)
|
if (calcAccountID(PublicKey(makeSlice(spk))) == id)
|
||||||
{
|
{
|
||||||
auto const sle = view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, view);
|
||||||
|
|
||||||
if (sle && !sle->isFlag(lsfPasswordSpent))
|
if (sle && !sle->isFlag(lsfPasswordSpent))
|
||||||
{
|
{
|
||||||
@@ -53,7 +54,7 @@ SetRegularKey::preflight(PreflightContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
SetRegularKey::doApply()
|
SetRegularKey::doApply()
|
||||||
{
|
{
|
||||||
auto const sle = view().peek(keylet::account(accountID_));
|
auto sle = AccountRootEntryW(accountID_, view());
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ SetRegularKey::doApply()
|
|||||||
sle->makeFieldAbsent(sfRegularKey);
|
sle->makeFieldAbsent(sfRegularKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_.view().update(sle);
|
sle.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -213,8 +214,9 @@ removeSignersFromLedger(
|
|||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountRootEntryW accountSle(accountKeylet, view);
|
||||||
decreaseOwnerCountForObject(
|
decreaseOwnerCountForObject(
|
||||||
view, view.peek(accountKeylet), signers, removeFromOwnerCount, registry.getJournal("View"));
|
view, accountSle, signers, removeFromOwnerCount, registry.getJournal("View"));
|
||||||
|
|
||||||
view.erase(signers);
|
view.erase(signers);
|
||||||
|
|
||||||
@@ -309,7 +311,7 @@ SignerListSet::replaceSignerList()
|
|||||||
ctx_.registry, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_))
|
ctx_.registry, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_))
|
||||||
return ter;
|
return ter;
|
||||||
|
|
||||||
auto const sle = view().peek(accountKeylet);
|
auto sle = AccountRootEntryW(accountKeylet, view(), ctx_.journal);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -319,12 +321,8 @@ SignerListSet::replaceSignerList()
|
|||||||
// We check the reserve against the starting balance because we want to
|
// We check the reserve against the starting balance because we want to
|
||||||
// allow dipping into the reserve to pay fees. This behavior is consistent
|
// allow dipping into the reserve to pay fees. This behavior is consistent
|
||||||
// with TicketCreate.
|
// with TicketCreate.
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = kAddedOwnerCount});
|
||||||
sle,
|
|
||||||
preFeeBalance_,
|
|
||||||
{.ownerCountDelta = kAddedOwnerCount},
|
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -333,7 +331,6 @@ SignerListSet::replaceSignerList()
|
|||||||
view().insert(signerList);
|
view().insert(signerList);
|
||||||
writeSignersToSLE(signerList, flags);
|
writeSignersToSLE(signerList, flags);
|
||||||
|
|
||||||
auto viewJ = ctx_.registry.get().getJournal("View");
|
|
||||||
// Add the signer list to the account's directory.
|
// Add the signer list to the account's directory.
|
||||||
auto const page =
|
auto const page =
|
||||||
ctx_.view().dirInsert(ownerDirKeylet, signerListKeylet, describeOwnerDir(accountID_));
|
ctx_.view().dirInsert(ownerDirKeylet, signerListKeylet, describeOwnerDir(accountID_));
|
||||||
@@ -348,7 +345,7 @@ SignerListSet::replaceSignerList()
|
|||||||
|
|
||||||
// If we succeeded, the new entry counts against the
|
// If we succeeded, the new entry counts against the
|
||||||
// creator's reserve.
|
// creator's reserve.
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, kAddedOwnerCount, viewJ);
|
sle.increaseOwnerCount(ctx_.getApplyViewContext(), kAddedOwnerCount);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), signerList);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), signerList);
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
@@ -359,7 +356,7 @@ SignerListSet::destroySignerList()
|
|||||||
auto const accountKeylet = keylet::account(accountID_);
|
auto const accountKeylet = keylet::account(accountID_);
|
||||||
// Destroying the signer list is only allowed if either the master key
|
// Destroying the signer list is only allowed if either the master key
|
||||||
// is enabled or there is a regular key.
|
// is enabled or there is a regular key.
|
||||||
SLE::pointer const ledgerEntry = view().peek(accountKeylet);
|
auto const ledgerEntry = AccountRootEntryW(accountKeylet, view());
|
||||||
if (!ledgerEntry)
|
if (!ledgerEntry)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
#include <xrpl/ledger/RawView.h>
|
#include <xrpl/ledger/RawView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -125,8 +126,7 @@ checkAttestationPublicKey(
|
|||||||
|
|
||||||
AccountID const accountFromPK = calcAccountID(pk);
|
AccountID const accountFromPK = calcAccountID(pk);
|
||||||
|
|
||||||
if (auto const sleAttestationSigningAccount =
|
if (auto const sleAttestationSigningAccount = AccountRootEntryR(attestationSignerAccount, view))
|
||||||
view.read(keylet::account(attestationSignerAccount)))
|
|
||||||
{
|
{
|
||||||
if (accountFromPK == attestationSignerAccount)
|
if (accountFromPK == attestationSignerAccount)
|
||||||
{
|
{
|
||||||
@@ -404,7 +404,7 @@ transferHelper(
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|
||||||
auto const dstK = keylet::account(dst);
|
auto const dstK = keylet::account(dst);
|
||||||
if (auto sleDst = psb.read(dstK))
|
if (auto sleDst = AccountRootEntryR(dstK, psb))
|
||||||
{
|
{
|
||||||
// Check dst tag and deposit auth
|
// Check dst tag and deposit auth
|
||||||
|
|
||||||
@@ -430,13 +430,13 @@ transferHelper(
|
|||||||
|
|
||||||
if (amt.native())
|
if (amt.native())
|
||||||
{
|
{
|
||||||
auto const sleSrc = psb.peek(keylet::account(src));
|
auto sleSrc = AccountRootEntryW(src, psb, j);
|
||||||
XRPL_ASSERT(sleSrc, "xrpl::transferHelper : non-null source account");
|
XRPL_ASSERT(sleSrc, "xrpl::transferHelper : non-null source account");
|
||||||
if (!sleSrc)
|
if (!sleSrc)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const reserve = accountReserve(psb, sleSrc, j);
|
auto const reserve = sleSrc.reserve();
|
||||||
|
|
||||||
auto const availableBalance = [&]() -> STAmount {
|
auto const availableBalance = [&]() -> STAmount {
|
||||||
STAmount curBal = (*sleSrc)[sfBalance];
|
STAmount curBal = (*sleSrc)[sfBalance];
|
||||||
@@ -455,7 +455,7 @@ transferHelper(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sleDst = psb.peek(dstK);
|
auto sleDst = AccountRootEntryW(dstK, psb);
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
{
|
{
|
||||||
if (canCreate == CanCreateDstPolicy::No)
|
if (canCreate == CanCreateDstPolicy::No)
|
||||||
@@ -470,17 +470,17 @@ transferHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the account.
|
// Create the account.
|
||||||
sleDst = std::make_shared<SLE>(dstK);
|
sleDst.newSLE();
|
||||||
sleDst->setAccountID(sfAccount, dst);
|
sleDst->setAccountID(sfAccount, dst);
|
||||||
sleDst->setFieldU32(sfSequence, psb.seq());
|
sleDst->setFieldU32(sfSequence, psb.seq());
|
||||||
|
|
||||||
psb.insert(sleDst);
|
sleDst.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
(*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
|
(*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
|
||||||
(*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
|
(*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
|
||||||
psb.update(sleSrc);
|
sleSrc.update();
|
||||||
psb.update(sleDst);
|
sleDst.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
@@ -724,7 +724,7 @@ finalizeClaimHelper(
|
|||||||
auto const cidOwner = (*sleClaimID)[sfAccount];
|
auto const cidOwner = (*sleClaimID)[sfAccount];
|
||||||
{
|
{
|
||||||
// Remove the claim id
|
// Remove the claim id
|
||||||
auto const sleOwner = outerSb.peek(keylet::account(cidOwner));
|
auto sleOwner = AccountRootEntryW(cidOwner, outerSb);
|
||||||
auto const page = (*sleClaimID)[sfOwnerNode];
|
auto const page = (*sleClaimID)[sfOwnerNode];
|
||||||
if (!outerSb.dirRemove(keylet::ownerDir(cidOwner), page, sleClaimID->key(), true))
|
if (!outerSb.dirRemove(keylet::ownerDir(cidOwner), page, sleClaimID->key(), true))
|
||||||
{
|
{
|
||||||
@@ -759,7 +759,7 @@ getSignersListAndQuorum(ReadView const& view, SLE const& sleBridge, beast::Journ
|
|||||||
std::uint32_t q = std::numeric_limits<std::uint32_t>::max();
|
std::uint32_t q = std::numeric_limits<std::uint32_t>::max();
|
||||||
|
|
||||||
AccountID const thisDoor = sleBridge[sfAccount];
|
AccountID const thisDoor = sleBridge[sfAccount];
|
||||||
auto const sleDoor = [&] { return view.read(keylet::account(thisDoor)); }();
|
auto const sleDoor = [&] { return AccountRootEntryR(thisDoor, view); }();
|
||||||
|
|
||||||
if (!sleDoor)
|
if (!sleDoor)
|
||||||
{
|
{
|
||||||
@@ -1036,7 +1036,7 @@ applyCreateAccountAttestations(
|
|||||||
|
|
||||||
// Check reserve
|
// Check reserve
|
||||||
auto const balance = (*sleDoor)[sfBalance];
|
auto const balance = (*sleDoor)[sfBalance];
|
||||||
auto const reserve = accountReserve(psb, sleDoor, j, {.ownerCountDelta = 1});
|
auto const reserve = AccountRootEntryR(sleDoor, psb, j).reserve({.ownerCountDelta = 1});
|
||||||
|
|
||||||
if (balance < reserve)
|
if (balance < reserve)
|
||||||
return std::unexpected(tecINSUFFICIENT_RESERVE);
|
return std::unexpected(tecINSUFFICIENT_RESERVE);
|
||||||
@@ -1145,7 +1145,9 @@ applyCreateAccountAttestations(
|
|||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Reserve was already checked
|
// Reserve was already checked
|
||||||
increaseOwnerCount(psb, sleDoor, {}, 1, j);
|
AccountRootEntryW doorSle(doorK, psb, j);
|
||||||
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
doorSle.increaseOwnerCount(noSponsor, 1);
|
||||||
psb.insert(createdSleClaimID);
|
psb.insert(createdSleClaimID);
|
||||||
psb.update(sleDoor);
|
psb.update(sleDoor);
|
||||||
}
|
}
|
||||||
@@ -1429,7 +1431,7 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
if (!isXRP(bridgeSpec.issue(chainType)))
|
if (!isXRP(bridgeSpec.issue(chainType)))
|
||||||
{
|
{
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(bridgeSpec.issue(chainType).account));
|
auto const sleIssuer = AccountRootEntryR(bridgeSpec.issue(chainType).account, ctx.view);
|
||||||
|
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
return tecNO_ISSUER;
|
return tecNO_ISSUER;
|
||||||
@@ -1442,12 +1444,12 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Check reserve
|
// Check reserve
|
||||||
auto const sleAcc = ctx.view.read(keylet::account(account));
|
auto const sleAcc = AccountRootEntryR(account, ctx.view, ctx.j);
|
||||||
if (!sleAcc)
|
if (!sleAcc)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
auto const balance = (*sleAcc)[sfBalance];
|
auto const balance = (*sleAcc)[sfBalance];
|
||||||
auto const reserve = accountReserve(ctx.view, sleAcc, ctx.j, {.ownerCountDelta = 1});
|
auto const reserve = sleAcc.reserve({.ownerCountDelta = 1});
|
||||||
|
|
||||||
if (balance < reserve)
|
if (balance < reserve)
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
@@ -1464,7 +1466,7 @@ XChainCreateBridge::doApply()
|
|||||||
auto const reward = ctx_.tx[sfSignatureReward];
|
auto const reward = ctx_.tx[sfSignatureReward];
|
||||||
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
|
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
|
||||||
|
|
||||||
auto const sleAcct = ctx_.view().peek(keylet::account(account));
|
auto sleAcct = AccountRootEntryW(account, ctx_.view(), ctx_.journal);
|
||||||
if (!sleAcct)
|
if (!sleAcct)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -1492,10 +1494,11 @@ XChainCreateBridge::doApply()
|
|||||||
(*sleBridge)[sfOwnerNode] = *page;
|
(*sleBridge)[sfOwnerNode] = *page;
|
||||||
}
|
}
|
||||||
|
|
||||||
increaseOwnerCount(ctx_.view(), sleAcct, {}, 1, ctx_.journal);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
sleAcct.increaseOwnerCount(noSponsor, 1);
|
||||||
|
|
||||||
ctx_.view().insert(sleBridge);
|
ctx_.view().insert(sleBridge);
|
||||||
ctx_.view().update(sleAcct);
|
sleAcct.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
@@ -1575,7 +1578,7 @@ BridgeModify::doApply()
|
|||||||
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
|
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
|
||||||
bool const clearAccountCreate = ctx_.tx.isFlag(tfClearAccountCreateAmount);
|
bool const clearAccountCreate = ctx_.tx.isFlag(tfClearAccountCreateAmount);
|
||||||
|
|
||||||
auto const sleAcct = ctx_.view().peek(keylet::account(account));
|
auto const sleAcct = AccountRootEntryW(account, ctx_.view());
|
||||||
if (!sleAcct)
|
if (!sleAcct)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -1633,7 +1636,7 @@ XChainClaim::preclaim(PreclaimContext const& ctx)
|
|||||||
return tecNO_ENTRY;
|
return tecNO_ENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.view.read(keylet::account(ctx.tx[sfDestination])))
|
if (!AccountRootEntryR(ctx.tx[sfDestination], ctx.view))
|
||||||
{
|
{
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
}
|
}
|
||||||
@@ -1738,7 +1741,7 @@ XChainClaim::doApply()
|
|||||||
// `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child
|
// `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child
|
||||||
// views, it's important that the sle's lifetime doesn't overlap.
|
// views, it's important that the sle's lifetime doesn't overlap.
|
||||||
|
|
||||||
auto const sleAcct = psb.peek(keylet::account(account));
|
auto const sleAcct = AccountRootEntryW(account, psb);
|
||||||
auto const sleBridge = peekBridge(psb, bridgeSpec);
|
auto const sleBridge = peekBridge(psb, bridgeSpec);
|
||||||
auto const sleClaimID = psb.peek(claimIDKeylet);
|
auto const sleClaimID = psb.peek(claimIDKeylet);
|
||||||
|
|
||||||
@@ -1919,7 +1922,7 @@ XChainCommit::doApply()
|
|||||||
auto const amount = ctx_.tx[sfAmount];
|
auto const amount = ctx_.tx[sfAmount];
|
||||||
auto const bridgeSpec = ctx_.tx[sfXChainBridge];
|
auto const bridgeSpec = ctx_.tx[sfXChainBridge];
|
||||||
|
|
||||||
auto const sleAccount = psb.read(keylet::account(account));
|
auto const sleAccount = AccountRootEntryR(account, psb);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -1990,12 +1993,12 @@ XChainCreateClaimID::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Check reserve
|
// Check reserve
|
||||||
auto const sleAcc = ctx.view.read(keylet::account(account));
|
auto const sleAcc = AccountRootEntryR(account, ctx.view, ctx.j);
|
||||||
if (!sleAcc)
|
if (!sleAcc)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
auto const balance = (*sleAcc)[sfBalance];
|
auto const balance = (*sleAcc)[sfBalance];
|
||||||
auto const reserve = accountReserve(ctx.view, sleAcc, ctx.j, {.ownerCountDelta = 1});
|
auto const reserve = sleAcc.reserve({.ownerCountDelta = 1});
|
||||||
if (balance < reserve)
|
if (balance < reserve)
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
}
|
}
|
||||||
@@ -2011,7 +2014,7 @@ XChainCreateClaimID::doApply()
|
|||||||
auto const reward = ctx_.tx[sfSignatureReward];
|
auto const reward = ctx_.tx[sfSignatureReward];
|
||||||
auto const otherChainSrc = ctx_.tx[sfOtherChainSource];
|
auto const otherChainSrc = ctx_.tx[sfOtherChainSource];
|
||||||
|
|
||||||
auto const sleAcct = ctx_.view().peek(keylet::account(account));
|
auto sleAcct = AccountRootEntryW(account, ctx_.view(), ctx_.journal);
|
||||||
if (!sleAcct)
|
if (!sleAcct)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -2053,11 +2056,12 @@ XChainCreateClaimID::doApply()
|
|||||||
(*sleClaimID)[sfOwnerNode] = *page;
|
(*sleClaimID)[sfOwnerNode] = *page;
|
||||||
}
|
}
|
||||||
|
|
||||||
increaseOwnerCount(ctx_.view(), sleAcct, {}, 1, ctx_.journal);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
sleAcct.increaseOwnerCount(noSponsor, 1);
|
||||||
|
|
||||||
ctx_.view().insert(sleClaimID);
|
ctx_.view().insert(sleClaimID);
|
||||||
ctx_.view().update(sleBridge);
|
ctx_.view().update(sleBridge);
|
||||||
ctx_.view().update(sleAcct);
|
sleAcct.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
@@ -2195,7 +2199,7 @@ XChainCreateAccountCommit::doApply()
|
|||||||
STAmount const reward = ctx_.tx[sfSignatureReward];
|
STAmount const reward = ctx_.tx[sfSignatureReward];
|
||||||
STXChainBridge const bridge = ctx_.tx[sfXChainBridge];
|
STXChainBridge const bridge = ctx_.tx[sfXChainBridge];
|
||||||
|
|
||||||
auto const sle = psb.peek(keylet::account(account));
|
auto const sle = AccountRootEntryW(account, psb);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
@@ -112,8 +113,8 @@ CheckCash::preclaim(PreclaimContext const& ctx)
|
|||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto const sleSrc = ctx.view.read(keylet::account(srcId));
|
auto const sleSrc = AccountRootEntryR(srcId, ctx.view);
|
||||||
auto const sleDst = ctx.view.read(keylet::account(dstId));
|
auto const sleDst = AccountRootEntryR(dstId, ctx.view);
|
||||||
if (!sleSrc || !sleDst)
|
if (!sleSrc || !sleDst)
|
||||||
{
|
{
|
||||||
// If the check exists this should never occur.
|
// If the check exists this should never occur.
|
||||||
@@ -201,7 +202,7 @@ CheckCash::preclaim(PreclaimContext const& ctx)
|
|||||||
auto const sleTrustLine =
|
auto const sleTrustLine =
|
||||||
ctx.view.read(keylet::trustLine(dstId, issuerId, currency));
|
ctx.view.read(keylet::trustLine(dstId, issuerId, currency));
|
||||||
|
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
|
auto const sleIssuer = AccountRootEntryR(issuerId, ctx.view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.warn()) << "Can't receive IOUs from "
|
JLOG(ctx.j.warn()) << "Can't receive IOUs from "
|
||||||
@@ -253,7 +254,7 @@ CheckCash::preclaim(PreclaimContext const& ctx)
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
},
|
},
|
||||||
[&](MPTIssue const& issue) -> TER {
|
[&](MPTIssue const& issue) -> TER {
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
|
auto const sleIssuer = AccountRootEntryR(issuerId, ctx.view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.warn()) << "Can't receive MPTs from "
|
JLOG(ctx.j.warn()) << "Can't receive MPTs from "
|
||||||
@@ -406,23 +407,18 @@ CheckCash::doApply()
|
|||||||
optDeliverMin ? maxDeliverMin() : ctx_.tx.getFieldAmount(sfAmount)};
|
optDeliverMin ? maxDeliverMin() : ctx_.tx.getFieldAmount(sfAmount)};
|
||||||
|
|
||||||
auto applyViewContext = ApplyViewContext({.view = psb, .tx = ctx_.tx});
|
auto applyViewContext = ApplyViewContext({.view = psb, .tx = ctx_.tx});
|
||||||
auto const sponsorSle = getTxReserveSponsor(applyViewContext);
|
auto sponsorSle = getTxReserveSponsor(applyViewContext);
|
||||||
if (!sponsorSle)
|
if (!sponsorSle)
|
||||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Check reserve. Return destination account SLE if enough reserve,
|
// Check reserve. Return destination account SLE if enough reserve,
|
||||||
// otherwise return nullptr.
|
// otherwise return nullptr.
|
||||||
auto checkDstReserve = [&]() -> SLE::pointer {
|
auto checkDstReserve = [&]() -> SLE::pointer {
|
||||||
auto sleDst = psb.peek(keylet::account(accountID_));
|
auto sleDst = AccountRootEntryW(accountID_, psb, j_);
|
||||||
|
|
||||||
// Can the account cover the trust line's or MPT reserve?
|
// Can the account cover the trust line's or MPT reserve?
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sleDst.checkReserve(
|
||||||
applyViewContext,
|
applyViewContext, preFeeBalance_, *sponsorSle, {.ownerCountDelta = 1});
|
||||||
sleDst,
|
|
||||||
preFeeBalance_,
|
|
||||||
*sponsorSle,
|
|
||||||
{.ownerCountDelta = 1},
|
|
||||||
j_);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
{
|
{
|
||||||
JLOG(j_.trace()) << "Trust line does not exist. "
|
JLOG(j_.trace()) << "Trust line does not exist. "
|
||||||
@@ -430,7 +426,7 @@ CheckCash::doApply()
|
|||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return sleDst;
|
return sleDst.mutableRawSle();
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<Keylet> trustLineKey;
|
std::optional<Keylet> trustLineKey;
|
||||||
@@ -486,8 +482,10 @@ CheckCash::doApply()
|
|||||||
Issue(currency, accountID_), // limit of zero
|
Issue(currency, accountID_), // limit of zero
|
||||||
0, // quality in
|
0, // quality in
|
||||||
0, // quality out
|
0, // quality out
|
||||||
*sponsorSle, // sponsor
|
sponsorSle->has_value() // sponsor
|
||||||
viewJ); // journal
|
? (*sponsorSle)->mutableRawSle()
|
||||||
|
: SLE::pointer{},
|
||||||
|
viewJ); // journal
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
{
|
{
|
||||||
return ter;
|
return ter;
|
||||||
@@ -533,8 +531,14 @@ CheckCash::doApply()
|
|||||||
if (sleDst == nullptr)
|
if (sleDst == nullptr)
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
|
|
||||||
if (auto const err =
|
if (auto const err = checkCreateMPT(
|
||||||
checkCreateMPT(psb, mptID, accountID_, *sponsorSle, 0, j_);
|
psb,
|
||||||
|
mptID,
|
||||||
|
accountID_,
|
||||||
|
sponsorSle->has_value() ? (*sponsorSle)->mutableRawSle()
|
||||||
|
: SLE::pointer{},
|
||||||
|
0,
|
||||||
|
j_);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
{
|
{
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
@@ -79,7 +80,7 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
{
|
{
|
||||||
AccountID const dstId{ctx.tx[sfDestination]};
|
AccountID const dstId{ctx.tx[sfDestination]};
|
||||||
AccountID const srcId{ctx.tx[sfAccount]};
|
AccountID const srcId{ctx.tx[sfAccount]};
|
||||||
auto const sleDst = ctx.view.read(keylet::account(dstId));
|
auto const sleDst = AccountRootEntryR(dstId, ctx.view);
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.warn()) << "Destination account does not exist.";
|
JLOG(ctx.j.warn()) << "Destination account does not exist.";
|
||||||
@@ -187,15 +188,15 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
CheckCreate::doApply()
|
CheckCreate::doApply()
|
||||||
{
|
{
|
||||||
auto const sle = view().peek(keylet::account(accountID_));
|
auto sle = AccountRootEntryW(accountID_, view(), ctx_.journal);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// A check counts against the reserve of the issuing account, but we
|
// A check counts against the reserve of the issuing account, but we
|
||||||
// check the starting balance because we want to allow dipping into the
|
// check the starting balance because we want to allow dipping into the
|
||||||
// reserve to pay fees.
|
// reserve to pay fees.
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret =
|
||||||
ctx_.getApplyViewContext(), sle, preFeeBalance_, {.ownerCountDelta = 1}, ctx_.journal);
|
sle.checkReserve(ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
// Note that we use the value from the sequence or ticket as the
|
// Note that we use the value from the sequence or ticket as the
|
||||||
@@ -220,7 +221,6 @@ CheckCreate::doApply()
|
|||||||
|
|
||||||
view().insert(sleCheck);
|
view().insert(sleCheck);
|
||||||
|
|
||||||
auto viewJ = ctx_.registry.get().getJournal("View");
|
|
||||||
// If it's not a self-send (and it shouldn't be), add Check to the
|
// If it's not a self-send (and it shouldn't be), add Check to the
|
||||||
// destination's owner directory.
|
// destination's owner directory.
|
||||||
if (dstAccountId != accountID_)
|
if (dstAccountId != accountID_)
|
||||||
@@ -251,7 +251,7 @@ CheckCreate::doApply()
|
|||||||
}
|
}
|
||||||
// If we succeeded, the new entry counts against the creator's reserve.
|
// If we succeeded, the new entry counts against the creator's reserve.
|
||||||
|
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, viewJ);
|
sle.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCheck);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCheck);
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -87,8 +88,8 @@ CredentialAccept::doApply()
|
|||||||
AccountID const issuer{ctx_.tx[sfIssuer]};
|
AccountID const issuer{ctx_.tx[sfIssuer]};
|
||||||
|
|
||||||
// Both exist as credential object exist itself (checked in preclaim)
|
// Both exist as credential object exist itself (checked in preclaim)
|
||||||
auto const sleSubject = view().peek(keylet::account(accountID_));
|
auto sleSubject = AccountRootEntryW(accountID_, view(), j_);
|
||||||
auto const sleIssuer = view().peek(keylet::account(issuer));
|
auto sleIssuer = AccountRootEntryW(issuer, view());
|
||||||
|
|
||||||
if (!sleSubject || !sleIssuer)
|
if (!sleSubject || !sleIssuer)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
@@ -97,13 +98,8 @@ CredentialAccept::doApply()
|
|||||||
if (!txSponsorSle)
|
if (!txSponsorSle)
|
||||||
return txSponsorSle.error(); // LCOV_EXCL_LINE
|
return txSponsorSle.error(); // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sleSubject.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(), preFeeBalance_, *txSponsorSle, {.ownerCountDelta = 1});
|
||||||
sleSubject,
|
|
||||||
preFeeBalance_,
|
|
||||||
*txSponsorSle,
|
|
||||||
{.ownerCountDelta = 1},
|
|
||||||
j_);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -130,7 +126,7 @@ CredentialAccept::doApply()
|
|||||||
removeSponsorFromLedgerEntry(sleCred);
|
removeSponsorFromLedgerEntry(sleCred);
|
||||||
|
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sleSubject, 1, j_);
|
sleSubject.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
|
||||||
view().update(sleCred);
|
view().update(sleCred);
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h> // IWYU pragma: keep
|
#include <xrpl/ledger/helpers/CredentialHelpers.h> // IWYU pragma: keep
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
@@ -84,7 +85,7 @@ CredentialCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
auto const credType(ctx.tx[sfCredentialType]);
|
auto const credType(ctx.tx[sfCredentialType]);
|
||||||
auto const subject = ctx.tx[sfSubject];
|
auto const subject = ctx.tx[sfSubject];
|
||||||
|
|
||||||
auto const subjectSle = ctx.view.read(keylet::account(subject));
|
auto const subjectSle = AccountRootEntryR(subject, ctx.view);
|
||||||
|
|
||||||
if (!subjectSle)
|
if (!subjectSle)
|
||||||
{
|
{
|
||||||
@@ -134,12 +135,12 @@ CredentialCreate::doApply()
|
|||||||
sleCred->setFieldU32(sfExpiration, *optExp);
|
sleCred->setFieldU32(sfExpiration, *optExp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleIssuer = view().peek(keylet::account(accountID_));
|
auto sleIssuer = AccountRootEntryW(accountID_, view(), j_);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sleIssuer.checkReserve(
|
||||||
ctx_.getApplyViewContext(), sleIssuer, preFeeBalance_, {.ownerCountDelta = 1}, j_);
|
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ CredentialCreate::doApply()
|
|||||||
return tecDIR_FULL;
|
return tecDIR_FULL;
|
||||||
sleCred->setFieldU64(sfIssuerNode, *page);
|
sleCred->setFieldU64(sfIssuerNode, *page);
|
||||||
|
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sleIssuer, 1, j_);
|
sleIssuer.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleCred);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -52,7 +53,7 @@ DelegateSet::preclaim(PreclaimContext const& ctx)
|
|||||||
if (!ctx.view.exists(keylet::account(ctx.tx[sfAccount])))
|
if (!ctx.view.exists(keylet::account(ctx.tx[sfAccount])))
|
||||||
return terNO_ACCOUNT; // LCOV_EXCL_LINE
|
return terNO_ACCOUNT; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const sleAuthorize = ctx.view.read(keylet::account(ctx.tx[sfAuthorize]));
|
auto const sleAuthorize = AccountRootEntryR(ctx.tx[sfAuthorize], ctx.view);
|
||||||
if (!sleAuthorize)
|
if (!sleAuthorize)
|
||||||
return tecNO_TARGET;
|
return tecNO_TARGET;
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ DelegateSet::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
DelegateSet::doApply()
|
DelegateSet::doApply()
|
||||||
{
|
{
|
||||||
auto const sleOwner = ctx_.view().peek(keylet::account(accountID_));
|
auto sleOwner = AccountRootEntryW(accountID_, ctx_.view(), ctx_.journal);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -98,12 +99,8 @@ DelegateSet::doApply()
|
|||||||
if (permissions.empty())
|
if (permissions.empty())
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sleOwner.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
|
||||||
sleOwner,
|
|
||||||
preFeeBalance_,
|
|
||||||
{.ownerCountDelta = 1},
|
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -133,7 +130,7 @@ DelegateSet::doApply()
|
|||||||
(*sle)[sfDestinationNode] = *destPage;
|
(*sle)[sfDestinationNode] = *destPage;
|
||||||
|
|
||||||
ctx_.view().insert(sle);
|
ctx_.view().insert(sle);
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sleOwner, 1, ctx_.journal);
|
sleOwner.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sle);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sle);
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
@@ -170,7 +167,7 @@ DelegateSet::deleteDelegate(ApplyView& view, SLE::Ref sle, beast::Journal j)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only the delegating account's owner count was incremented on creation
|
// Only the delegating account's owner count was incremented on creation
|
||||||
auto const sleOwner = view.peek(keylet::account(delegator));
|
auto sleOwner = AccountRootEntryW(delegator, view);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/Sandbox.h>
|
#include <xrpl/ledger/Sandbox.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
@@ -119,7 +120,7 @@ AMMBid::preclaim(PreclaimContext const& ctx)
|
|||||||
{
|
{
|
||||||
for (auto const& account : ctx.tx.getFieldArray(sfAuthAccounts))
|
for (auto const& account : ctx.tx.getFieldArray(sfAuthAccounts))
|
||||||
{
|
{
|
||||||
if (!ctx.view.read(keylet::account(account[sfAccount])))
|
if (!AccountRootEntryR(account[sfAccount], ctx.view))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.debug()) << "AMM Bid: Invalid Account.";
|
JLOG(ctx.j.debug()) << "AMM Bid: Invalid Account.";
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
@@ -208,7 +209,7 @@ applyBid(ApplyContext& ctx, Sandbox& sb, AccountID const& account, beast::Journa
|
|||||||
auto validOwner = [&](AccountID const& account) {
|
auto validOwner = [&](AccountID const& account) {
|
||||||
// Valid range is 0-19 but the tailing slot pays MinSlotPrice
|
// Valid range is 0-19 but the tailing slot pays MinSlotPrice
|
||||||
// and doesn't refund so the check is < instead of <= to optimize.
|
// and doesn't refund so the check is < instead of <= to optimize.
|
||||||
return timeSlot && *timeSlot < kTailingSlot && sb.read(keylet::account(account));
|
return timeSlot && *timeSlot < kTailingSlot && AccountRootEntryR(account, sb);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto updateSlot = [&](std::uint32_t fee, Number const& minPrice, Number const& burn) -> TER {
|
auto updateSlot = [&](std::uint32_t fee, Number const& minPrice, Number const& burn) -> TER {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/Sandbox.h>
|
#include <xrpl/ledger/Sandbox.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -102,11 +103,11 @@ AMMClawback::preclaim(PreclaimContext const& ctx)
|
|||||||
{
|
{
|
||||||
auto const asset = ctx.tx[sfAsset];
|
auto const asset = ctx.tx[sfAsset];
|
||||||
auto const asset2 = ctx.tx[sfAsset2];
|
auto const asset2 = ctx.tx[sfAsset2];
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
|
auto const sleIssuer = AccountRootEntryR(ctx.tx[sfAccount], ctx.view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
return terNO_ACCOUNT; // LCOV_EXCL_LINE
|
return terNO_ACCOUNT; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (!ctx.view.read(keylet::account(ctx.tx[sfHolder])))
|
if (!AccountRootEntryR(ctx.tx[sfHolder], ctx.view))
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
auto const ammSle = ctx.view.read(keylet::amm(asset, asset2));
|
auto const ammSle = ctx.view.read(keylet::amm(asset, asset2));
|
||||||
@@ -178,7 +179,7 @@ AMMClawback::applyGuts(Sandbox& sb)
|
|||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const ammAccount = (*ammSle)[sfAccount];
|
auto const ammAccount = (*ammSle)[sfAccount];
|
||||||
auto const accountSle = sb.read(keylet::account(ammAccount));
|
auto const accountSle = AccountRootEntryR(ammAccount, sb);
|
||||||
if (!accountSle)
|
if (!accountSle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/Sandbox.h>
|
#include <xrpl/ledger/Sandbox.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
@@ -133,7 +134,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
if (asset.holds<MPTIssue>() || isXRP(asset))
|
if (asset.holds<MPTIssue>() || isXRP(asset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (auto const issuerAccount = view.read(keylet::account(asset.getIssuer())))
|
if (auto const issuerAccount = AccountRootEntryR(asset.getIssuer(), view))
|
||||||
return !issuerAccount->isFlag(lsfDefaultRipple);
|
return !issuerAccount->isFlag(lsfDefaultRipple);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -173,7 +174,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto isLPToken = [&](STAmount const& amount) -> bool {
|
auto isLPToken = [&](STAmount const& amount) -> bool {
|
||||||
if (auto const sle = ctx.view.read(keylet::account(amount.asset().getIssuer())))
|
if (auto const sle = AccountRootEntryR(amount.asset().getIssuer(), ctx.view))
|
||||||
return sle->isFieldPresent(sfAMMID);
|
return sle->isFieldPresent(sfAMMID);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -237,7 +238,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
[&](Issue const& issue) -> TER {
|
[&](Issue const& issue) -> TER {
|
||||||
if (isXRP(issue))
|
if (isXRP(issue))
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
auto const sle = ctx.view.read(keylet::account(issue.account));
|
auto const sle = AccountRootEntryR(issue.account, ctx.view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
if (sle->isFlag(lsfAllowTrustLineClawback))
|
if (sle->isFlag(lsfAllowTrustLineClawback))
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/Sandbox.h>
|
#include <xrpl/ledger/Sandbox.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
#include <xrpl/ledger/helpers/AMMHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
@@ -344,7 +344,7 @@ AMMWithdraw::applyGuts(Sandbox& sb)
|
|||||||
if (!ammSle)
|
if (!ammSle)
|
||||||
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
|
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
|
||||||
auto const ammAccountID = (*ammSle)[sfAccount];
|
auto const ammAccountID = (*ammSle)[sfAccount];
|
||||||
auto const accountSle = sb.read(keylet::account(ammAccountID));
|
auto const accountSle = AccountRootEntryR(ammAccountID, sb);
|
||||||
if (!accountSle)
|
if (!accountSle)
|
||||||
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
|
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
|
||||||
auto const lpTokens = ammLPHolds(ctx_.view(), *ammSle, ctx_.tx[sfAccount], ctx_.journal);
|
auto const lpTokens = ammLPHolds(ctx_.view(), *ammSle, ctx_.tx[sfAccount], ctx_.journal);
|
||||||
@@ -691,16 +691,15 @@ AMMWithdraw::withdraw(
|
|||||||
reserveHandling == ReserveHandling::IgnoreReserve)
|
reserveHandling == ReserveHandling::IgnoreReserve)
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|
||||||
auto sleAccount = view.peek(keylet::account(account));
|
auto sleAccount = AccountRootEntryW(account, view, journal);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const balance = (*sleAccount)[sfBalance]->xrp();
|
auto const balance = (*sleAccount)[sfBalance]->xrp();
|
||||||
// See also TrustSet::doApply() and MPTokenAuthorize::authorize()
|
// See also TrustSet::doApply() and MPTokenAuthorize::authorize()
|
||||||
XRPAmount const reserve(
|
XRPAmount const reserve(
|
||||||
(ownerCount(sleAccount, journal) < 2)
|
(sleAccount.ownerCount() < 2) ? XRPAmount(beast::kZero)
|
||||||
? XRPAmount(beast::kZero)
|
: sleAccount.reserve({.ownerCountDelta = 1}));
|
||||||
: accountReserve(view, sleAccount, journal, {.ownerCountDelta = 1}));
|
|
||||||
|
|
||||||
auto const balanceAdj = std::max(priorBalance, balance);
|
auto const balanceAdj = std::max(priorBalance, balance);
|
||||||
if (balanceAdj < reserve)
|
if (balanceAdj < reserve)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <xrpl/tx/transactors/dex/OfferCancel.h>
|
#include <xrpl/tx/transactors/dex/OfferCancel.h>
|
||||||
|
|
||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/OfferHelpers.h>
|
#include <xrpl/ledger/helpers/OfferHelpers.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
@@ -33,7 +35,7 @@ OfferCancel::preclaim(PreclaimContext const& ctx)
|
|||||||
auto const id = ctx.tx[sfAccount];
|
auto const id = ctx.tx[sfAccount];
|
||||||
auto const offerSequence = ctx.tx[sfOfferSequence];
|
auto const offerSequence = ctx.tx[sfOfferSequence];
|
||||||
|
|
||||||
auto const sle = ctx.view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, ctx.view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ OfferCancel::doApply()
|
|||||||
{
|
{
|
||||||
auto const offerSequence = ctx_.tx[sfOfferSequence];
|
auto const offerSequence = ctx_.tx[sfOfferSequence];
|
||||||
|
|
||||||
auto const sle = view().read(keylet::account(accountID_));
|
auto const sle = AccountRootEntryW(accountID_, view());
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
#include <xrpl/ledger/Sandbox.h>
|
#include <xrpl/ledger/Sandbox.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
@@ -181,7 +181,7 @@ OfferCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
auto const cancelSequence = ctx.tx[~sfOfferSequence];
|
auto const cancelSequence = ctx.tx[~sfOfferSequence];
|
||||||
|
|
||||||
auto const sleCreator = ctx.view.read(keylet::account(id));
|
auto const sleCreator = AccountRootEntryR(id, ctx.view);
|
||||||
if (!sleCreator)
|
if (!sleCreator)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ OfferCreate::checkAcceptAsset(
|
|||||||
// Only valid for custom currencies
|
// Only valid for custom currencies
|
||||||
XRPL_ASSERT(!isXRP(asset), "xrpl::OfferCreate::checkAcceptAsset : input is not XRP");
|
XRPL_ASSERT(!isXRP(asset), "xrpl::OfferCreate::checkAcceptAsset : input is not XRP");
|
||||||
|
|
||||||
auto const issuerAccount = view.read(keylet::account(asset.getIssuer()));
|
auto const issuerAccount = AccountRootEntryR(asset.getIssuer(), view);
|
||||||
|
|
||||||
if (!issuerAccount)
|
if (!issuerAccount)
|
||||||
{
|
{
|
||||||
@@ -707,14 +707,14 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
|||||||
// Not XRP or MPT
|
// Not XRP or MPT
|
||||||
if (!saTakerPays.integral())
|
if (!saTakerPays.integral())
|
||||||
{
|
{
|
||||||
auto const sle = sb.read(keylet::account(uPaysIssuerID));
|
auto const sle = AccountRootEntryR(uPaysIssuerID, sb);
|
||||||
if (sle && sle->isFieldPresent(sfTickSize))
|
if (sle && sle->isFieldPresent(sfTickSize))
|
||||||
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
|
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
|
||||||
}
|
}
|
||||||
// Not XRP or MPT
|
// Not XRP or MPT
|
||||||
if (!saTakerGets.integral())
|
if (!saTakerGets.integral())
|
||||||
{
|
{
|
||||||
auto const sle = sb.read(keylet::account(uGetsIssuerID));
|
auto const sle = AccountRootEntryR(uGetsIssuerID, sb);
|
||||||
if (sle && sle->isFieldPresent(sfTickSize))
|
if (sle && sle->isFieldPresent(sfTickSize))
|
||||||
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
|
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
|
||||||
}
|
}
|
||||||
@@ -884,12 +884,12 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
|||||||
return {tesSUCCESS, true};
|
return {tesSUCCESS, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleCreator = sb.peek(keylet::account(accountID_));
|
auto sleCreator = AccountRootEntryW(accountID_, sb, viewJ);
|
||||||
if (!sleCreator)
|
if (!sleCreator)
|
||||||
return {tefINTERNAL, false};
|
return {tefINTERNAL, false};
|
||||||
|
|
||||||
{
|
{
|
||||||
XRPAmount const reserve = accountReserve(sb, sleCreator, viewJ, {.ownerCountDelta = 1});
|
XRPAmount const reserve = sleCreator.reserve({.ownerCountDelta = 1});
|
||||||
if (preFeeBalance_ < reserve)
|
if (preFeeBalance_ < reserve)
|
||||||
{
|
{
|
||||||
// If we are here, the signing account had an insufficient reserve
|
// If we are here, the signing account had an insufficient reserve
|
||||||
@@ -923,7 +923,8 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update owner count.
|
// Update owner count.
|
||||||
increaseOwnerCount(sb, sleCreator, {}, 1, viewJ);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
sleCreator.increaseOwnerCount(noSponsor, 1);
|
||||||
|
|
||||||
JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.asset()) << " : "
|
JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.asset()) << " : "
|
||||||
<< to_string(saTakerGets.asset())
|
<< to_string(saTakerGets.asset())
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
@@ -46,7 +47,7 @@ DIDDelete::deleteSLE(ApplyView& view, SLE::pointer sle, AccountID const owner, b
|
|||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleOwner = view.peek(keylet::account(owner));
|
auto sleOwner = AccountRootEntryW(owner, view);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
@@ -65,15 +66,14 @@ DIDSet::preflight(PreflightContext const& ctx)
|
|||||||
static TER
|
static TER
|
||||||
addSLE(ApplyContext& ctx, SLE::Ref sle, AccountID const& owner)
|
addSLE(ApplyContext& ctx, SLE::Ref sle, AccountID const& owner)
|
||||||
{
|
{
|
||||||
auto const sleAccount = ctx.view().peek(keylet::account(owner));
|
auto sleAccount = AccountRootEntryW(owner, ctx.view(), ctx.journal);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Check reserve availability for new object creation
|
// Check reserve availability for new object creation
|
||||||
{
|
{
|
||||||
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
|
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
|
||||||
auto const reserve =
|
auto const reserve = sleAccount.reserve({.ownerCountDelta = 1});
|
||||||
accountReserve(ctx.view(), sleAccount, ctx.journal, {.ownerCountDelta = 1});
|
|
||||||
|
|
||||||
if (balance < reserve)
|
if (balance < reserve)
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
@@ -90,8 +90,9 @@ addSLE(ApplyContext& ctx, SLE::Ref sle, AccountID const& owner)
|
|||||||
return tecDIR_FULL; // LCOV_EXCL_LINE
|
return tecDIR_FULL; // LCOV_EXCL_LINE
|
||||||
(*sle)[sfOwnerNode] = *page;
|
(*sle)[sfOwnerNode] = *page;
|
||||||
}
|
}
|
||||||
increaseOwnerCount(ctx.view(), sleAccount, {}, 1, ctx.journal);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
ctx.view().update(sleAccount);
|
sleAccount.increaseOwnerCount(noSponsor, 1);
|
||||||
|
sleAccount.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/EscrowHelpers.h>
|
#include <xrpl/ledger/helpers/EscrowHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
@@ -166,7 +167,7 @@ EscrowCancel::doApply()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sle = ctx_.view().peek(keylet::account(account));
|
auto sle = AccountRootEntryW(account, ctx_.view());
|
||||||
STAmount const amount = slep->getFieldAmount(sfAmount);
|
STAmount const amount = slep->getFieldAmount(sfAmount);
|
||||||
|
|
||||||
// The return can re-create a holding the owner deleted while the escrow
|
// The return can re-create a holding the owner deleted while the escrow
|
||||||
@@ -192,7 +193,7 @@ EscrowCancel::doApply()
|
|||||||
return escrowUnlockApplyHelper<T>(
|
return escrowUnlockApplyHelper<T>(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
kParityRate,
|
kParityRate,
|
||||||
ctx_.view().rules().enabled(fixCleanup3_2_0) ? sle : slep,
|
ctx_.view().rules().enabled(fixCleanup3_2_0) ? sle.mutableRawSle() : slep,
|
||||||
preFeeBalance_,
|
preFeeBalance_,
|
||||||
amount,
|
amount,
|
||||||
issuer,
|
issuer,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
@@ -207,7 +208,7 @@ escrowCreatePreclaimHelper<Issue>(
|
|||||||
return tecNO_PERMISSION;
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
|
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(issuer));
|
auto const sleIssuer = AccountRootEntryR(issuer, ctx.view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
return tecNO_ISSUER;
|
return tecNO_ISSUER;
|
||||||
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
|
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
|
||||||
@@ -347,7 +348,7 @@ EscrowCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
AccountID const account{ctx.tx[sfAccount]};
|
AccountID const account{ctx.tx[sfAccount]};
|
||||||
AccountID const dest{ctx.tx[sfDestination]};
|
AccountID const dest{ctx.tx[sfDestination]};
|
||||||
|
|
||||||
auto const sled = ctx.view.read(keylet::account(dest));
|
auto const sled = AccountRootEntryR(dest, ctx.view);
|
||||||
if (!sled)
|
if (!sled)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
@@ -433,7 +434,7 @@ EscrowCreate::doApply()
|
|||||||
if (ctx_.tx[~sfFinishAfter] && after(closeTime, ctx_.tx[sfFinishAfter]))
|
if (ctx_.tx[~sfFinishAfter] && after(closeTime, ctx_.tx[sfFinishAfter]))
|
||||||
return tecNO_PERMISSION;
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
auto const sle = ctx_.view().peek(keylet::account(accountID_));
|
auto sle = AccountRootEntryW(accountID_, ctx_.view(), j_);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -447,7 +448,7 @@ EscrowCreate::doApply()
|
|||||||
// unsponsored this hits the source branch and validates the
|
// unsponsored this hits the source branch and validates the
|
||||||
// source's pre-lock balance against base + (currentOC+1)*increment.
|
// source's pre-lock balance against base + (currentOC+1)*increment.
|
||||||
if (auto const ret =
|
if (auto const ret =
|
||||||
checkReserve(ctx_.getApplyViewContext(), sle, balance, {.ownerCountDelta = 1}, j_);
|
sle.checkReserve(ctx_.getApplyViewContext(), balance, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -464,15 +465,15 @@ EscrowCreate::doApply()
|
|||||||
// - sponsored: 0 — sponsor covers the new owner increment, so the
|
// - sponsored: 0 — sponsor covers the new owner increment, so the
|
||||||
// source only owes reserve for its current owners.
|
// source only owes reserve for its current owners.
|
||||||
// - unsponsored: 1 — source owes reserve including the new increment.
|
// - unsponsored: 1 — source owes reserve including the new increment.
|
||||||
auto const sourceReserve = accountReserve(
|
auto const sourceReserve =
|
||||||
ctx_.view(), sle, j_, {.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1});
|
sle.reserve({.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1});
|
||||||
if (balance - STAmount(amount).xrp() < sourceReserve)
|
if (balance - STAmount(amount).xrp() < sourceReserve)
|
||||||
return tecUNFUNDED;
|
return tecUNFUNDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check destination account
|
// Check destination account
|
||||||
{
|
{
|
||||||
auto const sled = ctx_.view().read(keylet::account(ctx_.tx[sfDestination]));
|
auto const sled = AccountRootEntryW(ctx_.tx[sfDestination], ctx_.view());
|
||||||
if (!sled)
|
if (!sled)
|
||||||
return tecNO_DST; // LCOV_EXCL_LINE
|
return tecNO_DST; // LCOV_EXCL_LINE
|
||||||
if (sled->isFlag(lsfRequireDestTag) && !ctx_.tx[~sfDestinationTag])
|
if (sled->isFlag(lsfRequireDestTag) && !ctx_.tx[~sfDestinationTag])
|
||||||
@@ -558,9 +559,9 @@ EscrowCreate::doApply()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// increment owner count
|
// increment owner count
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, ctx_.journal);
|
sle.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), slep);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), slep);
|
||||||
ctx_.view().update(sle);
|
sle.update();
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/EscrowHelpers.h>
|
#include <xrpl/ledger/helpers/EscrowHelpers.h>
|
||||||
@@ -314,12 +315,12 @@ EscrowFinish::doApply()
|
|||||||
|
|
||||||
// NOTE: Escrow payments cannot be used to fund accounts.
|
// NOTE: Escrow payments cannot be used to fund accounts.
|
||||||
AccountID const destID = (*slep)[sfDestination];
|
AccountID const destID = (*slep)[sfDestination];
|
||||||
auto const sled = ctx_.view().peek(keylet::account(destID));
|
auto sled = AccountRootEntryW(destID, ctx_.view());
|
||||||
if (!sled)
|
if (!sled)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
if (auto err =
|
if (auto err = verifyDepositPreauth(
|
||||||
verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, destID, sled, ctx_.journal);
|
ctx_.tx, ctx_.view(), accountID_, destID, sled.rawSle(), ctx_.journal);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -378,7 +379,7 @@ EscrowFinish::doApply()
|
|||||||
return escrowUnlockApplyHelper<T>(
|
return escrowUnlockApplyHelper<T>(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
lockedRate,
|
lockedRate,
|
||||||
sled,
|
sled.mutableRawSle(),
|
||||||
preFeeBalance_,
|
preFeeBalance_,
|
||||||
amount,
|
amount,
|
||||||
issuer,
|
issuer,
|
||||||
@@ -404,7 +405,7 @@ EscrowFinish::doApply()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx_.view().update(sled);
|
sled.update();
|
||||||
|
|
||||||
if (!recycleReserve)
|
if (!recycleReserve)
|
||||||
decreaseOwnerCountForObject(ctx_.view(), account, slep, 1, ctx_.journal);
|
decreaseOwnerCountForObject(ctx_.view(), account, slep, 1, ctx_.journal);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -108,7 +109,7 @@ determineBrokerID(ReadView const& view, STTx const& tx)
|
|||||||
// Thus, Amount.issuer _should_ be the loan broker's
|
// Thus, Amount.issuer _should_ be the loan broker's
|
||||||
// pseudo-account, but we don't know yet whether it is.
|
// pseudo-account, but we don't know yet whether it is.
|
||||||
auto const maybePseudo = dstAmount->getIssuer();
|
auto const maybePseudo = dstAmount->getIssuer();
|
||||||
auto const sle = view.read(keylet::account(maybePseudo));
|
auto const sle = AccountRootEntryR(maybePseudo, view);
|
||||||
|
|
||||||
// If the account was not found, the transaction can't go further.
|
// If the account was not found, the transaction can't go further.
|
||||||
if (!sle)
|
if (!sle)
|
||||||
@@ -319,7 +320,7 @@ LoanBrokerCoverClawback::preclaim(PreclaimContext const& ctx)
|
|||||||
return tecINTERNAL; // tecINSUFFICIENT_FUNDS; LCOV_EXCL_LINE
|
return tecINTERNAL; // tecINSUFFICIENT_FUNDS; LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Check if the vault asset issuer has the correct flags
|
// Check if the vault asset issuer has the correct flags
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(vaultAsset.getIssuer()));
|
auto const sleIssuer = AccountRootEntryR(vaultAsset.getIssuer(), ctx.view);
|
||||||
if (!sleIssuer)
|
if (!sleIssuer)
|
||||||
{
|
{
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/basics/Number.h>
|
#include <xrpl/basics/Number.h>
|
||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
@@ -161,7 +162,7 @@ LoanBrokerDelete::doApply()
|
|||||||
if (auto ter = removeEmptyHolding(ctx_.getApplyViewContext(), brokerPseudoID, vaultAsset, j_))
|
if (auto ter = removeEmptyHolding(ctx_.getApplyViewContext(), brokerPseudoID, vaultAsset, j_))
|
||||||
return ter;
|
return ter;
|
||||||
|
|
||||||
auto brokerPseudoSLE = view().peek(keylet::account(brokerPseudoID));
|
auto brokerPseudoSLE = AccountRootEntryW(brokerPseudoID, view());
|
||||||
if (!brokerPseudoSLE)
|
if (!brokerPseudoSLE)
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -183,10 +184,10 @@ LoanBrokerDelete::doApply()
|
|||||||
return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
|
return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
view().erase(brokerPseudoSLE);
|
brokerPseudoSLE.erase();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto owner = view().peek(keylet::account(accountID_));
|
auto owner = AccountRootEntryW(accountID_, view());
|
||||||
if (!owner)
|
if (!owner)
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
#include <xrpl/tx/Transactor.h>
|
#include <xrpl/tx/Transactor.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
@@ -236,7 +238,7 @@ LoanBrokerSet::doApply()
|
|||||||
auto const vaultAsset = sleVault->at(sfAsset);
|
auto const vaultAsset = sleVault->at(sfAsset);
|
||||||
auto const sequence = tx.getSeqProxy();
|
auto const sequence = tx.getSeqProxy();
|
||||||
|
|
||||||
auto owner = view.peek(keylet::account(accountID_));
|
auto owner = AccountRootEntryW(accountID_, view, j_);
|
||||||
if (!owner)
|
if (!owner)
|
||||||
{
|
{
|
||||||
// This should be impossible
|
// This should be impossible
|
||||||
@@ -254,8 +256,9 @@ LoanBrokerSet::doApply()
|
|||||||
|
|
||||||
// Increases the owner count by two: one for the LoanBroker object, and
|
// Increases the owner count by two: one for the LoanBroker object, and
|
||||||
// one for the pseudo-account.
|
// one for the pseudo-account.
|
||||||
increaseOwnerCount(view, owner, {}, 2, j_);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
if (preFeeBalance_ < accountReserve(view, owner, j_))
|
owner.increaseOwnerCount(noSponsor, 2);
|
||||||
|
if (preFeeBalance_ < owner.reserve())
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
|
|
||||||
auto maybePseudo = createPseudoAccount(view, broker->key(), sfLoanBrokerID);
|
auto maybePseudo = createPseudoAccount(view, broker->key(), sfLoanBrokerID);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/basics/Number.h> // IWYU pragma: keep
|
#include <xrpl/basics/Number.h> // IWYU pragma: keep
|
||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
@@ -80,7 +81,7 @@ LoanDelete::doApply()
|
|||||||
if (!loanSle)
|
if (!loanSle)
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
auto const borrower = loanSle->at(sfBorrower);
|
auto const borrower = loanSle->at(sfBorrower);
|
||||||
auto const borrowerSle = view.peek(keylet::account(borrower));
|
auto borrowerSle = AccountRootEntryW(borrower, view);
|
||||||
if (!borrowerSle)
|
if (!borrowerSle)
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/json/to_string.h>
|
#include <xrpl/json/to_string.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -56,7 +57,7 @@ conservationBalance(ReadView const& view, AccountID const& id, Asset const& asse
|
|||||||
{
|
{
|
||||||
if (isXRP(asset))
|
if (isXRP(asset))
|
||||||
{
|
{
|
||||||
auto const sle = view.read(keylet::account(id));
|
auto const sle = AccountRootEntryR(id, view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return STAmount{asset}; // LCOV_EXCL_LINE
|
return STAmount{asset}; // LCOV_EXCL_LINE
|
||||||
return view.balanceHookIOU(id, xrpAccount(), sle->getFieldAmount(sfBalance));
|
return view.balanceHookIOU(id, xrpAccount(), sle->getFieldAmount(sfBalance));
|
||||||
@@ -391,7 +392,7 @@ LoanPay::doApply()
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
auto const brokerPayee = sendBrokerFeeToOwner ? brokerOwner : brokerPseudoAccount;
|
auto const brokerPayee = sendBrokerFeeToOwner ? brokerOwner : brokerPseudoAccount;
|
||||||
auto const brokerPayeeSle = view.peek(keylet::account(brokerPayee));
|
auto const brokerPayeeSle = AccountRootEntryW(brokerPayee, view);
|
||||||
if (!sendBrokerFeeToOwner)
|
if (!sendBrokerFeeToOwner)
|
||||||
{
|
{
|
||||||
// If we can't send the fee to the owner, and the pseudo-account is
|
// If we can't send the fee to the owner, and the pseudo-account is
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -305,7 +306,7 @@ LoanSet::preclaim(PreclaimContext const& ctx)
|
|||||||
auto const brokerPseudo = brokerSle->at(sfAccount);
|
auto const brokerPseudo = brokerSle->at(sfAccount);
|
||||||
|
|
||||||
auto const borrower = counterparty == brokerOwner ? account : counterparty;
|
auto const borrower = counterparty == brokerOwner ? account : counterparty;
|
||||||
if (auto const borrowerSle = ctx.view.read(keylet::account(borrower)); !borrowerSle)
|
if (auto const borrowerSle = AccountRootEntryR(borrower, ctx.view); !borrowerSle)
|
||||||
{
|
{
|
||||||
// It may not be possible to hit this case, because it'll fail the
|
// It may not be possible to hit this case, because it'll fail the
|
||||||
// signature check with terNO_ACCOUNT.
|
// signature check with terNO_ACCOUNT.
|
||||||
@@ -443,7 +444,7 @@ LoanSet::doApply()
|
|||||||
if (!brokerSle)
|
if (!brokerSle)
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
auto const brokerOwner = brokerSle->at(sfOwner);
|
auto const brokerOwner = brokerSle->at(sfOwner);
|
||||||
auto const brokerOwnerSle = view.peek(keylet::account(brokerOwner));
|
auto const brokerOwnerSle = AccountRootEntryW(brokerOwner, view);
|
||||||
if (!brokerOwnerSle)
|
if (!brokerOwnerSle)
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -455,14 +456,14 @@ LoanSet::doApply()
|
|||||||
|
|
||||||
auto const counterparty = tx[~sfCounterparty].value_or(brokerOwner);
|
auto const counterparty = tx[~sfCounterparty].value_or(brokerOwner);
|
||||||
auto const borrower = counterparty == brokerOwner ? accountID_ : counterparty;
|
auto const borrower = counterparty == brokerOwner ? accountID_ : counterparty;
|
||||||
auto const borrowerSle = view.peek(keylet::account(borrower));
|
auto borrowerSle = AccountRootEntryW(borrower, view, j_);
|
||||||
if (!borrowerSle)
|
if (!borrowerSle)
|
||||||
{
|
{
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const brokerPseudo = brokerSle->at(sfAccount);
|
auto const brokerPseudo = brokerSle->at(sfAccount);
|
||||||
auto const brokerPseudoSle = view.peek(keylet::account(brokerPseudo));
|
auto const brokerPseudoSle = AccountRootEntryW(brokerPseudo, view);
|
||||||
if (!brokerPseudoSle)
|
if (!brokerPseudoSle)
|
||||||
{
|
{
|
||||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||||
@@ -581,12 +582,13 @@ LoanSet::doApply()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
increaseOwnerCount(view, borrowerSle, {}, 1, j_);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
borrowerSle.increaseOwnerCount(noSponsor, 1);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const balance =
|
auto const balance =
|
||||||
accountID_ == borrower ? preFeeBalance_ : borrowerSle->at(sfBalance).value().xrp();
|
accountID_ == borrower ? preFeeBalance_ : borrowerSle->at(sfBalance).value().xrp();
|
||||||
if (balance < accountReserve(view, borrowerSle, j_))
|
if (balance < borrowerSle.reserve())
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/Asset.h>
|
#include <xrpl/protocol/Asset.h>
|
||||||
@@ -376,7 +376,7 @@ NFTokenAcceptOffer::transferNFToken(
|
|||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
auto const sleBuyer = view().read(keylet::account(buyer));
|
auto const sleBuyer = AccountRootEntryW(buyer, view(), j_);
|
||||||
if (!sleBuyer)
|
if (!sleBuyer)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -397,7 +397,7 @@ NFTokenAcceptOffer::transferNFToken(
|
|||||||
auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
|
auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
|
||||||
if (buyerOwnerCountAfter > buyerOwnerCountBefore)
|
if (buyerOwnerCountAfter > buyerOwnerCountBefore)
|
||||||
{
|
{
|
||||||
if (buyerBalance < accountReserve(view(), sleBuyer, j_))
|
if (buyerBalance < sleBuyer.reserve())
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <xrpl/tx/transactors/nft/NFTokenBurn.h>
|
#include <xrpl/tx/transactors/nft/NFTokenBurn.h>
|
||||||
|
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/Protocol.h>
|
#include <xrpl/protocol/Protocol.h>
|
||||||
@@ -43,7 +45,7 @@ NFTokenBurn::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account)
|
if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account)
|
||||||
{
|
{
|
||||||
if (auto const sle = ctx.view.read(keylet::account(issuer)); sle)
|
if (auto const sle = AccountRootEntryR(issuer, ctx.view); sle)
|
||||||
{
|
{
|
||||||
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
|
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
|
||||||
return tecNO_PERMISSION;
|
return tecNO_PERMISSION;
|
||||||
@@ -68,10 +70,10 @@ NFTokenBurn::doApply()
|
|||||||
if (!isTesSuccess(ret))
|
if (!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (auto issuer = view().peek(keylet::account(nft::getIssuer(ctx_.tx[sfNFTokenID]))))
|
if (auto issuer = AccountRootEntryW(nft::getIssuer(ctx_.tx[sfNFTokenID]), view()))
|
||||||
{
|
{
|
||||||
(*issuer)[~sfBurnedNFTokens] = (*issuer)[~sfBurnedNFTokens].valueOr(0) + 1;
|
(*issuer)[~sfBurnedNFTokens] = (*issuer)[~sfBurnedNFTokens].valueOr(0) + 1;
|
||||||
view().update(issuer);
|
issuer.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete up to 500 offers in total.
|
// Delete up to 500 offers in total.
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
|
||||||
#include <xrpl/protocol/InnerObjectFormats.h>
|
#include <xrpl/protocol/InnerObjectFormats.h>
|
||||||
#include <xrpl/protocol/Protocol.h>
|
#include <xrpl/protocol/Protocol.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
@@ -186,7 +186,7 @@ NFTokenMint::preclaim(PreclaimContext const& ctx)
|
|||||||
// transaction. Check that and verify that this is allowed:
|
// transaction. Check that and verify that this is allowed:
|
||||||
if (auto issuer = ctx.tx[~sfIssuer])
|
if (auto issuer = ctx.tx[~sfIssuer])
|
||||||
{
|
{
|
||||||
auto const sle = ctx.view.read(keylet::account(*issuer));
|
auto const sle = AccountRootEntryR(*issuer, ctx.view);
|
||||||
|
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tecNO_ISSUER;
|
return tecNO_ISSUER;
|
||||||
@@ -225,8 +225,8 @@ NFTokenMint::doApply()
|
|||||||
auto const issuer = ctx_.tx[~sfIssuer].value_or(accountID_);
|
auto const issuer = ctx_.tx[~sfIssuer].value_or(accountID_);
|
||||||
|
|
||||||
auto const tokenSeq = [this, &issuer]() -> std::expected<std::uint32_t, TER> {
|
auto const tokenSeq = [this, &issuer]() -> std::expected<std::uint32_t, TER> {
|
||||||
auto const root = view().peek(keylet::account(issuer));
|
auto root = AccountRootEntryW(issuer, view());
|
||||||
if (root == nullptr)
|
if (!root)
|
||||||
{
|
{
|
||||||
// Should not happen. Checked in preclaim.
|
// Should not happen. Checked in preclaim.
|
||||||
return std::unexpected(tecNO_ISSUER);
|
return std::unexpected(tecNO_ISSUER);
|
||||||
@@ -271,7 +271,7 @@ NFTokenMint::doApply()
|
|||||||
if (tokenSeq + 1u == 0u || tokenSeq < offset)
|
if (tokenSeq + 1u == 0u || tokenSeq < offset)
|
||||||
return std::unexpected(tecMAX_SEQUENCE_REACHED);
|
return std::unexpected(tecMAX_SEQUENCE_REACHED);
|
||||||
|
|
||||||
ctx_.view().update(root);
|
root.update();
|
||||||
return tokenSeq;
|
return tokenSeq;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ NFTokenMint::doApply()
|
|||||||
return (tokenSeq.error());
|
return (tokenSeq.error());
|
||||||
|
|
||||||
std::uint32_t const ownerCountBefore =
|
std::uint32_t const ownerCountBefore =
|
||||||
view().read(keylet::account(accountID_))->getFieldU32(sfOwnerCount);
|
AccountRootEntryW(accountID_, view())->getFieldU32(sfOwnerCount);
|
||||||
|
|
||||||
// Assemble the new NFToken.
|
// Assemble the new NFToken.
|
||||||
SOTemplate const* nfTokenTemplate =
|
SOTemplate const* nfTokenTemplate =
|
||||||
@@ -332,14 +332,14 @@ NFTokenMint::doApply()
|
|||||||
// allows NFTs to be added to the page (and burn fees) without
|
// allows NFTs to be added to the page (and burn fees) without
|
||||||
// requiring the reserve to be met each time. The reserve is
|
// requiring the reserve to be met each time. The reserve is
|
||||||
// only managed when a new NFT page or sell offer is added.
|
// only managed when a new NFT page or sell offer is added.
|
||||||
auto const sleAccount = view().read(keylet::account(accountID_));
|
auto const sleAccount = AccountRootEntryW(accountID_, view(), j_);
|
||||||
if (!sleAccount)
|
if (!sleAccount)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ownerCountAfter = sleAccount->getFieldU32(sfOwnerCount);
|
if (auto const ownerCountAfter = sleAccount->getFieldU32(sfOwnerCount);
|
||||||
ownerCountAfter > ownerCountBefore)
|
ownerCountAfter > ownerCountBefore)
|
||||||
{
|
{
|
||||||
if (preFeeBalance_ < accountReserve(view(), sleAccount, j_))
|
if (preFeeBalance_ < sleAccount.reserve())
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
}
|
}
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
|
||||||
#include <xrpl/protocol/Protocol.h>
|
#include <xrpl/protocol/Protocol.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
#include <xrpl/protocol/STLedgerEntry.h>
|
#include <xrpl/protocol/STLedgerEntry.h>
|
||||||
@@ -47,7 +48,7 @@ NFTokenModify::preclaim(PreclaimContext const& ctx)
|
|||||||
// Verify permissions for the issuer
|
// Verify permissions for the issuer
|
||||||
if (AccountID const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account)
|
if (AccountID const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account)
|
||||||
{
|
{
|
||||||
auto const sle = ctx.view.read(keylet::account(issuer));
|
auto const sle = AccountRootEntryR(issuer, ctx.view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
|
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -67,7 +68,7 @@ OracleDelete::deleteOracle(
|
|||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleOwner = view.peek(keylet::account(account));
|
auto sleOwner = AccountRootEntryW(account, view);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <xrpl/basics/chrono.h>
|
#include <xrpl/basics/chrono.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ OracleSet::preflight(PreflightContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
OracleSet::preclaim(PreclaimContext const& ctx)
|
OracleSet::preclaim(PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const sleSetter = ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount)));
|
auto const sleSetter = AccountRootEntryR(ctx.tx.getAccountID(sfAccount), ctx.view, ctx.j);
|
||||||
if (!sleSetter)
|
if (!sleSetter)
|
||||||
return terNO_ACCOUNT; // LCOV_EXCL_LINE
|
return terNO_ACCOUNT; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -172,8 +173,7 @@ OracleSet::preclaim(PreclaimContext const& ctx)
|
|||||||
if (pairs.size() > kMaxOracleDataSeries)
|
if (pairs.size() > kMaxOracleDataSeries)
|
||||||
return tecARRAY_TOO_LARGE;
|
return tecARRAY_TOO_LARGE;
|
||||||
|
|
||||||
auto const reserve =
|
auto const reserve = sleSetter.reserve({.ownerCountDelta = adjustReserve});
|
||||||
accountReserve(ctx.view, sleSetter, ctx.j, {.ownerCountDelta = adjustReserve});
|
|
||||||
auto const& balance = sleSetter->getFieldAmount(sfBalance);
|
auto const& balance = sleSetter->getFieldAmount(sfBalance);
|
||||||
|
|
||||||
if (balance < reserve)
|
if (balance < reserve)
|
||||||
@@ -187,22 +187,20 @@ adjustOracleOwnerCount(ApplyContext& ctx, int count)
|
|||||||
{
|
{
|
||||||
XRPL_ASSERT(std::abs(count) <= 2, "xrpl::adjustOracleOwnerCount abs(counter) <= 2");
|
XRPL_ASSERT(std::abs(count) <= 2, "xrpl::adjustOracleOwnerCount abs(counter) <= 2");
|
||||||
|
|
||||||
if (auto const sleAccount = ctx.view().peek(keylet::account(ctx.tx[sfAccount])))
|
auto sleAccount = AccountRootEntryW(ctx.tx[sfAccount], ctx.view(), ctx.journal);
|
||||||
{
|
if (!sleAccount)
|
||||||
if (count > 0)
|
return false; // LCOV_EXCL_LINE
|
||||||
{
|
|
||||||
increaseOwnerCount(
|
|
||||||
ctx.view(), sleAccount, {}, static_cast<std::uint32_t>(count), ctx.journal);
|
|
||||||
}
|
|
||||||
else if (count < 0)
|
|
||||||
{
|
|
||||||
decreaseOwnerCount(
|
|
||||||
ctx.view(), sleAccount, {}, static_cast<std::uint32_t>(-count), ctx.journal);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // LCOV_EXCL_LINE
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
sleAccount.increaseOwnerCount(noSponsor, static_cast<std::uint32_t>(count));
|
||||||
|
}
|
||||||
|
else if (count < 0)
|
||||||
|
{
|
||||||
|
sleAccount.decreaseOwnerCount(noSponsor, static_cast<std::uint32_t>(-count));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/basics/Slice.h>
|
#include <xrpl/basics/Slice.h>
|
||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
@@ -103,7 +104,7 @@ DepositPreauth::preclaim(PreclaimContext const& ctx)
|
|||||||
{
|
{
|
||||||
// Verify that the Authorize account is present in the ledger.
|
// Verify that the Authorize account is present in the ledger.
|
||||||
AccountID const auth{ctx.tx[sfAuthorize]};
|
AccountID const auth{ctx.tx[sfAuthorize]};
|
||||||
auto const sleAuth = ctx.view.read(keylet::account(auth));
|
auto const sleAuth = AccountRootEntryR(auth, ctx.view);
|
||||||
if (!sleAuth)
|
if (!sleAuth)
|
||||||
return tecNO_TARGET;
|
return tecNO_TARGET;
|
||||||
|
|
||||||
@@ -161,15 +162,15 @@ DepositPreauth::doApply()
|
|||||||
auto applyViewContext = ctx_.getApplyViewContext();
|
auto applyViewContext = ctx_.getApplyViewContext();
|
||||||
if (ctx_.tx.isFieldPresent(sfAuthorize))
|
if (ctx_.tx.isFieldPresent(sfAuthorize))
|
||||||
{
|
{
|
||||||
auto const sleOwner = view().peek(keylet::account(accountID_));
|
auto sleOwner = AccountRootEntryW(accountID_, view(), j_);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return {tefINTERNAL};
|
return {tefINTERNAL};
|
||||||
|
|
||||||
// A preauth counts against the reserve of the issuing account, but we
|
// A preauth counts against the reserve of the issuing account, but we
|
||||||
// check the starting balance because we want to allow dipping into the
|
// check the starting balance because we want to allow dipping into the
|
||||||
// reserve to pay fees.
|
// reserve to pay fees.
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret =
|
||||||
applyViewContext, sleOwner, preFeeBalance_, {.ownerCountDelta = 1}, j_);
|
sleOwner.checkReserve(applyViewContext, preFeeBalance_, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ DepositPreauth::doApply()
|
|||||||
slePreauth->setFieldU64(sfOwnerNode, *page);
|
slePreauth->setFieldU64(sfOwnerNode, *page);
|
||||||
|
|
||||||
// If we succeeded, the new entry counts against the creator's reserve.
|
// If we succeeded, the new entry counts against the creator's reserve.
|
||||||
increaseOwnerCount(applyViewContext, sleOwner, 1, j_);
|
sleOwner.increaseOwnerCount(applyViewContext, 1);
|
||||||
addSponsorToLedgerEntry(applyViewContext, slePreauth);
|
addSponsorToLedgerEntry(applyViewContext, slePreauth);
|
||||||
}
|
}
|
||||||
else if (ctx_.tx.isFieldPresent(sfUnauthorize))
|
else if (ctx_.tx.isFieldPresent(sfUnauthorize))
|
||||||
@@ -206,15 +207,15 @@ DepositPreauth::doApply()
|
|||||||
}
|
}
|
||||||
else if (ctx_.tx.isFieldPresent(sfAuthorizeCredentials))
|
else if (ctx_.tx.isFieldPresent(sfAuthorizeCredentials))
|
||||||
{
|
{
|
||||||
auto const sleOwner = view().peek(keylet::account(accountID_));
|
auto sleOwner = AccountRootEntryW(accountID_, view(), j_);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// A preauth counts against the reserve of the issuing account, but we
|
// A preauth counts against the reserve of the issuing account, but we
|
||||||
// check the starting balance because we want to allow dipping into the
|
// check the starting balance because we want to allow dipping into the
|
||||||
// reserve to pay fees.
|
// reserve to pay fees.
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret =
|
||||||
applyViewContext, sleOwner, preFeeBalance_, {.ownerCountDelta = 1}, j_);
|
sleOwner.checkReserve(applyViewContext, preFeeBalance_, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -254,7 +255,7 @@ DepositPreauth::doApply()
|
|||||||
slePreauth->setFieldU64(sfOwnerNode, *page);
|
slePreauth->setFieldU64(sfOwnerNode, *page);
|
||||||
|
|
||||||
// If we succeeded, the new entry counts against the creator's reserve.
|
// If we succeeded, the new entry counts against the creator's reserve.
|
||||||
increaseOwnerCount(applyViewContext, sleOwner, 1, j_);
|
sleOwner.increaseOwnerCount(applyViewContext, 1);
|
||||||
addSponsorToLedgerEntry(applyViewContext, slePreauth);
|
addSponsorToLedgerEntry(applyViewContext, slePreauth);
|
||||||
}
|
}
|
||||||
else if (ctx_.tx.isFieldPresent(sfUnauthorizeCredentials))
|
else if (ctx_.tx.isFieldPresent(sfUnauthorizeCredentials))
|
||||||
@@ -289,7 +290,7 @@ DepositPreauth::removeFromLedger(ApplyView& view, UInt256 const& preauthIndex, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we succeeded, update the DepositPreauth owner's reserve.
|
// If we succeeded, update the DepositPreauth owner's reserve.
|
||||||
auto const sleOwner = view.peek(keylet::account(account));
|
auto sleOwner = AccountRootEntryW(account, view);
|
||||||
if (!sleOwner)
|
if (!sleOwner)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/PaymentSandbox.h>
|
#include <xrpl/ledger/PaymentSandbox.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
@@ -386,7 +387,7 @@ Payment::preclaim(PreclaimContext const& ctx)
|
|||||||
STAmount const dstAmount(ctx.tx[sfAmount]);
|
STAmount const dstAmount(ctx.tx[sfAmount]);
|
||||||
|
|
||||||
auto const k = keylet::account(dstAccountID);
|
auto const k = keylet::account(dstAccountID);
|
||||||
auto const sleDst = ctx.view.read(k);
|
auto const sleDst = AccountRootEntryR(k, ctx.view);
|
||||||
|
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
{
|
{
|
||||||
@@ -564,19 +565,19 @@ Payment::doApply()
|
|||||||
|
|
||||||
// Open a ledger for editing.
|
// Open a ledger for editing.
|
||||||
auto const k = keylet::account(dstAccountID);
|
auto const k = keylet::account(dstAccountID);
|
||||||
SLE::pointer sleDst = view().peek(k);
|
AccountRootEntryW sleDst(k, view());
|
||||||
|
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
{
|
{
|
||||||
// Create the account.
|
// Create the account.
|
||||||
sleDst = std::make_shared<SLE>(k);
|
sleDst.newSLE();
|
||||||
sleDst->setAccountID(sfAccount, dstAccountID);
|
sleDst->setAccountID(sfAccount, dstAccountID);
|
||||||
sleDst->setFieldU32(sfSequence, view().seq());
|
sleDst->setFieldU32(sfSequence, view().seq());
|
||||||
sleDst->setFieldAmount(sfBalance, XRPAmount(beast::kZero));
|
sleDst->setFieldAmount(sfBalance, XRPAmount(beast::kZero));
|
||||||
|
|
||||||
if (ctx_.tx.isFlag(tfSponsorCreatedAccount))
|
if (ctx_.tx.isFlag(tfSponsorCreatedAccount))
|
||||||
{
|
{
|
||||||
auto const sponsor = view().peek(keylet::account(accountID_));
|
auto sponsor = AccountRootEntryW(accountID_, view());
|
||||||
if (!sponsor)
|
if (!sponsor)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const currentSponsoringAccountCount =
|
auto const currentSponsoringAccountCount =
|
||||||
@@ -591,18 +592,18 @@ Payment::doApply()
|
|||||||
}
|
}
|
||||||
sponsor->setFieldU32(sfSponsoringAccountCount, currentSponsoringAccountCount + 1);
|
sponsor->setFieldU32(sfSponsoringAccountCount, currentSponsoringAccountCount + 1);
|
||||||
|
|
||||||
addSponsorToLedgerEntry(sleDst, sponsor);
|
addSponsorToLedgerEntry(sleDst.mutableRawSle(), sponsor.rawSle());
|
||||||
view().update(sponsor);
|
sponsor.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
view().insert(sleDst);
|
sleDst.insert();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Tell the engine that we are intending to change the destination
|
// Tell the engine that we are intending to change the destination
|
||||||
// account. The source account gets always charged a fee so it's always
|
// account. The source account gets always charged a fee so it's always
|
||||||
// marked as modified.
|
// marked as modified.
|
||||||
view().update(sleDst);
|
sleDst.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool const mpTokensV2 = view().rules().enabled(featureMPTokensV2);
|
bool const mpTokensV2 = view().rules().enabled(featureMPTokensV2);
|
||||||
@@ -621,7 +622,12 @@ Payment::doApply()
|
|||||||
// 2. If Account is deposit preauthorized by destination.
|
// 2. If Account is deposit preauthorized by destination.
|
||||||
|
|
||||||
if (auto err = verifyDepositPreauth(
|
if (auto err = verifyDepositPreauth(
|
||||||
ctx_.tx, ctx_.view(), accountID_, dstAccountID, sleDst, ctx_.journal);
|
ctx_.tx,
|
||||||
|
ctx_.view(),
|
||||||
|
accountID_,
|
||||||
|
dstAccountID,
|
||||||
|
sleDst.mutableRawSle(),
|
||||||
|
ctx_.journal);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -691,7 +697,12 @@ Payment::doApply()
|
|||||||
return ter;
|
return ter;
|
||||||
|
|
||||||
if (auto err = verifyDepositPreauth(
|
if (auto err = verifyDepositPreauth(
|
||||||
ctx_.tx, ctx_.view(), accountID_, dstAccountID, sleDst, ctx_.journal);
|
ctx_.tx,
|
||||||
|
ctx_.view(),
|
||||||
|
accountID_,
|
||||||
|
dstAccountID,
|
||||||
|
sleDst.mutableRawSle(),
|
||||||
|
ctx_.journal);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -757,13 +768,13 @@ Payment::doApply()
|
|||||||
|
|
||||||
// Direct XRP payment.
|
// Direct XRP payment.
|
||||||
|
|
||||||
auto const sleSrc = view().peek(keylet::account(accountID_));
|
auto sleSrc = AccountRootEntryW(accountID_, view(), j_);
|
||||||
if (!sleSrc)
|
if (!sleSrc)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// the number of reserves in this ledger for this account that require a
|
// the number of reserves in this ledger for this account that require a
|
||||||
// reserve.
|
// reserve.
|
||||||
auto const reserve = accountReserve(view(), sleSrc, j_);
|
auto const reserve = sleSrc.reserve();
|
||||||
|
|
||||||
// In a delegated / fee sponsored payment, the fee payer is not the source account (accountID_).
|
// In a delegated / fee sponsored payment, the fee payer is not the source account (accountID_).
|
||||||
bool const accountIsPayer = ctx_.tx.getFeePayerID() == accountID_;
|
bool const accountIsPayer = ctx_.tx.getFeePayerID() == accountID_;
|
||||||
@@ -820,7 +831,12 @@ Payment::doApply()
|
|||||||
if (dstAmount > dstReserve || sleDst->getFieldAmount(sfBalance) > dstReserve)
|
if (dstAmount > dstReserve || sleDst->getFieldAmount(sfBalance) > dstReserve)
|
||||||
{
|
{
|
||||||
if (auto err = verifyDepositPreauth(
|
if (auto err = verifyDepositPreauth(
|
||||||
ctx_.tx, ctx_.view(), accountID_, dstAccountID, sleDst, ctx_.journal);
|
ctx_.tx,
|
||||||
|
ctx_.view(),
|
||||||
|
accountID_,
|
||||||
|
dstAccountID,
|
||||||
|
sleDst.mutableRawSle(),
|
||||||
|
ctx_.journal);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/PaymentChannelHelpers.h>
|
#include <xrpl/ledger/helpers/PaymentChannelHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
|
||||||
#include <xrpl/protocol/Keylet.h>
|
#include <xrpl/protocol/Keylet.h>
|
||||||
#include <xrpl/protocol/LedgerFormats.h>
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
#include <xrpl/protocol/PayChan.h>
|
#include <xrpl/protocol/PayChan.h>
|
||||||
@@ -159,12 +159,12 @@ PaymentChannelClaim::doApply()
|
|||||||
return tecUNFUNDED_PAYMENT;
|
return tecUNFUNDED_PAYMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sled = ctx_.view().peek(keylet::account(dst));
|
auto sled = AccountRootEntryW(dst, ctx_.view());
|
||||||
if (!sled)
|
if (!sled)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
if (auto err =
|
if (auto err = verifyDepositPreauth(
|
||||||
verifyDepositPreauth(ctx_.tx, ctx_.view(), txAccount, dst, sled, ctx_.journal);
|
ctx_.tx, ctx_.view(), txAccount, dst, sled.rawSle(), ctx_.journal);
|
||||||
!isTesSuccess(err))
|
!isTesSuccess(err))
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ PaymentChannelClaim::doApply()
|
|||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
reqDelta >= beast::kZero, "xrpl::PaymentChannelClaim::doApply : minimum balance delta");
|
reqDelta >= beast::kZero, "xrpl::PaymentChannelClaim::doApply : minimum balance delta");
|
||||||
(*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta;
|
(*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta;
|
||||||
ctx_.view().update(sled);
|
sled.update();
|
||||||
ctx_.view().update(slep);
|
ctx_.view().update(slep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -73,7 +74,7 @@ TER
|
|||||||
PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
|
PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const account = ctx.tx[sfAccount];
|
auto const account = ctx.tx[sfAccount];
|
||||||
auto const sle = ctx.view.read(keylet::account(account));
|
auto const sle = AccountRootEntryR(account, ctx.view);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Check destination account
|
// Check destination account
|
||||||
auto const sled = ctx.view.read(keylet::account(dst));
|
auto const sled = AccountRootEntryR(dst, ctx.view);
|
||||||
if (!sled)
|
if (!sled)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ TER
|
|||||||
PaymentChannelCreate::doApply()
|
PaymentChannelCreate::doApply()
|
||||||
{
|
{
|
||||||
auto const account = ctx_.tx[sfAccount];
|
auto const account = ctx_.tx[sfAccount];
|
||||||
auto const sle = ctx_.view().peek(keylet::account(account));
|
auto sle = AccountRootEntryW(account, ctx_.view(), j_);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -140,8 +141,8 @@ PaymentChannelCreate::doApply()
|
|||||||
// validates the sponsor's reserve + remaining credit. When
|
// validates the sponsor's reserve + remaining credit. When
|
||||||
// unsponsored this hits the source branch and validates the
|
// unsponsored this hits the source branch and validates the
|
||||||
// source's pre-lock balance against base + (currentOC+1)*increment.
|
// source's pre-lock balance against base + (currentOC+1)*increment.
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sle.checkReserve(
|
||||||
ctx_.getApplyViewContext(), sle, preFeeBalance_, {.ownerCountDelta = 1}, j_);
|
ctx_.getApplyViewContext(), preFeeBalance_, {.ownerCountDelta = 1});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -157,8 +158,8 @@ PaymentChannelCreate::doApply()
|
|||||||
// - sponsored: 0 — sponsor covers the new owner increment, so
|
// - sponsored: 0 — sponsor covers the new owner increment, so
|
||||||
// the source only owes reserve for its current owners.
|
// the source only owes reserve for its current owners.
|
||||||
// - unsponsored: 1 — source owes reserve including the new increment.
|
// - unsponsored: 1 — source owes reserve including the new increment.
|
||||||
auto const sourceReserve = accountReserve(
|
auto const sourceReserve =
|
||||||
ctx_.view(), sle, j_, {.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1});
|
sle.reserve({.ownerCountDelta = getTxReserveSponsorID(ctx_.tx) ? 0 : 1});
|
||||||
if (preFeeBalance_ - ctx_.tx[sfAmount].xrp() < sourceReserve)
|
if (preFeeBalance_ - ctx_.tx[sfAmount].xrp() < sourceReserve)
|
||||||
return tecUNFUNDED;
|
return tecUNFUNDED;
|
||||||
}
|
}
|
||||||
@@ -210,9 +211,9 @@ PaymentChannelCreate::doApply()
|
|||||||
|
|
||||||
// Deduct owner's balance, increment owner count
|
// Deduct owner's balance, increment owner count
|
||||||
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
|
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, ctx_.journal);
|
sle.increaseOwnerCount(ctx_.getApplyViewContext(), 1);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), slep);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), slep);
|
||||||
ctx_.view().update(sle);
|
sle.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/PaymentChannelHelpers.h>
|
#include <xrpl/ledger/helpers/PaymentChannelHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
|
||||||
#include <xrpl/protocol/Keylet.h>
|
#include <xrpl/protocol/Keylet.h>
|
||||||
#include <xrpl/protocol/LedgerFormats.h>
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
@@ -82,14 +81,14 @@ PaymentChannelFund::doApply()
|
|||||||
ctx_.view().update(slep);
|
ctx_.view().update(slep);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sle = ctx_.view().peek(keylet::account(txAccount));
|
auto sle = AccountRootEntryW(txAccount, ctx_.view(), j_);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
{
|
{
|
||||||
// Check reserve and funds availability
|
// Check reserve and funds availability
|
||||||
STAmount const balance = (*sle)[sfBalance];
|
STAmount const balance = (*sle)[sfBalance];
|
||||||
if (auto const ret = checkReserve(ctx_.getApplyViewContext(), sle, balance.xrp(), {}, j_);
|
if (auto const ret = sle.checkReserve(ctx_.getApplyViewContext(), balance.xrp(), {});
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -99,12 +98,12 @@ PaymentChannelFund::doApply()
|
|||||||
// when a sponsor is present and would ignore the source's post-lock
|
// when a sponsor is present and would ignore the source's post-lock
|
||||||
// balance entirely. Funding an existing channel adds no owned object,
|
// balance entirely. Funding an existing channel adds no owned object,
|
||||||
// so there is no owner-count delta.
|
// so there is no owner-count delta.
|
||||||
if (balance < accountReserve(ctx_.view(), sle, j_) + ctx_.tx[sfAmount])
|
if (balance < sle.reserve() + ctx_.tx[sfAmount])
|
||||||
return tecUNFUNDED;
|
return tecUNFUNDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not allow adding funds if dst does not exist
|
// do not allow adding funds if dst does not exist
|
||||||
if (AccountID const dst = (*slep)[sfDestination]; !ctx_.view().read(keylet::account(dst)))
|
if (AccountID const dst = (*slep)[sfDestination]; !AccountRootEntryW(dst, ctx_.view()))
|
||||||
{
|
{
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
}
|
}
|
||||||
@@ -113,7 +112,7 @@ PaymentChannelFund::doApply()
|
|||||||
ctx_.view().update(slep);
|
ctx_.view().update(slep);
|
||||||
|
|
||||||
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
|
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
|
||||||
ctx_.view().update(sle);
|
sle.update();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/SField.h>
|
#include <xrpl/protocol/SField.h>
|
||||||
@@ -63,7 +64,7 @@ PermissionedDomainDelete::doApply()
|
|||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const ownerSle = view().peek(keylet::account(accountID_));
|
auto ownerSle = AccountRootEntryW(accountID_, view());
|
||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
ownerSle && ownerSle->getFieldU32(sfOwnerCount) > 0,
|
ownerSle && ownerSle->getFieldU32(sfOwnerCount) > 0,
|
||||||
"xrpl::PermissionedDomainDelete::doApply : nonzero owner count");
|
"xrpl::PermissionedDomainDelete::doApply : nonzero owner count");
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <xrpl/tx/Transactor.h>
|
#include <xrpl/tx/Transactor.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
@@ -80,7 +81,7 @@ PermissionedDomainSet::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
PermissionedDomainSet::doApply()
|
PermissionedDomainSet::doApply()
|
||||||
{
|
{
|
||||||
auto const ownerSle = view().peek(keylet::account(accountID_));
|
auto ownerSle = AccountRootEntryW(accountID_, view(), ctx_.journal);
|
||||||
if (!ownerSle)
|
if (!ownerSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -109,8 +110,7 @@ PermissionedDomainSet::doApply()
|
|||||||
// Create new permissioned domain.
|
// Create new permissioned domain.
|
||||||
// Check reserve availability for new object creation
|
// Check reserve availability for new object creation
|
||||||
auto const balance = STAmount((*ownerSle)[sfBalance]).xrp();
|
auto const balance = STAmount((*ownerSle)[sfBalance]).xrp();
|
||||||
auto const reserve =
|
auto const reserve = ownerSle.reserve({.ownerCountDelta = 1});
|
||||||
accountReserve(ctx_.view(), ownerSle, ctx_.journal, {.ownerCountDelta = 1});
|
|
||||||
if (balance < reserve)
|
if (balance < reserve)
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
|
|
||||||
@@ -130,7 +130,8 @@ PermissionedDomainSet::doApply()
|
|||||||
|
|
||||||
slePd->setFieldU64(sfOwnerNode, *page);
|
slePd->setFieldU64(sfOwnerNode, *page);
|
||||||
// If we succeeded, the new entry counts against the creator's reserve.
|
// If we succeeded, the new entry counts against the creator's reserve.
|
||||||
increaseOwnerCount(view(), ownerSle, {}, 1, ctx_.journal);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
ownerSle.increaseOwnerCount(noSponsor, 1);
|
||||||
view().insert(slePd);
|
view().insert(slePd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/View.h>
|
#include <xrpl/ledger/View.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/ProposalHelpers.h>
|
#include <xrpl/ledger/helpers/ProposalHelpers.h>
|
||||||
@@ -159,7 +160,7 @@ TransactionProposalCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AccountID const target = proposedTx.getAccountID(sfAccount);
|
AccountID const target = proposedTx.getAccountID(sfAccount);
|
||||||
auto const sleTarget = ctx.view.read(keylet::account(target));
|
auto const sleTarget = AccountRootEntryR(target, ctx.view);
|
||||||
if (!sleTarget)
|
if (!sleTarget)
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.debug()) << "TransactionProposalCreate: target account "
|
JLOG(ctx.j.debug()) << "TransactionProposalCreate: target account "
|
||||||
@@ -297,7 +298,7 @@ TransactionProposalCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
TransactionProposalCreate::doApply()
|
TransactionProposalCreate::doApply()
|
||||||
{
|
{
|
||||||
auto const sle = view().peek(keylet::account(accountID_));
|
auto sle = AccountRootEntryW(accountID_, view(), ctx_.journal);
|
||||||
if (!sle)
|
if (!sle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -307,12 +308,10 @@ TransactionProposalCreate::doApply()
|
|||||||
// The proposal holds a full transaction plus its collected signatures, so
|
// The proposal holds a full transaction plus its collected signatures, so
|
||||||
// it reserves more than a typical ledger entry (5 increments; 10 for a
|
// it reserves more than a typical ledger entry (5 increments; 10 for a
|
||||||
// proposed Batch).
|
// proposed Batch).
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sle,
|
|
||||||
preFeeBalance_,
|
preFeeBalance_,
|
||||||
{.ownerCountDelta = static_cast<int>(ownerCount)},
|
{.ownerCountDelta = static_cast<int>(ownerCount)});
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -327,7 +326,6 @@ TransactionProposalCreate::doApply()
|
|||||||
|
|
||||||
view().insert(sleProposal);
|
view().insert(sleProposal);
|
||||||
|
|
||||||
auto viewJ = ctx_.registry.get().getJournal("View");
|
|
||||||
{
|
{
|
||||||
auto const page = view().dirInsert(
|
auto const page = view().dirInsert(
|
||||||
keylet::ownerDir(accountID_), proposalKeylet, describeOwnerDir(accountID_));
|
keylet::ownerDir(accountID_), proposalKeylet, describeOwnerDir(accountID_));
|
||||||
@@ -336,7 +334,7 @@ TransactionProposalCreate::doApply()
|
|||||||
sleProposal->setFieldU64(sfOwnerNode, *page);
|
sleProposal->setFieldU64(sfOwnerNode, *page);
|
||||||
}
|
}
|
||||||
|
|
||||||
increaseOwnerCount(ctx_.getApplyViewContext(), sle, ownerCount, viewJ);
|
sle.increaseOwnerCount(ctx_.getApplyViewContext(), ownerCount);
|
||||||
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleProposal);
|
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), sleProposal);
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
@@ -164,11 +165,11 @@ SponsorshipSet::preclaim(PreclaimContext const& ctx)
|
|||||||
if (sponseeID == sponsorID)
|
if (sponseeID == sponsorID)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const sponsorAccSle = ctx.view.read(keylet::account(sponsorID));
|
auto const sponsorAccSle = AccountRootEntryR(sponsorID, ctx.view);
|
||||||
if (!sponsorAccSle)
|
if (!sponsorAccSle)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
auto const sponseeSle = ctx.view.read(keylet::account(sponseeID));
|
auto const sponseeSle = AccountRootEntryR(sponseeID, ctx.view);
|
||||||
if (!sponseeSle)
|
if (!sponseeSle)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
@@ -212,7 +213,7 @@ deleteSponsorship(ApplyView& view, SLE::Ref sle, beast::Journal j)
|
|||||||
|
|
||||||
// The sponsor owns the Sponsorship object, so deletion releases the
|
// The sponsor owns the Sponsorship object, so deletion releases the
|
||||||
// sponsor's owner reserve.
|
// sponsor's owner reserve.
|
||||||
auto sponsorAccSle = view.peek(keylet::account(sponsorID));
|
auto sponsorAccSle = AccountRootEntryW(sponsorID, view);
|
||||||
if (!sponsorAccSle)
|
if (!sponsorAccSle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ deleteSponsorship(ApplyView& view, SLE::Ref sle, beast::Journal j)
|
|||||||
if (sle->isFieldPresent(sfFeeAmount))
|
if (sle->isFieldPresent(sfFeeAmount))
|
||||||
{
|
{
|
||||||
(*sponsorAccSle)[sfBalance] += sle->getFieldAmount(sfFeeAmount);
|
(*sponsorAccSle)[sfBalance] += sle->getFieldAmount(sfFeeAmount);
|
||||||
view.update(sponsorAccSle);
|
sponsorAccSle.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
view.erase(sle);
|
view.erase(sle);
|
||||||
@@ -250,8 +251,8 @@ SponsorshipSet::createSponsorship(
|
|||||||
Keylet const& sponsorshipKeylet,
|
Keylet const& sponsorshipKeylet,
|
||||||
AccountID const& sponsorID,
|
AccountID const& sponsorID,
|
||||||
AccountID const& sponseeID,
|
AccountID const& sponseeID,
|
||||||
SLE::Ref sponsorAccSle,
|
AccountRootEntryW& sponsorAccSle,
|
||||||
SLE::Ref reserveSponsorAccSle)
|
std::optional<AccountRootEntryW>& reserveSponsorAccSle)
|
||||||
{
|
{
|
||||||
auto const feeAmountDelta = ctx_.tx[~sfFeeAmountDelta];
|
auto const feeAmountDelta = ctx_.tx[~sfFeeAmountDelta];
|
||||||
auto const maxFee = ctx_.tx[~sfMaxFee];
|
auto const maxFee = ctx_.tx[~sfMaxFee];
|
||||||
@@ -276,13 +277,11 @@ SponsorshipSet::createSponsorship(
|
|||||||
if (hasPositiveFeeAmount)
|
if (hasPositiveFeeAmount)
|
||||||
sponsorBalanceAfterFee -= *feeAmountDelta;
|
sponsorBalanceAfterFee -= *feeAmountDelta;
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sponsorAccSle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sponsorAccSle,
|
|
||||||
sponsorBalanceAfterFee.xrp(),
|
sponsorBalanceAfterFee.xrp(),
|
||||||
reserveSponsorAccSle,
|
reserveSponsorAccSle,
|
||||||
{.ownerCountDelta = 1},
|
{.ownerCountDelta = 1},
|
||||||
ctx_.journal,
|
|
||||||
tecUNFUNDED);
|
tecUNFUNDED);
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
{
|
{
|
||||||
@@ -323,8 +322,9 @@ SponsorshipSet::createSponsorship(
|
|||||||
(*newSle)[sfSponseeNode] = *sponseePage;
|
(*newSle)[sfSponseeNode] = *sponseePage;
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-suspicious-call-argument)
|
// NOLINTNEXTLINE(readability-suspicious-call-argument)
|
||||||
increaseOwnerCount(view(), sponsorAccSle, reserveSponsorAccSle, 1, ctx_.journal);
|
sponsorAccSle.increaseOwnerCount(reserveSponsorAccSle, 1);
|
||||||
addSponsorToLedgerEntry(newSle, reserveSponsorAccSle);
|
if (reserveSponsorAccSle.has_value())
|
||||||
|
addSponsorToLedgerEntry(newSle, reserveSponsorAccSle->rawSle());
|
||||||
|
|
||||||
ctx_.view().insert(newSle);
|
ctx_.view().insert(newSle);
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
@@ -339,7 +339,7 @@ SponsorshipSet::doApply()
|
|||||||
if (sponseeID == sponsorID)
|
if (sponseeID == sponsorID)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const sponsorAccSle = ctx_.view().peek(keylet::account(sponsorID));
|
auto sponsorAccSle = AccountRootEntryW(sponsorID, ctx_.view(), ctx_.journal);
|
||||||
if (!sponsorAccSle)
|
if (!sponsorAccSle)
|
||||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -388,13 +388,11 @@ SponsorshipSet::doApply()
|
|||||||
// object.
|
// object.
|
||||||
(*sponsorAccSle)[sfBalance] -= actualDelta;
|
(*sponsorAccSle)[sfBalance] -= actualDelta;
|
||||||
|
|
||||||
if (auto const ret = checkReserve(
|
if (auto const ret = sponsorAccSle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sponsorAccSle,
|
|
||||||
(*sponsorAccSle)[sfBalance]->xrp(),
|
(*sponsorAccSle)[sfBalance]->xrp(),
|
||||||
*reserveSponsorAccSle,
|
*reserveSponsorAccSle,
|
||||||
{},
|
{},
|
||||||
ctx_.journal,
|
|
||||||
tecUNFUNDED);
|
tecUNFUNDED);
|
||||||
!isTesSuccess(ret))
|
!isTesSuccess(ret))
|
||||||
{
|
{
|
||||||
@@ -413,7 +411,7 @@ SponsorshipSet::doApply()
|
|||||||
{
|
{
|
||||||
(*sponsorshipSle)[sfFeeAmount] = newFee;
|
(*sponsorshipSle)[sfFeeAmount] = newFee;
|
||||||
}
|
}
|
||||||
ctx_.view().update(sponsorAccSle);
|
sponsorAccSle.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxFee)
|
if (maxFee)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ApplyView.h>
|
#include <xrpl/ledger/ApplyView.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
@@ -20,17 +20,13 @@
|
|||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <optional>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
// Increment an uint32 sponsor count field and update the SLE.
|
// Increment an uint32 sponsor count field and update the SLE.
|
||||||
static TER
|
static TER
|
||||||
incrementSponsorCount(
|
incrementSponsorCount(AccountRootEntryW& sle, SF_UINT32 const& field, std::uint32_t const delta)
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref sle,
|
|
||||||
SF_UINT32 const& field,
|
|
||||||
std::uint32_t const delta)
|
|
||||||
{
|
{
|
||||||
auto const currentValue = sle->getFieldU32(field);
|
auto const currentValue = sle->getFieldU32(field);
|
||||||
if (std::numeric_limits<std::uint32_t>::max() - currentValue < delta)
|
if (std::numeric_limits<std::uint32_t>::max() - currentValue < delta)
|
||||||
@@ -42,17 +38,13 @@ incrementSponsorCount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sle->at(field) = currentValue + delta;
|
sle->at(field) = currentValue + delta;
|
||||||
view.update(sle);
|
sle.update();
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement an uint32 sponsor count field and update the SLE.
|
// Decrement an uint32 sponsor count field and update the SLE.
|
||||||
static TER
|
static TER
|
||||||
decrementSponsorCount(
|
decrementSponsorCount(AccountRootEntryW& sle, SF_UINT32 const& field, std::uint32_t const delta)
|
||||||
ApplyView& view,
|
|
||||||
SLE::Ref sle,
|
|
||||||
SF_UINT32 const& field,
|
|
||||||
std::uint32_t const delta)
|
|
||||||
{
|
{
|
||||||
auto const currentValue = sle->getFieldU32(field);
|
auto const currentValue = sle->getFieldU32(field);
|
||||||
if (currentValue < delta)
|
if (currentValue < delta)
|
||||||
@@ -64,7 +56,7 @@ decrementSponsorCount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sle->at(field) = currentValue - delta;
|
sle->at(field) = currentValue - delta;
|
||||||
view.update(sle);
|
sle.update();
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +224,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
auto const account = ctx.tx[sfAccount];
|
auto const account = ctx.tx[sfAccount];
|
||||||
auto const sponseeID = ctx.tx[~sfSponsee].value_or(account);
|
auto const sponseeID = ctx.tx[~sfSponsee].value_or(account);
|
||||||
auto const sponseeSle = ctx.view.read(keylet::account(sponseeID));
|
auto const sponseeSle = AccountRootEntryR(sponseeID, ctx.view);
|
||||||
if (!sponseeSle)
|
if (!sponseeSle)
|
||||||
{
|
{
|
||||||
// If it is ending sponsorship, sfSponsee is user input, return terNO_ACCOUNT if it does not
|
// If it is ending sponsorship, sfSponsee is user input, return terNO_ACCOUNT if it does not
|
||||||
@@ -248,7 +240,7 @@ SponsorshipTransfer::preclaim(PreclaimContext const& ctx)
|
|||||||
// Default setup with an account sponsorship transfer. If it is an object transfer, they will be
|
// Default setup with an account sponsorship transfer. If it is an object transfer, they will be
|
||||||
// overridden to the object SLE and its type-specific sponsor field:
|
// overridden to the object SLE and its type-specific sponsor field:
|
||||||
// sfHighSponsor/sfLowSponsor for a RippleState, sfSponsor for other object types.
|
// sfHighSponsor/sfLowSponsor for a RippleState, sfSponsor for other object types.
|
||||||
SLE::const_pointer targetSle = sponseeSle;
|
SLE::const_pointer targetSle = sponseeSle.rawSle();
|
||||||
auto const* sponsorField = &sfSponsor;
|
auto const* sponsorField = &sfSponsor;
|
||||||
|
|
||||||
if (objectID.has_value())
|
if (objectID.has_value())
|
||||||
@@ -313,7 +305,7 @@ SponsorshipTransfer::doApply()
|
|||||||
auto const objectID = ctx_.tx[~sfObjectID];
|
auto const objectID = ctx_.tx[~sfObjectID];
|
||||||
|
|
||||||
auto const sponseeID = ctx_.tx[~sfSponsee].value_or(accountID_);
|
auto const sponseeID = ctx_.tx[~sfSponsee].value_or(accountID_);
|
||||||
auto const sponseeSle = view().peek(keylet::account(sponseeID));
|
auto sponseeSle = AccountRootEntryW(sponseeID, view(), ctx_.journal);
|
||||||
if (!sponseeSle)
|
if (!sponseeSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -337,7 +329,7 @@ SponsorshipTransfer::doApply()
|
|||||||
if (!isLedgerEntryOwner(view(), *objectSle, sponseeID))
|
if (!isLedgerEntryOwner(view(), *objectSle, sponseeID))
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
auto const ownerSle = view().peek(keylet::account(sponseeID));
|
auto ownerSle = AccountRootEntryW(sponseeID, view());
|
||||||
if (!ownerSle)
|
if (!ownerSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -355,27 +347,25 @@ SponsorshipTransfer::doApply()
|
|||||||
if (!newSponsor)
|
if (!newSponsor)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const newSponsorID = *newSponsor;
|
auto const newSponsorID = *newSponsor;
|
||||||
auto const newSponsorSle = view().peek(keylet::account(newSponsorID));
|
auto newSponsorSle = AccountRootEntryW(newSponsorID, view());
|
||||||
if (!newSponsorSle)
|
if (!newSponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Check if new sponsor has sufficient balance
|
// Check if new sponsor has sufficient balance
|
||||||
// NOLINTNEXTLINE(readability-suspicious-call-argument)
|
// NOLINTNEXTLINE(readability-suspicious-call-argument)
|
||||||
if (auto const ter = checkReserve(
|
if (auto const ter = sponseeSle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sponseeSle,
|
|
||||||
sponseeSle->getFieldAmount(sfBalance).xrp(),
|
sponseeSle->getFieldAmount(sfBalance).xrp(),
|
||||||
newSponsorSle,
|
std::optional<AccountRootEntryR>{newSponsorSle},
|
||||||
{.ownerCountDelta = ownerCountDelta},
|
{.ownerCountDelta = ownerCountDelta});
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter;
|
return ter;
|
||||||
|
|
||||||
if (isCreate)
|
if (isCreate)
|
||||||
{
|
{
|
||||||
// Update owner's sponsored count
|
// Update owner's sponsored count
|
||||||
if (auto const ter = incrementSponsorCount(
|
if (auto const ter =
|
||||||
view(), ownerSle, sfSponsoredOwnerCount, ownerCountDelta);
|
incrementSponsorCount(ownerSle, sfSponsoredOwnerCount, ownerCountDelta);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
@@ -384,20 +374,20 @@ SponsorshipTransfer::doApply()
|
|||||||
auto const oldSponsorID = objectSle->getAccountID(sponsorField);
|
auto const oldSponsorID = objectSle->getAccountID(sponsorField);
|
||||||
if (!oldSponsorID)
|
if (!oldSponsorID)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const oldSponsorSle = view().peek(keylet::account(oldSponsorID));
|
auto oldSponsorSle = AccountRootEntryW(oldSponsorID, view());
|
||||||
if (!oldSponsorSle)
|
if (!oldSponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Decrement old sponsor's sponsoring count
|
// Decrement old sponsor's sponsoring count
|
||||||
if (auto const ter = decrementSponsorCount(
|
if (auto const ter = decrementSponsorCount(
|
||||||
view(), oldSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
|
oldSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment new sponsor's sponsoring count
|
// Increment new sponsor's sponsoring count
|
||||||
if (auto const ter = incrementSponsorCount(
|
if (auto const ter =
|
||||||
view(), newSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
|
incrementSponsorCount(newSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -421,7 +411,7 @@ SponsorshipTransfer::doApply()
|
|||||||
auto const oldSponsorID = objectSle->getAccountID(sponsorField);
|
auto const oldSponsorID = objectSle->getAccountID(sponsorField);
|
||||||
if (!oldSponsorID)
|
if (!oldSponsorID)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const oldSponsorSle = view().peek(keylet::account(oldSponsorID));
|
auto oldSponsorSle = AccountRootEntryW(oldSponsorID, view());
|
||||||
if (!oldSponsorSle)
|
if (!oldSponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -433,26 +423,24 @@ SponsorshipTransfer::doApply()
|
|||||||
// steps in (Reassign), or the object/account is deleted.
|
// steps in (Reassign), or the object/account is deleted.
|
||||||
if (view().rules().enabled(fixCleanup3_4_0))
|
if (view().rules().enabled(fixCleanup3_4_0))
|
||||||
{
|
{
|
||||||
if (auto const ter = checkReserve(
|
if (auto const ter = sponseeSle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sponseeSle,
|
balanceBeforeFee(sponseeSle.rawSle()),
|
||||||
balanceBeforeFee(sponseeSle),
|
std::nullopt,
|
||||||
SLE::pointer(),
|
{.ownerCountDelta = ownerCountDelta});
|
||||||
{.ownerCountDelta = ownerCountDelta},
|
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter;
|
return ter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement sponsored count
|
// Decrement sponsored count
|
||||||
if (auto const ter = decrementSponsorCount(
|
if (auto const ter =
|
||||||
view(), sponseeSle, sfSponsoredOwnerCount, ownerCountDelta);
|
decrementSponsorCount(sponseeSle, sfSponsoredOwnerCount, ownerCountDelta);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Decrement old sponsoring count
|
// Decrement old sponsoring count
|
||||||
if (auto const ter = decrementSponsorCount(
|
if (auto const ter =
|
||||||
view(), oldSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
|
decrementSponsorCount(oldSponsorSle, sfSponsoringOwnerCount, ownerCountDelta);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -475,17 +463,15 @@ SponsorshipTransfer::doApply()
|
|||||||
if (!newSponsor)
|
if (!newSponsor)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const newSponsorID = *newSponsor;
|
auto const newSponsorID = *newSponsor;
|
||||||
auto const newSponsorSle = view().peek(keylet::account(newSponsorID));
|
auto newSponsorSle = AccountRootEntryW(newSponsorID, view());
|
||||||
if (!newSponsorSle)
|
if (!newSponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
if (auto const ter = checkReserve(
|
if (auto const ter = sponseeSle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sponseeSle,
|
|
||||||
sponseeSle->getFieldAmount(sfBalance).xrp(),
|
sponseeSle->getFieldAmount(sfBalance).xrp(),
|
||||||
newSponsorSle,
|
std::optional<AccountRootEntryR>{newSponsorSle},
|
||||||
{.accountCountDelta = 1},
|
{.accountCountDelta = 1});
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter;
|
return ter;
|
||||||
|
|
||||||
@@ -494,26 +480,25 @@ SponsorshipTransfer::doApply()
|
|||||||
auto const oldSponsorID = sponseeSle->getAccountID(sfSponsor);
|
auto const oldSponsorID = sponseeSle->getAccountID(sfSponsor);
|
||||||
if (!oldSponsorID)
|
if (!oldSponsorID)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const oldSponsorSle = view().peek(keylet::account(oldSponsorID));
|
auto oldSponsorSle = AccountRootEntryW(oldSponsorID, view());
|
||||||
if (!oldSponsorSle)
|
if (!oldSponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Decrement old sponsoring count
|
// Decrement old sponsoring count
|
||||||
if (auto const ter =
|
if (auto const ter =
|
||||||
decrementSponsorCount(view(), oldSponsorSle, sfSponsoringAccountCount, 1);
|
decrementSponsorCount(oldSponsorSle, sfSponsoringAccountCount, 1);
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment new sponsoring count
|
// Increment new sponsoring count
|
||||||
if (auto const ter =
|
if (auto const ter = incrementSponsorCount(newSponsorSle, sfSponsoringAccountCount, 1);
|
||||||
incrementSponsorCount(view(), newSponsorSle, sfSponsoringAccountCount, 1);
|
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// Account is now sponsored by new sponsor
|
// Account is now sponsored by new sponsor
|
||||||
sponseeSle->setAccountID(sfSponsor, newSponsorID);
|
sponseeSle->setAccountID(sfSponsor, newSponsorID);
|
||||||
view().update(sponseeSle);
|
sponseeSle.update();
|
||||||
}
|
}
|
||||||
else if (ctx_.tx.isFlag(tfSponsorshipEnd))
|
else if (ctx_.tx.isFlag(tfSponsorshipEnd))
|
||||||
{
|
{
|
||||||
@@ -521,28 +506,25 @@ SponsorshipTransfer::doApply()
|
|||||||
auto const oldSponsorID = sponseeSle->getAccountID(sfSponsor);
|
auto const oldSponsorID = sponseeSle->getAccountID(sfSponsor);
|
||||||
if (!oldSponsorID)
|
if (!oldSponsorID)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
auto const oldSponsorSle = view().peek(keylet::account(oldSponsorID));
|
auto oldSponsorSle = AccountRootEntryW(oldSponsorID, view());
|
||||||
if (!oldSponsorSle)
|
if (!oldSponsorSle)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
// The sponsee must be able to hold its own account reserve after
|
// The sponsee must be able to hold its own account reserve after
|
||||||
// the sponsorship is removed.
|
// the sponsorship is removed.
|
||||||
if (auto const ter = checkReserve(
|
if (auto const ter = sponseeSle.checkReserve(
|
||||||
ctx_.getApplyViewContext(),
|
ctx_.getApplyViewContext(),
|
||||||
sponseeSle,
|
balanceBeforeFee(sponseeSle.rawSle()),
|
||||||
balanceBeforeFee(sponseeSle),
|
std::optional<AccountRootEntryR>{},
|
||||||
SLE::pointer(),
|
{.accountCountDelta = 1});
|
||||||
{.accountCountDelta = 1},
|
|
||||||
ctx_.journal);
|
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter;
|
return ter;
|
||||||
|
|
||||||
sponseeSle->makeFieldAbsent(sfSponsor);
|
sponseeSle->makeFieldAbsent(sfSponsor);
|
||||||
view().update(sponseeSle);
|
sponseeSle.update();
|
||||||
|
|
||||||
// Decrement account sponsoring count
|
// Decrement account sponsoring count
|
||||||
if (auto const ter =
|
if (auto const ter = decrementSponsorCount(oldSponsorSle, sfSponsoringAccountCount, 1);
|
||||||
decrementSponsorCount(view(), oldSponsorSle, sfSponsoringAccountCount, 1);
|
|
||||||
!isTesSuccess(ter))
|
!isTesSuccess(ter))
|
||||||
return ter; // LCOV_EXCL_LINE
|
return ter; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
#include <xrpl/ledger/helpers/NFTokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -96,7 +97,7 @@ LedgerStateFix::preclaim(PreclaimContext const& ctx)
|
|||||||
if (static_cast<FixType>(ctx.tx[sfLedgerFixType]) == FixType::NfTokenPageLink)
|
if (static_cast<FixType>(ctx.tx[sfLedgerFixType]) == FixType::NfTokenPageLink)
|
||||||
{
|
{
|
||||||
AccountID const owner{ctx.tx[sfOwner]};
|
AccountID const owner{ctx.tx[sfOwner]};
|
||||||
if (!ctx.view.read(keylet::account(owner)))
|
if (!AccountRootEntryR(owner, ctx.view))
|
||||||
return tecOBJECT_NOT_FOUND;
|
return tecOBJECT_NOT_FOUND;
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
#include <xrpl/basics/base_uint.h>
|
#include <xrpl/basics/base_uint.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||||
#include <xrpl/protocol/Indexes.h>
|
#include <xrpl/protocol/Indexes.h>
|
||||||
#include <xrpl/protocol/Keylet.h>
|
#include <xrpl/protocol/Keylet.h>
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace xrpl {
|
namespace xrpl {
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ TER
|
|||||||
TicketCreate::preclaim(PreclaimContext const& ctx)
|
TicketCreate::preclaim(PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const id = ctx.tx[sfAccount];
|
auto const id = ctx.tx[sfAccount];
|
||||||
auto const sleAccountRoot = ctx.view.read(keylet::account(id));
|
auto const sleAccountRoot = AccountRootEntryR(id, ctx.view);
|
||||||
if (!sleAccountRoot)
|
if (!sleAccountRoot)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ TicketCreate::preclaim(PreclaimContext const& ctx)
|
|||||||
TER
|
TER
|
||||||
TicketCreate::doApply()
|
TicketCreate::doApply()
|
||||||
{
|
{
|
||||||
SLE::pointer const sleAccountRoot = view().peek(keylet::account(accountID_));
|
auto sleAccountRoot = AccountRootEntryW(accountID_, view(), j_);
|
||||||
if (!sleAccountRoot)
|
if (!sleAccountRoot)
|
||||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||||
|
|
||||||
@@ -75,15 +77,10 @@ TicketCreate::doApply()
|
|||||||
// check the starting balance because we want to allow dipping into the
|
// check the starting balance because we want to allow dipping into the
|
||||||
// reserve to pay fees.
|
// reserve to pay fees.
|
||||||
std::uint32_t const ticketCount = ctx_.tx[sfTicketCount];
|
std::uint32_t const ticketCount = ctx_.tx[sfTicketCount];
|
||||||
if (preFeeBalance_ < accountReserve(
|
if (preFeeBalance_ <
|
||||||
view(),
|
sleAccountRoot.reserve({.ownerCountDelta = static_cast<std::int32_t>(ticketCount)}))
|
||||||
sleAccountRoot,
|
|
||||||
j_,
|
|
||||||
{.ownerCountDelta = static_cast<std::int32_t>(ticketCount)}))
|
|
||||||
return tecINSUFFICIENT_RESERVE;
|
return tecINSUFFICIENT_RESERVE;
|
||||||
|
|
||||||
beast::Journal const viewJ{ctx_.registry.get().getJournal("View")};
|
|
||||||
|
|
||||||
// The starting ticket sequence is the same as the current account
|
// The starting ticket sequence is the same as the current account
|
||||||
// root sequence. Before we got here to doApply(), the transaction
|
// root sequence. Before we got here to doApply(), the transaction
|
||||||
// machinery already incremented the account root sequence if that
|
// machinery already incremented the account root sequence if that
|
||||||
@@ -125,7 +122,8 @@ TicketCreate::doApply()
|
|||||||
sleAccountRoot->setFieldU32(sfTicketCount, oldTicketCount + ticketCount);
|
sleAccountRoot->setFieldU32(sfTicketCount, oldTicketCount + ticketCount);
|
||||||
|
|
||||||
// Every added Ticket counts against the creator's reserve.
|
// Every added Ticket counts against the creator's reserve.
|
||||||
increaseOwnerCount(view(), sleAccountRoot, {}, ticketCount, viewJ);
|
std::optional<AccountRootEntryW> noSponsor;
|
||||||
|
sleAccountRoot.increaseOwnerCount(noSponsor, ticketCount);
|
||||||
|
|
||||||
// TicketCreate is the only transaction that can cause an account root's
|
// TicketCreate is the only transaction that can cause an account root's
|
||||||
// Sequence field to increase by more than one. October 2018.
|
// Sequence field to increase by more than one. October 2018.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/Zero.h>
|
#include <xrpl/beast/utility/Zero.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/AccountID.h>
|
#include <xrpl/protocol/AccountID.h>
|
||||||
@@ -186,8 +187,8 @@ Clawback::preclaim(PreclaimContext const& ctx)
|
|||||||
auto const clawAmount = ctx.tx[sfAmount];
|
auto const clawAmount = ctx.tx[sfAmount];
|
||||||
AccountID const holder = clawAmount.holds<Issue>() ? clawAmount.getIssuer() : ctx.tx[sfHolder];
|
AccountID const holder = clawAmount.holds<Issue>() ? clawAmount.getIssuer() : ctx.tx[sfHolder];
|
||||||
|
|
||||||
auto const sleIssuer = ctx.view.read(keylet::account(issuer));
|
auto const sleIssuer = AccountRootEntryR(issuer, ctx.view);
|
||||||
auto const sleHolder = ctx.view.read(keylet::account(holder));
|
auto const sleHolder = AccountRootEntryR(holder, ctx.view);
|
||||||
if (!sleIssuer || !sleHolder)
|
if (!sleIssuer || !sleHolder)
|
||||||
return terNO_ACCOUNT;
|
return terNO_ACCOUNT;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,220 @@
|
|||||||
|
#include <xrpl/tx/transactors/token/ConfidentialMPTHolderKeyUpdate.h>
|
||||||
|
|
||||||
|
#include <xrpl/basics/Slice.h>
|
||||||
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/protocol/ConfidentialTransfer.h>
|
||||||
|
#include <xrpl/protocol/Feature.h>
|
||||||
|
#include <xrpl/protocol/Indexes.h>
|
||||||
|
#include <xrpl/protocol/LedgerFormats.h>
|
||||||
|
#include <xrpl/protocol/MPTIssue.h>
|
||||||
|
#include <xrpl/protocol/Protocol.h>
|
||||||
|
#include <xrpl/protocol/SField.h>
|
||||||
|
#include <xrpl/protocol/TER.h>
|
||||||
|
#include <xrpl/protocol/TxFlags.h>
|
||||||
|
#include <xrpl/protocol/XRPAmount.h>
|
||||||
|
#include <xrpl/tx/Transactor.h>
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace xrpl {
|
||||||
|
|
||||||
|
bool
|
||||||
|
ConfidentialMPTHolderKeyUpdate::checkExtraFeatures(PreflightContext const& ctx)
|
||||||
|
{
|
||||||
|
// Holder key update is only meaningful when confidential transfers are enabled.
|
||||||
|
return ctx.rules.enabled(featureConfidentialTransfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t
|
||||||
|
ConfidentialMPTHolderKeyUpdate::getFlagsMask(PreflightContext const& ctx)
|
||||||
|
{
|
||||||
|
return tfConfidentialMPTHolderKeyUpdateMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotTEC
|
||||||
|
ConfidentialMPTHolderKeyUpdate::preflight(PreflightContext const& ctx)
|
||||||
|
{
|
||||||
|
bool const rotation = ctx.tx.isFlag(tfHolderKeyRotation);
|
||||||
|
bool const recovery = ctx.tx.isFlag(tfHolderKeyRecovery);
|
||||||
|
bool const cancel = ctx.tx.isFlag(tfCancelRecovery);
|
||||||
|
|
||||||
|
// Exactly one of the three mode flags must be set.
|
||||||
|
static constexpr auto modeFlags = tfHolderKeyRotation | tfHolderKeyRecovery | tfCancelRecovery;
|
||||||
|
if (std::popcount(ctx.tx.getFlags() & modeFlags) != 1)
|
||||||
|
return temINVALID_FLAG;
|
||||||
|
|
||||||
|
// The issuer cannot hold confidential balances.
|
||||||
|
if (ctx.tx[sfAccount] == MPTIssue(ctx.tx[sfMPTokenIssuanceID]).getIssuer())
|
||||||
|
return temMALFORMED;
|
||||||
|
|
||||||
|
bool const hasHolderKey = ctx.tx.isFieldPresent(sfHolderEncryptionKey);
|
||||||
|
bool const hasSpending = ctx.tx.isFieldPresent(sfConfidentialBalanceSpending);
|
||||||
|
bool const hasInbox = ctx.tx.isFieldPresent(sfConfidentialBalanceInbox);
|
||||||
|
bool const hasProof = ctx.tx.isFieldPresent(sfZKProof);
|
||||||
|
|
||||||
|
if (cancel)
|
||||||
|
{
|
||||||
|
// Cancel mode only revokes a pending recovery authorization; it
|
||||||
|
// carries no key material, balances, or proof.
|
||||||
|
if (hasHolderKey || hasSpending || hasInbox || hasProof)
|
||||||
|
return temMALFORMED;
|
||||||
|
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotation and Recovery both require a holder key and a proof.
|
||||||
|
if (!hasHolderKey || !hasProof)
|
||||||
|
return temMALFORMED;
|
||||||
|
|
||||||
|
// Rotation mode requires re-encrypted balances; Recovery mode must not
|
||||||
|
// provide them since the holder cannot decrypt the current ones.
|
||||||
|
if (rotation && (!hasSpending || !hasInbox))
|
||||||
|
return temMALFORMED;
|
||||||
|
|
||||||
|
if (recovery && (hasSpending || hasInbox))
|
||||||
|
return temMALFORMED;
|
||||||
|
|
||||||
|
if (hasSpending &&
|
||||||
|
ctx.tx[sfConfidentialBalanceSpending].length() != kEcGamalEncryptedTotalLength)
|
||||||
|
return temBAD_CIPHERTEXT;
|
||||||
|
|
||||||
|
if (hasInbox && ctx.tx[sfConfidentialBalanceInbox].length() != kEcGamalEncryptedTotalLength)
|
||||||
|
return temBAD_CIPHERTEXT;
|
||||||
|
|
||||||
|
if (!isValidCompressedECPoint(ctx.tx[sfHolderEncryptionKey]))
|
||||||
|
return temMALFORMED;
|
||||||
|
|
||||||
|
if (hasSpending && !isValidCiphertext(ctx.tx[sfConfidentialBalanceSpending]))
|
||||||
|
return temBAD_CIPHERTEXT;
|
||||||
|
|
||||||
|
if (hasInbox && !isValidCiphertext(ctx.tx[sfConfidentialBalanceInbox]))
|
||||||
|
return temBAD_CIPHERTEXT;
|
||||||
|
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
XRPAmount
|
||||||
|
ConfidentialMPTHolderKeyUpdate::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||||
|
{
|
||||||
|
return Transactor::calculateBaseFee(view, tx, kConfidentialFeeMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
TER
|
||||||
|
ConfidentialMPTHolderKeyUpdate::preclaim(PreclaimContext const& ctx)
|
||||||
|
{
|
||||||
|
auto const account = ctx.tx[sfAccount];
|
||||||
|
auto const mptIssuanceID = ctx.tx[sfMPTokenIssuanceID];
|
||||||
|
|
||||||
|
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||||
|
if (!sleIssuance)
|
||||||
|
return tecOBJECT_NOT_FOUND;
|
||||||
|
|
||||||
|
if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance))
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
|
auto const sleMptoken = ctx.view.read(keylet::mptoken(mptIssuanceID, account));
|
||||||
|
if (!sleMptoken)
|
||||||
|
return tecOBJECT_NOT_FOUND;
|
||||||
|
|
||||||
|
if (!sleMptoken->isFieldPresent(sfHolderEncryptionKey) ||
|
||||||
|
!sleMptoken->isFieldPresent(sfConfidentialBalanceSpending) ||
|
||||||
|
!sleMptoken->isFieldPresent(sfConfidentialBalanceInbox))
|
||||||
|
{
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.tx.isFlag(tfCancelRecovery))
|
||||||
|
{
|
||||||
|
// Nothing to cancel if no recovery is pending.
|
||||||
|
if (!sleMptoken->isFieldPresent(sfRecoveryKey))
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.tx[sfHolderEncryptionKey] == (*sleMptoken)[sfHolderEncryptionKey])
|
||||||
|
return tecDUPLICATE;
|
||||||
|
|
||||||
|
// Recovery mode: reject if a recovery is already pending
|
||||||
|
if (ctx.tx.isFlag(tfHolderKeyRecovery) && sleMptoken->isFieldPresent(sfRecoveryKey))
|
||||||
|
return tecNO_PERMISSION;
|
||||||
|
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
TER
|
||||||
|
ConfidentialMPTHolderKeyUpdate::doApply()
|
||||||
|
{
|
||||||
|
auto const mptIssuanceID = ctx_.tx[sfMPTokenIssuanceID];
|
||||||
|
auto sleMptoken = view().peek(keylet::mptoken(mptIssuanceID, accountID_));
|
||||||
|
if (!sleMptoken)
|
||||||
|
{
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
UNREACHABLE(
|
||||||
|
"xrpl::ConfidentialMPTHolderKeyUpdate::doApply : preclaim already validated the "
|
||||||
|
"MPToken exists");
|
||||||
|
return tecINTERNAL;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx_.tx.isFlag(tfCancelRecovery))
|
||||||
|
{
|
||||||
|
// The holder revokes their pending recovery authorization; the
|
||||||
|
// current key and balances are left untouched.
|
||||||
|
sleMptoken->makeFieldAbsent(sfRecoveryKey);
|
||||||
|
view().update(sleMptoken);
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const newPubKey = ctx_.tx[sfHolderEncryptionKey];
|
||||||
|
|
||||||
|
if (ctx_.tx.isFlag(tfHolderKeyRotation))
|
||||||
|
{
|
||||||
|
// Replace the key and balances in rotation mode. Rotation proves the
|
||||||
|
// holder still has the old key, so any pending recovery is cancelled.
|
||||||
|
(*sleMptoken)[sfHolderEncryptionKey] = newPubKey;
|
||||||
|
(*sleMptoken)[sfConfidentialBalanceSpending] = ctx_.tx[sfConfidentialBalanceSpending];
|
||||||
|
(*sleMptoken)[sfConfidentialBalanceInbox] = ctx_.tx[sfConfidentialBalanceInbox];
|
||||||
|
sleMptoken->makeFieldAbsent(sfRecoveryKey);
|
||||||
|
incrementConfidentialVersion(*sleMptoken);
|
||||||
|
}
|
||||||
|
else if (ctx_.tx.isFlag(tfHolderKeyRecovery))
|
||||||
|
{
|
||||||
|
// Recovery mode: the holder cannot decrypt their current balances,
|
||||||
|
// so only the pending recovery key is recorded. The balances are
|
||||||
|
// rewritten separately by the issuer via ConfidentialMPTRecoverBalance.
|
||||||
|
(*sleMptoken)[sfRecoveryKey] = newPubKey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LCOV_EXCL_START
|
||||||
|
UNREACHABLE("xrpl::ConfidentialMPTHolderKeyUpdate::doApply : invalid mode");
|
||||||
|
return tecINTERNAL;
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
view().update(sleMptoken);
|
||||||
|
return tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfidentialMPTHolderKeyUpdate::visitInvariantEntry(bool, SLE::ConstRef, SLE::ConstRef)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ConfidentialMPTHolderKeyUpdate::finalizeInvariants(
|
||||||
|
STTx const&,
|
||||||
|
TER,
|
||||||
|
XRPAmount,
|
||||||
|
ReadView const&,
|
||||||
|
beast::Journal const&)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xrpl
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
#include <xrpl/ledger/ReadView.h>
|
#include <xrpl/ledger/ReadView.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||||
#include <xrpl/protocol/ConfidentialTransfer.h>
|
#include <xrpl/protocol/ConfidentialTransfer.h>
|
||||||
@@ -167,7 +168,7 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx)
|
|||||||
|
|
||||||
// Check if destination account exists
|
// Check if destination account exists
|
||||||
auto const destination = ctx.tx[sfDestination];
|
auto const destination = ctx.tx[sfDestination];
|
||||||
auto const sleDst = ctx.view.read(keylet::account(destination));
|
auto const sleDst = AccountRootEntryR(destination, ctx.view);
|
||||||
if (!sleDst)
|
if (!sleDst)
|
||||||
return tecNO_TARGET;
|
return tecNO_TARGET;
|
||||||
|
|
||||||
@@ -292,7 +293,7 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx)
|
|||||||
// Check deposit preauth before the expensive ZK proof verification.
|
// Check deposit preauth before the expensive ZK proof verification.
|
||||||
// Uses read-only view.
|
// Uses read-only view.
|
||||||
auto const preauthErr =
|
auto const preauthErr =
|
||||||
checkDepositPreauth(ctx.tx, ctx.view, account, destination, sleDst, ctx.j);
|
checkDepositPreauth(ctx.tx, ctx.view, account, destination, sleDst.rawSle(), ctx.j);
|
||||||
if (!isTesSuccess(preauthErr))
|
if (!isTesSuccess(preauthErr))
|
||||||
return preauthErr;
|
return preauthErr;
|
||||||
|
|
||||||
@@ -309,7 +310,7 @@ ConfidentialMPTSend::doApply()
|
|||||||
auto sleDestinationMPToken = view().peek(keylet::mptoken(mptIssuanceID, destination));
|
auto sleDestinationMPToken = view().peek(keylet::mptoken(mptIssuanceID, destination));
|
||||||
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
|
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
|
||||||
|
|
||||||
auto const sleDestAcct = view().read(keylet::account(destination));
|
auto const sleDestAcct = AccountRootEntryW(destination, view());
|
||||||
|
|
||||||
if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance || !sleDestAcct)
|
if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance || !sleDestAcct)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <xrpl/tx/transactors/token/MPTokenAuthorize.h>
|
#include <xrpl/tx/transactors/token/MPTokenAuthorize.h>
|
||||||
|
|
||||||
#include <xrpl/core/ServiceRegistry.h>
|
#include <xrpl/core/ServiceRegistry.h>
|
||||||
|
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||||
#include <xrpl/protocol/Feature.h>
|
#include <xrpl/protocol/Feature.h>
|
||||||
@@ -120,7 +121,7 @@ MPTokenAuthorize::preclaim(PreclaimContext const& ctx)
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const sleHolder = ctx.view.read(keylet::account(*holderID));
|
auto const sleHolder = AccountRootEntryR(*holderID, ctx.view);
|
||||||
if (!sleHolder)
|
if (!sleHolder)
|
||||||
return tecNO_DST;
|
return tecNO_DST;
|
||||||
|
|
||||||
|
|||||||
Loaded 100 of 132 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user