mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'develop' into Bronek/vault_enable
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
#include <xrpl/basics/Resolver.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
explicit ResolverAsio() = default;
|
||||
|
||||
static std::unique_ptr<ResolverAsio>
|
||||
New(boost::asio::io_service&, beast::Journal);
|
||||
New(boost::asio::io_context&, beast::Journal);
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/partitioned_unordered_map.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
|
||||
@@ -90,6 +90,9 @@ public:
|
||||
int
|
||||
getCacheSize() const;
|
||||
|
||||
int
|
||||
getTrackSize() const;
|
||||
|
||||
float
|
||||
getHitRate();
|
||||
|
||||
@@ -167,6 +170,9 @@ public:
|
||||
bool
|
||||
retrieve(key_type const& key, T& data);
|
||||
|
||||
mutex_type&
|
||||
peekMutex();
|
||||
|
||||
std::vector<key_type>
|
||||
getKeys() const;
|
||||
|
||||
@@ -187,14 +193,11 @@ public:
|
||||
|
||||
private:
|
||||
SharedPointerType
|
||||
initialFetch(key_type const& key);
|
||||
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l);
|
||||
|
||||
void
|
||||
collect_metrics();
|
||||
|
||||
Mutex&
|
||||
lockPartition(key_type const& key) const;
|
||||
|
||||
private:
|
||||
struct Stats
|
||||
{
|
||||
@@ -297,8 +300,8 @@ private:
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemoval,
|
||||
Mutex& partitionLock);
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&);
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
@@ -307,12 +310,14 @@ private:
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
Mutex& partitionLock);
|
||||
std::lock_guard<std::recursive_mutex> const&);
|
||||
|
||||
beast::Journal m_journal;
|
||||
clock_type& m_clock;
|
||||
Stats m_stats;
|
||||
|
||||
mutex_type mutable m_mutex;
|
||||
|
||||
// Used for logging
|
||||
std::string m_name;
|
||||
|
||||
@@ -323,11 +328,10 @@ private:
|
||||
clock_type::duration const m_target_age;
|
||||
|
||||
// Number of items cached
|
||||
std::atomic<int> m_cache_count;
|
||||
int m_cache_count;
|
||||
cache_type m_cache; // Hold strong reference to recent objects
|
||||
std::atomic<std::uint64_t> m_hits;
|
||||
std::atomic<std::uint64_t> m_misses;
|
||||
mutable std::vector<mutex_type> partitionLocks_;
|
||||
std::uint64_t m_hits;
|
||||
std::uint64_t m_misses;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.ipp>
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -61,7 +60,6 @@ inline TaggedCache<
|
||||
, m_hits(0)
|
||||
, m_misses(0)
|
||||
{
|
||||
partitionLocks_ = std::vector<mutex_type>(m_cache.partitions());
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -107,13 +105,8 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::size() const
|
||||
{
|
||||
std::size_t totalSize = 0;
|
||||
for (size_t i = 0; i < partitionLocks_.size(); ++i)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(partitionLocks_[i]);
|
||||
totalSize += m_cache.map()[i].size();
|
||||
}
|
||||
return totalSize;
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -136,7 +129,32 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::getCacheSize() const
|
||||
{
|
||||
return m_cache_count.load(std::memory_order_relaxed);
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache_count;
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache,
|
||||
class SharedWeakUnionPointer,
|
||||
class SharedPointerType,
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline int
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::getTrackSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -159,10 +177,9 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::getHitRate()
|
||||
{
|
||||
auto const hits = m_hits.load(std::memory_order_relaxed);
|
||||
auto const misses = m_misses.load(std::memory_order_relaxed);
|
||||
float const total = float(hits + misses);
|
||||
return hits * (100.0f / std::max(1.0f, total));
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const total = static_cast<float>(m_hits + m_misses);
|
||||
return m_hits * (100.0f / std::max(1.0f, total));
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -185,12 +202,9 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::clear()
|
||||
{
|
||||
for (auto& mutex : partitionLocks_)
|
||||
mutex.lock();
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
for (auto& mutex : partitionLocks_)
|
||||
mutex.unlock();
|
||||
m_cache_count.store(0, std::memory_order_relaxed);
|
||||
m_cache_count = 0;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -213,9 +227,11 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::reset()
|
||||
{
|
||||
clear();
|
||||
m_hits.store(0, std::memory_order_relaxed);
|
||||
m_misses.store(0, std::memory_order_relaxed);
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
m_hits = 0;
|
||||
m_misses = 0;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -239,7 +255,7 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::touch_if_exists(KeyComparable const& key)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(lockPartition(key));
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const iter(m_cache.find(key));
|
||||
if (iter == m_cache.end())
|
||||
{
|
||||
@@ -281,6 +297,8 @@ TaggedCache<
|
||||
|
||||
auto const start = std::chrono::steady_clock::now();
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_target_size == 0 ||
|
||||
(static_cast<int>(m_cache.size()) <= m_target_size))
|
||||
{
|
||||
@@ -312,13 +330,12 @@ TaggedCache<
|
||||
m_cache.map()[p],
|
||||
allStuffToSweep[p],
|
||||
allRemovals,
|
||||
partitionLocks_[p]));
|
||||
lock));
|
||||
}
|
||||
for (std::thread& worker : workers)
|
||||
worker.join();
|
||||
|
||||
int removals = allRemovals.load(std::memory_order_relaxed);
|
||||
m_cache_count.fetch_sub(removals, std::memory_order_relaxed);
|
||||
m_cache_count -= allRemovals;
|
||||
}
|
||||
// At this point allStuffToSweep will go out of scope outside the lock
|
||||
// and decrement the reference count on each strong pointer.
|
||||
@@ -352,8 +369,7 @@ TaggedCache<
|
||||
{
|
||||
// Remove from cache, if !valid, remove from map too. Returns true if
|
||||
// removed from cache
|
||||
|
||||
std::lock_guard<Mutex> lock(lockPartition(key));
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
auto cit = m_cache.find(key);
|
||||
|
||||
@@ -366,7 +382,7 @@ TaggedCache<
|
||||
|
||||
if (entry.isCached())
|
||||
{
|
||||
m_cache_count.fetch_sub(1, std::memory_order_relaxed);
|
||||
--m_cache_count;
|
||||
entry.ptr.convertToWeak();
|
||||
ret = true;
|
||||
}
|
||||
@@ -404,16 +420,17 @@ TaggedCache<
|
||||
{
|
||||
// Return canonical value, store if needed, refresh in cache
|
||||
// Return values: true=we had the data already
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
std::lock_guard<Mutex> lock(lockPartition(key));
|
||||
auto cit = m_cache.find(key);
|
||||
|
||||
if (cit == m_cache.end())
|
||||
{
|
||||
m_cache.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
std::forward_as_tuple(m_clock.now(), data));
|
||||
m_cache_count.fetch_add(1, std::memory_order_relaxed);
|
||||
++m_cache_count;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -462,12 +479,12 @@ TaggedCache<
|
||||
data = cachedData;
|
||||
}
|
||||
|
||||
m_cache_count.fetch_add(1, std::memory_order_relaxed);
|
||||
++m_cache_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
entry.ptr = data;
|
||||
m_cache_count.fetch_add(1, std::memory_order_relaxed);
|
||||
++m_cache_count;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -543,11 +560,10 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::fetch(key_type const& key)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(lockPartition(key));
|
||||
|
||||
auto ret = initialFetch(key);
|
||||
std::lock_guard<mutex_type> l(m_mutex);
|
||||
auto ret = initialFetch(key, l);
|
||||
if (!ret)
|
||||
m_misses.fetch_add(1, std::memory_order_relaxed);
|
||||
++m_misses;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -611,8 +627,8 @@ TaggedCache<
|
||||
Mutex>::insert(key_type const& key)
|
||||
-> std::enable_if_t<IsKeyCache, ReturnType>
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
std::lock_guard<Mutex> lock(lockPartition(key));
|
||||
auto [it, inserted] = m_cache.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
@@ -652,6 +668,29 @@ TaggedCache<
|
||||
return true;
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache,
|
||||
class SharedWeakUnionPointer,
|
||||
class SharedPointerType,
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline auto
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::peekMutex() -> mutex_type&
|
||||
{
|
||||
return m_mutex;
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
@@ -675,13 +714,10 @@ TaggedCache<
|
||||
std::vector<key_type> v;
|
||||
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
v.reserve(m_cache.size());
|
||||
for (std::size_t i = 0; i < partitionLocks_.size(); ++i)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(partitionLocks_[i]);
|
||||
for (auto const& entry : m_cache.map()[i])
|
||||
v.push_back(entry.first);
|
||||
}
|
||||
for (auto const& _ : m_cache)
|
||||
v.push_back(_.first);
|
||||
}
|
||||
|
||||
return v;
|
||||
@@ -707,12 +743,11 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::rate() const
|
||||
{
|
||||
auto const hits = m_hits.load(std::memory_order_relaxed);
|
||||
auto const misses = m_misses.load(std::memory_order_relaxed);
|
||||
auto const tot = hits + misses;
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const tot = m_hits + m_misses;
|
||||
if (tot == 0)
|
||||
return 0.0;
|
||||
return double(hits) / tot;
|
||||
return 0;
|
||||
return double(m_hits) / tot;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -736,16 +771,18 @@ TaggedCache<
|
||||
KeyEqual,
|
||||
Mutex>::fetch(key_type const& digest, Handler const& h)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(lockPartition(digest));
|
||||
|
||||
if (auto ret = initialFetch(digest))
|
||||
return ret;
|
||||
{
|
||||
std::lock_guard l(m_mutex);
|
||||
if (auto ret = initialFetch(digest, l))
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto sle = h();
|
||||
if (!sle)
|
||||
return {};
|
||||
|
||||
m_misses.fetch_add(1, std::memory_order_relaxed);
|
||||
std::lock_guard l(m_mutex);
|
||||
++m_misses;
|
||||
auto const [it, inserted] =
|
||||
m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
|
||||
if (!inserted)
|
||||
@@ -772,10 +809,9 @@ TaggedCache<
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::initialFetch(key_type const& key)
|
||||
Mutex>::
|
||||
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(lockPartition(key));
|
||||
|
||||
auto cit = m_cache.find(key);
|
||||
if (cit == m_cache.end())
|
||||
return {};
|
||||
@@ -783,7 +819,7 @@ TaggedCache<
|
||||
Entry& entry = cit->second;
|
||||
if (entry.isCached())
|
||||
{
|
||||
m_hits.fetch_add(1, std::memory_order_relaxed);
|
||||
++m_hits;
|
||||
entry.touch(m_clock.now());
|
||||
return entry.ptr.getStrong();
|
||||
}
|
||||
@@ -791,13 +827,12 @@ TaggedCache<
|
||||
if (entry.isCached())
|
||||
{
|
||||
// independent of cache size, so not counted as a hit
|
||||
m_cache_count.fetch_add(1, std::memory_order_relaxed);
|
||||
++m_cache_count;
|
||||
entry.touch(m_clock.now());
|
||||
return entry.ptr.getStrong();
|
||||
}
|
||||
|
||||
m_cache.erase(cit);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -826,11 +861,10 @@ TaggedCache<
|
||||
{
|
||||
beast::insight::Gauge::value_type hit_rate(0);
|
||||
{
|
||||
auto const hits = m_hits.load(std::memory_order_relaxed);
|
||||
auto const misses = m_misses.load(std::memory_order_relaxed);
|
||||
auto const total = hits + misses;
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const total(m_hits + m_misses);
|
||||
if (total != 0)
|
||||
hit_rate = (hits * 100) / total;
|
||||
hit_rate = (m_hits * 100) / total;
|
||||
}
|
||||
m_stats.hit_rate.set(hit_rate);
|
||||
}
|
||||
@@ -861,16 +895,12 @@ TaggedCache<
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
Mutex& partitionLock)
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
beast::setCurrentThreadName("sweep-KVCache");
|
||||
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
|
||||
std::lock_guard<Mutex> lock(partitionLock);
|
||||
|
||||
// Keep references to all the stuff we sweep
|
||||
// so that we can destroy them outside the lock.
|
||||
stuffToSweep.reserve(partition.size());
|
||||
@@ -954,16 +984,12 @@ TaggedCache<
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
Mutex& partitionLock)
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
beast::setCurrentThreadName("sweep-KCache");
|
||||
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
|
||||
std::lock_guard<Mutex> lock(partitionLock);
|
||||
|
||||
// Keep references to all the stuff we sweep
|
||||
// so that we can destroy them outside the lock.
|
||||
{
|
||||
@@ -998,29 +1024,6 @@ TaggedCache<
|
||||
});
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache,
|
||||
class SharedWeakUnionPointer,
|
||||
class SharedPointerType,
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline Mutex&
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::lockPartition(key_type const& key) const
|
||||
{
|
||||
return partitionLocks_[m_cache.partition_index(key)];
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -277,12 +277,6 @@ public:
|
||||
return map_;
|
||||
}
|
||||
|
||||
partition_map_type const&
|
||||
map() const
|
||||
{
|
||||
return map_;
|
||||
}
|
||||
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
@@ -327,12 +321,6 @@ public:
|
||||
return cend();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
partition_index(key_type const& key) const
|
||||
{
|
||||
return partitioner(key);
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
void
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <boost/asio/basic_waitable_timer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
@@ -32,7 +33,7 @@
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Measures handler latency on an io_service queue. */
|
||||
/** Measures handler latency on an io_context queue. */
|
||||
template <class Clock>
|
||||
class io_latency_probe
|
||||
{
|
||||
@@ -44,12 +45,12 @@ private:
|
||||
std::condition_variable_any m_cond;
|
||||
std::size_t m_count;
|
||||
duration const m_period;
|
||||
boost::asio::io_service& m_ios;
|
||||
boost::asio::io_context& m_ios;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
|
||||
bool m_cancel;
|
||||
|
||||
public:
|
||||
io_latency_probe(duration const& period, boost::asio::io_service& ios)
|
||||
io_latency_probe(duration const& period, boost::asio::io_context& ios)
|
||||
: m_count(1)
|
||||
, m_period(period)
|
||||
, m_ios(ios)
|
||||
@@ -64,16 +65,16 @@ public:
|
||||
cancel(lock, true);
|
||||
}
|
||||
|
||||
/** Return the io_service associated with the latency probe. */
|
||||
/** Return the io_context associated with the latency probe. */
|
||||
/** @{ */
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
boost::asio::io_context&
|
||||
get_io_context()
|
||||
{
|
||||
return m_ios;
|
||||
}
|
||||
|
||||
boost::asio::io_service const&
|
||||
get_io_service() const
|
||||
boost::asio::io_context const&
|
||||
get_io_context() const
|
||||
{
|
||||
return m_ios;
|
||||
}
|
||||
@@ -109,8 +110,10 @@ public:
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
m_ios.post(sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
boost::asio::post(
|
||||
m_ios,
|
||||
sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
}
|
||||
|
||||
/** Initiate continuous i/o latency sampling.
|
||||
@@ -124,8 +127,10 @@ public:
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
m_ios.post(sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
boost::asio::post(
|
||||
m_ios,
|
||||
sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -236,12 +241,13 @@ private:
|
||||
// The latency is too high to maintain the desired
|
||||
// period so don't bother with a timer.
|
||||
//
|
||||
m_probe->m_ios.post(
|
||||
boost::asio::post(
|
||||
m_probe->m_ios,
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_probe->m_timer.expires_from_now(when - now);
|
||||
m_probe->m_timer.expires_after(when - now);
|
||||
m_probe->m_timer.async_wait(
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
@@ -254,7 +260,8 @@ private:
|
||||
if (!m_probe)
|
||||
return;
|
||||
typename Clock::time_point const now(Clock::now());
|
||||
m_probe->m_ios.post(
|
||||
boost::asio::post(
|
||||
m_probe->m_ios,
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#ifndef BEAST_TEST_YIELD_TO_HPP
|
||||
#define BEAST_TEST_YIELD_TO_HPP
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/thread/csbl/memory/allocator_arg.hpp>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
@@ -29,10 +31,12 @@ namespace test {
|
||||
class enable_yield_to
|
||||
{
|
||||
protected:
|
||||
boost::asio::io_service ios_;
|
||||
boost::asio::io_context ios_;
|
||||
|
||||
private:
|
||||
boost::optional<boost::asio::io_service::work> work_;
|
||||
boost::optional<boost::asio::executor_work_guard<
|
||||
boost::asio::io_context::executor_type>>
|
||||
work_;
|
||||
std::vector<std::thread> threads_;
|
||||
std::mutex m_;
|
||||
std::condition_variable cv_;
|
||||
@@ -42,7 +46,8 @@ public:
|
||||
/// The type of yield context passed to functions.
|
||||
using yield_context = boost::asio::yield_context;
|
||||
|
||||
explicit enable_yield_to(std::size_t concurrency = 1) : work_(ios_)
|
||||
explicit enable_yield_to(std::size_t concurrency = 1)
|
||||
: work_(boost::asio::make_work_guard(ios_))
|
||||
{
|
||||
threads_.reserve(concurrency);
|
||||
while (concurrency--)
|
||||
@@ -56,9 +61,9 @@ public:
|
||||
t.join();
|
||||
}
|
||||
|
||||
/// Return the `io_service` associated with the object
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
/// Return the `io_context` associated with the object
|
||||
boost::asio::io_context&
|
||||
get_io_context()
|
||||
{
|
||||
return ios_;
|
||||
}
|
||||
@@ -111,13 +116,18 @@ enable_yield_to::spawn(F0&& f, FN&&... fn)
|
||||
{
|
||||
boost::asio::spawn(
|
||||
ios_,
|
||||
boost::allocator_arg,
|
||||
boost::context::fixedsize_stack(2 * 1024 * 1024),
|
||||
[&](yield_context yield) {
|
||||
f(yield);
|
||||
std::lock_guard lock{m_};
|
||||
if (--running_ == 0)
|
||||
cv_.notify_all();
|
||||
},
|
||||
boost::coroutines::attributes(2 * 1024 * 1024));
|
||||
[](std::exception_ptr e) {
|
||||
if (e)
|
||||
std::rethrow_exception(e);
|
||||
});
|
||||
spawn(fn...);
|
||||
}
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ Reader::parse(Value& root, BufferSequence const& bs)
|
||||
std::string s;
|
||||
s.reserve(buffer_size(bs));
|
||||
for (auto const& b : bs)
|
||||
s.append(buffer_cast<char const*>(b), buffer_size(b));
|
||||
s.append(static_cast<char const*>(b.data()), buffer_size(b));
|
||||
return parse(s, root);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
public:
|
||||
AutoSocket(
|
||||
boost::asio::io_service& s,
|
||||
boost::asio::io_context& s,
|
||||
boost::asio::ssl::context& c,
|
||||
bool secureOnly,
|
||||
bool plainOnly)
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
mSocket = std::make_unique<ssl_socket>(s, c);
|
||||
}
|
||||
|
||||
AutoSocket(boost::asio::io_service& s, boost::asio::ssl::context& c)
|
||||
AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c)
|
||||
: AutoSocket(s, c, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
|
||||
#include <chrono>
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
static void
|
||||
get(bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
boost::asio::io_context& io_context,
|
||||
std::deque<std::string> deqSites,
|
||||
unsigned short const port,
|
||||
std::string const& strPath,
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
static void
|
||||
get(bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
boost::asio::io_context& io_context,
|
||||
std::string strSite,
|
||||
unsigned short const port,
|
||||
std::string const& strPath,
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
static void
|
||||
request(
|
||||
bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
boost::asio::io_context& io_context,
|
||||
std::string strSite,
|
||||
unsigned short const port,
|
||||
std::function<
|
||||
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
{
|
||||
strm.set_verify_callback(
|
||||
std::bind(
|
||||
&rfc2818_verify,
|
||||
&rfc6125_verify,
|
||||
host,
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2,
|
||||
@@ -167,7 +167,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief callback invoked for name verification - just passes through
|
||||
* to the asio rfc2818 implementation.
|
||||
* to the asio `host_name_verification` (rfc6125) implementation.
|
||||
*
|
||||
* @param domain hostname expected
|
||||
* @param preverified passed by implementation
|
||||
@@ -175,13 +175,13 @@ public:
|
||||
* @param j journal for logging
|
||||
*/
|
||||
static bool
|
||||
rfc2818_verify(
|
||||
rfc6125_verify(
|
||||
std::string const& domain,
|
||||
bool preverified,
|
||||
boost::asio::ssl::verify_context& ctx,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (boost::asio::ssl::rfc2818_verification(domain)(preverified, ctx))
|
||||
if (boost::asio::ssl::host_name_verification(domain)(preverified, ctx))
|
||||
return true;
|
||||
|
||||
JLOG(j.warn()) << "Outbound SSL connection to " << domain
|
||||
|
||||
@@ -6,89 +6,81 @@ option java_multiple_files = true;
|
||||
|
||||
import "org/xrpl/rpc/v1/ledger.proto";
|
||||
|
||||
message GetLedgerRequest
|
||||
{
|
||||
message GetLedgerRequest {
|
||||
LedgerSpecifier ledger = 1;
|
||||
|
||||
LedgerSpecifier ledger = 1;
|
||||
// If true, include transactions contained in this ledger
|
||||
bool transactions = 2;
|
||||
|
||||
// If true, include transactions contained in this ledger
|
||||
bool transactions = 2;
|
||||
// If true and transactions, include full transactions and metadata
|
||||
// If false and transactions, include only transaction hashes
|
||||
bool expand = 3;
|
||||
|
||||
// If true and transactions, include full transactions and metadata
|
||||
// If false and transactions, include only transaction hashes
|
||||
bool expand = 3;
|
||||
// If true, include state map difference between this ledger and the
|
||||
// previous ledger. This includes all added, modified or deleted ledger
|
||||
// objects
|
||||
bool get_objects = 4;
|
||||
|
||||
// If true, include state map difference between this ledger and the
|
||||
// previous ledger. This includes all added, modified or deleted ledger
|
||||
// objects
|
||||
bool get_objects = 4;
|
||||
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 5;
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 5;
|
||||
|
||||
// Identifying string. If user is set, client_ip is not set, and request is
|
||||
// coming from a secure_gateway host, then the client is not subject to
|
||||
// resource controls
|
||||
string user = 6;
|
||||
// Identifying string. If user is set, client_ip is not set, and request is
|
||||
// coming from a secure_gateway host, then the client is not subject to
|
||||
// resource controls
|
||||
string user = 6;
|
||||
|
||||
// For every object in the diff, get the object's predecessor and successor
|
||||
// in the state map. Only used if get_objects is also true.
|
||||
bool get_object_neighbors = 7;
|
||||
// For every object in the diff, get the object's predecessor and successor
|
||||
// in the state map. Only used if get_objects is also true.
|
||||
bool get_object_neighbors = 7;
|
||||
}
|
||||
|
||||
message GetLedgerResponse
|
||||
{
|
||||
bytes ledger_header = 1;
|
||||
message GetLedgerResponse {
|
||||
bytes ledger_header = 1;
|
||||
|
||||
oneof transactions
|
||||
{
|
||||
// Just the hashes
|
||||
TransactionHashList hashes_list = 2;
|
||||
|
||||
// Full transactions and metadata
|
||||
TransactionAndMetadataList transactions_list = 3;
|
||||
}
|
||||
oneof transactions {
|
||||
// Just the hashes
|
||||
TransactionHashList hashes_list = 2;
|
||||
|
||||
// True if the ledger has been validated
|
||||
bool validated = 4;
|
||||
// Full transactions and metadata
|
||||
TransactionAndMetadataList transactions_list = 3;
|
||||
}
|
||||
|
||||
// State map difference between this ledger and the previous ledger
|
||||
RawLedgerObjects ledger_objects = 5;
|
||||
// True if the ledger has been validated
|
||||
bool validated = 4;
|
||||
|
||||
// True if the skiplist object is included in ledger_objects
|
||||
bool skiplist_included = 6;
|
||||
// State map difference between this ledger and the previous ledger
|
||||
RawLedgerObjects ledger_objects = 5;
|
||||
|
||||
// True if request was exempt from resource controls
|
||||
bool is_unlimited = 7;
|
||||
// True if the skiplist object is included in ledger_objects
|
||||
bool skiplist_included = 6;
|
||||
|
||||
// True if the response contains the state map diff
|
||||
bool objects_included = 8;
|
||||
// True if request was exempt from resource controls
|
||||
bool is_unlimited = 7;
|
||||
|
||||
// True if the response contains key of objects adjacent to objects in state
|
||||
// map diff
|
||||
bool object_neighbors_included = 9;
|
||||
// True if the response contains the state map diff
|
||||
bool objects_included = 8;
|
||||
|
||||
// True if the response contains key of objects adjacent to objects in state
|
||||
// map diff
|
||||
bool object_neighbors_included = 9;
|
||||
|
||||
// Successor information for book directories modified as part of this
|
||||
// ledger
|
||||
repeated BookSuccessor book_successors = 10;
|
||||
// Successor information for book directories modified as part of this
|
||||
// ledger
|
||||
repeated BookSuccessor book_successors = 10;
|
||||
}
|
||||
|
||||
message TransactionHashList
|
||||
{
|
||||
repeated bytes hashes = 1;
|
||||
message TransactionHashList {
|
||||
repeated bytes hashes = 1;
|
||||
}
|
||||
|
||||
message TransactionAndMetadata
|
||||
{
|
||||
bytes transaction_blob = 1;
|
||||
message TransactionAndMetadata {
|
||||
bytes transaction_blob = 1;
|
||||
|
||||
bytes metadata_blob = 2;
|
||||
bytes metadata_blob = 2;
|
||||
}
|
||||
|
||||
message TransactionAndMetadataList
|
||||
{
|
||||
repeated TransactionAndMetadata transactions = 1;
|
||||
message TransactionAndMetadataList {
|
||||
repeated TransactionAndMetadata transactions = 1;
|
||||
}
|
||||
|
||||
@@ -8,46 +8,43 @@ import "org/xrpl/rpc/v1/ledger.proto";
|
||||
|
||||
// Get ledger objects for a specific ledger. You can iterate through several
|
||||
// calls to retrieve the entire contents of a single ledger version.
|
||||
message GetLedgerDataRequest
|
||||
{
|
||||
// If set, only objects with a key greater than marker are returned.
|
||||
// This can be used to pick up where a previous call left off.
|
||||
// Set marker to the value of marker in the previous response.
|
||||
bytes marker = 1;
|
||||
message GetLedgerDataRequest {
|
||||
// If set, only objects with a key greater than marker are returned.
|
||||
// This can be used to pick up where a previous call left off.
|
||||
// Set marker to the value of marker in the previous response.
|
||||
bytes marker = 1;
|
||||
|
||||
LedgerSpecifier ledger = 2;
|
||||
LedgerSpecifier ledger = 2;
|
||||
|
||||
// If set, only objects with a key less than end_marker are returned
|
||||
bytes end_marker = 3;
|
||||
// If set, only objects with a key less than end_marker are returned
|
||||
bytes end_marker = 3;
|
||||
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 4;
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 4;
|
||||
|
||||
// Identifying string. If user is set, client_ip is not set, and request is
|
||||
// coming from a secure_gateway host, then the client is not subject to
|
||||
// resource controls
|
||||
string user = 6;
|
||||
// Identifying string. If user is set, client_ip is not set, and request is
|
||||
// coming from a secure_gateway host, then the client is not subject to
|
||||
// resource controls
|
||||
string user = 6;
|
||||
}
|
||||
|
||||
message GetLedgerDataResponse
|
||||
{
|
||||
// Sequence of the ledger containing the returned ledger objects
|
||||
uint32 ledger_index = 1;
|
||||
message GetLedgerDataResponse {
|
||||
// Sequence of the ledger containing the returned ledger objects
|
||||
uint32 ledger_index = 1;
|
||||
|
||||
// Hash of the ledger containing the returned ledger objects
|
||||
bytes ledger_hash = 2;
|
||||
|
||||
// Ledger objects
|
||||
RawLedgerObjects ledger_objects = 3;
|
||||
// Hash of the ledger containing the returned ledger objects
|
||||
bytes ledger_hash = 2;
|
||||
|
||||
// Key to be passed into a subsequent call to continue iteration. If not
|
||||
// set, there are no more objects left in the ledger, or no more objects
|
||||
// with key less than end_marker (if end_marker was set in the request)
|
||||
bytes marker = 4;
|
||||
// Ledger objects
|
||||
RawLedgerObjects ledger_objects = 3;
|
||||
|
||||
// True if request was exempt from resource controls
|
||||
bool is_unlimited = 7;
|
||||
// Key to be passed into a subsequent call to continue iteration. If not
|
||||
// set, there are no more objects left in the ledger, or no more objects
|
||||
// with key less than end_marker (if end_marker was set in the request)
|
||||
bytes marker = 4;
|
||||
|
||||
// True if request was exempt from resource controls
|
||||
bool is_unlimited = 7;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,27 +6,23 @@ option java_multiple_files = true;
|
||||
|
||||
import "org/xrpl/rpc/v1/ledger.proto";
|
||||
|
||||
|
||||
// Get the state map difference between the two specified ledgers
|
||||
message GetLedgerDiffRequest
|
||||
{
|
||||
LedgerSpecifier base_ledger = 1;
|
||||
message GetLedgerDiffRequest {
|
||||
LedgerSpecifier base_ledger = 1;
|
||||
|
||||
LedgerSpecifier desired_ledger = 2;
|
||||
LedgerSpecifier desired_ledger = 2;
|
||||
|
||||
// If true, include the full ledger object. If false, only keys are included.
|
||||
bool include_blobs = 3;
|
||||
// If true, include the full ledger object. If false, only keys are included.
|
||||
bool include_blobs = 3;
|
||||
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 4;
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 4;
|
||||
}
|
||||
|
||||
message GetLedgerDiffResponse
|
||||
{
|
||||
// All ledger objects that were added, modified or deleted between
|
||||
// base_ledger and desired_ledger
|
||||
RawLedgerObjects ledger_objects = 1;
|
||||
message GetLedgerDiffResponse {
|
||||
// All ledger objects that were added, modified or deleted between
|
||||
// base_ledger and desired_ledger
|
||||
RawLedgerObjects ledger_objects = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,25 +7,23 @@ option java_multiple_files = true;
|
||||
import "org/xrpl/rpc/v1/ledger.proto";
|
||||
|
||||
// Get a single ledger object
|
||||
message GetLedgerEntryRequest
|
||||
{
|
||||
// Key of the desired object
|
||||
bytes key = 1;
|
||||
message GetLedgerEntryRequest {
|
||||
// Key of the desired object
|
||||
bytes key = 1;
|
||||
|
||||
// Ledger containing the object
|
||||
LedgerSpecifier ledger = 2;
|
||||
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 3;
|
||||
// Ledger containing the object
|
||||
LedgerSpecifier ledger = 2;
|
||||
|
||||
// If the request needs to be forwarded from a reporting node to a p2p node,
|
||||
// the reporting node will set this field. Clients should not set this
|
||||
// field.
|
||||
string client_ip = 3;
|
||||
}
|
||||
|
||||
message GetLedgerEntryResponse
|
||||
{
|
||||
RawLedgerObject ledger_object = 1;
|
||||
message GetLedgerEntryResponse {
|
||||
RawLedgerObject ledger_object = 1;
|
||||
|
||||
// Ledger containing the object. Will match the value specified in the
|
||||
// request.
|
||||
LedgerSpecifier ledger = 2;
|
||||
// Ledger containing the object. Will match the value specified in the
|
||||
// request.
|
||||
LedgerSpecifier ledger = 2;
|
||||
}
|
||||
|
||||
@@ -5,71 +5,61 @@ option java_package = "org.xrpl.rpc.v1";
|
||||
option java_multiple_files = true;
|
||||
|
||||
// Next field: 4
|
||||
message LedgerSpecifier
|
||||
{
|
||||
// Next field: 4
|
||||
enum Shortcut
|
||||
{
|
||||
SHORTCUT_UNSPECIFIED = 0;
|
||||
SHORTCUT_VALIDATED = 1;
|
||||
SHORTCUT_CLOSED = 2;
|
||||
SHORTCUT_CURRENT = 3;
|
||||
}
|
||||
message LedgerSpecifier {
|
||||
// Next field: 4
|
||||
enum Shortcut {
|
||||
SHORTCUT_UNSPECIFIED = 0;
|
||||
SHORTCUT_VALIDATED = 1;
|
||||
SHORTCUT_CLOSED = 2;
|
||||
SHORTCUT_CURRENT = 3;
|
||||
}
|
||||
|
||||
oneof ledger
|
||||
{
|
||||
Shortcut shortcut = 1;
|
||||
uint32 sequence = 2;
|
||||
// 32 bytes
|
||||
bytes hash = 3;
|
||||
}
|
||||
oneof ledger {
|
||||
Shortcut shortcut = 1;
|
||||
uint32 sequence = 2;
|
||||
// 32 bytes
|
||||
bytes hash = 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Next field: 3
|
||||
message RawLedgerObject
|
||||
{
|
||||
// Raw data of the ledger object. In GetLedgerResponse and
|
||||
// GetLedgerDiffResponse, data will be empty if the object was deleted.
|
||||
bytes data = 1;
|
||||
message RawLedgerObject {
|
||||
// Raw data of the ledger object. In GetLedgerResponse and
|
||||
// GetLedgerDiffResponse, data will be empty if the object was deleted.
|
||||
bytes data = 1;
|
||||
|
||||
// Key of the ledger object
|
||||
bytes key = 2;
|
||||
// Key of the ledger object
|
||||
bytes key = 2;
|
||||
|
||||
enum ModificationType
|
||||
{
|
||||
UNSPECIFIED = 0;
|
||||
CREATED = 1;
|
||||
MODIFIED = 2;
|
||||
DELETED = 3;
|
||||
}
|
||||
enum ModificationType {
|
||||
UNSPECIFIED = 0;
|
||||
CREATED = 1;
|
||||
MODIFIED = 2;
|
||||
DELETED = 3;
|
||||
}
|
||||
|
||||
// Whether the object was created, modified or deleted
|
||||
ModificationType mod_type = 3;
|
||||
// Whether the object was created, modified or deleted
|
||||
ModificationType mod_type = 3;
|
||||
|
||||
// Key of the object preceding this object in the desired ledger
|
||||
bytes predecessor = 4;
|
||||
// Key of the object preceding this object in the desired ledger
|
||||
bytes predecessor = 4;
|
||||
|
||||
// Key of the object succeeding this object in the desired ledger
|
||||
bytes successor = 5;
|
||||
// Key of the object succeeding this object in the desired ledger
|
||||
bytes successor = 5;
|
||||
}
|
||||
|
||||
message RawLedgerObjects
|
||||
{
|
||||
repeated RawLedgerObject objects = 1;
|
||||
message RawLedgerObjects {
|
||||
repeated RawLedgerObject objects = 1;
|
||||
}
|
||||
|
||||
// Successor information for book directories. The book base is (usually) not
|
||||
// an actual object, yet we need to be able to ask for the successor to the
|
||||
// book base.
|
||||
message BookSuccessor {
|
||||
// Base of the book in question
|
||||
bytes book_base = 1;
|
||||
|
||||
// Base of the book in question
|
||||
bytes book_base = 1;
|
||||
|
||||
// First book directory in the book. An empty value here means the entire
|
||||
// book is deleted
|
||||
bytes first_book = 2;
|
||||
|
||||
// First book directory in the book. An empty value here means the entire
|
||||
// book is deleted
|
||||
bytes first_book = 2;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,13 +9,11 @@ import "org/xrpl/rpc/v1/get_ledger_entry.proto";
|
||||
import "org/xrpl/rpc/v1/get_ledger_data.proto";
|
||||
import "org/xrpl/rpc/v1/get_ledger_diff.proto";
|
||||
|
||||
|
||||
// These methods are binary only methods for retrieiving arbitrary ledger state
|
||||
// via gRPC. These methods are used by clio, but can also be
|
||||
// used by any client that wants to extract ledger state in an efficient manner.
|
||||
// They do not directly mimic the JSON equivalent methods.
|
||||
service XRPLedgerAPIService {
|
||||
|
||||
// Get a specific ledger, optionally including transactions and any modified,
|
||||
// added or deleted ledger objects
|
||||
rpc GetLedger(GetLedgerRequest) returns (GetLedgerResponse);
|
||||
@@ -29,5 +27,4 @@ service XRPLedgerAPIService {
|
||||
// Get all ledger objects that are different between the two specified
|
||||
// ledgers. Note, this method has no JSON equivalent.
|
||||
rpc GetLedgerDiff(GetLedgerDiffRequest) returns (GetLedgerDiffResponse);
|
||||
|
||||
}
|
||||
|
||||
@@ -4,29 +4,28 @@ package protocol;
|
||||
// Unused numbers in the list below may have been used previously. Please don't
|
||||
// reassign them for reuse unless you are 100% certain that there won't be a
|
||||
// conflict. Even if you're sure, it's probably best to assign a new type.
|
||||
enum MessageType
|
||||
{
|
||||
mtMANIFESTS = 2;
|
||||
mtPING = 3;
|
||||
mtCLUSTER = 5;
|
||||
mtENDPOINTS = 15;
|
||||
mtTRANSACTION = 30;
|
||||
mtGET_LEDGER = 31;
|
||||
mtLEDGER_DATA = 32;
|
||||
mtPROPOSE_LEDGER = 33;
|
||||
mtSTATUS_CHANGE = 34;
|
||||
mtHAVE_SET = 35;
|
||||
mtVALIDATION = 41;
|
||||
mtGET_OBJECTS = 42;
|
||||
mtVALIDATORLIST = 54;
|
||||
mtSQUELCH = 55;
|
||||
mtVALIDATORLISTCOLLECTION = 56;
|
||||
mtPROOF_PATH_REQ = 57;
|
||||
mtPROOF_PATH_RESPONSE = 58;
|
||||
mtREPLAY_DELTA_REQ = 59;
|
||||
mtREPLAY_DELTA_RESPONSE = 60;
|
||||
mtHAVE_TRANSACTIONS = 63;
|
||||
mtTRANSACTIONS = 64;
|
||||
enum MessageType {
|
||||
mtMANIFESTS = 2;
|
||||
mtPING = 3;
|
||||
mtCLUSTER = 5;
|
||||
mtENDPOINTS = 15;
|
||||
mtTRANSACTION = 30;
|
||||
mtGET_LEDGER = 31;
|
||||
mtLEDGER_DATA = 32;
|
||||
mtPROPOSE_LEDGER = 33;
|
||||
mtSTATUS_CHANGE = 34;
|
||||
mtHAVE_SET = 35;
|
||||
mtVALIDATION = 41;
|
||||
mtGET_OBJECTS = 42;
|
||||
mtVALIDATORLIST = 54;
|
||||
mtSQUELCH = 55;
|
||||
mtVALIDATORLISTCOLLECTION = 56;
|
||||
mtPROOF_PATH_REQ = 57;
|
||||
mtPROOF_PATH_RESPONSE = 58;
|
||||
mtREPLAY_DELTA_REQ = 59;
|
||||
mtREPLAY_DELTA_RESPONSE = 60;
|
||||
mtHAVE_TRANSACTIONS = 63;
|
||||
mtTRANSACTIONS = 64;
|
||||
}
|
||||
|
||||
// token, iterations, target, challenge = issue demand for proof of work
|
||||
@@ -36,352 +35,309 @@ enum MessageType
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* Provides the current ephemeral key for a validator. */
|
||||
message TMManifest
|
||||
{
|
||||
// A Manifest object in the Ripple serialization format.
|
||||
required bytes stobject = 1;
|
||||
message TMManifest {
|
||||
// A Manifest object in the Ripple serialization format.
|
||||
required bytes stobject = 1;
|
||||
}
|
||||
|
||||
message TMManifests
|
||||
{
|
||||
repeated TMManifest list = 1;
|
||||
message TMManifests {
|
||||
repeated TMManifest list = 1;
|
||||
|
||||
// The manifests sent when a peer first connects to another peer are `history`.
|
||||
optional bool history = 2 [deprecated=true];
|
||||
// The manifests sent when a peer first connects to another peer are `history`.
|
||||
optional bool history = 2 [deprecated = true];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// The status of a node in our cluster
|
||||
message TMClusterNode
|
||||
{
|
||||
required string publicKey = 1;
|
||||
required uint32 reportTime = 2;
|
||||
required uint32 nodeLoad = 3;
|
||||
optional string nodeName = 4;
|
||||
optional string address = 5;
|
||||
message TMClusterNode {
|
||||
required string publicKey = 1;
|
||||
required uint32 reportTime = 2;
|
||||
required uint32 nodeLoad = 3;
|
||||
optional string nodeName = 4;
|
||||
optional string address = 5;
|
||||
}
|
||||
|
||||
// Sources that are placing load on the server
|
||||
message TMLoadSource
|
||||
{
|
||||
required string name = 1;
|
||||
required uint32 cost = 2;
|
||||
optional uint32 count = 3; // number of connections
|
||||
message TMLoadSource {
|
||||
required string name = 1;
|
||||
required uint32 cost = 2;
|
||||
optional uint32 count = 3; // number of connections
|
||||
}
|
||||
|
||||
// The status of all nodes in the cluster
|
||||
message TMCluster
|
||||
{
|
||||
repeated TMClusterNode clusterNodes = 1;
|
||||
repeated TMLoadSource loadSources = 2;
|
||||
message TMCluster {
|
||||
repeated TMClusterNode clusterNodes = 1;
|
||||
repeated TMLoadSource loadSources = 2;
|
||||
}
|
||||
|
||||
// Node public key
|
||||
message TMLink
|
||||
{
|
||||
required bytes nodePubKey = 1 [deprecated=true]; // node public key
|
||||
message TMLink {
|
||||
required bytes nodePubKey = 1 [deprecated = true]; // node public key
|
||||
}
|
||||
|
||||
// Peer public key
|
||||
message TMPublicKey
|
||||
{
|
||||
required bytes publicKey = 1;
|
||||
message TMPublicKey {
|
||||
required bytes publicKey = 1;
|
||||
}
|
||||
|
||||
// A transaction can have only one input and one output.
|
||||
// If you want to send an amount that is greater than any single address of yours
|
||||
// you must first combine coins from one address to another.
|
||||
|
||||
enum TransactionStatus
|
||||
{
|
||||
tsNEW = 1; // origin node did/could not validate
|
||||
tsCURRENT = 2; // scheduled to go in this ledger
|
||||
tsCOMMITED = 3; // in a closed ledger
|
||||
tsREJECT_CONFLICT = 4;
|
||||
tsREJECT_INVALID = 5;
|
||||
tsREJECT_FUNDS = 6;
|
||||
tsHELD_SEQ = 7;
|
||||
tsHELD_LEDGER = 8; // held for future ledger
|
||||
enum TransactionStatus {
|
||||
tsNEW = 1; // origin node did/could not validate
|
||||
tsCURRENT = 2; // scheduled to go in this ledger
|
||||
tsCOMMITED = 3; // in a closed ledger
|
||||
tsREJECT_CONFLICT = 4;
|
||||
tsREJECT_INVALID = 5;
|
||||
tsREJECT_FUNDS = 6;
|
||||
tsHELD_SEQ = 7;
|
||||
tsHELD_LEDGER = 8; // held for future ledger
|
||||
}
|
||||
|
||||
message TMTransaction
|
||||
{
|
||||
required bytes rawTransaction = 1;
|
||||
required TransactionStatus status = 2;
|
||||
optional uint64 receiveTimestamp = 3;
|
||||
optional bool deferred = 4; // not applied to open ledger
|
||||
message TMTransaction {
|
||||
required bytes rawTransaction = 1;
|
||||
required TransactionStatus status = 2;
|
||||
optional uint64 receiveTimestamp = 3;
|
||||
optional bool deferred = 4; // not applied to open ledger
|
||||
}
|
||||
|
||||
message TMTransactions
|
||||
{
|
||||
repeated TMTransaction transactions = 1;
|
||||
message TMTransactions {
|
||||
repeated TMTransaction transactions = 1;
|
||||
}
|
||||
|
||||
|
||||
enum NodeStatus
|
||||
{
|
||||
nsCONNECTING = 1; // acquiring connections
|
||||
nsCONNECTED = 2; // convinced we are connected to the real network
|
||||
nsMONITORING = 3; // we know what the previous ledger is
|
||||
nsVALIDATING = 4; // we have the full ledger contents
|
||||
nsSHUTTING = 5; // node is shutting down
|
||||
enum NodeStatus {
|
||||
nsCONNECTING = 1; // acquiring connections
|
||||
nsCONNECTED = 2; // convinced we are connected to the real network
|
||||
nsMONITORING = 3; // we know what the previous ledger is
|
||||
nsVALIDATING = 4; // we have the full ledger contents
|
||||
nsSHUTTING = 5; // node is shutting down
|
||||
}
|
||||
|
||||
enum NodeEvent
|
||||
{
|
||||
neCLOSING_LEDGER = 1; // closing a ledger because its close time has come
|
||||
neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it
|
||||
neSWITCHED_LEDGER = 3; // changing due to network consensus
|
||||
neLOST_SYNC = 4;
|
||||
enum NodeEvent {
|
||||
neCLOSING_LEDGER = 1; // closing a ledger because its close time has come
|
||||
neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it
|
||||
neSWITCHED_LEDGER = 3; // changing due to network consensus
|
||||
neLOST_SYNC = 4;
|
||||
}
|
||||
|
||||
message TMStatusChange
|
||||
{
|
||||
optional NodeStatus newStatus = 1;
|
||||
optional NodeEvent newEvent = 2;
|
||||
optional uint32 ledgerSeq = 3;
|
||||
optional bytes ledgerHash = 4;
|
||||
optional bytes ledgerHashPrevious = 5;
|
||||
optional uint64 networkTime = 6;
|
||||
optional uint32 firstSeq = 7;
|
||||
optional uint32 lastSeq = 8;
|
||||
message TMStatusChange {
|
||||
optional NodeStatus newStatus = 1;
|
||||
optional NodeEvent newEvent = 2;
|
||||
optional uint32 ledgerSeq = 3;
|
||||
optional bytes ledgerHash = 4;
|
||||
optional bytes ledgerHashPrevious = 5;
|
||||
optional uint64 networkTime = 6;
|
||||
optional uint32 firstSeq = 7;
|
||||
optional uint32 lastSeq = 8;
|
||||
}
|
||||
|
||||
|
||||
// Announce to the network our position on a closing ledger
|
||||
message TMProposeSet
|
||||
{
|
||||
required uint32 proposeSeq = 1;
|
||||
required bytes currentTxHash = 2; // the hash of the ledger we are proposing
|
||||
required bytes nodePubKey = 3;
|
||||
required uint32 closeTime = 4;
|
||||
required bytes signature = 5; // signature of above fields
|
||||
required bytes previousledger = 6;
|
||||
repeated bytes addedTransactions = 10; // not required if number is large
|
||||
repeated bytes removedTransactions = 11; // not required if number is large
|
||||
message TMProposeSet {
|
||||
required uint32 proposeSeq = 1;
|
||||
required bytes currentTxHash = 2; // the hash of the ledger we are proposing
|
||||
required bytes nodePubKey = 3;
|
||||
required uint32 closeTime = 4;
|
||||
required bytes signature = 5; // signature of above fields
|
||||
required bytes previousledger = 6;
|
||||
repeated bytes addedTransactions = 10; // not required if number is large
|
||||
repeated bytes removedTransactions = 11; // not required if number is large
|
||||
|
||||
// node vouches signature is correct
|
||||
optional bool checkedSignature = 7 [deprecated=true];
|
||||
// node vouches signature is correct
|
||||
optional bool checkedSignature = 7 [deprecated = true];
|
||||
|
||||
// Number of hops traveled
|
||||
optional uint32 hops = 12 [deprecated=true];
|
||||
// Number of hops traveled
|
||||
optional uint32 hops = 12 [deprecated = true];
|
||||
}
|
||||
|
||||
enum TxSetStatus
|
||||
{
|
||||
tsHAVE = 1; // We have this set locally
|
||||
tsCAN_GET = 2; // We have a peer with this set
|
||||
tsNEED = 3; // We need this set and can't get it
|
||||
enum TxSetStatus {
|
||||
tsHAVE = 1; // We have this set locally
|
||||
tsCAN_GET = 2; // We have a peer with this set
|
||||
tsNEED = 3; // We need this set and can't get it
|
||||
}
|
||||
|
||||
message TMHaveTransactionSet
|
||||
{
|
||||
required TxSetStatus status = 1;
|
||||
required bytes hash = 2;
|
||||
message TMHaveTransactionSet {
|
||||
required TxSetStatus status = 1;
|
||||
required bytes hash = 2;
|
||||
}
|
||||
|
||||
// Validator list (UNL)
|
||||
message TMValidatorList
|
||||
{
|
||||
required bytes manifest = 1;
|
||||
required bytes blob = 2;
|
||||
required bytes signature = 3;
|
||||
required uint32 version = 4;
|
||||
message TMValidatorList {
|
||||
required bytes manifest = 1;
|
||||
required bytes blob = 2;
|
||||
required bytes signature = 3;
|
||||
required uint32 version = 4;
|
||||
}
|
||||
|
||||
// Validator List v2
|
||||
message ValidatorBlobInfo
|
||||
{
|
||||
optional bytes manifest = 1;
|
||||
required bytes blob = 2;
|
||||
required bytes signature = 3;
|
||||
message ValidatorBlobInfo {
|
||||
optional bytes manifest = 1;
|
||||
required bytes blob = 2;
|
||||
required bytes signature = 3;
|
||||
}
|
||||
|
||||
// Collection of Validator List v2 (UNL)
|
||||
message TMValidatorListCollection
|
||||
{
|
||||
required uint32 version = 1;
|
||||
required bytes manifest = 2;
|
||||
repeated ValidatorBlobInfo blobs = 3;
|
||||
message TMValidatorListCollection {
|
||||
required uint32 version = 1;
|
||||
required bytes manifest = 2;
|
||||
repeated ValidatorBlobInfo blobs = 3;
|
||||
}
|
||||
|
||||
// Used to sign a final closed ledger after reprocessing
|
||||
message TMValidation
|
||||
{
|
||||
// The serialized validation
|
||||
required bytes validation = 1;
|
||||
message TMValidation {
|
||||
// The serialized validation
|
||||
required bytes validation = 1;
|
||||
|
||||
// node vouches signature is correct
|
||||
optional bool checkedSignature = 2 [deprecated = true];
|
||||
// node vouches signature is correct
|
||||
optional bool checkedSignature = 2 [deprecated = true];
|
||||
|
||||
// Number of hops traveled
|
||||
optional uint32 hops = 3 [deprecated = true];
|
||||
// Number of hops traveled
|
||||
optional uint32 hops = 3 [deprecated = true];
|
||||
}
|
||||
|
||||
// An array of Endpoint messages
|
||||
message TMEndpoints
|
||||
{
|
||||
// Previously used - don't reuse.
|
||||
reserved 2;
|
||||
message TMEndpoints {
|
||||
// Previously used - don't reuse.
|
||||
reserved 2;
|
||||
|
||||
// This field is used to allow the TMEndpoints message format to be
|
||||
// modified as necessary in the future.
|
||||
required uint32 version = 1;
|
||||
// This field is used to allow the TMEndpoints message format to be
|
||||
// modified as necessary in the future.
|
||||
required uint32 version = 1;
|
||||
|
||||
// An update to the Endpoint type that uses a string
|
||||
// to represent endpoints, thus allowing ipv6 or ipv4 addresses
|
||||
message TMEndpointv2
|
||||
{
|
||||
required string endpoint = 1;
|
||||
required uint32 hops = 2;
|
||||
}
|
||||
repeated TMEndpointv2 endpoints_v2 = 3;
|
||||
// An update to the Endpoint type that uses a string
|
||||
// to represent endpoints, thus allowing ipv6 or ipv4 addresses
|
||||
message TMEndpointv2 {
|
||||
required string endpoint = 1;
|
||||
required uint32 hops = 2;
|
||||
}
|
||||
repeated TMEndpointv2 endpoints_v2 = 3;
|
||||
};
|
||||
|
||||
message TMIndexedObject
|
||||
{
|
||||
optional bytes hash = 1;
|
||||
optional bytes nodeID = 2;
|
||||
optional bytes index = 3;
|
||||
optional bytes data = 4;
|
||||
optional uint32 ledgerSeq = 5;
|
||||
message TMIndexedObject {
|
||||
optional bytes hash = 1;
|
||||
optional bytes nodeID = 2;
|
||||
optional bytes index = 3;
|
||||
optional bytes data = 4;
|
||||
optional uint32 ledgerSeq = 5;
|
||||
}
|
||||
|
||||
message TMGetObjectByHash
|
||||
{
|
||||
enum ObjectType {
|
||||
otUNKNOWN = 0;
|
||||
otLEDGER = 1;
|
||||
otTRANSACTION = 2;
|
||||
otTRANSACTION_NODE = 3;
|
||||
otSTATE_NODE = 4;
|
||||
otCAS_OBJECT = 5;
|
||||
otFETCH_PACK = 6;
|
||||
otTRANSACTIONS = 7;
|
||||
}
|
||||
message TMGetObjectByHash {
|
||||
enum ObjectType {
|
||||
otUNKNOWN = 0;
|
||||
otLEDGER = 1;
|
||||
otTRANSACTION = 2;
|
||||
otTRANSACTION_NODE = 3;
|
||||
otSTATE_NODE = 4;
|
||||
otCAS_OBJECT = 5;
|
||||
otFETCH_PACK = 6;
|
||||
otTRANSACTIONS = 7;
|
||||
}
|
||||
|
||||
required ObjectType type = 1;
|
||||
required bool query = 2; // is this a query or a reply?
|
||||
optional uint32 seq = 3; // used to match replies to queries
|
||||
optional bytes ledgerHash = 4; // the hash of the ledger these queries are for
|
||||
optional bool fat = 5; // return related nodes
|
||||
repeated TMIndexedObject objects = 6; // the specific objects requested
|
||||
required ObjectType type = 1;
|
||||
required bool query = 2; // is this a query or a reply?
|
||||
optional uint32 seq = 3; // used to match replies to queries
|
||||
optional bytes ledgerHash = 4; // the hash of the ledger these queries are for
|
||||
optional bool fat = 5; // return related nodes
|
||||
repeated TMIndexedObject objects = 6; // the specific objects requested
|
||||
}
|
||||
|
||||
|
||||
message TMLedgerNode
|
||||
{
|
||||
required bytes nodedata = 1;
|
||||
optional bytes nodeid = 2; // missing for ledger base data
|
||||
message TMLedgerNode {
|
||||
required bytes nodedata = 1;
|
||||
optional bytes nodeid = 2; // missing for ledger base data
|
||||
}
|
||||
|
||||
enum TMLedgerInfoType
|
||||
{
|
||||
liBASE = 0; // basic ledger info
|
||||
liTX_NODE = 1; // transaction node
|
||||
liAS_NODE = 2; // account state node
|
||||
liTS_CANDIDATE = 3; // candidate transaction set
|
||||
enum TMLedgerInfoType {
|
||||
liBASE = 0; // basic ledger info
|
||||
liTX_NODE = 1; // transaction node
|
||||
liAS_NODE = 2; // account state node
|
||||
liTS_CANDIDATE = 3; // candidate transaction set
|
||||
}
|
||||
|
||||
enum TMLedgerType
|
||||
{
|
||||
ltACCEPTED = 0;
|
||||
ltCURRENT = 1; // no longer supported
|
||||
ltCLOSED = 2;
|
||||
enum TMLedgerType {
|
||||
ltACCEPTED = 0;
|
||||
ltCURRENT = 1; // no longer supported
|
||||
ltCLOSED = 2;
|
||||
}
|
||||
|
||||
enum TMQueryType
|
||||
{
|
||||
qtINDIRECT = 0;
|
||||
enum TMQueryType {
|
||||
qtINDIRECT = 0;
|
||||
}
|
||||
|
||||
message TMGetLedger
|
||||
{
|
||||
required TMLedgerInfoType itype = 1;
|
||||
optional TMLedgerType ltype = 2;
|
||||
optional bytes ledgerHash = 3; // Can also be the transaction set hash if liTS_CANDIDATE
|
||||
optional uint32 ledgerSeq = 4;
|
||||
repeated bytes nodeIDs = 5;
|
||||
optional uint64 requestCookie = 6;
|
||||
optional TMQueryType queryType = 7;
|
||||
optional uint32 queryDepth = 8; // How deep to go, number of extra levels
|
||||
message TMGetLedger {
|
||||
required TMLedgerInfoType itype = 1;
|
||||
optional TMLedgerType ltype = 2;
|
||||
optional bytes ledgerHash = 3; // Can also be the transaction set hash if liTS_CANDIDATE
|
||||
optional uint32 ledgerSeq = 4;
|
||||
repeated bytes nodeIDs = 5;
|
||||
optional uint64 requestCookie = 6;
|
||||
optional TMQueryType queryType = 7;
|
||||
optional uint32 queryDepth = 8; // How deep to go, number of extra levels
|
||||
}
|
||||
|
||||
enum TMReplyError
|
||||
{
|
||||
reNO_LEDGER = 1; // We don't have the ledger you are asking about
|
||||
reNO_NODE = 2; // We don't have any of the nodes you are asking for
|
||||
reBAD_REQUEST = 3; // The request is wrong, e.g. wrong format
|
||||
enum TMReplyError {
|
||||
reNO_LEDGER = 1; // We don't have the ledger you are asking about
|
||||
reNO_NODE = 2; // We don't have any of the nodes you are asking for
|
||||
reBAD_REQUEST = 3; // The request is wrong, e.g. wrong format
|
||||
}
|
||||
|
||||
message TMLedgerData
|
||||
{
|
||||
required bytes ledgerHash = 1;
|
||||
required uint32 ledgerSeq = 2;
|
||||
required TMLedgerInfoType type = 3;
|
||||
repeated TMLedgerNode nodes = 4;
|
||||
optional uint32 requestCookie = 5;
|
||||
optional TMReplyError error = 6;
|
||||
message TMLedgerData {
|
||||
required bytes ledgerHash = 1;
|
||||
required uint32 ledgerSeq = 2;
|
||||
required TMLedgerInfoType type = 3;
|
||||
repeated TMLedgerNode nodes = 4;
|
||||
optional uint32 requestCookie = 5;
|
||||
optional TMReplyError error = 6;
|
||||
}
|
||||
|
||||
message TMPing
|
||||
{
|
||||
enum pingType {
|
||||
ptPING = 0; // we want a reply
|
||||
ptPONG = 1; // this is a reply
|
||||
}
|
||||
required pingType type = 1;
|
||||
optional uint32 seq = 2; // detect stale replies, ensure other side is reading
|
||||
optional uint64 pingTime = 3; // know when we think we sent the ping
|
||||
optional uint64 netTime = 4;
|
||||
message TMPing {
|
||||
enum pingType {
|
||||
ptPING = 0; // we want a reply
|
||||
ptPONG = 1; // this is a reply
|
||||
}
|
||||
required pingType type = 1;
|
||||
optional uint32 seq = 2; // detect stale replies, ensure other side is reading
|
||||
optional uint64 pingTime = 3; // know when we think we sent the ping
|
||||
optional uint64 netTime = 4;
|
||||
}
|
||||
|
||||
message TMSquelch
|
||||
{
|
||||
required bool squelch = 1; // squelch if true, otherwise unsquelch
|
||||
required bytes validatorPubKey = 2; // validator's public key
|
||||
optional uint32 squelchDuration = 3; // squelch duration in seconds
|
||||
message TMSquelch {
|
||||
required bool squelch = 1; // squelch if true, otherwise unsquelch
|
||||
required bytes validatorPubKey = 2; // validator's public key
|
||||
optional uint32 squelchDuration = 3; // squelch duration in seconds
|
||||
}
|
||||
|
||||
enum TMLedgerMapType
|
||||
{
|
||||
lmTRANASCTION = 1; // transaction map
|
||||
lmACCOUNT_STATE = 2; // account state map
|
||||
enum TMLedgerMapType {
|
||||
lmTRANASCTION = 1; // transaction map
|
||||
lmACCOUNT_STATE = 2; // account state map
|
||||
}
|
||||
|
||||
message TMProofPathRequest
|
||||
{
|
||||
required bytes key = 1;
|
||||
required bytes ledgerHash = 2;
|
||||
required TMLedgerMapType type = 3;
|
||||
message TMProofPathRequest {
|
||||
required bytes key = 1;
|
||||
required bytes ledgerHash = 2;
|
||||
required TMLedgerMapType type = 3;
|
||||
}
|
||||
|
||||
message TMProofPathResponse
|
||||
{
|
||||
required bytes key = 1;
|
||||
required bytes ledgerHash = 2;
|
||||
required TMLedgerMapType type = 3;
|
||||
optional bytes ledgerHeader = 4;
|
||||
repeated bytes path = 5;
|
||||
optional TMReplyError error = 6;
|
||||
message TMProofPathResponse {
|
||||
required bytes key = 1;
|
||||
required bytes ledgerHash = 2;
|
||||
required TMLedgerMapType type = 3;
|
||||
optional bytes ledgerHeader = 4;
|
||||
repeated bytes path = 5;
|
||||
optional TMReplyError error = 6;
|
||||
}
|
||||
|
||||
message TMReplayDeltaRequest
|
||||
{
|
||||
required bytes ledgerHash = 1;
|
||||
message TMReplayDeltaRequest {
|
||||
required bytes ledgerHash = 1;
|
||||
}
|
||||
|
||||
message TMReplayDeltaResponse
|
||||
{
|
||||
required bytes ledgerHash = 1;
|
||||
optional bytes ledgerHeader = 2;
|
||||
repeated bytes transaction = 3;
|
||||
optional TMReplyError error = 4;
|
||||
message TMReplayDeltaResponse {
|
||||
required bytes ledgerHash = 1;
|
||||
optional bytes ledgerHeader = 2;
|
||||
repeated bytes transaction = 3;
|
||||
optional TMReplyError error = 4;
|
||||
}
|
||||
|
||||
message TMHaveTransactions
|
||||
{
|
||||
repeated bytes hashes = 1;
|
||||
message TMHaveTransactions {
|
||||
repeated bytes hashes = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,4 +34,4 @@ serializeBatch(
|
||||
msg.addBitString(txid);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
} // namespace ripple
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/partitioned_unordered_map.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ constexpr std::uint32_t const tfTransferable = 0x00000008;
|
||||
constexpr std::uint32_t const tfMutable = 0x00000010;
|
||||
|
||||
// MPTokenIssuanceCreate flags:
|
||||
// NOTE - there is intentionally no flag here for lsfMPTLocked, which this transaction cannot mutate.
|
||||
// NOTE - there is intentionally no flag here for lsfMPTLocked, which this transaction cannot mutate.
|
||||
constexpr std::uint32_t const tfMPTCanLock = lsfMPTCanLock;
|
||||
constexpr std::uint32_t const tfMPTRequireAuth = lsfMPTRequireAuth;
|
||||
constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow;
|
||||
@@ -243,7 +243,7 @@ constexpr std::uint32_t tfUntilFailure = 0x00040000;
|
||||
constexpr std::uint32_t tfIndependent = 0x00080000;
|
||||
/**
|
||||
* @note If nested Batch transactions are supported in the future, the tfInnerBatchTxn flag
|
||||
* will need to be removed from this mask to allow Batch transaction to be inside
|
||||
* will need to be removed from this mask to allow Batch transaction to be inside
|
||||
* the sfRawTransactions array.
|
||||
*/
|
||||
constexpr std::uint32_t const tfBatchMask =
|
||||
|
||||
@@ -505,4 +505,3 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
|
||||
#undef EXPAND
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <xrpl/server/Port.h>
|
||||
#include <xrpl/server/detail/ServerImpl.h>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -34,10 +34,10 @@ template <class Handler>
|
||||
std::unique_ptr<Server>
|
||||
make_Server(
|
||||
Handler& handler,
|
||||
boost::asio::io_service& io_service,
|
||||
boost::asio::io_context& io_context,
|
||||
beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<ServerImpl<Handler>>(handler, io_service, journal);
|
||||
return std::make_unique<ServerImpl<Handler>>(handler, io_context, journal);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -88,9 +88,7 @@ public:
|
||||
++iter)
|
||||
{
|
||||
typename BufferSequence::value_type const& buffer(*iter);
|
||||
write(
|
||||
boost::asio::buffer_cast<void const*>(buffer),
|
||||
boost::asio::buffer_size(buffer));
|
||||
write(buffer.data(), boost::asio::buffer_size(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +102,7 @@ public:
|
||||
|
||||
/** Detach the session.
|
||||
This holds the session open so that the response can be sent
|
||||
asynchronously. Calls to io_service::run made by the server
|
||||
asynchronously. Calls to io_context::run made by the server
|
||||
will not return until all detached sessions are closed.
|
||||
*/
|
||||
virtual std::shared_ptr<Session>
|
||||
|
||||
@@ -24,11 +24,13 @@
|
||||
#include <xrpl/beast/net/IPAddressConversion.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/server/Session.h>
|
||||
#include <xrpl/server/detail/Spawn.h>
|
||||
#include <xrpl/server/detail/io_list.h>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/beast/core/stream_traits.hpp>
|
||||
#include <boost/beast/http/dynamic_body.hpp>
|
||||
@@ -215,8 +217,8 @@ BaseHTTPPeer<Handler, Impl>::BaseHTTPPeer(
|
||||
ConstBufferSequence const& buffers)
|
||||
: port_(port)
|
||||
, handler_(handler)
|
||||
, work_(executor)
|
||||
, strand_(executor)
|
||||
, work_(boost::asio::make_work_guard(executor))
|
||||
, strand_(boost::asio::make_strand(executor))
|
||||
, remote_address_(remote_address)
|
||||
, journal_(journal)
|
||||
{
|
||||
@@ -356,7 +358,7 @@ BaseHTTPPeer<Handler, Impl>::on_write(
|
||||
return;
|
||||
if (graceful_)
|
||||
return do_close();
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&BaseHTTPPeer<Handler, Impl>::do_read,
|
||||
@@ -375,7 +377,7 @@ BaseHTTPPeer<Handler, Impl>::do_writer(
|
||||
{
|
||||
auto const p = impl().shared_from_this();
|
||||
resume = std::function<void(void)>([this, p, writer, keep_alive]() {
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&BaseHTTPPeer<Handler, Impl>::do_writer,
|
||||
@@ -406,7 +408,7 @@ BaseHTTPPeer<Handler, Impl>::do_writer(
|
||||
if (!keep_alive)
|
||||
return do_close();
|
||||
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&BaseHTTPPeer<Handler, Impl>::do_read,
|
||||
@@ -448,14 +450,14 @@ BaseHTTPPeer<Handler, Impl>::write(
|
||||
std::shared_ptr<Writer> const& writer,
|
||||
bool keep_alive)
|
||||
{
|
||||
boost::asio::spawn(bind_executor(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&BaseHTTPPeer<Handler, Impl>::do_writer,
|
||||
impl().shared_from_this(),
|
||||
writer,
|
||||
keep_alive,
|
||||
std::placeholders::_1)));
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
@@ -490,12 +492,12 @@ BaseHTTPPeer<Handler, Impl>::complete()
|
||||
}
|
||||
|
||||
// keep-alive
|
||||
boost::asio::spawn(bind_executor(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&BaseHTTPPeer<Handler, Impl>::do_read,
|
||||
impl().shared_from_this(),
|
||||
std::placeholders::_1)));
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
|
||||
@@ -91,8 +91,8 @@ BasePeer<Handler, Impl>::BasePeer(
|
||||
return "##" + std::to_string(++id) + " ";
|
||||
}())
|
||||
, j_(sink_)
|
||||
, work_(executor)
|
||||
, strand_(executor)
|
||||
, work_(boost::asio::make_work_guard(executor))
|
||||
, strand_(boost::asio::make_strand(executor))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <xrpl/server/detail/BasePeer.h>
|
||||
#include <xrpl/server/detail/LowestLayer.h>
|
||||
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/beast/core/multi_buffer.hpp>
|
||||
#include <boost/beast/http/message.hpp>
|
||||
#include <boost/beast/websocket.hpp>
|
||||
@@ -420,11 +421,17 @@ BaseWSPeer<Handler, Impl>::start_timer()
|
||||
// Max seconds without completing a message
|
||||
static constexpr std::chrono::seconds timeout{30};
|
||||
static constexpr std::chrono::seconds timeoutLocal{3};
|
||||
error_code ec;
|
||||
timer_.expires_from_now(
|
||||
remote_endpoint().address().is_loopback() ? timeoutLocal : timeout, ec);
|
||||
if (ec)
|
||||
return fail(ec, "start_timer");
|
||||
|
||||
try
|
||||
{
|
||||
timer_.expires_after(
|
||||
remote_endpoint().address().is_loopback() ? timeoutLocal : timeout);
|
||||
}
|
||||
catch (boost::system::system_error const& e)
|
||||
{
|
||||
return fail(e.code(), "start_timer");
|
||||
}
|
||||
|
||||
timer_.async_wait(bind_executor(
|
||||
strand_,
|
||||
std::bind(
|
||||
@@ -438,8 +445,14 @@ template <class Handler, class Impl>
|
||||
void
|
||||
BaseWSPeer<Handler, Impl>::cancel_timer()
|
||||
{
|
||||
error_code ec;
|
||||
timer_.cancel(ec);
|
||||
try
|
||||
{
|
||||
timer_.cancel();
|
||||
}
|
||||
catch (boost::system::system_error const&)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
template <class Handler, class Impl>
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
stream_type stream_;
|
||||
socket_type& socket_;
|
||||
endpoint_type remote_address_;
|
||||
boost::asio::io_context::strand strand_;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
|
||||
beast::Journal const j_;
|
||||
|
||||
public:
|
||||
@@ -95,7 +95,7 @@ private:
|
||||
Handler& handler_;
|
||||
boost::asio::io_context& ioc_;
|
||||
acceptor_type acceptor_;
|
||||
boost::asio::io_context::strand strand_;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
|
||||
bool ssl_;
|
||||
bool plain_;
|
||||
|
||||
@@ -155,7 +155,7 @@ Door<Handler>::Detector::Detector(
|
||||
, stream_(std::move(stream))
|
||||
, socket_(stream_.socket())
|
||||
, remote_address_(remote_address)
|
||||
, strand_(ioc_)
|
||||
, strand_(boost::asio::make_strand(ioc_))
|
||||
, j_(j)
|
||||
{
|
||||
}
|
||||
@@ -164,7 +164,7 @@ template <class Handler>
|
||||
void
|
||||
Door<Handler>::Detector::run()
|
||||
{
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&Detector::do_detect,
|
||||
@@ -269,7 +269,7 @@ Door<Handler>::reOpen()
|
||||
Throw<std::exception>();
|
||||
}
|
||||
|
||||
acceptor_.listen(boost::asio::socket_base::max_connections, ec);
|
||||
acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
if (ec)
|
||||
{
|
||||
JLOG(j_.error()) << "Listen on port '" << port_.name
|
||||
@@ -291,7 +291,7 @@ Door<Handler>::Door(
|
||||
, handler_(handler)
|
||||
, ioc_(io_context)
|
||||
, acceptor_(io_context)
|
||||
, strand_(io_context)
|
||||
, strand_(boost::asio::make_strand(io_context))
|
||||
, ssl_(
|
||||
port_.protocol.count("https") > 0 ||
|
||||
port_.protocol.count("wss") > 0 || port_.protocol.count("wss2") > 0 ||
|
||||
@@ -307,7 +307,7 @@ template <class Handler>
|
||||
void
|
||||
Door<Handler>::run()
|
||||
{
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
strand_,
|
||||
std::bind(
|
||||
&Door<Handler>::do_accept,
|
||||
@@ -320,7 +320,8 @@ void
|
||||
Door<Handler>::close()
|
||||
{
|
||||
if (!strand_.running_in_this_thread())
|
||||
return strand_.post(
|
||||
return boost::asio::post(
|
||||
strand_,
|
||||
std::bind(&Door<Handler>::close, this->shared_from_this()));
|
||||
error_code ec;
|
||||
acceptor_.close(ec);
|
||||
|
||||
@@ -105,7 +105,7 @@ PlainHTTPPeer<Handler>::run()
|
||||
{
|
||||
if (!this->handler_.onAccept(this->session(), this->remote_address_))
|
||||
{
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
this->strand_,
|
||||
std::bind(&PlainHTTPPeer::do_close, this->shared_from_this()));
|
||||
return;
|
||||
@@ -114,7 +114,7 @@ PlainHTTPPeer<Handler>::run()
|
||||
if (!socket_.is_open())
|
||||
return;
|
||||
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
this->strand_,
|
||||
std::bind(
|
||||
&PlainHTTPPeer::do_read,
|
||||
|
||||
@@ -115,14 +115,14 @@ SSLHTTPPeer<Handler>::run()
|
||||
{
|
||||
if (!this->handler_.onAccept(this->session(), this->remote_address_))
|
||||
{
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
this->strand_,
|
||||
std::bind(&SSLHTTPPeer::do_close, this->shared_from_this()));
|
||||
return;
|
||||
}
|
||||
if (!socket_.is_open())
|
||||
return;
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
this->strand_,
|
||||
std::bind(
|
||||
&SSLHTTPPeer::do_handshake,
|
||||
@@ -164,7 +164,7 @@ SSLHTTPPeer<Handler>::do_handshake(yield_context do_yield)
|
||||
this->port().protocol.count("https") > 0;
|
||||
if (http)
|
||||
{
|
||||
boost::asio::spawn(
|
||||
util::spawn(
|
||||
this->strand_,
|
||||
std::bind(
|
||||
&SSLHTTPPeer::do_read,
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <xrpl/server/detail/io_list.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
@@ -85,9 +87,11 @@ private:
|
||||
|
||||
Handler& handler_;
|
||||
beast::Journal const j_;
|
||||
boost::asio::io_service& io_service_;
|
||||
boost::asio::io_service::strand strand_;
|
||||
std::optional<boost::asio::io_service::work> work_;
|
||||
boost::asio::io_context& io_context_;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
|
||||
std::optional<boost::asio::executor_work_guard<
|
||||
boost::asio::io_context::executor_type>>
|
||||
work_;
|
||||
|
||||
std::mutex m_;
|
||||
std::vector<Port> ports_;
|
||||
@@ -100,7 +104,7 @@ private:
|
||||
public:
|
||||
ServerImpl(
|
||||
Handler& handler,
|
||||
boost::asio::io_service& io_service,
|
||||
boost::asio::io_context& io_context,
|
||||
beast::Journal journal);
|
||||
|
||||
~ServerImpl();
|
||||
@@ -123,10 +127,10 @@ public:
|
||||
return ios_;
|
||||
}
|
||||
|
||||
boost::asio::io_service&
|
||||
get_io_service()
|
||||
boost::asio::io_context&
|
||||
get_io_context()
|
||||
{
|
||||
return io_service_;
|
||||
return io_context_;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -140,13 +144,13 @@ private:
|
||||
template <class Handler>
|
||||
ServerImpl<Handler>::ServerImpl(
|
||||
Handler& handler,
|
||||
boost::asio::io_service& io_service,
|
||||
boost::asio::io_context& io_context,
|
||||
beast::Journal journal)
|
||||
: handler_(handler)
|
||||
, j_(journal)
|
||||
, io_service_(io_service)
|
||||
, strand_(io_service_)
|
||||
, work_(io_service_)
|
||||
, io_context_(io_context)
|
||||
, strand_(boost::asio::make_strand(io_context_))
|
||||
, work_(std::in_place, boost::asio::make_work_guard(io_context_))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -173,7 +177,7 @@ ServerImpl<Handler>::ports(std::vector<Port> const& ports)
|
||||
ports_.push_back(port);
|
||||
auto& internalPort = ports_.back();
|
||||
if (auto sp = ios_.emplace<Door<Handler>>(
|
||||
handler_, io_service_, internalPort, j_))
|
||||
handler_, io_context_, internalPort, j_))
|
||||
{
|
||||
list_.push_back(sp);
|
||||
|
||||
|
||||
108
include/xrpl/server/detail/Spawn.h
Normal file
108
include/xrpl/server/detail/Spawn.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright(c) 2025 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERVER_SPAWN_H_INCLUDED
|
||||
#define RIPPLE_SERVER_SPAWN_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple::util {
|
||||
namespace impl {
|
||||
|
||||
template <typename T>
|
||||
concept IsStrand = std::same_as<
|
||||
std::decay_t<T>,
|
||||
boost::asio::strand<typename std::decay_t<T>::inner_executor_type>>;
|
||||
|
||||
/**
|
||||
* @brief A completion handler that restores `boost::asio::spawn`'s behaviour
|
||||
* from Boost 1.83
|
||||
*
|
||||
* This is intended to be passed as the third argument to `boost::asio::spawn`
|
||||
* so that exceptions are not ignored but propagated to `io_context.run()` call
|
||||
* site.
|
||||
*
|
||||
* @param ePtr The exception that was caught on the coroutine
|
||||
*/
|
||||
inline constexpr auto kPROPAGATE_EXCEPTIONS = [](std::exception_ptr ePtr) {
|
||||
if (ePtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ePtr);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(debugLog().warn()) << "Spawn exception: " << e.what();
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(debugLog().warn()) << "Spawn exception: Unknown";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
/**
|
||||
* @brief Spawns a coroutine using `boost::asio::spawn`
|
||||
*
|
||||
* @note This uses kPROPAGATE_EXCEPTIONS to force asio to propagate exceptions
|
||||
* through `io_context`
|
||||
* @note Since implicit strand was removed from boost::asio::spawn this helper
|
||||
* function adds the strand back
|
||||
*
|
||||
* @tparam Ctx The type of the context/strand
|
||||
* @tparam F The type of the function to execute
|
||||
* @param ctx The execution context
|
||||
* @param func The function to execute. Must return `void`
|
||||
*/
|
||||
template <typename Ctx, typename F>
|
||||
requires std::is_invocable_r_v<void, F, boost::asio::yield_context>
|
||||
void
|
||||
spawn(Ctx&& ctx, F&& func)
|
||||
{
|
||||
if constexpr (impl::IsStrand<Ctx>)
|
||||
{
|
||||
boost::asio::spawn(
|
||||
std::forward<Ctx>(ctx),
|
||||
std::forward<F>(func),
|
||||
impl::kPROPAGATE_EXCEPTIONS);
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::spawn(
|
||||
boost::asio::make_strand(
|
||||
boost::asio::get_associated_executor(std::forward<Ctx>(ctx))),
|
||||
std::forward<F>(func),
|
||||
impl::kPROPAGATE_EXCEPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ripple::util
|
||||
|
||||
#endif
|
||||
@@ -166,7 +166,7 @@ public:
|
||||
May be called concurrently.
|
||||
|
||||
Preconditions:
|
||||
No call to io_service::run on any io_service
|
||||
No call to io_context::run on any io_context
|
||||
used by work objects associated with this io_list
|
||||
exists in the caller's call stack.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user