mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-24 07:30:30 +00:00
Merge branch 'pratik/otel-phase6-statsd' into pratik/otel-phase7-native-metrics
This commit is contained in:
@@ -12,8 +12,8 @@ template <int Window, typename Clock>
|
||||
class DecayingSample
|
||||
{
|
||||
public:
|
||||
using value_type = typename Clock::duration::rep;
|
||||
using time_point = typename Clock::time_point;
|
||||
using value_type = Clock::duration::rep;
|
||||
using time_point = Clock::time_point;
|
||||
|
||||
DecayingSample() = delete;
|
||||
|
||||
@@ -93,7 +93,7 @@ template <int HalfLife, class Clock>
|
||||
class DecayWindow
|
||||
{
|
||||
public:
|
||||
using time_point = typename Clock::time_point;
|
||||
using time_point = Clock::time_point;
|
||||
|
||||
explicit DecayWindow(time_point now) : when_(now)
|
||||
{
|
||||
|
||||
@@ -206,8 +206,7 @@ private:
|
||||
#ifndef JLOG
|
||||
#define JLOG(x) \
|
||||
if (!(x)) \
|
||||
{ \
|
||||
} \
|
||||
; \
|
||||
else \
|
||||
x
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpl/beast/insight/Insight.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
@@ -17,6 +18,22 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Replace-policy tags selecting how TaggedCache::canonicalizeImpl resolves a
|
||||
// collision when the key already exists (defined in TaggedCache.ipp):
|
||||
// - ReplaceCached: always replace the cached value with `data`. `data` is
|
||||
// never written back and may be const.
|
||||
// - ReplaceClient: keep the cached value and write it back into `data` (the
|
||||
// client's pointer), which must therefore be writable.
|
||||
// - ReplaceDynamically: call the supplied callback to decide per call; `data`
|
||||
// is written back when the cached value is kept, so it must be writable.
|
||||
struct ReplaceCached;
|
||||
struct ReplaceClient;
|
||||
struct ReplaceDynamically;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** Map/cache combination.
|
||||
This class implements a cache and a map. The cache keeps objects alive
|
||||
in the map. The map allows multiple code paths that reference objects
|
||||
@@ -96,6 +113,32 @@ public:
|
||||
bool
|
||||
del(key_type const& key, bool valid);
|
||||
|
||||
private:
|
||||
// Selects the `data` parameter type of canonicalizeImpl from the replace
|
||||
// policy: const for detail::ReplaceCached (never written back), otherwise
|
||||
// writable.
|
||||
template <typename Policy>
|
||||
using CanonicalizeClientPointerType = std::conditional_t<
|
||||
std::is_same_v<detail::ReplaceCached, Policy>,
|
||||
SharedPointerType const&,
|
||||
SharedPointerType&>;
|
||||
|
||||
/** Shared implementation of the canonicalize family.
|
||||
|
||||
`policy` selects how a collision is resolved when `key` already exists:
|
||||
detail::ReplaceCached, detail::ReplaceClient or
|
||||
detail::ReplaceDynamically. For ReplaceDynamically `replaceCallback` is
|
||||
invoked with the existing strong pointer and returns whether to replace
|
||||
the cached value with `data`; for the tag policies it is unused.
|
||||
*/
|
||||
template <class Policy, class Callback = std::nullptr_t>
|
||||
bool
|
||||
canonicalizeImpl(
|
||||
key_type const& key,
|
||||
CanonicalizeClientPointerType<Policy> data,
|
||||
Policy policy,
|
||||
Callback&& replaceCallback = nullptr);
|
||||
|
||||
public:
|
||||
/** Replace aliased objects with originals.
|
||||
|
||||
@@ -104,19 +147,52 @@ public:
|
||||
This routine eliminates the duplicate and performs a replacement
|
||||
on the callers shared pointer if needed.
|
||||
|
||||
`replaceCallback` is a callable taking the existing strong pointer and
|
||||
returning whether to replace the cached value with `data` (true) or to
|
||||
keep the cached value and write it back into `data` (false). Because the
|
||||
write-back case mutates `data`, `data` must be writable.
|
||||
|
||||
@param key The key corresponding to the object
|
||||
@param data A shared pointer to the data corresponding to the object.
|
||||
@param replace Function that decides if cache should be replaced
|
||||
@param replaceCallback A callable (existing strong pointer -> bool).
|
||||
|
||||
@return `true` If the key already existed.
|
||||
*/
|
||||
template <class R>
|
||||
@return `true` if an existing live entry was found and used; `false` if a new entry was
|
||||
inserted or an expired tracked entry was re-cached.
|
||||
**/
|
||||
template <class Callback>
|
||||
bool
|
||||
canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback);
|
||||
canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback);
|
||||
|
||||
/** Insert/update the canonical entry for `key`, always replacing the
|
||||
cached value with `data`.
|
||||
|
||||
If an entry already exists for `key`, the cached value is unconditionally
|
||||
replaced with `data`; otherwise `data` is inserted. `data` is never
|
||||
written back, so it may be const.
|
||||
|
||||
@param key The key corresponding to the object.
|
||||
@param data A shared pointer to the data corresponding to the object.
|
||||
|
||||
@return `true` if an existing live entry was found and used; `false` if a new entry was
|
||||
inserted or an expired tracked entry was re-cached.
|
||||
**/
|
||||
bool
|
||||
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data);
|
||||
|
||||
/** Insert the canonical entry for `key`, keeping any existing cached value.
|
||||
|
||||
If an entry already exists for `key`, the cached value is kept and
|
||||
written back into `data` so the caller ends up with the canonical
|
||||
object; otherwise `data` is inserted. Because `data` may be overwritten
|
||||
it must be writable.
|
||||
|
||||
@param key The key corresponding to the object.
|
||||
@param data A shared pointer to the data corresponding to the object;
|
||||
updated to the canonical value when one already exists.
|
||||
|
||||
@return `true` if an existing live entry was found and used; `false` if a new entry was
|
||||
inserted or an expired tracked entry was re-cached.
|
||||
**/
|
||||
bool
|
||||
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data);
|
||||
|
||||
@@ -262,7 +338,7 @@ private:
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&);
|
||||
@@ -271,7 +347,7 @@ private:
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&);
|
||||
|
||||
@@ -5,6 +5,30 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Replace-policy tags selecting how TaggedCache::canonicalizeImpl resolves a
|
||||
// collision when the key already exists:
|
||||
// - ReplaceCached: always replace the cached value with `data`. `data` is
|
||||
// never written back and may be const.
|
||||
// - ReplaceClient: keep the cached value and write it back into `data` (the
|
||||
// client's pointer), which must therefore be writable.
|
||||
// - ReplaceDynamically: call the supplied callback to decide per call; `data`
|
||||
// is written back when the cached value is kept, so it must be writable.
|
||||
struct ReplaceCached
|
||||
{
|
||||
};
|
||||
|
||||
struct ReplaceClient
|
||||
{
|
||||
};
|
||||
|
||||
struct ReplaceDynamically
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
@@ -300,13 +324,29 @@ template <
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
template <class R>
|
||||
template <class Policy, class Callback>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback)
|
||||
canonicalizeImpl(
|
||||
key_type const& key,
|
||||
CanonicalizeClientPointerType<Policy> data,
|
||||
[[maybe_unused]] Policy policy,
|
||||
[[maybe_unused]] Callback&& replaceCallback)
|
||||
{
|
||||
// Return canonical value, store if needed, refresh in cache
|
||||
// Return values: true=we had the data already
|
||||
|
||||
// `Policy` is one of:
|
||||
// - detail::ReplaceCached: always replace the cached value with `data`;
|
||||
// `data` is never written back and may be const.
|
||||
// - detail::ReplaceClient: keep the cached value and write it back into
|
||||
// `data` (the client's pointer), which must therefore be writable.
|
||||
// - detail::ReplaceDynamically: call `replaceCallback` to decide at run
|
||||
// time; `data` must be writable.
|
||||
// For the latter two the write-back below requires a mutable `data`, so
|
||||
// passing a const argument is a compile error.
|
||||
constexpr bool replaceCached = std::is_same_v<Policy, detail::ReplaceCached>;
|
||||
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
auto cit = cache_.find(key);
|
||||
@@ -324,13 +364,14 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
Entry& entry = cit->second;
|
||||
entry.touch(clock_.now());
|
||||
|
||||
auto shouldReplace = [&] {
|
||||
if constexpr (std::is_invocable_r_v<bool, R>)
|
||||
auto shouldReplaceCached = [&] {
|
||||
if constexpr (replaceCached)
|
||||
{
|
||||
// The reason for this extra complexity is for intrusive
|
||||
// strong/weak combo getting a strong is relatively expensive
|
||||
// and not needed for many cases.
|
||||
return replaceCallback();
|
||||
return true;
|
||||
}
|
||||
else if constexpr (std::is_same_v<Policy, detail::ReplaceClient>)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -340,11 +381,11 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
if (entry.isCached())
|
||||
{
|
||||
if (shouldReplace())
|
||||
if (shouldReplaceCached())
|
||||
{
|
||||
entry.ptr = data;
|
||||
}
|
||||
else
|
||||
else if constexpr (!replaceCached)
|
||||
{
|
||||
data = entry.ptr.getStrong();
|
||||
}
|
||||
@@ -356,11 +397,11 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
if (cachedData)
|
||||
{
|
||||
if (shouldReplace())
|
||||
if (shouldReplaceCached())
|
||||
{
|
||||
entry.ptr = data;
|
||||
}
|
||||
else
|
||||
else if constexpr (!replaceCached)
|
||||
{
|
||||
entry.ptr.convertToStrong();
|
||||
data = cachedData;
|
||||
@@ -376,6 +417,24 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
return false;
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache,
|
||||
class SharedWeakUnionPointer,
|
||||
class SharedPointerType,
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
template <class Callback>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback)
|
||||
{
|
||||
return canonicalizeImpl(
|
||||
key, data, detail::ReplaceDynamically{}, std::forward<Callback>(replaceCallback));
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
@@ -389,7 +448,7 @@ inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data)
|
||||
{
|
||||
return canonicalize(key, const_cast<SharedPointerType&>(data), []() { return true; });
|
||||
return canonicalizeImpl(key, data, detail::ReplaceCached{});
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -405,7 +464,7 @@ inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data)
|
||||
{
|
||||
return canonicalize(key, data, []() { return false; });
|
||||
return canonicalizeImpl(key, data, detail::ReplaceClient{});
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -676,7 +735,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&)
|
||||
@@ -756,7 +815,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&)
|
||||
|
||||
@@ -75,7 +75,7 @@ private:
|
||||
detail::seed_pair seeds_{detail::makeSeedPair<>()};
|
||||
|
||||
public:
|
||||
using result_type = typename HashAlgorithm::result_type;
|
||||
using result_type = HashAlgorithm::result_type;
|
||||
|
||||
HardenedHash() = default;
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ public:
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
partition_map_type* map{nullptr};
|
||||
typename partition_map_type::iterator ait{};
|
||||
typename map_type::iterator mit;
|
||||
partition_map_type::iterator ait{};
|
||||
map_type::iterator mit;
|
||||
|
||||
Iterator() = default;
|
||||
|
||||
@@ -126,8 +126,8 @@ public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
partition_map_type* map{nullptr};
|
||||
typename partition_map_type::iterator ait{};
|
||||
typename map_type::iterator mit;
|
||||
partition_map_type::iterator ait{};
|
||||
map_type::iterator mit;
|
||||
|
||||
ConstIterator() = default;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ static_assert(
|
||||
namespace detail {
|
||||
|
||||
// Determines if a type can be called like an Engine
|
||||
// NOLINTNEXTLINE(readability-redundant-typename): typename required by MSVC
|
||||
template <class Engine, class Result = typename Engine::result_type>
|
||||
using is_engine = std::is_invocable_r<Result, Engine>;
|
||||
} // namespace detail
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if XRPL_ROCKSDB_AVAILABLE
|
||||
// #include <rocksdb2/port/port_posix.h>
|
||||
#include <rocksdb/cache.h>
|
||||
#include <rocksdb/compaction_filter.h>
|
||||
#include <rocksdb/comparator.h>
|
||||
#include <rocksdb/convenience.h>
|
||||
#include <rocksdb/db.h>
|
||||
#include <rocksdb/env.h>
|
||||
#include <rocksdb/filter_policy.h>
|
||||
#include <rocksdb/flush_block_policy.h>
|
||||
#include <rocksdb/iterator.h>
|
||||
#include <rocksdb/memtablerep.h>
|
||||
#include <rocksdb/merge_operator.h>
|
||||
#include <rocksdb/options.h>
|
||||
#include <rocksdb/perf_context.h>
|
||||
#include <rocksdb/slice.h>
|
||||
#include <rocksdb/slice_transform.h>
|
||||
#include <rocksdb/statistics.h>
|
||||
#include <rocksdb/status.h>
|
||||
#include <rocksdb/table.h>
|
||||
#include <rocksdb/table_properties.h>
|
||||
#include <rocksdb/transaction_log.h>
|
||||
#include <rocksdb/types.h>
|
||||
#include <rocksdb/universal_compaction.h>
|
||||
#include <rocksdb/write_batch.h>
|
||||
|
||||
#endif
|
||||
@@ -4,7 +4,7 @@
|
||||
/*
|
||||
ASAN flags some false positives with sudden jumps in control flow, like
|
||||
exceptions, or when encountering coroutine stack switches. This macro can be used to disable ASAN
|
||||
intrumentation for specific functions.
|
||||
instrumentation for specific functions.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define XRPL_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))
|
||||
|
||||
@@ -18,8 +18,8 @@ template <class Clock>
|
||||
class IOLatencyProbe
|
||||
{
|
||||
private:
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
using duration = Clock::duration;
|
||||
using time_point = Clock::time_point;
|
||||
|
||||
std::recursive_mutex mutex_;
|
||||
std::condition_variable_any cond_;
|
||||
|
||||
@@ -34,10 +34,10 @@ template <class Clock>
|
||||
class AbstractClock
|
||||
{
|
||||
public:
|
||||
using rep = typename Clock::rep;
|
||||
using period = typename Clock::period;
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
using rep = Clock::rep;
|
||||
using period = Clock::period;
|
||||
using duration = Clock::duration;
|
||||
using time_point = Clock::time_point;
|
||||
using clock_type = Clock;
|
||||
|
||||
static bool const is_steady = Clock::is_steady; // NOLINT(readability-identifier-naming)
|
||||
|
||||
@@ -20,10 +20,10 @@ public:
|
||||
|
||||
explicit BasicSecondsClock() = default;
|
||||
|
||||
using rep = typename Clock::rep;
|
||||
using period = typename Clock::period;
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
using rep = Clock::rep;
|
||||
using period = Clock::period;
|
||||
using duration = Clock::duration;
|
||||
using time_point = Clock::time_point;
|
||||
|
||||
static bool const is_steady = // NOLINT(readability-identifier-naming)
|
||||
Clock::is_steady;
|
||||
|
||||
@@ -16,15 +16,15 @@ template <bool IsConst, class Iterator>
|
||||
class AgedContainerIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
|
||||
using iterator_category = std::iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = std::conditional_t<
|
||||
IsConst,
|
||||
typename Iterator::value_type::Stashed::value_type const,
|
||||
typename Iterator::value_type::Stashed::value_type>;
|
||||
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
|
||||
using difference_type = std::iterator_traits<Iterator>::difference_type;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using time_point = typename Iterator::value_type::Stashed::time_point;
|
||||
using time_point = Iterator::value_type::Stashed::time_point;
|
||||
|
||||
AgedContainerIterator() = default;
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ class AgedOrderedContainer
|
||||
{
|
||||
public:
|
||||
using clock_type = AbstractClock<Clock>;
|
||||
using time_point = typename clock_type::time_point;
|
||||
using duration = typename clock_type::duration;
|
||||
using time_point = clock_type::time_point;
|
||||
using duration = clock_type::duration;
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using value_type = std::conditional_t<IsMap, std::pair<Key const, T>, Key>;
|
||||
@@ -94,8 +94,8 @@ private:
|
||||
{
|
||||
explicit Stashed() = default;
|
||||
|
||||
using value_type = typename AgedOrderedContainer::value_type;
|
||||
using time_point = typename AgedOrderedContainer::time_point;
|
||||
using value_type = AgedOrderedContainer::value_type;
|
||||
using time_point = AgedOrderedContainer::time_point;
|
||||
};
|
||||
|
||||
Element(time_point const& when, value_type const& value) : value(value), when(when)
|
||||
@@ -192,8 +192,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
using list_type = typename boost::intrusive::
|
||||
make_list<Element, boost::intrusive::constant_time_size<false>>::type;
|
||||
using list_type =
|
||||
boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
|
||||
|
||||
using cont_type = std::conditional_t<
|
||||
IsMulti,
|
||||
@@ -206,8 +206,7 @@ private:
|
||||
boost::intrusive::constant_time_size<true>,
|
||||
boost::intrusive::compare<KeyValueCompare>>::type>;
|
||||
|
||||
using ElementAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<Element>;
|
||||
using ElementAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
|
||||
|
||||
using ElementAllocatorTraits = std::allocator_traits<ElementAllocator>;
|
||||
|
||||
@@ -373,8 +372,8 @@ public:
|
||||
using allocator_type = Allocator;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using pointer = std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = std::allocator_traits<Allocator>::const_pointer;
|
||||
|
||||
// A set iterator (IsMap==false) is always const
|
||||
// because the elements of a set are immutable.
|
||||
@@ -617,7 +616,7 @@ public:
|
||||
bool MaybeMulti = IsMulti,
|
||||
bool MaybeMap = IsMap,
|
||||
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
|
||||
typename std::conditional<IsMap, T, void*>::type const&
|
||||
std::conditional<IsMap, T, void*>::type const&
|
||||
at(K const& k) const;
|
||||
|
||||
template <
|
||||
@@ -1146,7 +1145,7 @@ private:
|
||||
void
|
||||
touch(
|
||||
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
|
||||
typename clock_type::time_point const& now);
|
||||
clock_type::time_point const& now);
|
||||
|
||||
template <
|
||||
bool MaybePropagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
|
||||
@@ -1393,7 +1392,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::at(K co
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
|
||||
template <class K, bool MaybeMulti, bool MaybeMap, class>
|
||||
typename std::conditional<IsMap, T, void*>::type const&
|
||||
std::conditional<IsMap, T, void*>::type const&
|
||||
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::at(K const& k) const
|
||||
{
|
||||
auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
|
||||
@@ -1732,7 +1731,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operato
|
||||
cend(),
|
||||
other.cbegin(),
|
||||
other.cend(),
|
||||
[&eq, &other](value_type const& lhs, typename Other::value_type const& rhs) {
|
||||
[&eq, &other](value_type const& lhs, Other::value_type const& rhs) {
|
||||
return eq(extract(lhs), other.extract(rhs));
|
||||
});
|
||||
}
|
||||
@@ -1744,7 +1743,7 @@ template <bool IsConst, class Iterator, class>
|
||||
void
|
||||
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::touch(
|
||||
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
|
||||
typename clock_type::time_point const& now)
|
||||
clock_type::time_point const& now)
|
||||
{
|
||||
auto& e(*pos.iterator());
|
||||
e.when = now;
|
||||
|
||||
@@ -67,8 +67,8 @@ class AgedUnorderedContainer
|
||||
{
|
||||
public:
|
||||
using clock_type = AbstractClock<Clock>;
|
||||
using time_point = typename clock_type::time_point;
|
||||
using duration = typename clock_type::duration;
|
||||
using time_point = clock_type::time_point;
|
||||
using duration = clock_type::duration;
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using value_type = std::conditional_t<IsMap, std::pair<Key const, T>, Key>;
|
||||
@@ -99,8 +99,8 @@ private:
|
||||
{
|
||||
explicit Stashed() = default;
|
||||
|
||||
using value_type = typename AgedUnorderedContainer::value_type;
|
||||
using time_point = typename AgedUnorderedContainer::time_point;
|
||||
using value_type = AgedUnorderedContainer::value_type;
|
||||
using time_point = AgedUnorderedContainer::time_point;
|
||||
};
|
||||
|
||||
Element(time_point const& when, value_type const& value) : value(value), when(when)
|
||||
@@ -201,8 +201,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
using list_type = typename boost::intrusive::
|
||||
make_list<Element, boost::intrusive::constant_time_size<false>>::type;
|
||||
using list_type =
|
||||
boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
|
||||
|
||||
using cont_type = std::conditional_t<
|
||||
IsMulti,
|
||||
@@ -219,16 +219,14 @@ private:
|
||||
boost::intrusive::equal<KeyValueEqual>,
|
||||
boost::intrusive::cache_begin<true>>::type>;
|
||||
|
||||
using bucket_type = typename cont_type::bucket_type;
|
||||
using bucket_traits = typename cont_type::bucket_traits;
|
||||
using bucket_type = cont_type::bucket_type;
|
||||
using bucket_traits = cont_type::bucket_traits;
|
||||
|
||||
using ElementAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<Element>;
|
||||
using ElementAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
|
||||
|
||||
using ElementAllocatorTraits = std::allocator_traits<ElementAllocator>;
|
||||
|
||||
using BucketAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<Element>;
|
||||
using BucketAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
|
||||
|
||||
using BucketAllocatorTraits = std::allocator_traits<BucketAllocator>;
|
||||
|
||||
@@ -542,8 +540,8 @@ public:
|
||||
using allocator_type = Allocator;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using pointer = std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = std::allocator_traits<Allocator>::const_pointer;
|
||||
|
||||
// A set iterator (IsMap==false) is always const
|
||||
// because the elements of a set are immutable.
|
||||
@@ -850,7 +848,7 @@ public:
|
||||
bool MaybeMulti = IsMulti,
|
||||
bool MaybeMap = IsMap,
|
||||
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
|
||||
typename std::conditional<IsMap, T, void*>::type const&
|
||||
std::conditional<IsMap, T, void*>::type const&
|
||||
at(K const& k) const;
|
||||
|
||||
template <
|
||||
@@ -1414,7 +1412,7 @@ private:
|
||||
void
|
||||
touch(
|
||||
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
|
||||
typename clock_type::time_point const& now)
|
||||
clock_type::time_point const& now)
|
||||
{
|
||||
auto& e(*pos.iterator());
|
||||
e.when = now;
|
||||
@@ -2111,7 +2109,7 @@ template <
|
||||
class KeyEqual,
|
||||
class Allocator>
|
||||
template <class K, bool MaybeMulti, bool MaybeMap, class>
|
||||
typename std::conditional<IsMap, T, void*>::type const&
|
||||
std::conditional<IsMap, T, void*>::type const&
|
||||
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::at(
|
||||
K const& k) const
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ struct CopyConst<T const, U>
|
||||
{
|
||||
explicit CopyConst() = default;
|
||||
|
||||
using type = typename std::remove_const<U>::type const;
|
||||
using type = std::remove_const<U>::type const;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
@@ -56,7 +56,7 @@ class ListIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename beast::detail::CopyConst<N, typename N::value_type>::type;
|
||||
using value_type = beast::detail::CopyConst<N, typename N::value_type>::type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
@@ -259,7 +259,7 @@ template <typename T, typename Tag = void>
|
||||
class List
|
||||
{
|
||||
public:
|
||||
using Node = typename detail::ListNode<T, Tag>;
|
||||
using Node = detail::ListNode<T, Tag>;
|
||||
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
|
||||
@@ -12,13 +12,13 @@ template <class Container, bool IsConst>
|
||||
class LockFreeStackIterator
|
||||
{
|
||||
protected:
|
||||
using Node = typename Container::Node;
|
||||
using Node = Container::Node;
|
||||
using NodePtr = std::conditional_t<IsConst, Node const*, Node*>;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = typename Container::value_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
using value_type = Container::value_type;
|
||||
using difference_type = Container::difference_type;
|
||||
using pointer =
|
||||
std::conditional_t<IsConst, typename Container::const_pointer, typename Container::pointer>;
|
||||
using reference = std::
|
||||
|
||||
@@ -11,7 +11,7 @@ struct Uhash
|
||||
{
|
||||
Uhash() = default;
|
||||
|
||||
using result_type = typename Hasher::result_type;
|
||||
using result_type = Hasher::result_type;
|
||||
|
||||
template <class T>
|
||||
result_type
|
||||
|
||||
@@ -102,7 +102,7 @@ Result
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
{
|
||||
using namespace detail;
|
||||
using string = typename Result::value_type;
|
||||
using string = Result::value_type;
|
||||
|
||||
Result result;
|
||||
|
||||
|
||||
@@ -32,11 +32,11 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = typename cont_type::value_type;
|
||||
using size_type = typename cont_type::size_type;
|
||||
using difference_type = typename cont_type::difference_type;
|
||||
using iterator = typename cont_type::const_iterator;
|
||||
using const_iterator = typename cont_type::const_iterator;
|
||||
using value_type = cont_type::value_type;
|
||||
using size_type = cont_type::size_type;
|
||||
using difference_type = cont_type::difference_type;
|
||||
using iterator = cont_type::const_iterator;
|
||||
using const_iterator = cont_type::const_iterator;
|
||||
|
||||
/** Returns `true` if the container is empty. */
|
||||
[[nodiscard]] bool
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
std::size_t cases = 0;
|
||||
std::size_t total = 0;
|
||||
std::size_t failed = 0;
|
||||
typename clock_type::time_point start = clock_type::now();
|
||||
clock_type::time_point start = clock_type::now();
|
||||
|
||||
explicit SuiteResults(std::string name = "") : name(std::move(name))
|
||||
{
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
|
||||
struct Results
|
||||
{
|
||||
using run_time = std::pair<std::string, typename clock_type::duration>;
|
||||
using run_time = std::pair<std::string, clock_type::duration>;
|
||||
|
||||
static constexpr auto kMaxTop = 10;
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
std::size_t total = 0;
|
||||
std::size_t failed = 0;
|
||||
std::vector<run_time> top;
|
||||
typename clock_type::time_point start = clock_type::now();
|
||||
clock_type::time_point start = clock_type::now();
|
||||
|
||||
void
|
||||
add(SuiteResults const& r);
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
|
||||
private:
|
||||
static std::string
|
||||
fmtdur(typename clock_type::duration const& d);
|
||||
fmtdur(clock_type::duration const& d);
|
||||
|
||||
void
|
||||
onSuiteBegin(SuiteInfo const& info) override;
|
||||
@@ -141,9 +141,7 @@ Reporter<Unused>::Results::add(SuiteResults const& r)
|
||||
top.begin(),
|
||||
top.end(),
|
||||
elapsed,
|
||||
[](run_time const& t1, typename clock_type::duration const& t2) {
|
||||
return t1.second > t2;
|
||||
});
|
||||
[](run_time const& t1, clock_type::duration const& t2) { return t1.second > t2; });
|
||||
if (iter != top.end())
|
||||
{
|
||||
if (top.size() == kMaxTop)
|
||||
@@ -181,7 +179,7 @@ Reporter<Unused>::~Reporter()
|
||||
|
||||
template <class Unused>
|
||||
std::string
|
||||
Reporter<Unused>::fmtdur(typename clock_type::duration const& d)
|
||||
Reporter<Unused>::fmtdur(clock_type::duration const& d)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto const ms = duration_cast<milliseconds>(d);
|
||||
|
||||
@@ -411,9 +411,9 @@ class BasicLogstream : public std::basic_ostream<CharT, Traits>
|
||||
{
|
||||
using char_type = CharT;
|
||||
using traits_type = Traits;
|
||||
using int_type = typename traits_type::int_type;
|
||||
using pos_type = typename traits_type::pos_type;
|
||||
using off_type = typename traits_type::off_type;
|
||||
using int_type = traits_type::int_type;
|
||||
using pos_type = traits_type::pos_type;
|
||||
using off_type = traits_type::off_type;
|
||||
|
||||
detail::LogStreamBuf<CharT, Traits> buf_;
|
||||
|
||||
|
||||
@@ -15,6 +15,6 @@ struct MaybeConst
|
||||
|
||||
/** Alias for omitting `typename`. */
|
||||
template <bool IsConst, class T>
|
||||
using maybe_const_t = typename MaybeConst<IsConst, T>::type;
|
||||
using maybe_const_t = MaybeConst<IsConst, T>::type;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -13,7 +13,7 @@ template <class Generator>
|
||||
void
|
||||
rngfill(void* const buffer, std::size_t const bytes, Generator& g)
|
||||
{
|
||||
using result_type = typename Generator::result_type;
|
||||
using result_type = Generator::result_type;
|
||||
constexpr std::size_t kResultSize = sizeof(result_type);
|
||||
|
||||
std::uint8_t* const bufferStart = static_cast<std::uint8_t*>(buffer);
|
||||
@@ -42,7 +42,7 @@ template <
|
||||
void
|
||||
rngfill(std::array<std::uint8_t, N>& a, Generator& g)
|
||||
{
|
||||
using result_type = typename Generator::result_type;
|
||||
using result_type = Generator::result_type;
|
||||
auto i = N / sizeof(result_type);
|
||||
result_type* p = reinterpret_cast<result_type*>(a.data());
|
||||
while (i--)
|
||||
|
||||
@@ -566,6 +566,7 @@ public:
|
||||
using SelfType = ValueConstIterator;
|
||||
|
||||
ValueConstIterator() = default;
|
||||
ValueConstIterator(ValueConstIterator const& other) = default;
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
@@ -574,12 +575,12 @@ private:
|
||||
|
||||
public:
|
||||
SelfType&
|
||||
operator=(ValueIteratorBase const& other);
|
||||
operator=(SelfType const& other);
|
||||
|
||||
SelfType
|
||||
operator++(int)
|
||||
{
|
||||
SelfType temp(*this);
|
||||
SelfType const temp(*this);
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
@@ -587,7 +588,7 @@ public:
|
||||
SelfType
|
||||
operator--(int)
|
||||
{
|
||||
SelfType temp(*this);
|
||||
SelfType const temp(*this);
|
||||
--*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/MultiApiJson.h>
|
||||
#include <xrpl/server/InfoSub.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/** Listen to public/subscribe messages from a book. */
|
||||
class BookListeners
|
||||
{
|
||||
public:
|
||||
using pointer = std::shared_ptr<BookListeners>;
|
||||
|
||||
BookListeners() = default;
|
||||
|
||||
/** Add a new subscription for this book
|
||||
*/
|
||||
void
|
||||
addSubscriber(InfoSub::ref sub);
|
||||
|
||||
/** Stop publishing to a subscriber
|
||||
*/
|
||||
void
|
||||
removeSubscriber(std::uint64_t sub);
|
||||
|
||||
/** Publish a transaction to subscribers
|
||||
|
||||
Publish a transaction to clients subscribed to changes on this book.
|
||||
Uses havePublished to prevent sending duplicate transactions to clients
|
||||
that have subscribed to multiple books.
|
||||
|
||||
@param jvObj JSON transaction data to publish
|
||||
@param havePublished InfoSub sequence numbers that have already
|
||||
published this transaction.
|
||||
|
||||
*/
|
||||
void
|
||||
publish(MultiApiJson const& jvObj, hash_set<std::uint64_t>& havePublished);
|
||||
|
||||
private:
|
||||
std::recursive_mutex lock_;
|
||||
|
||||
hash_map<std::uint64_t, InfoSub::wptr> listeners_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/AcceptedLedgerTx.h>
|
||||
#include <xrpl/ledger/BookListeners.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Book.h>
|
||||
#include <xrpl/protocol/MultiApiJson.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <memory>
|
||||
@@ -77,34 +77,24 @@ public:
|
||||
*/
|
||||
virtual bool
|
||||
isBookToXRP(Asset const& asset, std::optional<Domain> const& domain = std::nullopt) = 0;
|
||||
|
||||
/**
|
||||
* Process a transaction for order book tracking.
|
||||
* @param ledger The ledger the transaction was applied to
|
||||
* @param alTx The transaction to process
|
||||
* @param jvObj The JSON object of the transaction
|
||||
*/
|
||||
virtual void
|
||||
processTxn(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
AcceptedLedgerTx const& alTx,
|
||||
MultiApiJson const& jvObj) = 0;
|
||||
|
||||
/**
|
||||
* Get the book listeners for a book.
|
||||
* @param book The book to get the listeners for
|
||||
* @return The book listeners for the book
|
||||
*/
|
||||
virtual BookListeners::pointer
|
||||
getBookListeners(Book const&) = 0;
|
||||
|
||||
/**
|
||||
* Create a new book listeners for a book.
|
||||
* @param book The book to create the listeners for
|
||||
* @return The new book listeners for the book
|
||||
*/
|
||||
virtual BookListeners::pointer
|
||||
makeBookListeners(Book const&) = 0;
|
||||
};
|
||||
|
||||
/** Extract the set of books affected by a transaction.
|
||||
*
|
||||
* Walks the transaction's metadata nodes and collects every order book
|
||||
* whose offers were created, modified, or deleted. Used by NetworkOPs to
|
||||
* fan transaction notifications out to book subscribers.
|
||||
*
|
||||
* @param alTx The accepted ledger transaction to inspect.
|
||||
* @param j Journal used to log per-node parsing failures. Inspecting an
|
||||
* offer node can throw if a required field is missing; in that
|
||||
* case the bad node is skipped and a warn-level message is
|
||||
* emitted via @p j. Other affected books in the same transaction
|
||||
* are still returned.
|
||||
* @return The set of books whose offers were created, modified, or
|
||||
* deleted. May be empty for non-offer transactions.
|
||||
*/
|
||||
hash_set<Book>
|
||||
affectedBooks(AcceptedLedgerTx const& alTx, beast::Journal const& j);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -37,6 +37,8 @@ reduceOffer(auto const& amount)
|
||||
|
||||
enum class IsDeposit : bool { No = false, Yes = true };
|
||||
|
||||
inline Number const kAMMInvariantRelativeTolerance{1, -11};
|
||||
|
||||
/** Calculate LP Tokens given AMM pool reserves.
|
||||
* @param asset1 AMM one side of the pool reserve
|
||||
* @param asset2 AMM another side of the pool reserve
|
||||
@@ -738,6 +740,30 @@ ammPoolHolds(
|
||||
AuthHandling authHandling,
|
||||
beast::Journal const j);
|
||||
|
||||
/** Check AMM pool product invariant after an AMM operation that changes LP tokens
|
||||
* (deposit/withdraw/clawback) from an already calculated pool product mean.
|
||||
* Returns tecPRECISION_LOSS if poolProductMean < newLPTokenBalance beyond the
|
||||
* invariant tolerance,
|
||||
* tesSUCCESS otherwise. Skips check when newLPTokenBalance is zero (last withdrawal).
|
||||
*/
|
||||
TER
|
||||
checkAMMPrecisionLoss(Number const& poolProductMean, STAmount const& newLPTokenBalance);
|
||||
|
||||
/** Check AMM pool product invariant after an AMM operation that changes LP tokens
|
||||
* (deposit/withdraw/clawback).
|
||||
* Returns tecPRECISION_LOSS if sqrt(asset1 * asset2) < newLPTokenBalance beyond
|
||||
* the invariant tolerance,
|
||||
* tesSUCCESS otherwise. Skips check when newLPTokenBalance is zero (last withdrawal).
|
||||
*/
|
||||
TER
|
||||
checkAMMPrecisionLoss(
|
||||
ReadView const& view,
|
||||
AccountID const& ammAccountID,
|
||||
Asset const& asset1,
|
||||
Asset const& asset2,
|
||||
STAmount const& newLPTokenBalance,
|
||||
beast::Journal const j);
|
||||
|
||||
/** Get AMM pool and LP token balances. If both optIssue are
|
||||
* provided then they are used as the AMM token pair issues.
|
||||
* Otherwise the missing issues are fetched from ammSle.
|
||||
|
||||
@@ -36,13 +36,13 @@ checkFields(STTx const& tx, beast::Journal j);
|
||||
TER
|
||||
valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal j);
|
||||
|
||||
// Check if subject has any credential maching the given domain. If you call it
|
||||
// Check if subject has any credential matching the given domain. If you call it
|
||||
// in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in
|
||||
// doApply. This will ensure that expired credentials are deleted.
|
||||
TER
|
||||
validDomain(ReadView const& view, uint256 domainID, AccountID const& subject);
|
||||
|
||||
// This function is only called when we about to return tecNO_PERMISSION
|
||||
// This function is only called when we are about to return tecNO_PERMISSION
|
||||
// because all the checks for the DepositPreauth authorization failed.
|
||||
TER
|
||||
authorizedDepositPreauth(ReadView const& view, STVector256 const& ctx, AccountID const& dst);
|
||||
@@ -58,7 +58,7 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
|
||||
|
||||
} // namespace credentials
|
||||
|
||||
// Check expired credentials and for credentials maching DomainID of the ledger
|
||||
// Check expired credentials and for credentials matching DomainID of the ledger
|
||||
// object
|
||||
TER
|
||||
verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j);
|
||||
|
||||
@@ -23,13 +23,9 @@ checkTxPermission(SLE::const_ref delegate, STTx const& tx);
|
||||
* @param delegate The delegate account.
|
||||
* @param type Used to determine which granted granular permissions to load,
|
||||
* based on the transaction type.
|
||||
* @param granularPermissions Granted granular permissions tied to the
|
||||
* transaction type.
|
||||
* @return the granted granular permissions tied to the transaction type.
|
||||
*/
|
||||
void
|
||||
loadGranularPermission(
|
||||
SLE::const_ref delegate,
|
||||
TxType const& type,
|
||||
std::unordered_set<GranularPermissionType>& granularPermissions);
|
||||
std::unordered_set<GranularPermissionType>
|
||||
getGranularPermission(SLE::const_ref delegate, TxType const& type);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -42,7 +42,7 @@ escrowUnlockApplyHelper<Issue>(
|
||||
beast::Journal journal)
|
||||
{
|
||||
Issue const& issue = amount.get<Issue>();
|
||||
Keylet const trustLineKey = keylet::line(receiver, issue);
|
||||
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
|
||||
bool const recvLow = issuer > receiver;
|
||||
bool const senderIssuer = issuer == sender;
|
||||
bool const receiverIssuer = issuer == receiver;
|
||||
@@ -175,7 +175,7 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
bool const receiverIssuer = issuer == receiver;
|
||||
|
||||
auto const mptID = amount.get<MPTIssue>().getMptID();
|
||||
auto const issuanceKey = keylet::mptIssuance(mptID);
|
||||
auto const issuanceKey = keylet::mptokenIssuance(mptID);
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer)
|
||||
{
|
||||
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
|
||||
|
||||
@@ -5,9 +5,45 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/** Close a payment channel and return its remaining funds to the channel owner.
|
||||
*
|
||||
* @param slep The SLE for the PayChannel object to close.
|
||||
* @param view The apply view in which ledger state modifications are made.
|
||||
* @param key The ledger key identifying the PayChannel entry.
|
||||
* @param j Journal used for fatal-level diagnostic messages.
|
||||
* @return tesSUCCESS on success; tefBAD_LEDGER if a directory removal
|
||||
* fails; tefINTERNAL if the source account SLE cannot be found.
|
||||
*/
|
||||
TER
|
||||
closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal j);
|
||||
|
||||
/** Add two uint32_t values with saturation at UINT32_MAX.
|
||||
*
|
||||
* @param rules The current ledger rules used to check amendment status.
|
||||
* @param lhs Left-hand operand.
|
||||
* @param rhs Right-hand operand.
|
||||
* @return @p lhs + @p rhs, saturated at UINT32_MAX when the amendment
|
||||
* is active.
|
||||
*/
|
||||
uint32_t
|
||||
saturatingAdd(Rules const& rules, uint32_t const lhs, uint32_t const rhs);
|
||||
|
||||
/** Determine whether a payment channel time field represents an expired time.
|
||||
*
|
||||
* @param view The apply view providing the parent close time and rules.
|
||||
* @param timeField The optional expiry timestamp (seconds since the XRP
|
||||
* Ledger epoch). If empty, the function returns false.
|
||||
* @return @c true if @p timeField is set and the indicated time is
|
||||
* in the past relative to the view's parent close time;
|
||||
* @c false otherwise.
|
||||
*/
|
||||
bool
|
||||
isChannelExpired(ApplyView const& view, std::optional<std::uint32_t> timeField);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/View.h>
|
||||
|
||||
namespace xrpl::permissioned_dex {
|
||||
|
||||
@@ -102,25 +102,32 @@ getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
|
||||
json::Value const maxVersion(
|
||||
betaEnabled ? RPC::kApiBetaVersion : RPC::kApiMaximumSupportedVersion);
|
||||
|
||||
if (jv.isObject())
|
||||
if (!jv.isObject() || !jv.isMember(jss::api_version))
|
||||
return RPC::kApiVersionIfUnspecified;
|
||||
|
||||
try
|
||||
{
|
||||
if (jv.isMember(jss::api_version))
|
||||
auto const& rawVersion = jv[jss::api_version];
|
||||
switch (rawVersion.type())
|
||||
{
|
||||
auto const specifiedVersion = jv[jss::api_version];
|
||||
if (!specifiedVersion.isInt() && !specifiedVersion.isUInt())
|
||||
{
|
||||
return RPC::kApiInvalidVersion;
|
||||
case json::ValueType::Int:
|
||||
if (rawVersion.asInt() < 0)
|
||||
return RPC::kApiInvalidVersion;
|
||||
[[fallthrough]];
|
||||
case json::ValueType::UInt: {
|
||||
auto const apiVersion = rawVersion.asUInt();
|
||||
if (apiVersion < kMinVersion || apiVersion > maxVersion)
|
||||
return RPC::kApiInvalidVersion;
|
||||
return apiVersion;
|
||||
}
|
||||
auto const specifiedVersionInt = specifiedVersion.asInt();
|
||||
if (specifiedVersionInt < kMinVersion || specifiedVersionInt > maxVersion)
|
||||
{
|
||||
default:
|
||||
return RPC::kApiInvalidVersion;
|
||||
}
|
||||
return specifiedVersionInt;
|
||||
}
|
||||
}
|
||||
|
||||
return RPC::kApiVersionIfUnspecified;
|
||||
catch (...)
|
||||
{
|
||||
return RPC::kApiInvalidVersion;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RPC
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
@@ -68,21 +68,15 @@ skip(LedgerIndex ledger) noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the ledger fees. */
|
||||
Keylet const&
|
||||
fees() noexcept;
|
||||
feeSettings() noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the ledger negativeUNL. */
|
||||
Keylet const&
|
||||
negativeUNL() noexcept;
|
||||
|
||||
/** The beginning of an order book */
|
||||
struct BookT
|
||||
{
|
||||
explicit BookT() = default;
|
||||
|
||||
Keylet
|
||||
operator()(Book const& b) const;
|
||||
};
|
||||
static BookT const kBook{};
|
||||
Keylet
|
||||
book(Book const& b);
|
||||
|
||||
/** The index of a trust line for a given currency
|
||||
|
||||
@@ -93,12 +87,12 @@ static BookT const kBook{};
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept;
|
||||
trustLine(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept;
|
||||
|
||||
inline Keylet
|
||||
line(AccountID const& id, Issue const& issue) noexcept
|
||||
trustLine(AccountID const& id, Issue const& issue) noexcept
|
||||
{
|
||||
return line(id, issue.account, issue.currency);
|
||||
return trustLine(id, issue.account, issue.currency);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -119,37 +113,27 @@ Keylet
|
||||
quality(Keylet const& k, std::uint64_t q) noexcept;
|
||||
|
||||
/** The directory for the next lower quality */
|
||||
struct NextT
|
||||
{
|
||||
explicit NextT() = default;
|
||||
|
||||
Keylet
|
||||
operator()(Keylet const& k) const;
|
||||
};
|
||||
static NextT const kNext{};
|
||||
Keylet
|
||||
next(Keylet const& k);
|
||||
|
||||
/** A ticket belonging to an account */
|
||||
struct TicketT
|
||||
/** @{ */
|
||||
Keylet
|
||||
ticket(AccountID const& id, std::uint32_t ticketSeq);
|
||||
|
||||
Keylet
|
||||
ticket(AccountID const& id, SeqProxy ticketSeq);
|
||||
|
||||
inline Keylet
|
||||
ticket(uint256 const& key)
|
||||
{
|
||||
explicit TicketT() = default;
|
||||
|
||||
Keylet
|
||||
operator()(AccountID const& id, std::uint32_t ticketSeq) const;
|
||||
|
||||
Keylet
|
||||
operator()(AccountID const& id, SeqProxy ticketSeq) const;
|
||||
|
||||
Keylet
|
||||
operator()(uint256 const& key) const
|
||||
{
|
||||
return {ltTICKET, key};
|
||||
}
|
||||
};
|
||||
static TicketT const kTicket{};
|
||||
return {ltTICKET, key};
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** A SignerList */
|
||||
Keylet
|
||||
signers(AccountID const& account) noexcept;
|
||||
signerList(AccountID const& account) noexcept;
|
||||
|
||||
/** A Check */
|
||||
/** @{ */
|
||||
@@ -209,7 +193,7 @@ escrow(AccountID const& src, std::uint32_t seq) noexcept;
|
||||
|
||||
/** A PaymentChannel */
|
||||
Keylet
|
||||
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
payChannel(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
|
||||
/** NFT page keylets
|
||||
|
||||
@@ -221,22 +205,22 @@ payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
/** @{ */
|
||||
/** A keylet for the owner's first possible NFT page. */
|
||||
Keylet
|
||||
nftpageMin(AccountID const& owner);
|
||||
nftokenPageMin(AccountID const& owner);
|
||||
|
||||
/** A keylet for the owner's last possible NFT page. */
|
||||
Keylet
|
||||
nftpageMax(AccountID const& owner);
|
||||
nftokenPageMax(AccountID const& owner);
|
||||
|
||||
Keylet
|
||||
nftpage(Keylet const& k, uint256 const& token);
|
||||
nftokenPage(Keylet const& k, uint256 const& token);
|
||||
/** @} */
|
||||
|
||||
/** An offer from an account to buy or sell an NFT */
|
||||
Keylet
|
||||
nftoffer(AccountID const& owner, std::uint32_t seq);
|
||||
nftokenOffer(AccountID const& owner, std::uint32_t seq);
|
||||
|
||||
inline Keylet
|
||||
nftoffer(uint256 const& offer)
|
||||
nftokenOffer(uint256 const& offer)
|
||||
{
|
||||
return {ltNFTOKEN_OFFER, offer};
|
||||
}
|
||||
@@ -287,13 +271,13 @@ credential(uint256 const& key) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept;
|
||||
mptokenIssuance(std::uint32_t seq, AccountID const& issuer) noexcept;
|
||||
|
||||
Keylet
|
||||
mptIssuance(MPTID const& issuanceID) noexcept;
|
||||
mptokenIssuance(MPTID const& issuanceID) noexcept;
|
||||
|
||||
inline Keylet
|
||||
mptIssuance(uint256 const& issuanceKey)
|
||||
mptokenIssuance(uint256 const& issuanceKey)
|
||||
{
|
||||
return {ltMPTOKEN_ISSUANCE, issuanceKey};
|
||||
}
|
||||
@@ -320,10 +304,10 @@ vault(uint256 const& vaultKey)
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
loanBroker(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
loanbroker(uint256 const& key)
|
||||
loanBroker(uint256 const& key)
|
||||
{
|
||||
return {ltLOAN_BROKER, key};
|
||||
}
|
||||
@@ -376,11 +360,15 @@ struct KeyletDesc
|
||||
std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets{
|
||||
{{.function = &keylet::account, .expectedLEName = jss::AccountRoot, .includeInTests = false},
|
||||
{.function = &keylet::ownerDir, .expectedLEName = jss::DirectoryNode, .includeInTests = true},
|
||||
{.function = &keylet::signers, .expectedLEName = jss::SignerList, .includeInTests = true},
|
||||
{.function = &keylet::signerList, .expectedLEName = jss::SignerList, .includeInTests = true},
|
||||
// It's normally impossible to create an item at nftpage_min, but
|
||||
// test it anyway, since the invariant checks for it.
|
||||
{.function = &keylet::nftpageMin, .expectedLEName = jss::NFTokenPage, .includeInTests = true},
|
||||
{.function = &keylet::nftpageMax, .expectedLEName = jss::NFTokenPage, .includeInTests = true},
|
||||
{.function = &keylet::nftokenPageMin,
|
||||
.expectedLEName = jss::NFTokenPage,
|
||||
.includeInTests = true},
|
||||
{.function = &keylet::nftokenPageMax,
|
||||
.expectedLEName = jss::NFTokenPage,
|
||||
.includeInTests = true},
|
||||
{.function = &keylet::did, .expectedLEName = jss::DID, .includeInTests = true}}};
|
||||
|
||||
MPTID
|
||||
|
||||
@@ -118,13 +118,13 @@ public:
|
||||
}
|
||||
|
||||
// begin() and end() are provided for testing purposes.
|
||||
[[nodiscard]] typename std::forward_list<Item>::const_iterator
|
||||
[[nodiscard]] std::forward_list<Item>::const_iterator
|
||||
begin() const
|
||||
{
|
||||
return formats_.begin();
|
||||
}
|
||||
|
||||
[[nodiscard]] typename std::forward_list<Item>::const_iterator
|
||||
[[nodiscard]] std::forward_list<Item>::const_iterator
|
||||
end() const
|
||||
{
|
||||
return formats_.end();
|
||||
|
||||
@@ -180,12 +180,12 @@ enum LedgerEntryType : std::uint16_t {
|
||||
LSF_FLAG(lsfMPTCanClawback, 0x00000040)) \
|
||||
\
|
||||
LEDGER_OBJECT(MPTokenIssuanceMutable, \
|
||||
LSF_FLAG(lsmfMPTCanMutateCanLock, 0x00000002) \
|
||||
LSF_FLAG(lsmfMPTCanMutateRequireAuth, 0x00000004) \
|
||||
LSF_FLAG(lsmfMPTCanMutateCanEscrow, 0x00000008) \
|
||||
LSF_FLAG(lsmfMPTCanMutateCanTrade, 0x00000010) \
|
||||
LSF_FLAG(lsmfMPTCanMutateCanTransfer, 0x00000020) \
|
||||
LSF_FLAG(lsmfMPTCanMutateCanClawback, 0x00000040) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanLock, 0x00000002) \
|
||||
LSF_FLAG(lsmfMPTCanEnableRequireAuth, 0x00000004) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanEscrow, 0x00000008) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanTrade, 0x00000010) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanTransfer, 0x00000020) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanClawback, 0x00000040) \
|
||||
LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \
|
||||
LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \
|
||||
\
|
||||
|
||||
@@ -7,8 +7,13 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class STTx;
|
||||
|
||||
/**
|
||||
* We have both transaction type permissions and granular type permissions.
|
||||
* Since we will reuse the TransactionFormats to parse the Transaction
|
||||
@@ -19,15 +24,15 @@ namespace xrpl {
|
||||
// Macro-generated, complex
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum GranularPermissionType : std::uint32_t {
|
||||
#pragma push_macro("PERMISSION")
|
||||
#undef PERMISSION
|
||||
#pragma push_macro("GRANULAR_PERMISSION")
|
||||
#undef GRANULAR_PERMISSION
|
||||
|
||||
#define PERMISSION(type, txType, value) type = (value),
|
||||
#define GRANULAR_PERMISSION(name, txType, value, ...) name = (value),
|
||||
|
||||
#include <xrpl/protocol/detail/permissions.macro>
|
||||
|
||||
#undef PERMISSION
|
||||
#pragma pop_macro("PERMISSION")
|
||||
#undef GRANULAR_PERMISSION
|
||||
#pragma pop_macro("GRANULAR_PERMISSION")
|
||||
};
|
||||
|
||||
// Injected bare enumerators (xrpl::delegable / xrpl::notDelegable) are required by preprocessor
|
||||
@@ -40,15 +45,30 @@ class Permission
|
||||
private:
|
||||
Permission();
|
||||
|
||||
std::unordered_map<std::uint16_t, uint256> txFeatureMap_;
|
||||
struct GranularPermissionEntry
|
||||
{
|
||||
std::string name;
|
||||
TxType txType;
|
||||
std::uint32_t permittedFlags;
|
||||
SOTemplate permittedFields;
|
||||
|
||||
std::unordered_map<std::uint16_t, Delegation> delegableTx_;
|
||||
GranularPermissionEntry(
|
||||
std::string name,
|
||||
TxType txType,
|
||||
std::uint32_t permittedFlags,
|
||||
std::vector<SOElement> fields);
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, GranularPermissionType> granularPermissionMap_;
|
||||
struct TxDelegationEntry
|
||||
{
|
||||
uint256 amendment;
|
||||
Delegation delegable{NotDelegable};
|
||||
};
|
||||
|
||||
std::unordered_map<GranularPermissionType, std::string> granularNameMap_;
|
||||
|
||||
std::unordered_map<GranularPermissionType, TxType> granularTxTypeMap_;
|
||||
std::unordered_set<TxType> granularTxTypes_;
|
||||
std::unordered_map<TxType, TxDelegationEntry> txDelegationMap_;
|
||||
std::unordered_map<std::string, GranularPermissionType> granularPermissionsByName_;
|
||||
std::unordered_map<GranularPermissionType, GranularPermissionEntry> granularPermissions_;
|
||||
|
||||
public:
|
||||
static Permission const&
|
||||
@@ -59,30 +79,52 @@ public:
|
||||
operator=(Permission const&) = delete;
|
||||
|
||||
[[nodiscard]] std::optional<std::string>
|
||||
getPermissionName(std::uint32_t const value) const;
|
||||
getPermissionName(std::uint32_t value) const;
|
||||
|
||||
[[nodiscard]] std::optional<std::uint32_t>
|
||||
getGranularValue(std::string const& name) const;
|
||||
|
||||
[[nodiscard]] std::optional<std::string>
|
||||
getGranularName(GranularPermissionType const& value) const;
|
||||
getGranularName(GranularPermissionType value) const;
|
||||
|
||||
[[nodiscard]] std::optional<TxType>
|
||||
getGranularTxType(GranularPermissionType const& gpType) const;
|
||||
getGranularTxType(GranularPermissionType gpType) const;
|
||||
|
||||
// Returns a reference to avoid copying uint256 - 32 bytes. std::optional
|
||||
// cannot hold references directly, so std::reference_wrapper is used.
|
||||
[[nodiscard]] std::optional<std::reference_wrapper<uint256 const>>
|
||||
getTxFeature(TxType txType) const;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDelegable(std::uint32_t const& permissionValue, Rules const& rules) const;
|
||||
isDelegable(std::uint32_t permissionValue, Rules const& rules) const;
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasGranularPermissions(TxType txType) const;
|
||||
|
||||
// for tx level permission, permission value is equal to tx type plus one
|
||||
static uint32_t
|
||||
txToPermissionType(TxType const& type);
|
||||
[[nodiscard]] static uint32_t
|
||||
txToPermissionType(TxType type);
|
||||
|
||||
// tx type value is permission value minus one
|
||||
static TxType
|
||||
permissionToTxType(uint32_t const& value);
|
||||
[[nodiscard]] static TxType
|
||||
permissionToTxType(std::uint32_t value);
|
||||
|
||||
/**
|
||||
* @brief Verifies a delegated transaction against its granular permission template.
|
||||
*
|
||||
* @note WARNING: Do not move this check before standard transaction-level
|
||||
* format checks, which is in preclaim. This function assumes the transaction's
|
||||
* base structural integrity (fees, sequence, signatures) has already been
|
||||
* validated.
|
||||
*
|
||||
* @param tx The transaction to verify.
|
||||
* @param heldPermissions The granular permissions that the sender hold.
|
||||
* @return true if the transaction fields and flags comply with the granular template.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
checkGranularSandbox(
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType> const& heldPermissions) const;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -163,7 +163,7 @@ STBitString<Bits>::setValue(BaseUInt<Bits, Tag> const& v)
|
||||
}
|
||||
|
||||
template <int Bits>
|
||||
typename STBitString<Bits>::value_type const&
|
||||
STBitString<Bits>::value_type const&
|
||||
STBitString<Bits>::value() const
|
||||
{
|
||||
return value_;
|
||||
|
||||
@@ -120,7 +120,7 @@ STInteger<Integer>::operator=(value_type const& v)
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
inline typename STInteger<Integer>::value_type
|
||||
inline STInteger<Integer>::value_type
|
||||
STInteger<Integer>::value() const noexcept
|
||||
{
|
||||
return value_;
|
||||
|
||||
@@ -243,7 +243,7 @@ public:
|
||||
@throws STObject::FieldErr if the field is not present.
|
||||
*/
|
||||
template <class T>
|
||||
typename T::value_type
|
||||
T::value_type
|
||||
operator[](TypedField<T> const& f) const;
|
||||
|
||||
/** Get the value of a field as a std::optional
|
||||
@@ -290,7 +290,7 @@ public:
|
||||
@throws STObject::FieldErr if the field is not present.
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] typename T::value_type
|
||||
[[nodiscard]] T::value_type
|
||||
at(TypedField<T> const& f) const;
|
||||
|
||||
/** Get the value of a field as std::optional
|
||||
@@ -478,7 +478,7 @@ template <class T>
|
||||
class STObject::Proxy
|
||||
{
|
||||
public:
|
||||
using value_type = typename T::value_type;
|
||||
using value_type = T::value_type;
|
||||
|
||||
[[nodiscard]] value_type
|
||||
value() const;
|
||||
@@ -513,13 +513,10 @@ protected:
|
||||
template <typename U>
|
||||
concept IsArithmeticNumber =
|
||||
std::is_arithmetic_v<U> || std::is_same_v<U, Number> || std::is_same_v<U, STAmount>;
|
||||
template <
|
||||
typename U,
|
||||
typename Value = typename U::value_type,
|
||||
typename Unit = typename U::unit_type>
|
||||
template <typename U, typename Value = U::value_type, typename Unit = U::unit_type>
|
||||
concept IsArithmeticValueUnit = std::is_same_v<U, unit::ValueUnit<Unit, Value>> &&
|
||||
IsArithmeticNumber<Value> && std::is_class_v<Unit>;
|
||||
template <typename U, typename Value = typename U::value_type>
|
||||
template <typename U, typename Value = U::value_type>
|
||||
concept IsArithmeticST = !IsArithmeticValueUnit<U> && IsArithmeticNumber<Value>;
|
||||
template <typename U>
|
||||
concept IsArithmetic = IsArithmeticNumber<U> || IsArithmeticST<U> || IsArithmeticValueUnit<U>;
|
||||
@@ -534,7 +531,7 @@ template <class T>
|
||||
class STObject::ValueProxy : public Proxy<T>
|
||||
{
|
||||
private:
|
||||
using value_type = typename T::value_type;
|
||||
using value_type = T::value_type;
|
||||
|
||||
public:
|
||||
ValueProxy(ValueProxy const&) = default;
|
||||
@@ -576,7 +573,7 @@ template <class T>
|
||||
class STObject::OptionalProxy : public Proxy<T>
|
||||
{
|
||||
private:
|
||||
using value_type = typename T::value_type;
|
||||
using value_type = T::value_type;
|
||||
|
||||
using optional_type = std::optional<std::decay_t<value_type>>;
|
||||
|
||||
@@ -840,7 +837,7 @@ operator typename STObject::OptionalProxy<T>::optional_type() const
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename STObject::OptionalProxy<T>::optional_type
|
||||
STObject::OptionalProxy<T>::optional_type
|
||||
STObject::OptionalProxy<T>::operator~() const
|
||||
{
|
||||
return optionalValue();
|
||||
@@ -933,7 +930,7 @@ STObject::OptionalProxy<T>::optionalValue() const -> optional_type
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename STObject::OptionalProxy<T>::value_type
|
||||
STObject::OptionalProxy<T>::value_type
|
||||
STObject::OptionalProxy<T>::valueOr(value_type val) const
|
||||
{
|
||||
return engaged() ? this->value() : val;
|
||||
@@ -1040,7 +1037,7 @@ STObject::getPIndex(int offset)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename T::value_type
|
||||
T::value_type
|
||||
STObject::operator[](TypedField<T> const& f) const
|
||||
{
|
||||
return at(f);
|
||||
@@ -1068,7 +1065,7 @@ STObject::operator[](OptionaledField<T> const& of) -> OptionalProxy<T>
|
||||
}
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] typename T::value_type
|
||||
[[nodiscard]] T::value_type
|
||||
STObject::at(TypedField<T> const& f) const
|
||||
{
|
||||
auto const b = peekAtPField(f);
|
||||
|
||||
@@ -657,13 +657,13 @@ inline bool
|
||||
isTesSuccess(TER x) noexcept
|
||||
{
|
||||
// Makes use of TERSubset::operator bool()
|
||||
return !(x);
|
||||
return !x;
|
||||
}
|
||||
|
||||
inline bool
|
||||
isTecClaim(TER x) noexcept
|
||||
{
|
||||
return ((x) >= tecCLAIM);
|
||||
return (x >= tecCLAIM);
|
||||
}
|
||||
|
||||
std::unordered_map<TERUnderlyingType, std::pair<char const* const, char const* const>> const&
|
||||
|
||||
@@ -341,38 +341,32 @@ inline constexpr FlagValue tfTrustSetPermissionMask =
|
||||
|
||||
// MPTokenIssuanceCreate MutableFlags:
|
||||
// Indicating specific fields or flags may be changed after issuance.
|
||||
inline constexpr FlagValue tmfMPTCanMutateCanLock = lsmfMPTCanMutateCanLock;
|
||||
inline constexpr FlagValue tmfMPTCanMutateRequireAuth = lsmfMPTCanMutateRequireAuth;
|
||||
inline constexpr FlagValue tmfMPTCanMutateCanEscrow = lsmfMPTCanMutateCanEscrow;
|
||||
inline constexpr FlagValue tmfMPTCanMutateCanTrade = lsmfMPTCanMutateCanTrade;
|
||||
inline constexpr FlagValue tmfMPTCanMutateCanTransfer = lsmfMPTCanMutateCanTransfer;
|
||||
inline constexpr FlagValue tmfMPTCanMutateCanClawback = lsmfMPTCanMutateCanClawback;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanLock = lsmfMPTCanEnableCanLock;
|
||||
inline constexpr FlagValue tmfMPTCanEnableRequireAuth = lsmfMPTCanEnableRequireAuth;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanEscrow = lsmfMPTCanEnableCanEscrow;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanTrade = lsmfMPTCanEnableCanTrade;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanTransfer = lsmfMPTCanEnableCanTransfer;
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanClawback = lsmfMPTCanEnableCanClawback;
|
||||
inline constexpr FlagValue tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata;
|
||||
inline constexpr FlagValue tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceCreateMutableMask =
|
||||
~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow |
|
||||
tmfMPTCanMutateCanTrade | tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback |
|
||||
~(tmfMPTCanEnableCanLock | tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanEscrow |
|
||||
tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer | tmfMPTCanEnableCanClawback |
|
||||
tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee);
|
||||
|
||||
// MPTokenIssuanceSet MutableFlags:
|
||||
// Set or Clear flags.
|
||||
// Enable mutable capability flags. These flags are one-way: once enabled,
|
||||
// the corresponding capability cannot be disabled by MPTokenIssuanceSet.
|
||||
|
||||
inline constexpr FlagValue tmfMPTSetCanLock = 0x00000001;
|
||||
inline constexpr FlagValue tmfMPTClearCanLock = 0x00000002;
|
||||
inline constexpr FlagValue tmfMPTSetRequireAuth = 0x00000004;
|
||||
inline constexpr FlagValue tmfMPTClearRequireAuth = 0x00000008;
|
||||
inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000010;
|
||||
inline constexpr FlagValue tmfMPTClearCanEscrow = 0x00000020;
|
||||
inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000040;
|
||||
inline constexpr FlagValue tmfMPTClearCanTrade = 0x00000080;
|
||||
inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000100;
|
||||
inline constexpr FlagValue tmfMPTClearCanTransfer = 0x00000200;
|
||||
inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000400;
|
||||
inline constexpr FlagValue tmfMPTClearCanClawback = 0x00000800;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask = ~(
|
||||
tmfMPTSetCanLock | tmfMPTClearCanLock | tmfMPTSetRequireAuth | tmfMPTClearRequireAuth |
|
||||
tmfMPTSetCanEscrow | tmfMPTClearCanEscrow | tmfMPTSetCanTrade | tmfMPTClearCanTrade |
|
||||
tmfMPTSetCanTransfer | tmfMPTClearCanTransfer | tmfMPTSetCanClawback | tmfMPTClearCanClawback);
|
||||
inline constexpr FlagValue tmfMPTSetRequireAuth = 0x00000002;
|
||||
inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000004;
|
||||
inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000008;
|
||||
inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000010;
|
||||
inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000020;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask =
|
||||
~(tmfMPTSetCanLock | tmfMPTSetRequireAuth | tmfMPTSetCanEscrow | tmfMPTSetCanTrade |
|
||||
tmfMPTSetCanTransfer | tmfMPTSetCanClawback);
|
||||
|
||||
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between accounts allowed a
|
||||
// TrustLine to be added to the issuer of that token without explicit permission from that issuer.
|
||||
|
||||
@@ -391,7 +391,7 @@ mulDivU(Source1 value, Dest mul, Source2 div)
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
using desttype = typename Dest::value_type;
|
||||
using desttype = Dest::value_type;
|
||||
constexpr auto kMax = std::numeric_limits<desttype>::max();
|
||||
|
||||
// Shortcuts, since these happen a lot in the real world
|
||||
|
||||
@@ -379,16 +379,16 @@ public:
|
||||
[[nodiscard]] STArray
|
||||
toSTArray() const;
|
||||
|
||||
[[nodiscard]] typename AttCollection::const_iterator
|
||||
[[nodiscard]] AttCollection::const_iterator
|
||||
begin() const;
|
||||
|
||||
[[nodiscard]] typename AttCollection::const_iterator
|
||||
[[nodiscard]] AttCollection::const_iterator
|
||||
end() const;
|
||||
|
||||
typename AttCollection::iterator
|
||||
AttCollection::iterator
|
||||
begin();
|
||||
|
||||
typename AttCollection::iterator
|
||||
AttCollection::iterator
|
||||
end();
|
||||
|
||||
template <class F>
|
||||
@@ -419,7 +419,7 @@ operator==(
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline typename XChainAttestationsBase<TAttestation>::AttCollection const&
|
||||
inline XChainAttestationsBase<TAttestation>::AttCollection const&
|
||||
XChainAttestationsBase<TAttestation>::attestations() const
|
||||
{
|
||||
return attestations_;
|
||||
|
||||
@@ -21,10 +21,10 @@ XRPL_FEATURE(MPTokensV2, Supported::No, VoteBehavior::DefaultN
|
||||
XRPL_FIX (Cleanup3_1_3, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (BatchInnerSigs, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocol, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionDelegationV1_1, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionDelegationV1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DirectoryLimit, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (IncludeKeyletFields, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DynamicMPT, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DynamicMPT, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (TokenEscrowV1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PriceOracleOrder, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (MPTDeliveredAmount, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
@@ -58,13 +58,11 @@ XRPL_FIX (EmptyDID, Supported::Yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(PriceOracle, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMOverflowOffer, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (InnerObjTemplate, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (NFTokenReserve, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (FillOrKill, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DisallowIncomingV1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Clawback, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
|
||||
@@ -105,6 +103,7 @@ XRPL_RETIRE_FIX(CheckThreading)
|
||||
XRPL_RETIRE_FIX(MasterKeyAsRegularKey)
|
||||
XRPL_RETIRE_FIX(NonFungibleTokensV1_2)
|
||||
XRPL_RETIRE_FIX(NFTokenRemint)
|
||||
XRPL_RETIRE_FIX(NFTokenReserve)
|
||||
XRPL_RETIRE_FIX(PayChanRecipientOwnerDir)
|
||||
XRPL_RETIRE_FIX(QualityUpperBound)
|
||||
XRPL_RETIRE_FIX(ReducedOffersV1)
|
||||
@@ -116,6 +115,7 @@ XRPL_RETIRE_FIX(UniversalNumber)
|
||||
|
||||
XRPL_RETIRE_FEATURE(Checks)
|
||||
XRPL_RETIRE_FEATURE(CheckCashMakesTrustLine)
|
||||
XRPL_RETIRE_FEATURE(Clawback)
|
||||
XRPL_RETIRE_FEATURE(CryptoConditions)
|
||||
XRPL_RETIRE_FEATURE(CryptoConditionsSuite)
|
||||
XRPL_RETIRE_FEATURE(DeletableAccounts)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
/** A ledger object which identifies an offer to buy or sell an NFT.
|
||||
|
||||
\sa keylet::nftoffer
|
||||
\sa keylet::nftokenOffer
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, nft_offer, ({
|
||||
{sfOwner, SoeRequired},
|
||||
@@ -84,7 +84,7 @@ LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, ({
|
||||
|
||||
/** A ledger object which contains a list of NFTs
|
||||
|
||||
\sa keylet::nftpageMin, keylet::nftpageMax, keylet::nftpage
|
||||
\sa keylet::nftokenPageMin, keylet::nftokenPageMax, keylet::nftokenPage
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
{sfPreviousPageMin, SoeOptional},
|
||||
@@ -96,7 +96,7 @@ LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
|
||||
/** A ledger object which contains a signer list for an account.
|
||||
|
||||
\sa keylet::signers
|
||||
\sa keylet::signerList
|
||||
*/
|
||||
// All fields are SoeRequired because there is always a SignerEntries.
|
||||
// If there are no SignerEntries the node is deleted.
|
||||
@@ -112,7 +112,7 @@ LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, ({
|
||||
|
||||
/** A ledger object which describes a ticket.
|
||||
|
||||
\sa keylet::kTicket
|
||||
\sa keylet::ticket
|
||||
*/
|
||||
LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({
|
||||
{sfAccount, SoeRequired},
|
||||
@@ -272,7 +272,7 @@ LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_c
|
||||
|
||||
@note Per Vinnie Falco this should be renamed to ltTRUST_LINE
|
||||
|
||||
\sa keylet::line
|
||||
\sa keylet::trustLine
|
||||
*/
|
||||
LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
{sfBalance, SoeRequired},
|
||||
@@ -292,7 +292,7 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
|
||||
\note This is a singleton: only one such object exists in the ledger.
|
||||
|
||||
\sa keylet::fees
|
||||
\sa keylet::feeSettings
|
||||
*/
|
||||
LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
// Old version uses raw numbers
|
||||
@@ -346,7 +346,7 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
|
||||
|
||||
/** A ledger object describing a single unidirectional XRP payment channel.
|
||||
|
||||
\sa keylet::payChan
|
||||
\sa keylet::payChannel
|
||||
*/
|
||||
LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, ({
|
||||
{sfAccount, SoeRequired},
|
||||
@@ -384,7 +384,7 @@ LEDGER_ENTRY(ltAMM, 0x0079, AMM, amm, ({
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPTokenIssuance
|
||||
\sa keylet::mptIssuance
|
||||
\sa keylet::mptokenIssuance
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfIssuer, SoeRequired},
|
||||
@@ -499,7 +499,7 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
|
||||
/** A ledger object representing a loan broker
|
||||
|
||||
\sa keylet::loanbroker
|
||||
\sa keylet::loanBroker
|
||||
*/
|
||||
LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
|
||||
@@ -1,49 +1,74 @@
|
||||
#if !defined(PERMISSION)
|
||||
#error "undefined macro: PERMISSION"
|
||||
#if !defined(GRANULAR_PERMISSION)
|
||||
#error "undefined macro: GRANULAR_PERMISSION"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* PERMISSION(name, type, txType, value)
|
||||
* GRANULAR_PERMISSION(name, txType, value, allowedFlags, allowedFields)
|
||||
*
|
||||
* This macro defines a permission:
|
||||
* name: the name of the permission.
|
||||
* type: the GranularPermissionType enum.
|
||||
* txType: the corresponding TxType for this permission.
|
||||
* value: the uint32 numeric value for the enum type.
|
||||
* Defines a granular permission:
|
||||
* name: the granular permission name.
|
||||
* txType: the corresponding TxType for this permission.
|
||||
* value: the uint32 numeric value for the enum type.
|
||||
* allowedFlags: transaction flags permitted under this permission.
|
||||
* allowedFields: transaction fields permitted under this permission.
|
||||
*/
|
||||
|
||||
/** This permission grants the delegated account the ability to authorize a trustline. */
|
||||
PERMISSION(TrustlineAuthorize, ttTRUST_SET, 65537)
|
||||
/** Grants the ability to authorize a trustline. */
|
||||
GRANULAR_PERMISSION(TrustlineAuthorize, ttTRUST_SET, 65537, tfUniversal | tfSetfAuth,
|
||||
({{sfLimitAmount, SoeRequired}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to freeze a trustline. */
|
||||
PERMISSION(TrustlineFreeze, ttTRUST_SET, 65538)
|
||||
/** Grants the ability to freeze a trustline. */
|
||||
GRANULAR_PERMISSION(TrustlineFreeze, ttTRUST_SET, 65538, tfUniversal | tfSetFreeze,
|
||||
({{sfLimitAmount, SoeRequired}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to unfreeze a trustline. */
|
||||
PERMISSION(TrustlineUnfreeze, ttTRUST_SET, 65539)
|
||||
/** Grants the ability to unfreeze a trustline. */
|
||||
GRANULAR_PERMISSION(TrustlineUnfreeze, ttTRUST_SET, 65539, tfUniversal | tfClearFreeze,
|
||||
({{sfLimitAmount, SoeRequired}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to set Domain. */
|
||||
PERMISSION(AccountDomainSet, ttACCOUNT_SET, 65540)
|
||||
/** Grants the ability to set Domain. */
|
||||
GRANULAR_PERMISSION(AccountDomainSet, ttACCOUNT_SET, 65540, tfUniversal,
|
||||
({{sfDomain, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to set EmailHashSet. */
|
||||
PERMISSION(AccountEmailHashSet, ttACCOUNT_SET, 65541)
|
||||
/** Grants the ability to set EmailHash. */
|
||||
GRANULAR_PERMISSION(AccountEmailHashSet, ttACCOUNT_SET, 65541, tfUniversal,
|
||||
({{sfEmailHash, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to set MessageKey. */
|
||||
PERMISSION(AccountMessageKeySet, ttACCOUNT_SET, 65542)
|
||||
/** Grants the ability to set MessageKey. */
|
||||
GRANULAR_PERMISSION(AccountMessageKeySet, ttACCOUNT_SET, 65542, tfUniversal,
|
||||
({{sfMessageKey, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to set TransferRate. */
|
||||
PERMISSION(AccountTransferRateSet, ttACCOUNT_SET, 65543)
|
||||
/** Grants the ability to set TransferRate. */
|
||||
GRANULAR_PERMISSION(AccountTransferRateSet, ttACCOUNT_SET, 65543, tfUniversal,
|
||||
({{sfTransferRate, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to set TickSize. */
|
||||
PERMISSION(AccountTickSizeSet, ttACCOUNT_SET, 65544)
|
||||
/** Grants the ability to set TickSize. */
|
||||
GRANULAR_PERMISSION(AccountTickSizeSet, ttACCOUNT_SET, 65544, tfUniversal,
|
||||
({{sfTickSize, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to mint payment, which means sending a payment for a currency where the sending account is the issuer. */
|
||||
PERMISSION(PaymentMint, ttPAYMENT, 65545)
|
||||
/** Grants the ability to mint payment (sending account is the issuer). Cross-currency payments are disallowed. */
|
||||
GRANULAR_PERMISSION(PaymentMint, ttPAYMENT, 65545, tfUniversal,
|
||||
({{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSendMax, SoeOptional},
|
||||
{sfInvoiceID, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfCredentialIDs, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to burn payment, which means sending a payment for a currency where the destination account is the issuer */
|
||||
PERMISSION(PaymentBurn, ttPAYMENT, 65546)
|
||||
/** Grants the ability to burn payment (destination account is the issuer). Cross-currency payments are disallowed. */
|
||||
GRANULAR_PERMISSION(PaymentBurn, ttPAYMENT, 65546, tfUniversal,
|
||||
({{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSendMax, SoeOptional},
|
||||
{sfInvoiceID, SoeOptional},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfCredentialIDs, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to lock MPToken. */
|
||||
PERMISSION(MPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET, 65547)
|
||||
/** Grants the ability to lock an MPToken. */
|
||||
GRANULAR_PERMISSION(MPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET, 65547, tfUniversal | tfMPTLock,
|
||||
({{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfHolder, SoeOptional}}))
|
||||
|
||||
/** This permission grants the delegated account the ability to unlock MPToken. */
|
||||
PERMISSION(MPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET, 65548)
|
||||
/** Grants the ability to unlock an MPToken. */
|
||||
GRANULAR_PERMISSION(MPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET, 65548, tfUniversal | tfMPTUnlock,
|
||||
({{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfHolder, SoeOptional}}))
|
||||
|
||||
@@ -395,7 +395,7 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
#endif
|
||||
TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
Delegation::Delegable,
|
||||
featureClawback,
|
||||
uint256{},
|
||||
NoPriv,
|
||||
({
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
|
||||
@@ -206,7 +206,7 @@ sha512Half(Args const&... args)
|
||||
sha512_half_hasher h;
|
||||
using beast::hash_append;
|
||||
hash_append(h, args...);
|
||||
return static_cast<typename sha512_half_hasher::result_type>(h);
|
||||
return static_cast<sha512_half_hasher::result_type>(h);
|
||||
}
|
||||
|
||||
/** Returns the SHA512-Half of a series of objects.
|
||||
@@ -222,7 +222,7 @@ sha512HalfS(Args const&... args)
|
||||
sha512_half_hasher_s h;
|
||||
using beast::hash_append;
|
||||
hash_append(h, args...);
|
||||
return static_cast<typename sha512_half_hasher_s::result_type>(h);
|
||||
return static_cast<sha512_half_hasher_s::result_type>(h);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -52,7 +52,7 @@ getTransferFee(uint256 const& id)
|
||||
}
|
||||
|
||||
inline std::uint32_t
|
||||
getSerial(uint256 const& id)
|
||||
getSequence(uint256 const& id)
|
||||
{
|
||||
std::uint32_t seq = 0;
|
||||
memcpy(&seq, id.begin() + 28, 4);
|
||||
@@ -92,7 +92,7 @@ getTaxon(uint256 const& id)
|
||||
|
||||
// The taxon cipher is just an XOR, so it is reversible by applying the
|
||||
// XOR a second time.
|
||||
return cipheredTaxon(getSerial(id), toTaxon(taxon));
|
||||
return cipheredTaxon(getSequence(id), toTaxon(taxon));
|
||||
}
|
||||
|
||||
inline AccountID
|
||||
|
||||
@@ -20,7 +20,7 @@ class ClawbackBuilder;
|
||||
*
|
||||
* Type: ttCLAWBACK (30)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureClawback
|
||||
* Amendment: uint256{}
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/Book.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
@@ -26,6 +27,19 @@ public:
|
||||
};
|
||||
|
||||
/** Manages a client's subscription to data feeds.
|
||||
*
|
||||
* An InfoSub holds a non-owning reference to its `Source` (typically the
|
||||
* process-wide `NetworkOPsImp`). The destructor reaches back into the
|
||||
* `Source` to remove this subscriber from every server-side subscription
|
||||
* map.
|
||||
*
|
||||
* @note Lifetime contract: every `InfoSub` instance MUST be destroyed
|
||||
* before the backing `Source`. NetworkOPsImp shutdown drops all
|
||||
* subscriber strong refs before its own teardown to satisfy this.
|
||||
* @note Thread-safety: per-instance state is guarded by `lock_`. The
|
||||
* destructor reads tracking sets without taking `lock_` because
|
||||
* the strong-pointer ref-count is zero at destruction time, so
|
||||
* no other thread can be calling the public mutators.
|
||||
*/
|
||||
class InfoSub : public CountedObject<InfoSub>
|
||||
{
|
||||
@@ -117,8 +131,43 @@ public:
|
||||
|
||||
virtual bool
|
||||
subBook(ref ispListener, Book const&) = 0;
|
||||
|
||||
/**
|
||||
* Remove a book subscription for a live subscriber.
|
||||
*
|
||||
* Clears the book from the subscriber's own tracking set
|
||||
* (InfoSub::bookSubscriptions_) and then removes the server-side
|
||||
* entry from subBook_. Call this from RPC unsubscribe handlers.
|
||||
*
|
||||
* @param ispListener The subscriber requesting removal.
|
||||
* @param book The order book to unsubscribe from.
|
||||
* @return true if the entry was present and removed, false if the
|
||||
* subscriber was not subscribed to @p book.
|
||||
*
|
||||
* @note Thread-safety: acquires subLock_ internally.
|
||||
* @note Do NOT call from ~InfoSub(). Use unsubBookInternal instead
|
||||
* to avoid a redundant write-back to bookSubscriptions_ on a
|
||||
* partially-destroyed object.
|
||||
*/
|
||||
virtual bool
|
||||
unsubBook(std::uint64_t uListener, Book const&) = 0;
|
||||
unsubBook(ref ispListener, Book const&) = 0;
|
||||
|
||||
/**
|
||||
* Remove a book subscription during InfoSub teardown.
|
||||
*
|
||||
* Removes only the server-side entry from subBook_. Does NOT touch
|
||||
* InfoSub::bookSubscriptions_ because the InfoSub is being destroyed.
|
||||
* Called by ~InfoSub() for each book in bookSubscriptions_.
|
||||
*
|
||||
* @param uListener The sequence number of the subscriber being torn down.
|
||||
* @param book The order book entry to remove.
|
||||
* @return true if the entry was present and removed, false otherwise
|
||||
* (e.g., already removed by a concurrent RPC unsubscribe).
|
||||
*
|
||||
* @note Thread-safety: acquires subLock_ internally.
|
||||
*/
|
||||
virtual bool
|
||||
unsubBookInternal(std::uint64_t uListener, Book const&) = 0;
|
||||
|
||||
virtual bool
|
||||
subTransactions(ref ispListener) = 0;
|
||||
@@ -158,6 +207,13 @@ public:
|
||||
addRpcSub(std::string const& strUrl, ref rspEntry) = 0;
|
||||
virtual bool
|
||||
tryRemoveRpcSub(std::string const& strUrl) = 0;
|
||||
|
||||
/** Journal used by InfoSub for diagnostics that occur after the
|
||||
* owning subsystem (e.g. application-level Logs) is the only
|
||||
* surviving sink — primarily destructor-time cleanup failures.
|
||||
*/
|
||||
[[nodiscard]] virtual beast::Journal const&
|
||||
journal() const = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -184,6 +240,31 @@ public:
|
||||
void
|
||||
deleteSubAccountInfo(AccountID const& account, bool rt);
|
||||
|
||||
/** Record that this subscriber is following @p book.
|
||||
*
|
||||
* Called by NetworkOPsImp::subBook so that ~InfoSub() can issue a
|
||||
* matching unsubBook for every book this subscriber is tracking,
|
||||
* keeping per-subscriber state symmetric with the server-side map.
|
||||
*
|
||||
* @param book The order book this subscriber has just subscribed to.
|
||||
* @note Idempotent: re-inserting an already-tracked book is a no-op.
|
||||
* @note Thread-safe: takes InfoSub::lock_.
|
||||
*/
|
||||
void
|
||||
insertBookSubscription(Book const& book);
|
||||
|
||||
/** Stop tracking @p book for this subscriber.
|
||||
*
|
||||
* Called by the unsubscribe RPC handler so that the book is not
|
||||
* re-unsubscribed by ~InfoSub(). Pairs with insertBookSubscription.
|
||||
*
|
||||
* @param book The order book to forget.
|
||||
* @note No-op if @p book was not previously inserted.
|
||||
* @note Thread-safe: takes InfoSub::lock_.
|
||||
*/
|
||||
void
|
||||
deleteBookSubscription(Book const& book);
|
||||
|
||||
// return false if already subscribed to this account
|
||||
bool
|
||||
insertSubAccountHistory(AccountID const& account);
|
||||
@@ -217,6 +298,7 @@ private:
|
||||
std::shared_ptr<InfoSubRequest> request_;
|
||||
std::uint64_t seq_;
|
||||
hash_set<AccountID> accountHistorySubscriptions_;
|
||||
hash_set<Book> bookSubscriptions_;
|
||||
unsigned int apiVersion_ = 0;
|
||||
|
||||
static int
|
||||
|
||||
@@ -249,6 +249,19 @@ public:
|
||||
|
||||
virtual void
|
||||
stateAccounting(json::Value& obj) = 0;
|
||||
|
||||
/** Total number of (book, subscriber) entries currently tracked.
|
||||
*
|
||||
* Counts every weak_ptr stored across every book in subBook_, NOT the
|
||||
* number of distinct subscribers and NOT the number of distinct
|
||||
* books: a single subscriber following N books contributes N entries.
|
||||
*
|
||||
* @note Diagnostic accessor; intended for tests and operator visibility
|
||||
* into per-book subscription state. The returned value is a
|
||||
* snapshot under the subscription lock.
|
||||
*/
|
||||
virtual std::size_t
|
||||
getBookSubscribersCount() = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
static constexpr auto kDefaultCacheTargetSize = 0;
|
||||
|
||||
using key_type = uint256;
|
||||
using clock_type = typename CacheType::clock_type;
|
||||
using clock_type = CacheType::clock_type;
|
||||
|
||||
/** Construct the cache.
|
||||
|
||||
|
||||
@@ -1,25 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
/** Thread-local flag for span discard signaling.
|
||||
/** Thread-local discard signaling between SpanGuard and the span processor.
|
||||
|
||||
SpanGuard::discard() sets gTlDiscardCurrentSpan to true before calling
|
||||
Span::End(). The OTel SDK calls SpanProcessor::OnEnd() synchronously on
|
||||
the same thread, so FilteringSpanProcessor checks and clears this flag
|
||||
in OnEnd() to drop the span before it enters the batch export queue.
|
||||
SpanGuard::discard() wants to drop a span without sending it to the
|
||||
exporter. The OTel SDK calls SpanProcessor::OnEnd() synchronously on the
|
||||
same thread that calls Span::End(), so a thread-local flag set just before
|
||||
End() and read inside OnEnd() lets FilteringSpanProcessor drop the span
|
||||
before it enters the batch export queue.
|
||||
|
||||
This side-channel avoids inspecting the Recordable's internals (which
|
||||
vary by exporter type — SpanData vs OtlpRecordable).
|
||||
This side-channel avoids inspecting the Recordable's internals (which vary
|
||||
by exporter type — SpanData vs OtlpRecordable).
|
||||
|
||||
The flag is a *private* thread-local member of DiscardScope, mutated only by
|
||||
its constructor and destructor. This gives real access control rather than a
|
||||
naming convention: no code that includes this header can flip the flag
|
||||
directly — it can only enter a DiscardScope (which sets and clears the flag
|
||||
over its own lifetime) and observe the state via DiscardScope::isActive().
|
||||
Binding set/clear to a scope also means the flag cannot leak onto the next
|
||||
span even if End() were to throw.
|
||||
|
||||
Kept in a separate header to avoid transitive include bloat: SpanGuard.h
|
||||
only needs this flag, not the full Telemetry.h with BasicConfig/Journal.
|
||||
only needs this signaling, not the full Telemetry.h with BasicConfig/Journal.
|
||||
|
||||
Usage:
|
||||
@code
|
||||
// In SpanGuard::discard():
|
||||
{
|
||||
DiscardScope discardScope; // flag set for this scope only
|
||||
span->End(); // OnEnd() runs synchronously, sees flag
|
||||
} // flag cleared here, unconditionally
|
||||
|
||||
// In FilteringSpanProcessor::OnEnd():
|
||||
if (DiscardScope::isActive())
|
||||
return; // drop the span
|
||||
@endcode
|
||||
|
||||
@note Thread safety: the flag is thread-local, so each thread observes only
|
||||
its own discard signal — no synchronization is required.
|
||||
|
||||
@see SpanGuard::discard(), FilteringSpanProcessor (Telemetry.cpp)
|
||||
*/
|
||||
|
||||
namespace xrpl::telemetry {
|
||||
|
||||
/** When true, the FilteringSpanProcessor drops the current span in
|
||||
OnEnd(). Set by SpanGuard::discard(), cleared by OnEnd(). */
|
||||
inline thread_local bool gTlDiscardCurrentSpan = false;
|
||||
/** RAII guard that marks the current thread's span for discard.
|
||||
|
||||
Sets the thread-local discard flag on construction and clears it on
|
||||
destruction, so a span ended within the guard's scope is dropped by
|
||||
FilteringSpanProcessor::OnEnd() while the flag stays confined to that scope.
|
||||
The flag is private and mutated only here, so no other code can set it.
|
||||
Non-copyable and non-movable — its sole purpose is the scoped flag lifetime.
|
||||
*/
|
||||
class DiscardScope
|
||||
{
|
||||
public:
|
||||
DiscardScope() noexcept
|
||||
{
|
||||
discarding = true;
|
||||
}
|
||||
|
||||
~DiscardScope()
|
||||
{
|
||||
discarding = false;
|
||||
}
|
||||
|
||||
DiscardScope(DiscardScope const&) = delete;
|
||||
DiscardScope&
|
||||
operator=(DiscardScope const&) = delete;
|
||||
DiscardScope(DiscardScope&&) = delete;
|
||||
DiscardScope&
|
||||
operator=(DiscardScope&&) = delete;
|
||||
|
||||
/** @return true if the current thread is inside a DiscardScope, i.e. the
|
||||
span ending now should be dropped rather than exported. Read by
|
||||
FilteringSpanProcessor::OnEnd(). */
|
||||
[[nodiscard]] static bool
|
||||
isActive() noexcept
|
||||
{
|
||||
return discarding;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Thread-local discard flag. Private, so only this class's ctor/dtor can
|
||||
mutate it; observers use isActive(). One instance per thread. */
|
||||
inline static thread_local bool discarding = false;
|
||||
};
|
||||
|
||||
} // namespace xrpl::telemetry
|
||||
|
||||
@@ -107,7 +107,6 @@ inline constexpr auto link = makeStr("link");
|
||||
namespace attr {
|
||||
inline constexpr auto networkId = join(join(seg::xrpl, seg::network), makeStr("id"));
|
||||
inline constexpr auto networkType = join(join(seg::xrpl, seg::network), makeStr("type"));
|
||||
inline constexpr auto linkType = makeStr("link_type");
|
||||
|
||||
/// Canonical shared attrs (rule 5 — <domain>_<field> underscore form).
|
||||
///
|
||||
@@ -139,7 +138,6 @@ inline constexpr auto fullValidation = makeStr("full_validation");
|
||||
namespace attr_val {
|
||||
inline constexpr auto success = makeStr("success");
|
||||
inline constexpr auto error = makeStr("error");
|
||||
inline constexpr auto followsFrom = makeStr("follows_from");
|
||||
} // namespace attr_val
|
||||
|
||||
} // namespace xrpl::telemetry
|
||||
|
||||
@@ -104,6 +104,13 @@
|
||||
|
||||
namespace xrpl::telemetry {
|
||||
|
||||
#ifdef XRPL_ENABLE_TELEMETRY
|
||||
/** OTel instrumentation scope (tracer) name. Identifies this library as the
|
||||
source of spans; distinct from the `service.name` resource attribute
|
||||
(Setup::serviceName), which is config-overridable. */
|
||||
inline constexpr std::string_view kTracerName{"xrpld"};
|
||||
#endif
|
||||
|
||||
class Telemetry
|
||||
{
|
||||
/** Global singleton pointer, set by start()/stop() in the active
|
||||
@@ -184,13 +191,13 @@ public:
|
||||
delegated to the collector's tail sampling; for node-local post-hoc
|
||||
dropping see SpanGuard::discard().
|
||||
*/
|
||||
double const samplingRatio = 1.0;
|
||||
static constexpr double samplingRatio = 1.0;
|
||||
|
||||
/** Maximum number of spans per batch export. */
|
||||
std::uint32_t batchSize = 512;
|
||||
|
||||
/** Delay between batch exports. */
|
||||
std::chrono::milliseconds batchDelay{5000};
|
||||
std::chrono::milliseconds batchDelay = std::chrono::milliseconds{5000};
|
||||
|
||||
/** Maximum number of spans queued before dropping. */
|
||||
std::uint32_t maxQueueSize = 2048;
|
||||
@@ -291,7 +298,7 @@ public:
|
||||
@return A shared pointer to the Tracer.
|
||||
*/
|
||||
virtual opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer>
|
||||
getTracer(std::string_view name = "xrpld") = 0;
|
||||
getTracer(std::string_view name = kTracerName) = 0;
|
||||
|
||||
/** Start a new span on the current thread's context.
|
||||
|
||||
@@ -351,7 +358,7 @@ makeTelemetry(Telemetry::Setup const& setup, beast::Journal journal);
|
||||
@return A populated Setup struct with defaults for missing values.
|
||||
*/
|
||||
Telemetry::Setup
|
||||
setupTelemetry(
|
||||
makeTelemetrySetup(
|
||||
Section const& section,
|
||||
std::string const& nodePublicKey,
|
||||
std::string const& version,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/applySteps.h>
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -222,8 +223,63 @@ public:
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function can be overridden to introduce additional semantic constraints beyond the
|
||||
* granular template validation for granular permissions. It is called by the base
|
||||
* invokeCheckPermission method only after the transaction has successfully passed
|
||||
* checkGranularSandbox.
|
||||
*/
|
||||
static NotTEC
|
||||
checkPermission(ReadView const& view, STTx const& tx);
|
||||
checkGranularSemantics(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType> const& heldGranularPermissions)
|
||||
{
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the transaction is authorized to be executed by the delegated account.
|
||||
* This function enforces the strict permission check hierarchy. It is explicitly
|
||||
* designed NOT to be overridden. Derived transactors must instead implement
|
||||
* checkGranularSemantics to add custom validation logic for granular permissions.
|
||||
*
|
||||
* The evaluation proceeds as follows:
|
||||
* - If transaction-level permission is granted, the function immediately returns tesSUCCESS.
|
||||
* - If transaction-level permission is not granted, the function checks whether the transaction
|
||||
* matches the granular permission template defined in permissions.macro. If it does, it then
|
||||
* calls checkGranularSemantics to perform any additional, fine-grained validation.
|
||||
*
|
||||
*/
|
||||
template <class T>
|
||||
static NotTEC
|
||||
invokeCheckPermission(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
// heldGranularPermissions is passed by reference into checkPermission.
|
||||
// It is populated with the sender’s granular permissions only when the sender
|
||||
// lacks tx-level permission but has granular permissions that satisfy the
|
||||
// granular permission template.
|
||||
//
|
||||
// - result is terNO_DELEGATE_PERMISSION: return immediately.
|
||||
// - result is tesSUCCESS and heldGranularPermissions is empty: tx-level permission was
|
||||
// granted, so we returned success before populating it.
|
||||
// - result is tesSUCCESS and heldGranularPermissions is not empty: tx-level permission was
|
||||
// not granted, but the held granular permissions passed checkGranularSandbox, so we proceed
|
||||
// to checkGranularSemantics.
|
||||
//
|
||||
// WARNING: Do not simplify checkPermission to return only
|
||||
// heldGranularPermissions or the ter code. Both the result and the
|
||||
// populated set are required to enforce the strict permission hierarchy
|
||||
// described above.
|
||||
std::unordered_set<GranularPermissionType> heldGranularPermissions;
|
||||
if (NotTEC const result = checkPermission(view, tx, heldGranularPermissions);
|
||||
!isTesSuccess(result) || heldGranularPermissions.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return T::checkGranularSemantics(view, tx, heldGranularPermissions);
|
||||
}
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
// Interface used by AccountDelete
|
||||
@@ -353,13 +409,24 @@ protected:
|
||||
unit::ValueUnit<Unit, T> min = unit::ValueUnit<Unit, T>{});
|
||||
|
||||
private:
|
||||
static NotTEC
|
||||
checkPermission(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType>& heldGranularPermissions);
|
||||
|
||||
std::pair<TER, XRPAmount>
|
||||
reset(XRPAmount fee);
|
||||
|
||||
TER
|
||||
consumeSeqProxy(SLE::pointer const& sleAccount);
|
||||
|
||||
TER
|
||||
payFee();
|
||||
|
||||
std::tuple<TER, XRPAmount, bool>
|
||||
processPersistentChanges(TER result, XRPAmount fee);
|
||||
|
||||
static NotTEC
|
||||
checkSingleSign(
|
||||
ReadView const& view,
|
||||
@@ -367,6 +434,7 @@ private:
|
||||
AccountID const& idAccount,
|
||||
SLE::const_pointer sleAccount,
|
||||
beast::Journal const j);
|
||||
|
||||
static NotTEC
|
||||
checkMultiSign(
|
||||
ReadView const& view,
|
||||
|
||||
@@ -15,7 +15,9 @@ class ValidAMM
|
||||
std::optional<AccountID> ammAccount_;
|
||||
std::optional<STAmount> lptAMMBalanceAfter_;
|
||||
std::optional<STAmount> lptAMMBalanceBefore_;
|
||||
std::optional<STAmount> lptAMMBalanceBeforeDeletion_;
|
||||
bool ammPoolChanged_{false};
|
||||
bool ammDeleted_{false};
|
||||
|
||||
public:
|
||||
enum class ZeroAllowed : bool { No = false, Yes = true };
|
||||
@@ -35,12 +37,17 @@ private:
|
||||
[[nodiscard]] bool
|
||||
finalizeCreate(STTx const&, ReadView const&, bool enforce, beast::Journal const&) const;
|
||||
[[nodiscard]] bool
|
||||
finalizeDelete(bool enforce, TER res, beast::Journal const&) const;
|
||||
finalizeDelete(bool enforce, bool enforceAMMDelete, TER res, beast::Journal const&) const;
|
||||
[[nodiscard]] bool
|
||||
finalizeDeposit(STTx const&, ReadView const&, bool enforce, beast::Journal const&) const;
|
||||
// Includes clawback
|
||||
[[nodiscard]] bool
|
||||
finalizeWithdraw(STTx const&, ReadView const&, bool enforce, beast::Journal const&) const;
|
||||
finalizeWithdraw(
|
||||
STTx const&,
|
||||
ReadView const&,
|
||||
bool enforce,
|
||||
bool enforceAMMDelete,
|
||||
beast::Journal const&) const;
|
||||
[[nodiscard]] bool
|
||||
finalizeDEX(bool enforce, beast::Journal const&) const;
|
||||
[[nodiscard]] bool
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <xrpl/ledger/PaymentSandbox.h>
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/paths/detail/AmountSpec.h>
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ checkFreeze(
|
||||
}
|
||||
}
|
||||
|
||||
if (auto sle = view.read(keylet::line(src, dst, currency)))
|
||||
if (auto sle = view.read(keylet::trustLine(src, dst, currency)))
|
||||
{
|
||||
if (sle->isFlag((dst > src) ? lsfHighFreeze : lsfLowFreeze))
|
||||
{
|
||||
@@ -71,8 +71,8 @@ checkNoRipple(
|
||||
beast::Journal j)
|
||||
{
|
||||
// fetch the ripple lines into and out of this node
|
||||
auto sleIn = view.read(keylet::line(prev, cur, currency));
|
||||
auto sleOut = view.read(keylet::line(cur, next, currency));
|
||||
auto sleIn = view.read(keylet::trustLine(prev, cur, currency));
|
||||
auto sleOut = view.read(keylet::trustLine(cur, next, currency));
|
||||
|
||||
if (!sleIn || !sleOut)
|
||||
return terNO_LINE;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/paths/Flow.h>
|
||||
#include <xrpl/tx/paths/detail/AmountSpec.h>
|
||||
#include <xrpl/tx/paths/detail/FlatSets.h>
|
||||
#include <xrpl/tx/paths/detail/FlowDebugInfo.h>
|
||||
#include <xrpl/tx/paths/detail/Steps.h>
|
||||
|
||||
@@ -23,9 +23,6 @@ public:
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
checkPermission(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
|
||||
@@ -32,7 +32,10 @@ public:
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
checkPermission(ReadView const& view, STTx const& tx);
|
||||
checkGranularSemantics(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType> const& heldGranularPermissions);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
@@ -22,9 +22,6 @@ public:
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
checkPermission(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ public:
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
checkPermission(ReadView const& view, STTx const& tx);
|
||||
checkGranularSemantics(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType> const& heldGranularPermissions);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
Reference in New Issue
Block a user