mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-30 10:30:22 +00:00
Merge branch 'pratik/otel-phase8-log-correlation' into pratik/otel-phase9-metric-gap-fill
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
This commit is contained in:
@@ -28,7 +28,7 @@ void
|
||||
Section::append(std::vector<std::string> const& lines)
|
||||
{
|
||||
// <key> '=' <value>
|
||||
static boost::regex const re1(
|
||||
static boost::regex const kRe1(
|
||||
"^" // start of line
|
||||
"(?:\\s*)" // whitespace (optional)
|
||||
"([a-zA-Z][_a-zA-Z0-9]*)" // <key>
|
||||
@@ -43,8 +43,8 @@ Section::append(std::vector<std::string> const& lines)
|
||||
lines_.reserve(lines_.size() + lines.size());
|
||||
for (auto line : lines)
|
||||
{
|
||||
auto remove_comment = [](std::string& val) -> bool {
|
||||
bool removed_trailing = false;
|
||||
auto removeComment = [](std::string& val) -> bool {
|
||||
bool removedTrailing = false;
|
||||
auto comment = val.find('#');
|
||||
while (comment != std::string::npos)
|
||||
{
|
||||
@@ -65,24 +65,24 @@ Section::append(std::vector<std::string> const& lines)
|
||||
{
|
||||
// this must be a real comment. Extract the value
|
||||
// as a substring and stop looking.
|
||||
val = trim_whitespace(val.substr(0, comment));
|
||||
removed_trailing = true;
|
||||
val = trimWhitespace(val.substr(0, comment));
|
||||
removedTrailing = true;
|
||||
break;
|
||||
}
|
||||
|
||||
comment = val.find('#', comment);
|
||||
}
|
||||
return removed_trailing;
|
||||
return removedTrailing;
|
||||
};
|
||||
|
||||
if (remove_comment(line) && !line.empty())
|
||||
had_trailing_comments_ = true;
|
||||
if (removeComment(line) && !line.empty())
|
||||
hadTrailingComments_ = true;
|
||||
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
boost::smatch match;
|
||||
if (boost::regex_match(line, match, re1))
|
||||
if (boost::regex_match(line, match, kRe1))
|
||||
{
|
||||
set(match[1], match[2]);
|
||||
}
|
||||
@@ -126,10 +126,10 @@ BasicConfig::section(std::string const& name)
|
||||
Section const&
|
||||
BasicConfig::section(std::string const& name) const
|
||||
{
|
||||
static Section const none("");
|
||||
static Section const kNone("");
|
||||
auto const iter = map_.find(name);
|
||||
if (iter == map_.end())
|
||||
return none;
|
||||
return kNone;
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ namespace xrpl {
|
||||
CountedObjects&
|
||||
CountedObjects::getInstance() noexcept
|
||||
{
|
||||
static CountedObjects instance;
|
||||
static CountedObjects kInstance;
|
||||
|
||||
return instance;
|
||||
return kInstance;
|
||||
}
|
||||
|
||||
CountedObjects::CountedObjects() noexcept : m_count(0), m_head(nullptr)
|
||||
CountedObjects::CountedObjects() noexcept : count_(0), head_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ CountedObjects::getCounts(int minimumThreshold) const
|
||||
|
||||
// When other operations are concurrent, the count
|
||||
// might be temporarily less than the actual count.
|
||||
counts.reserve(m_count.load());
|
||||
counts.reserve(count_.load());
|
||||
|
||||
for (auto* ctr = m_head.load(); ctr != nullptr; ctr = ctr->getNext())
|
||||
for (auto* ctr = head_.load(); ctr != nullptr; ctr = ctr->getNext())
|
||||
{
|
||||
if (ctr->getCount() >= minimumThreshold)
|
||||
counts.emplace_back(ctr->getName(), ctr->getCount());
|
||||
|
||||
@@ -19,19 +19,20 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
Logs::Sink::Sink(std::string partition, beast::severities::Severity thresh, Logs& logs)
|
||||
Logs::Sink::Sink(std::string partition, beast::Severity thresh, Logs& logs)
|
||||
: beast::Journal::Sink(thresh, false), logs_(logs), partition_(std::move(partition))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Logs::Sink::write(beast::severities::Severity level, std::string const& text)
|
||||
Logs::Sink::write(beast::Severity level, std::string const& text)
|
||||
{
|
||||
if (level < threshold())
|
||||
return;
|
||||
@@ -40,21 +41,21 @@ Logs::Sink::write(beast::severities::Severity level, std::string const& text)
|
||||
}
|
||||
|
||||
void
|
||||
Logs::Sink::writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
Logs::Sink::writeAlways(beast::Severity level, std::string const& text)
|
||||
{
|
||||
logs_.write(level, partition_, text, console());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Logs::File::File() : m_stream(nullptr)
|
||||
Logs::File::File() : stream_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Logs::File::isOpen() const noexcept
|
||||
{
|
||||
return m_stream != nullptr;
|
||||
return stream_ != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -69,9 +70,9 @@ Logs::File::open(boost::filesystem::path const& path)
|
||||
|
||||
if (stream->good())
|
||||
{
|
||||
m_path = path;
|
||||
path_ = path;
|
||||
|
||||
m_stream = std::move(stream);
|
||||
stream_ = std::move(stream);
|
||||
|
||||
wasOpened = true;
|
||||
}
|
||||
@@ -84,35 +85,35 @@ Logs::File::closeAndReopen()
|
||||
{
|
||||
close();
|
||||
|
||||
return open(m_path);
|
||||
return open(path_);
|
||||
}
|
||||
|
||||
void
|
||||
Logs::File::close()
|
||||
{
|
||||
m_stream = nullptr;
|
||||
stream_ = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::File::write(char const* text)
|
||||
{
|
||||
if (m_stream != nullptr)
|
||||
(*m_stream) << text;
|
||||
if (stream_ != nullptr)
|
||||
(*stream_) << text;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::File::writeln(char const* text)
|
||||
{
|
||||
if (m_stream != nullptr)
|
||||
if (stream_ != nullptr)
|
||||
{
|
||||
(*m_stream) << text;
|
||||
(*m_stream) << std::endl;
|
||||
(*stream_) << text;
|
||||
(*stream_) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Logs::Logs(beast::severities::Severity thresh) : thresh_(thresh) // default severity
|
||||
Logs::Logs(beast::Severity thresh) : thresh_(thresh) // default severity
|
||||
{
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ Logs::open(boost::filesystem::path const& pathToLogFile)
|
||||
beast::Journal::Sink&
|
||||
Logs::get(std::string const& name)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto const result = sinks_.emplace(name, makeSink(name, thresh_));
|
||||
return *result.first->second;
|
||||
}
|
||||
@@ -142,42 +143,42 @@ Logs::journal(std::string const& name)
|
||||
return beast::Journal(get(name));
|
||||
}
|
||||
|
||||
beast::severities::Severity
|
||||
beast::Severity
|
||||
Logs::threshold() const
|
||||
{
|
||||
return thresh_;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::threshold(beast::severities::Severity thresh)
|
||||
Logs::threshold(beast::Severity thresh)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
thresh_ = thresh;
|
||||
for (auto& sink : sinks_)
|
||||
sink.second->threshold(thresh);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
Logs::partition_severities() const
|
||||
Logs::partitionSeverities() const
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> list;
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
list.reserve(sinks_.size());
|
||||
for (auto const& [name, sink] : sinks_)
|
||||
list.emplace_back(name, toString(fromSeverity(sink->threshold())));
|
||||
list.emplace_back(name, toString(sink->threshold()));
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::write(
|
||||
beast::severities::Severity level,
|
||||
beast::Severity level,
|
||||
std::string const& partition,
|
||||
std::string const& text,
|
||||
bool console)
|
||||
{
|
||||
std::string s;
|
||||
format(s, text, level, partition);
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
file_.writeln(s);
|
||||
if (!silent_)
|
||||
std::cerr << s << '\n';
|
||||
@@ -189,7 +190,7 @@ Logs::write(
|
||||
std::string
|
||||
Logs::rotate()
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
bool const wasOpened = file_.closeAndReopen();
|
||||
if (wasOpened)
|
||||
return "The log file was closed and reopened.";
|
||||
@@ -197,84 +198,27 @@ Logs::rotate()
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
Logs::makeSink(std::string const& name, beast::severities::Severity threshold)
|
||||
Logs::makeSink(std::string const& name, beast::Severity threshold)
|
||||
{
|
||||
return std::make_unique<Sink>(name, threshold, *this);
|
||||
}
|
||||
|
||||
LogSeverity
|
||||
Logs::fromSeverity(beast::severities::Severity level)
|
||||
{
|
||||
using namespace beast::severities;
|
||||
switch (level)
|
||||
{
|
||||
case kTrace:
|
||||
return lsTRACE;
|
||||
case kDebug:
|
||||
return lsDEBUG;
|
||||
case kInfo:
|
||||
return lsINFO;
|
||||
case kWarning:
|
||||
return lsWARNING;
|
||||
case kError:
|
||||
return lsERROR;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("xrpl::Logs::fromSeverity : invalid severity");
|
||||
[[fallthrough]];
|
||||
// LCOV_EXCL_STOP
|
||||
case kFatal:
|
||||
break;
|
||||
}
|
||||
|
||||
return lsFATAL;
|
||||
}
|
||||
|
||||
beast::severities::Severity
|
||||
Logs::toSeverity(LogSeverity level)
|
||||
{
|
||||
using namespace beast::severities;
|
||||
switch (level)
|
||||
{
|
||||
case lsTRACE:
|
||||
return kTrace;
|
||||
case lsDEBUG:
|
||||
return kDebug;
|
||||
case lsINFO:
|
||||
return kInfo;
|
||||
case lsWARNING:
|
||||
return kWarning;
|
||||
case lsERROR:
|
||||
return kError;
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("xrpl::Logs::toSeverity : invalid severity");
|
||||
[[fallthrough]];
|
||||
// LCOV_EXCL_STOP
|
||||
case lsFATAL:
|
||||
break;
|
||||
}
|
||||
|
||||
return kFatal;
|
||||
}
|
||||
|
||||
std::string
|
||||
Logs::toString(LogSeverity s)
|
||||
Logs::toString(beast::Severity s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case lsTRACE:
|
||||
case beast::Severity::Trace:
|
||||
return "Trace";
|
||||
case lsDEBUG:
|
||||
case beast::Severity::Debug:
|
||||
return "Debug";
|
||||
case lsINFO:
|
||||
case beast::Severity::Info:
|
||||
return "Info";
|
||||
case lsWARNING:
|
||||
case beast::Severity::Warning:
|
||||
return "Warning";
|
||||
case lsERROR:
|
||||
case beast::Severity::Error:
|
||||
return "Error";
|
||||
case lsFATAL:
|
||||
case beast::Severity::Fatal:
|
||||
return "Fatal";
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
@@ -284,61 +228,61 @@ Logs::toString(LogSeverity s)
|
||||
}
|
||||
}
|
||||
|
||||
LogSeverity
|
||||
std::optional<beast::Severity>
|
||||
Logs::fromString(std::string const& s)
|
||||
{
|
||||
if (boost::iequals(s, "trace"))
|
||||
return lsTRACE;
|
||||
return beast::Severity::Trace;
|
||||
|
||||
if (boost::iequals(s, "debug"))
|
||||
return lsDEBUG;
|
||||
return beast::Severity::Debug;
|
||||
|
||||
if (boost::iequals(s, "info") || boost::iequals(s, "information"))
|
||||
return lsINFO;
|
||||
return beast::Severity::Info;
|
||||
|
||||
if (boost::iequals(s, "warn") || boost::iequals(s, "warning") || boost::iequals(s, "warnings"))
|
||||
return lsWARNING;
|
||||
return beast::Severity::Warning;
|
||||
|
||||
if (boost::iequals(s, "error") || boost::iequals(s, "errors"))
|
||||
return lsERROR;
|
||||
return beast::Severity::Error;
|
||||
|
||||
if (boost::iequals(s, "fatal") || boost::iequals(s, "fatals"))
|
||||
return lsFATAL;
|
||||
return beast::Severity::Fatal;
|
||||
|
||||
return lsINVALID;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::format(
|
||||
std::string& output,
|
||||
std::string const& message,
|
||||
beast::severities::Severity severity,
|
||||
beast::Severity severity,
|
||||
std::string const& partition)
|
||||
{
|
||||
output.reserve(message.size() + partition.size() + 100);
|
||||
|
||||
output = to_string(std::chrono::system_clock::now());
|
||||
output = xrpl::to_string(std::chrono::system_clock::now());
|
||||
|
||||
output += " ";
|
||||
if (!partition.empty())
|
||||
output += partition + ":";
|
||||
|
||||
using namespace beast::severities;
|
||||
using beast::Severity;
|
||||
switch (severity)
|
||||
{
|
||||
case kTrace:
|
||||
case Severity::Trace:
|
||||
output += "TRC ";
|
||||
break;
|
||||
case kDebug:
|
||||
case Severity::Debug:
|
||||
output += "DBG ";
|
||||
break;
|
||||
case kInfo:
|
||||
case Severity::Info:
|
||||
output += "NFO ";
|
||||
break;
|
||||
case kWarning:
|
||||
case Severity::Warning:
|
||||
output += "WRN ";
|
||||
break;
|
||||
case kError:
|
||||
case Severity::Error:
|
||||
output += "ERR ";
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
@@ -346,7 +290,7 @@ Logs::format(
|
||||
UNREACHABLE("xrpl::Logs::format : invalid severity");
|
||||
[[fallthrough]];
|
||||
// LCOV_EXCL_STOP
|
||||
case kFatal:
|
||||
case Severity::Fatal:
|
||||
output += "FTL ";
|
||||
break;
|
||||
}
|
||||
@@ -382,9 +326,9 @@ Logs::format(
|
||||
output += message;
|
||||
|
||||
// Limit the maximum length of the output
|
||||
if (output.size() > maximumMessageCharacters)
|
||||
if (output.size() > kMaximumMessageCharacters)
|
||||
{
|
||||
output.resize(maximumMessageCharacters - 3);
|
||||
output.resize(kMaximumMessageCharacters - 3);
|
||||
output += "...";
|
||||
}
|
||||
|
||||
@@ -427,7 +371,7 @@ class DebugSink
|
||||
private:
|
||||
std::reference_wrapper<beast::Journal::Sink> sink_;
|
||||
std::unique_ptr<beast::Journal::Sink> holder_;
|
||||
std::mutex m_;
|
||||
std::mutex mtx_;
|
||||
|
||||
public:
|
||||
DebugSink() : sink_(beast::Journal::getNullSink())
|
||||
@@ -445,7 +389,7 @@ public:
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
set(std::unique_ptr<beast::Journal::Sink> sink)
|
||||
{
|
||||
std::lock_guard const _(m_);
|
||||
std::scoped_lock const _(mtx_);
|
||||
|
||||
using std::swap;
|
||||
swap(holder_, sink);
|
||||
@@ -465,7 +409,7 @@ public:
|
||||
beast::Journal::Sink&
|
||||
get()
|
||||
{
|
||||
std::lock_guard const _(m_);
|
||||
std::scoped_lock const _(mtx_);
|
||||
return sink_.get();
|
||||
}
|
||||
};
|
||||
@@ -473,8 +417,8 @@ public:
|
||||
static DebugSink&
|
||||
debugSink()
|
||||
{
|
||||
static DebugSink _;
|
||||
return _;
|
||||
static DebugSink kInst;
|
||||
return kInst;
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
|
||||
@@ -86,7 +86,7 @@ mallocTrim(std::string_view tag, beast::Journal journal)
|
||||
// Keep glibc malloc_trim padding at 0 (default): 12h Mainnet tests across 0/256KB/1MB/16MB
|
||||
// showed no clear, consistent benefit from custom padding—0 provided the best overall balance
|
||||
// of RSS reduction and trim-latency stability without adding a tuning surface.
|
||||
constexpr std::size_t TRIM_PAD = 0;
|
||||
static constexpr std::size_t kTrimPad = 0;
|
||||
|
||||
report.supported = true;
|
||||
|
||||
@@ -110,16 +110,16 @@ mallocTrim(std::string_view tag, beast::Journal journal)
|
||||
long const rssBeforeKB = detail::parseStatmRSSkB(statmBefore);
|
||||
|
||||
struct rusage ru0{};
|
||||
bool const have_ru0 = getRusageThread(ru0);
|
||||
bool const haveRu0 = getRusageThread(ru0);
|
||||
|
||||
auto const t0 = std::chrono::steady_clock::now();
|
||||
|
||||
report.trimResult = detail::mallocTrimWithPad(TRIM_PAD);
|
||||
report.trimResult = detail::mallocTrimWithPad(kTrimPad);
|
||||
|
||||
auto const t1 = std::chrono::steady_clock::now();
|
||||
|
||||
struct rusage ru1{};
|
||||
bool const have_ru1 = getRusageThread(ru1);
|
||||
bool const haveRu1 = getRusageThread(ru1);
|
||||
|
||||
auto const statmAfter = readFile(statmPath);
|
||||
long const rssAfterKB = detail::parseStatmRSSkB(statmAfter);
|
||||
@@ -129,7 +129,7 @@ mallocTrim(std::string_view tag, beast::Journal journal)
|
||||
report.rssAfterKB = rssAfterKB;
|
||||
report.durationUs = std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0);
|
||||
|
||||
if (have_ru0 && have_ru1)
|
||||
if (haveRu0 && haveRu1)
|
||||
{
|
||||
report.minfltDelta = ru1.ru_minflt - ru0.ru_minflt;
|
||||
report.majfltDelta = ru1.ru_majflt - ru0.ru_majflt;
|
||||
@@ -140,7 +140,7 @@ mallocTrim(std::string_view tag, beast::Journal journal)
|
||||
: (static_cast<std::int64_t>(rssAfterKB) - static_cast<std::int64_t>(rssBeforeKB));
|
||||
|
||||
JLOG(journal.debug()) << "malloc_trim tag=" << tagStr << " result=" << report.trimResult
|
||||
<< " pad=" << TRIM_PAD << " bytes"
|
||||
<< " pad=" << kTrimPad << " bytes"
|
||||
<< " rss_before=" << rssBeforeKB << "kB"
|
||||
<< " rss_after=" << rssAfterKB << "kB"
|
||||
<< " delta=" << deltaKB << "kB"
|
||||
@@ -150,7 +150,7 @@ mallocTrim(std::string_view tag, beast::Journal journal)
|
||||
}
|
||||
else
|
||||
{
|
||||
report.trimResult = detail::mallocTrimWithPad(TRIM_PAD);
|
||||
report.trimResult = detail::mallocTrimWithPad(kTrimPad);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,7 @@ namespace xrpl {
|
||||
template <class Derived>
|
||||
class AsyncObject
|
||||
{
|
||||
AsyncObject() : m_pending(0)
|
||||
AsyncObject() : pending_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
~AsyncObject()
|
||||
{
|
||||
// Destroying the object with I/O pending? Not a clean exit!
|
||||
XRPL_ASSERT(m_pending.load() == 0, "xrpl::AsyncObject::~AsyncObject : nothing pending");
|
||||
XRPL_ASSERT(pending_.load() == 0, "xrpl::AsyncObject::~AsyncObject : nothing pending");
|
||||
}
|
||||
|
||||
/** RAII container that maintains the count of pending I/O.
|
||||
@@ -58,45 +58,45 @@ public:
|
||||
class CompletionCounter
|
||||
{
|
||||
public:
|
||||
explicit CompletionCounter(Derived* owner) : m_owner(owner)
|
||||
explicit CompletionCounter(Derived* owner) : owner_(owner)
|
||||
{
|
||||
++m_owner->m_pending;
|
||||
++owner_->pending_;
|
||||
}
|
||||
|
||||
CompletionCounter(CompletionCounter const& other) : m_owner(other.m_owner)
|
||||
CompletionCounter(CompletionCounter const& other) : owner_(other.owner_)
|
||||
{
|
||||
++m_owner->m_pending;
|
||||
++owner_->pending_;
|
||||
}
|
||||
|
||||
~CompletionCounter()
|
||||
{
|
||||
if (--m_owner->m_pending == 0)
|
||||
m_owner->asyncHandlersComplete();
|
||||
if (--owner_->pending_ == 0)
|
||||
owner_->asyncHandlersComplete();
|
||||
}
|
||||
|
||||
CompletionCounter&
|
||||
operator=(CompletionCounter const&) = delete;
|
||||
|
||||
private:
|
||||
Derived* m_owner;
|
||||
Derived* owner_;
|
||||
};
|
||||
|
||||
void
|
||||
addReference()
|
||||
{
|
||||
++m_pending;
|
||||
++pending_;
|
||||
}
|
||||
|
||||
void
|
||||
removeReference()
|
||||
{
|
||||
if (--m_pending == 0)
|
||||
if (--pending_ == 0)
|
||||
(static_cast<Derived*>(this))->asyncHandlersComplete();
|
||||
}
|
||||
|
||||
private:
|
||||
// The number of handlers pending.
|
||||
std::atomic<int> m_pending;
|
||||
std::atomic<int> pending_;
|
||||
|
||||
friend Derived;
|
||||
};
|
||||
@@ -106,18 +106,18 @@ class ResolverAsioImpl : public ResolverAsio, public AsyncObject<ResolverAsioImp
|
||||
public:
|
||||
using HostAndPort = std::pair<std::string, std::string>;
|
||||
|
||||
beast::Journal m_journal;
|
||||
beast::Journal journal;
|
||||
|
||||
boost::asio::io_context& m_io_context;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> m_strand;
|
||||
boost::asio::ip::tcp::resolver m_resolver;
|
||||
boost::asio::io_context& ioContext;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> strand;
|
||||
boost::asio::ip::tcp::resolver resolver;
|
||||
|
||||
std::condition_variable m_cv;
|
||||
std::mutex m_mut;
|
||||
bool m_asyncHandlersCompleted{true};
|
||||
std::condition_variable cv;
|
||||
std::mutex mut;
|
||||
bool asyncHandlersCompleted{true};
|
||||
|
||||
std::atomic<bool> m_stop_called;
|
||||
std::atomic<bool> m_stopped;
|
||||
std::atomic<bool> stopCalled;
|
||||
std::atomic<bool> stopped;
|
||||
|
||||
// Represents a unit of work for the resolver to do
|
||||
struct Work
|
||||
@@ -126,30 +126,30 @@ public:
|
||||
HandlerType handler;
|
||||
|
||||
template <class StringSequence>
|
||||
Work(StringSequence const& names_, HandlerType handler_) : handler(std::move(handler_))
|
||||
Work(StringSequence const& inNames, HandlerType handler) : handler(std::move(handler))
|
||||
{
|
||||
names.reserve(names_.size());
|
||||
names.reserve(inNames.size());
|
||||
|
||||
std::reverse_copy(names_.begin(), names_.end(), std::back_inserter(names));
|
||||
std::reverse_copy(inNames.begin(), inNames.end(), std::back_inserter(names));
|
||||
}
|
||||
};
|
||||
|
||||
std::deque<Work> m_work;
|
||||
std::deque<Work> work;
|
||||
|
||||
ResolverAsioImpl(boost::asio::io_context& io_context, beast::Journal journal)
|
||||
: m_journal(journal)
|
||||
, m_io_context(io_context)
|
||||
, m_strand(boost::asio::make_strand(io_context))
|
||||
, m_resolver(io_context)
|
||||
, m_stop_called(false)
|
||||
, m_stopped(true)
|
||||
ResolverAsioImpl(boost::asio::io_context& ioContext, beast::Journal journal)
|
||||
: journal(journal)
|
||||
, ioContext(ioContext)
|
||||
, strand(boost::asio::make_strand(ioContext))
|
||||
, resolver(ioContext)
|
||||
, stopCalled(false)
|
||||
, stopped(true)
|
||||
{
|
||||
}
|
||||
|
||||
~ResolverAsioImpl() override
|
||||
{
|
||||
XRPL_ASSERT(m_work.empty(), "xrpl::ResolverAsioImpl::~ResolverAsioImpl : no pending work");
|
||||
XRPL_ASSERT(m_stopped, "xrpl::ResolverAsioImpl::~ResolverAsioImpl : stopped");
|
||||
XRPL_ASSERT(work.empty(), "xrpl::ResolverAsioImpl::~ResolverAsioImpl : no pending work");
|
||||
XRPL_ASSERT(stopped, "xrpl::ResolverAsioImpl::~ResolverAsioImpl : stopped");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -157,9 +157,9 @@ public:
|
||||
void
|
||||
asyncHandlersComplete()
|
||||
{
|
||||
std::unique_lock<std::mutex> const lk{m_mut};
|
||||
m_asyncHandlersCompleted = true;
|
||||
m_cv.notify_all();
|
||||
std::unique_lock<std::mutex> const lk{mut};
|
||||
asyncHandlersCompleted = true;
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -171,80 +171,79 @@ public:
|
||||
void
|
||||
start() override
|
||||
{
|
||||
XRPL_ASSERT(m_stopped == true, "xrpl::ResolverAsioImpl::start : stopped");
|
||||
XRPL_ASSERT(m_stop_called == false, "xrpl::ResolverAsioImpl::start : not stopping");
|
||||
XRPL_ASSERT(stopped == true, "xrpl::ResolverAsioImpl::start : stopped");
|
||||
XRPL_ASSERT(stopCalled == false, "xrpl::ResolverAsioImpl::start : not stopping");
|
||||
|
||||
if (m_stopped.exchange(false))
|
||||
if (stopped.exchange(false))
|
||||
{
|
||||
{
|
||||
std::lock_guard const lk{m_mut};
|
||||
m_asyncHandlersCompleted = false;
|
||||
std::scoped_lock const lk{mut};
|
||||
asyncHandlersCompleted = false;
|
||||
}
|
||||
addReference();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stop_async() override
|
||||
stopAsync() override
|
||||
{
|
||||
if (!m_stop_called.exchange(true))
|
||||
if (!stopCalled.exchange(true))
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_io_context,
|
||||
ioContext,
|
||||
boost::asio::bind_executor(
|
||||
m_strand,
|
||||
std::bind(&ResolverAsioImpl::do_stop, this, CompletionCounter(this))));
|
||||
strand, std::bind(&ResolverAsioImpl::doStop, this, CompletionCounter(this))));
|
||||
|
||||
JLOG(m_journal.debug()) << "Queued a stop request";
|
||||
JLOG(journal.debug()) << "Queued a stop request";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stop() override
|
||||
{
|
||||
stop_async();
|
||||
stopAsync();
|
||||
|
||||
JLOG(m_journal.debug()) << "Waiting to stop";
|
||||
std::unique_lock<std::mutex> lk{m_mut};
|
||||
m_cv.wait(lk, [this] { return m_asyncHandlersCompleted; });
|
||||
JLOG(journal.debug()) << "Waiting to stop";
|
||||
std::unique_lock<std::mutex> lk{mut};
|
||||
cv.wait(lk, [this] { return asyncHandlersCompleted; });
|
||||
lk.unlock();
|
||||
JLOG(m_journal.debug()) << "Stopped";
|
||||
JLOG(journal.debug()) << "Stopped";
|
||||
}
|
||||
|
||||
void
|
||||
resolve(std::vector<std::string> const& names, HandlerType const& handler) override
|
||||
{
|
||||
XRPL_ASSERT(m_stop_called == false, "xrpl::ResolverAsioImpl::resolve : not stopping");
|
||||
XRPL_ASSERT(stopCalled == false, "xrpl::ResolverAsioImpl::resolve : not stopping");
|
||||
XRPL_ASSERT(!names.empty(), "xrpl::ResolverAsioImpl::resolve : names non-empty");
|
||||
|
||||
// TODO NIKB use rvalue references to construct and move
|
||||
// reducing cost.
|
||||
boost::asio::dispatch(
|
||||
m_io_context,
|
||||
ioContext,
|
||||
boost::asio::bind_executor(
|
||||
m_strand,
|
||||
strand,
|
||||
std::bind(
|
||||
&ResolverAsioImpl::do_resolve, this, names, handler, CompletionCounter(this))));
|
||||
&ResolverAsioImpl::doResolve, this, names, handler, CompletionCounter(this))));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Resolver
|
||||
void
|
||||
do_stop(CompletionCounter)
|
||||
doStop(CompletionCounter)
|
||||
{
|
||||
XRPL_ASSERT(m_stop_called == true, "xrpl::ResolverAsioImpl::do_stop : stopping");
|
||||
XRPL_ASSERT(stopCalled == true, "xrpl::ResolverAsioImpl::doStop : stopping");
|
||||
|
||||
if (!m_stopped.exchange(true))
|
||||
if (!stopped.exchange(true))
|
||||
{
|
||||
m_work.clear();
|
||||
m_resolver.cancel();
|
||||
work.clear();
|
||||
resolver.cancel();
|
||||
|
||||
removeReference();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
do_finish(
|
||||
doFinish(
|
||||
std::string name,
|
||||
boost::system::error_code const& ec,
|
||||
HandlerType handler,
|
||||
@@ -263,7 +262,7 @@ public:
|
||||
{
|
||||
while (iter != results.end())
|
||||
{
|
||||
addresses.push_back(beast::IPAddressConversion::from_asio(*iter));
|
||||
addresses.push_back(beast::IPAddressConversion::fromAsio(*iter));
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
@@ -271,9 +270,9 @@ public:
|
||||
handler(name, addresses);
|
||||
|
||||
boost::asio::post(
|
||||
m_io_context,
|
||||
ioContext,
|
||||
boost::asio::bind_executor(
|
||||
m_strand, std::bind(&ResolverAsioImpl::do_work, this, CompletionCounter(this))));
|
||||
strand, std::bind(&ResolverAsioImpl::doWork, this, CompletionCounter(this))));
|
||||
}
|
||||
|
||||
static HostAndPort
|
||||
@@ -282,7 +281,7 @@ public:
|
||||
// first attempt to parse as an endpoint (IP addr + port).
|
||||
// If that doesn't succeed, fall back to generic name + port parsing
|
||||
|
||||
if (auto const result = beast::IP::Endpoint::from_string_checked(str))
|
||||
if (auto const result = beast::IP::Endpoint::fromStringChecked(str))
|
||||
{
|
||||
return make_pair(result->address().to_string(), std::to_string(result->port()));
|
||||
}
|
||||
@@ -292,20 +291,20 @@ public:
|
||||
// a port separator
|
||||
|
||||
// Attempt to find the first and last non-whitespace
|
||||
auto const find_whitespace =
|
||||
auto const findWhitespace =
|
||||
std::bind(&std::isspace<std::string::value_type>, std::placeholders::_1, std::locale());
|
||||
|
||||
auto host_first = std::ranges::find_if_not(str, find_whitespace);
|
||||
auto hostFirst = std::ranges::find_if_not(str, findWhitespace);
|
||||
|
||||
auto port_last =
|
||||
std::ranges::find_if_not(std::ranges::reverse_view(str), find_whitespace).base();
|
||||
auto portLast =
|
||||
std::ranges::find_if_not(std::ranges::reverse_view(str), findWhitespace).base();
|
||||
|
||||
// This should only happen for all-whitespace strings
|
||||
if (host_first >= port_last)
|
||||
if (hostFirst >= portLast)
|
||||
return std::make_pair(std::string(), std::string());
|
||||
|
||||
// Attempt to find the first and last valid port separators
|
||||
auto const find_port_separator = [](char const c) -> bool {
|
||||
auto const findPortSeparator = [](char const c) -> bool {
|
||||
if (std::isspace(static_cast<unsigned char>(c)))
|
||||
return true;
|
||||
|
||||
@@ -315,51 +314,50 @@ public:
|
||||
return false;
|
||||
};
|
||||
|
||||
auto host_last = std::find_if(host_first, port_last, find_port_separator);
|
||||
auto hostLast = std::find_if(hostFirst, portLast, findPortSeparator);
|
||||
|
||||
auto port_first = std::find_if_not(host_last, port_last, find_port_separator);
|
||||
auto portFirst = std::find_if_not(hostLast, portLast, findPortSeparator);
|
||||
|
||||
return make_pair(std::string(host_first, host_last), std::string(port_first, port_last));
|
||||
return make_pair(std::string(hostFirst, hostLast), std::string(portFirst, portLast));
|
||||
}
|
||||
|
||||
void
|
||||
do_work(CompletionCounter)
|
||||
doWork(CompletionCounter)
|
||||
{
|
||||
if (m_stop_called)
|
||||
if (stopCalled)
|
||||
return;
|
||||
|
||||
// We don't have any work to do at this time
|
||||
if (m_work.empty())
|
||||
if (work.empty())
|
||||
return;
|
||||
|
||||
std::string const name(m_work.front().names.back());
|
||||
HandlerType const handler(m_work.front().handler);
|
||||
std::string const name(work.front().names.back());
|
||||
HandlerType const handler(work.front().handler);
|
||||
|
||||
m_work.front().names.pop_back();
|
||||
work.front().names.pop_back();
|
||||
|
||||
if (m_work.front().names.empty())
|
||||
m_work.pop_front();
|
||||
if (work.front().names.empty())
|
||||
work.pop_front();
|
||||
|
||||
auto const [host, port] = parseName(name);
|
||||
|
||||
if (host.empty())
|
||||
{
|
||||
JLOG(m_journal.error()) << "Unable to parse '" << name << "'";
|
||||
JLOG(journal.error()) << "Unable to parse '" << name << "'";
|
||||
|
||||
boost::asio::post(
|
||||
m_io_context,
|
||||
ioContext,
|
||||
boost::asio::bind_executor(
|
||||
m_strand,
|
||||
std::bind(&ResolverAsioImpl::do_work, this, CompletionCounter(this))));
|
||||
strand, std::bind(&ResolverAsioImpl::doWork, this, CompletionCounter(this))));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_resolver.async_resolve(
|
||||
resolver.async_resolve(
|
||||
host,
|
||||
port,
|
||||
std::bind(
|
||||
&ResolverAsioImpl::do_finish,
|
||||
&ResolverAsioImpl::doFinish,
|
||||
this,
|
||||
name,
|
||||
std::placeholders::_1,
|
||||
@@ -369,24 +367,24 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
do_resolve(std::vector<std::string> const& names, HandlerType const& handler, CompletionCounter)
|
||||
doResolve(std::vector<std::string> const& names, HandlerType const& handler, CompletionCounter)
|
||||
{
|
||||
XRPL_ASSERT(!names.empty(), "xrpl::ResolverAsioImpl::do_resolve : names non-empty");
|
||||
XRPL_ASSERT(!names.empty(), "xrpl::ResolverAsioImpl::doResolve : names non-empty");
|
||||
|
||||
if (!m_stop_called)
|
||||
if (!stopCalled)
|
||||
{
|
||||
m_work.emplace_back(names, handler);
|
||||
work.emplace_back(names, handler);
|
||||
|
||||
JLOG(m_journal.debug()) << "Queued new job with " << names.size() << " tasks. "
|
||||
<< m_work.size() << " jobs outstanding.";
|
||||
JLOG(journal.debug()) << "Queued new job with " << names.size() << " tasks. "
|
||||
<< work.size() << " jobs outstanding.";
|
||||
|
||||
if (!m_work.empty())
|
||||
if (!work.empty())
|
||||
{
|
||||
boost::asio::post(
|
||||
m_io_context,
|
||||
ioContext,
|
||||
boost::asio::bind_executor(
|
||||
m_strand,
|
||||
std::bind(&ResolverAsioImpl::do_work, this, CompletionCounter(this))));
|
||||
strand,
|
||||
std::bind(&ResolverAsioImpl::doWork, this, CompletionCounter(this))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,9 +393,9 @@ public:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
std::unique_ptr<ResolverAsio>
|
||||
ResolverAsio::New(boost::asio::io_context& io_context, beast::Journal journal)
|
||||
ResolverAsio::make(boost::asio::io_context& ioContext, beast::Journal journal)
|
||||
{
|
||||
return std::make_unique<ResolverAsioImpl>(io_context, journal);
|
||||
return std::make_unique<ResolverAsioImpl>(ioContext, journal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -34,10 +34,10 @@ sqlBlobLiteral(Blob const& blob)
|
||||
}
|
||||
|
||||
bool
|
||||
parseUrl(parsedURL& pUrl, std::string const& strUrl)
|
||||
parseUrl(ParsedUrl& pUrl, std::string const& strUrl)
|
||||
{
|
||||
// scheme://username:password@hostname:port/rest
|
||||
static boost::regex const reUrl(
|
||||
static boost::regex const kReUrl(
|
||||
"(?i)\\`\\s*"
|
||||
// required scheme
|
||||
"([[:alpha:]][-+.[:alpha:][:digit:]]*?):"
|
||||
@@ -58,7 +58,7 @@ parseUrl(parsedURL& pUrl, std::string const& strUrl)
|
||||
// Bail if there is no match.
|
||||
try
|
||||
{
|
||||
if (!boost::regex_match(strUrl, smMatch, reUrl))
|
||||
if (!boost::regex_match(strUrl, smMatch, kReUrl))
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
@@ -74,7 +74,7 @@ parseUrl(parsedURL& pUrl, std::string const& strUrl)
|
||||
// We need to use Endpoint to parse the domain to
|
||||
// strip surrounding brackets from IPv6 addresses,
|
||||
// e.g. [::1] => ::1.
|
||||
auto const result = beast::IP::Endpoint::from_string_checked(domain);
|
||||
auto const result = beast::IP::Endpoint::fromStringChecked(domain);
|
||||
pUrl.domain = result ? result->address().to_string() : domain;
|
||||
std::string const port = smMatch[5];
|
||||
if (!port.empty())
|
||||
@@ -94,14 +94,14 @@ parseUrl(parsedURL& pUrl, std::string const& strUrl)
|
||||
}
|
||||
|
||||
std::string
|
||||
trim_whitespace(std::string str)
|
||||
trimWhitespace(std::string str)
|
||||
{
|
||||
boost::trim(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::optional<std::uint64_t>
|
||||
to_uint64(std::string const& s)
|
||||
toUInt64(std::string const& s)
|
||||
{
|
||||
std::uint64_t result = 0;
|
||||
if (beast::lexicalCastChecked(result, s))
|
||||
@@ -120,7 +120,7 @@ isProperlyFormedTomlDomain(std::string_view domain)
|
||||
// obviously wrong domain names but it isn't perfect. It does not
|
||||
// really support IDNs. If this turns out to be an issue, a more
|
||||
// thorough regex can be used or this check can just be removed.
|
||||
static boost::regex const re(
|
||||
static boost::regex const kRE(
|
||||
"^" // Beginning of line
|
||||
"(" // Beginning of a segment
|
||||
"(?!-)" // - must not begin with '-'
|
||||
@@ -133,7 +133,7 @@ isProperlyFormedTomlDomain(std::string_view domain)
|
||||
,
|
||||
boost::regex_constants::optimize);
|
||||
|
||||
return boost::regex_match(domain.begin(), domain.end(), re);
|
||||
return boost::regex_match(domain.begin(), domain.end(), kRE);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
#include <xrpl/basics/UptimeClock.h>
|
||||
|
||||
#include <atomic>
|
||||
@@ -6,15 +7,15 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
std::atomic<UptimeClock::rep> UptimeClock::now_{0}; // seconds since start
|
||||
std::atomic<bool> UptimeClock::stop_{false}; // stop update thread
|
||||
std::atomic<UptimeClock::rep> UptimeClock::kNow{0}; // seconds since start
|
||||
std::atomic<bool> UptimeClock::kStop{false}; // stop update thread
|
||||
|
||||
// On xrpld shutdown, cancel and wait for the update thread
|
||||
UptimeClock::update_thread::~update_thread()
|
||||
UptimeClock::UpdateThread::~UpdateThread()
|
||||
{
|
||||
if (joinable())
|
||||
{
|
||||
stop_ = true;
|
||||
kStop = true;
|
||||
// This join() may take up to a 1s, but happens only
|
||||
// once at xrpld shutdown.
|
||||
join();
|
||||
@@ -22,20 +23,20 @@ UptimeClock::update_thread::~update_thread()
|
||||
}
|
||||
|
||||
// Launch the update thread
|
||||
UptimeClock::update_thread
|
||||
UptimeClock::start_clock()
|
||||
UptimeClock::UpdateThread
|
||||
UptimeClock::startClock()
|
||||
{
|
||||
return update_thread{[] {
|
||||
return UpdateThread{[] {
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
// Wake up every second and update now_
|
||||
// Wake up every second and update kNow
|
||||
auto next = system_clock::now() + 1s;
|
||||
while (!stop_)
|
||||
while (!kStop)
|
||||
{
|
||||
this_thread::sleep_until(next);
|
||||
next += 1s;
|
||||
++now_;
|
||||
++kNow;
|
||||
}
|
||||
}};
|
||||
}
|
||||
@@ -48,10 +49,10 @@ UptimeClock::time_point
|
||||
UptimeClock::now()
|
||||
{
|
||||
// start the update thread on first use
|
||||
static auto const init = start_clock();
|
||||
static auto const kInit = startClock();
|
||||
|
||||
// Return the number of seconds since xrpld start
|
||||
return time_point{duration{now_}};
|
||||
return time_point{duration{kNow}};
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -45,17 +45,17 @@ namespace xrpl {
|
||||
namespace base64 {
|
||||
|
||||
inline char const*
|
||||
get_alphabet()
|
||||
getAlphabet()
|
||||
{
|
||||
static char constexpr tab[] = {
|
||||
static constexpr char kTab[] = {
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
|
||||
return &tab[0];
|
||||
return &kTab[0];
|
||||
}
|
||||
|
||||
inline signed char const*
|
||||
get_inverse()
|
||||
getInverse()
|
||||
{
|
||||
static signed char constexpr tab[] = {
|
||||
static constexpr signed char kTab[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
|
||||
@@ -73,17 +73,19 @@ get_inverse()
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
|
||||
};
|
||||
return &tab[0];
|
||||
return &kTab[0];
|
||||
}
|
||||
|
||||
/// Returns max chars needed to encode a base64 string
|
||||
std::size_t constexpr encoded_size(std::size_t n)
|
||||
constexpr std::size_t
|
||||
encodedSize(std::size_t n)
|
||||
{
|
||||
return 4 * ((n + 2) / 3);
|
||||
}
|
||||
|
||||
/// Returns max bytes needed to decode a base64 string
|
||||
std::size_t constexpr decoded_size(std::size_t n)
|
||||
constexpr std::size_t
|
||||
decodedSize(std::size_t n)
|
||||
{
|
||||
return ((n / 4) * 3) + 2;
|
||||
}
|
||||
@@ -105,7 +107,7 @@ encode(void* dest, void const* src, std::size_t len)
|
||||
{
|
||||
char* out = static_cast<char*>(dest); // NOLINT(misc-const-correctness)
|
||||
char const* in = static_cast<char const*>(src);
|
||||
auto const tab = base64::get_alphabet();
|
||||
auto const tab = base64::getAlphabet();
|
||||
|
||||
for (auto n = len / 3; n > 0; --n)
|
||||
{
|
||||
@@ -160,7 +162,7 @@ decode(void* dest, char const* src, std::size_t len)
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
auto const inverse = base64::get_inverse();
|
||||
auto const inverse = base64::getInverse();
|
||||
|
||||
while (((len--) != 0u) && *in != '=')
|
||||
{
|
||||
@@ -197,19 +199,19 @@ decode(void* dest, char const* src, std::size_t len)
|
||||
} // namespace base64
|
||||
|
||||
std::string
|
||||
base64_encode(std::uint8_t const* data, std::size_t len)
|
||||
base64Encode(std::uint8_t const* data, std::size_t len)
|
||||
{
|
||||
std::string dest;
|
||||
dest.resize(base64::encoded_size(len));
|
||||
dest.resize(base64::encodedSize(len));
|
||||
dest.resize(base64::encode(&dest[0], data, len));
|
||||
return dest;
|
||||
}
|
||||
|
||||
std::string
|
||||
base64_decode(std::string_view data)
|
||||
base64Decode(std::string_view data)
|
||||
{
|
||||
std::string dest;
|
||||
dest.resize(base64::decoded_size(data.size()));
|
||||
dest.resize(base64::decodedSize(data.size()));
|
||||
auto const result = base64::decode(&dest[0], data.data(), data.size());
|
||||
dest.resize(result.first);
|
||||
return dest;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
namespace xrpl {
|
||||
|
||||
void
|
||||
LogThrow(std::string const& title)
|
||||
logThrow(std::string const& title)
|
||||
{
|
||||
JLOG(debugLog().warn()) << title;
|
||||
}
|
||||
|
||||
[[noreturn]] void
|
||||
LogicError(std::string const& s) noexcept
|
||||
logicError(std::string const& s) noexcept
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(debugLog().fatal()) << s;
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace openssl::detail {
|
||||
@note If you increase the number of bits you need to generate new
|
||||
default DH parameters and update defaultDH accordingly.
|
||||
* */
|
||||
int defaultRSAKeyBits = 2048;
|
||||
int gDefaultRsaKeyBits = 2048;
|
||||
|
||||
/** The default DH parameters.
|
||||
|
||||
@@ -60,7 +60,7 @@ int defaultRSAKeyBits = 2048;
|
||||
@note If you increase the number of bits you need to update
|
||||
defaultRSAKeyBits accordingly.
|
||||
*/
|
||||
static constexpr char const defaultDH[] =
|
||||
static constexpr char kDefaultDh[] =
|
||||
"-----BEGIN DH PARAMETERS-----\n"
|
||||
"MIIBCAKCAQEApKSWfR7LKy0VoZ/SDCObCvJ5HKX2J93RJ+QN8kJwHh+uuA8G+t8Q\n"
|
||||
"MDRjL5HanlV/sKN9HXqBc7eqHmmbqYwIXKUt9MUZTLNheguddxVlc2IjdP5i9Ps8\n"
|
||||
@@ -84,52 +84,52 @@ static constexpr char const defaultDH[] =
|
||||
global or per-port basis, using the `ssl_ciphers` directive in the
|
||||
config file.
|
||||
*/
|
||||
std::string const defaultCipherList = "TLSv1.2:!CBC:!DSS:!PSK:!eNULL:!aNULL";
|
||||
std::string const kDefaultCipherList = "TLSv1.2:!CBC:!DSS:!PSK:!eNULL:!aNULL";
|
||||
|
||||
static void
|
||||
initAnonymous(boost::asio::ssl::context& context)
|
||||
{
|
||||
using namespace openssl;
|
||||
|
||||
static auto defaultRSA = []() {
|
||||
static auto kDefaultRsa = []() {
|
||||
BIGNUM* bn = BN_new();
|
||||
BN_set_word(bn, RSA_F4);
|
||||
|
||||
auto rsa = RSA_new();
|
||||
|
||||
if (!rsa)
|
||||
LogicError("RSA_new failed");
|
||||
logicError("RSA_new failed");
|
||||
|
||||
if (RSA_generate_key_ex(rsa, defaultRSAKeyBits, bn, nullptr) != 1)
|
||||
LogicError("RSA_generate_key_ex failure");
|
||||
if (RSA_generate_key_ex(rsa, gDefaultRsaKeyBits, bn, nullptr) != 1)
|
||||
logicError("RSA_generate_key_ex failure");
|
||||
|
||||
BN_clear_free(bn);
|
||||
|
||||
return rsa;
|
||||
}();
|
||||
|
||||
static auto defaultEphemeralPrivateKey = []() {
|
||||
static auto kDefaultEphemeralPrivateKey = []() {
|
||||
auto pkey = EVP_PKEY_new();
|
||||
|
||||
if (!pkey)
|
||||
LogicError("EVP_PKEY_new failed");
|
||||
logicError("EVP_PKEY_new failed");
|
||||
|
||||
// We need to up the reference count of here, since we are retaining a
|
||||
// copy of the key for (potential) reuse.
|
||||
if (RSA_up_ref(defaultRSA) != 1)
|
||||
LogicError("EVP_PKEY_assign_RSA: incrementing reference count failed");
|
||||
if (RSA_up_ref(kDefaultRsa) != 1)
|
||||
logicError("EVP_PKEY_assign_RSA: incrementing reference count failed");
|
||||
|
||||
if (!EVP_PKEY_assign_RSA(pkey, defaultRSA))
|
||||
LogicError("EVP_PKEY_assign_RSA failed");
|
||||
if (!EVP_PKEY_assign_RSA(pkey, kDefaultRsa))
|
||||
logicError("EVP_PKEY_assign_RSA failed");
|
||||
|
||||
return pkey;
|
||||
}();
|
||||
|
||||
static auto defaultCert = []() {
|
||||
static auto kDefaultCert = []() {
|
||||
auto x509 = X509_new();
|
||||
|
||||
if (x509 == nullptr)
|
||||
LogicError("X509_new failed");
|
||||
logicError("X509_new failed");
|
||||
|
||||
// According to the standards (X.509 et al), the value should be one
|
||||
// less than the actually certificate version we want. Since we want
|
||||
@@ -147,7 +147,7 @@ initAnonymous(boost::asio::ssl::context& context)
|
||||
buf[ret] = 0;
|
||||
|
||||
if (ASN1_TIME_set_string_X509(X509_get_notBefore(x509), buf) != 1)
|
||||
LogicError("Unable to set certificate validity date");
|
||||
logicError("Unable to set certificate validity date");
|
||||
|
||||
// And make it valid for two years
|
||||
X509_gmtime_adj(X509_get_notAfter(x509), 2 * 365 * 24 * 60 * 60);
|
||||
@@ -205,61 +205,61 @@ initAnonymous(boost::asio::ssl::context& context)
|
||||
}
|
||||
|
||||
// And a private key
|
||||
X509_set_pubkey(x509, defaultEphemeralPrivateKey);
|
||||
X509_set_pubkey(x509, kDefaultEphemeralPrivateKey);
|
||||
|
||||
if (!X509_sign(x509, defaultEphemeralPrivateKey, EVP_sha256()))
|
||||
LogicError("X509_sign failed");
|
||||
if (!X509_sign(x509, kDefaultEphemeralPrivateKey, EVP_sha256()))
|
||||
logicError("X509_sign failed");
|
||||
|
||||
return x509;
|
||||
}();
|
||||
|
||||
SSL_CTX* const ctx = context.native_handle();
|
||||
|
||||
if (SSL_CTX_use_certificate(ctx, defaultCert) <= 0)
|
||||
LogicError("SSL_CTX_use_certificate failed");
|
||||
if (SSL_CTX_use_certificate(ctx, kDefaultCert) <= 0)
|
||||
logicError("SSL_CTX_use_certificate failed");
|
||||
|
||||
if (SSL_CTX_use_PrivateKey(ctx, defaultEphemeralPrivateKey) <= 0)
|
||||
LogicError("SSL_CTX_use_PrivateKey failed");
|
||||
if (SSL_CTX_use_PrivateKey(ctx, kDefaultEphemeralPrivateKey) <= 0)
|
||||
logicError("SSL_CTX_use_PrivateKey failed");
|
||||
}
|
||||
|
||||
static void
|
||||
initAuthenticated(
|
||||
boost::asio::ssl::context& context,
|
||||
std::string const& key_file,
|
||||
std::string const& cert_file,
|
||||
std::string const& chain_file)
|
||||
std::string const& keyFile,
|
||||
std::string const& certFile,
|
||||
std::string const& chainFile)
|
||||
{
|
||||
auto fmt_error = [](boost::system::error_code ec) -> std::string {
|
||||
auto fmtError = [](boost::system::error_code ec) -> std::string {
|
||||
return " [" + std::to_string(ec.value()) + ": " + ec.message() + "]";
|
||||
};
|
||||
|
||||
SSL_CTX* const ssl = context.native_handle();
|
||||
|
||||
bool cert_set = false;
|
||||
bool certSet = false;
|
||||
|
||||
if (!cert_file.empty())
|
||||
if (!certFile.empty())
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
context.use_certificate_file(cert_file, boost::asio::ssl::context::pem, ec);
|
||||
context.use_certificate_file(certFile, boost::asio::ssl::context::pem, ec);
|
||||
|
||||
if (ec)
|
||||
LogicError("Problem with SSL certificate file" + fmt_error(ec));
|
||||
logicError("Problem with SSL certificate file" + fmtError(ec));
|
||||
|
||||
cert_set = true;
|
||||
certSet = true;
|
||||
}
|
||||
|
||||
if (!chain_file.empty())
|
||||
if (!chainFile.empty())
|
||||
{
|
||||
// VFALCO Replace fopen() with RAII
|
||||
FILE* f = fopen(chain_file.c_str(), "r");
|
||||
FILE* f = fopen(chainFile.c_str(), "r");
|
||||
|
||||
if (f == nullptr)
|
||||
{
|
||||
LogicError(
|
||||
logicError(
|
||||
"Problem opening SSL chain file" +
|
||||
fmt_error(boost::system::error_code(errno, boost::system::generic_category())));
|
||||
fmtError(boost::system::error_code(errno, boost::system::generic_category())));
|
||||
}
|
||||
|
||||
try
|
||||
@@ -271,21 +271,21 @@ initAuthenticated(
|
||||
if (x == nullptr)
|
||||
break;
|
||||
|
||||
if (!cert_set)
|
||||
if (!certSet)
|
||||
{
|
||||
if (SSL_CTX_use_certificate(ssl, x) != 1)
|
||||
{
|
||||
LogicError(
|
||||
logicError(
|
||||
"Problem retrieving SSL certificate from chain "
|
||||
"file.");
|
||||
}
|
||||
|
||||
cert_set = true;
|
||||
certSet = true;
|
||||
}
|
||||
else if (SSL_CTX_add_extra_chain_cert(ssl, x) != 1)
|
||||
{
|
||||
X509_free(x);
|
||||
LogicError("Problem adding SSL chain certificate.");
|
||||
logicError("Problem adding SSL chain certificate.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,32 +294,32 @@ initAuthenticated(
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
fclose(f);
|
||||
LogicError(
|
||||
logicError(
|
||||
std::string("Reading the SSL chain file generated an exception: ") + ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
if (!key_file.empty())
|
||||
if (!keyFile.empty())
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
context.use_private_key_file(key_file, boost::asio::ssl::context::pem, ec);
|
||||
context.use_private_key_file(keyFile, boost::asio::ssl::context::pem, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
LogicError("Problem using the SSL private key file" + fmt_error(ec));
|
||||
logicError("Problem using the SSL private key file" + fmtError(ec));
|
||||
}
|
||||
}
|
||||
|
||||
if (SSL_CTX_check_private_key(ssl) != 1)
|
||||
{
|
||||
LogicError("Invalid key in SSL private key file.");
|
||||
logicError("Invalid key in SSL private key file.");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
get_context(std::string cipherList)
|
||||
getContext(std::string cipherList)
|
||||
{
|
||||
auto c = std::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);
|
||||
|
||||
@@ -330,12 +330,12 @@ get_context(std::string cipherList)
|
||||
boost::asio::ssl::context::no_compression);
|
||||
|
||||
if (cipherList.empty())
|
||||
cipherList = defaultCipherList;
|
||||
cipherList = kDefaultCipherList;
|
||||
|
||||
if (auto result = SSL_CTX_set_cipher_list(c->native_handle(), cipherList.c_str()); result != 1)
|
||||
LogicError("SSL_CTX_set_cipher_list failed");
|
||||
logicError("SSL_CTX_set_cipher_list failed");
|
||||
|
||||
c->use_tmp_dh({std::addressof(detail::defaultDH), sizeof(defaultDH)});
|
||||
c->use_tmp_dh({std::addressof(detail::kDefaultDh), sizeof(kDefaultDh)});
|
||||
|
||||
// Disable all renegotiation support in TLS v1.2. This can help prevent
|
||||
// exploitation of the bug described in CVE-2021-3499 (for details see
|
||||
@@ -350,9 +350,9 @@ get_context(std::string cipherList)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
make_SSLContext(std::string const& cipherList)
|
||||
makeSslContext(std::string const& cipherList)
|
||||
{
|
||||
auto context = openssl::detail::get_context(cipherList);
|
||||
auto context = openssl::detail::getContext(cipherList);
|
||||
openssl::detail::initAnonymous(*context);
|
||||
// VFALCO NOTE, It seems the WebSocket context never has
|
||||
// set_verify_mode called, for either setting of WEBSOCKET_SECURE
|
||||
@@ -361,13 +361,13 @@ make_SSLContext(std::string const& cipherList)
|
||||
}
|
||||
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
make_SSLContextAuthed(
|
||||
makeSslContextAuthed(
|
||||
std::string const& keyFile,
|
||||
std::string const& certFile,
|
||||
std::string const& chainFile,
|
||||
std::string const& cipherList)
|
||||
{
|
||||
auto context = openssl::detail::get_context(cipherList);
|
||||
auto context = openssl::detail::getContext(cipherList);
|
||||
openssl::detail::initAuthenticated(*context, keyFile, certFile, chainFile);
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
|
||||
|
||||
result /= div;
|
||||
|
||||
if (result > xrpl::muldiv_max)
|
||||
if (result > xrpl::kMuldivMax)
|
||||
return std::nullopt;
|
||||
|
||||
return static_cast<std::uint64_t>(result);
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace beast {
|
||||
namespace {
|
||||
|
||||
// Updates the clock
|
||||
class seconds_clock_thread
|
||||
class SecondsClockThread
|
||||
{
|
||||
using Clock = basic_seconds_clock::Clock;
|
||||
using Clock = BasicSecondsClock::Clock;
|
||||
|
||||
bool stop_{false};
|
||||
std::mutex mut_;
|
||||
@@ -24,8 +24,8 @@ class seconds_clock_thread
|
||||
std::atomic<Clock::time_point::rep> tp_;
|
||||
|
||||
public:
|
||||
~seconds_clock_thread();
|
||||
seconds_clock_thread();
|
||||
~SecondsClockThread();
|
||||
SecondsClockThread();
|
||||
|
||||
Clock::time_point
|
||||
now();
|
||||
@@ -37,31 +37,31 @@ private:
|
||||
|
||||
static_assert(std::atomic<std::chrono::steady_clock::rep>::is_always_lock_free);
|
||||
|
||||
seconds_clock_thread::~seconds_clock_thread()
|
||||
SecondsClockThread::~SecondsClockThread()
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
thread_.joinable(), "beast::seconds_clock_thread::~seconds_clock_thread : thread joinable");
|
||||
thread_.joinable(), "beast::SecondsClockThread::~SecondsClockThread : thread joinable");
|
||||
{
|
||||
std::lock_guard const lock(mut_);
|
||||
std::scoped_lock const lock(mut_);
|
||||
stop_ = true;
|
||||
} // publish stop_ asap so if waiting thread times-out, it will see it
|
||||
cv_.notify_one();
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
seconds_clock_thread::seconds_clock_thread() : tp_{Clock::now().time_since_epoch().count()}
|
||||
SecondsClockThread::SecondsClockThread() : tp_{Clock::now().time_since_epoch().count()}
|
||||
{
|
||||
thread_ = std::thread(&seconds_clock_thread::run, this);
|
||||
thread_ = std::thread(&SecondsClockThread::run, this);
|
||||
}
|
||||
|
||||
seconds_clock_thread::Clock::time_point
|
||||
seconds_clock_thread::now()
|
||||
SecondsClockThread::Clock::time_point
|
||||
SecondsClockThread::now()
|
||||
{
|
||||
return Clock::time_point{Clock::duration{tp_.load()}};
|
||||
}
|
||||
|
||||
void
|
||||
seconds_clock_thread::run()
|
||||
SecondsClockThread::run()
|
||||
{
|
||||
std::unique_lock lock(mut_);
|
||||
while (true)
|
||||
@@ -78,11 +78,11 @@ seconds_clock_thread::run()
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
basic_seconds_clock::time_point
|
||||
basic_seconds_clock::now()
|
||||
BasicSecondsClock::time_point
|
||||
BasicSecondsClock::now()
|
||||
{
|
||||
static seconds_clock_thread clk;
|
||||
return clk.now();
|
||||
static SecondsClockThread kClk;
|
||||
return kClk.now();
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -80,21 +80,19 @@ inline void
|
||||
setCurrentThreadNameImpl(std::string_view name)
|
||||
{
|
||||
// truncate and set the thread name.
|
||||
char boundedName[maxThreadNameLength + 1];
|
||||
std::snprintf(
|
||||
boundedName,
|
||||
sizeof(boundedName),
|
||||
"%.*s",
|
||||
static_cast<int>(maxThreadNameLength),
|
||||
name.data()); // NOLINT(bugprone-suspicious-stringview-data-usage)
|
||||
char boundedName[kMaxThreadNameLength + 1];
|
||||
auto const boundedSize =
|
||||
name.size() < kMaxThreadNameLength ? name.size() : kMaxThreadNameLength;
|
||||
name.copy(boundedName, boundedSize);
|
||||
boundedName[boundedSize] = '\0';
|
||||
|
||||
pthread_setname_np(pthread_self(), boundedName);
|
||||
|
||||
#ifdef TRUNCATED_THREAD_NAME_LOGS
|
||||
if (name.size() > maxThreadNameLength)
|
||||
if (name.size() > kMaxThreadNameLength)
|
||||
{
|
||||
std::cerr << "WARNING: Thread name \"" << name << "\" (length " << name.size()
|
||||
<< ") exceeds maximum of " << maxThreadNameLength << " characters on Linux.\n";
|
||||
<< ") exceeds maximum of " << kMaxThreadNameLength << " characters on Linux.\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -105,19 +103,19 @@ setCurrentThreadNameImpl(std::string_view name)
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
thread_local std::string threadName;
|
||||
thread_local std::string gThreadName;
|
||||
} // namespace detail
|
||||
|
||||
std::string
|
||||
getCurrentThreadName()
|
||||
{
|
||||
return detail::threadName;
|
||||
return detail::gThreadName;
|
||||
}
|
||||
|
||||
void
|
||||
setCurrentThreadName(std::string_view name)
|
||||
{
|
||||
detail::threadName = name;
|
||||
detail::gThreadName = name;
|
||||
detail::setCurrentThreadNameImpl(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
namespace beast {
|
||||
|
||||
std::string
|
||||
print_identifiers(SemanticVersion::identifier_list const& list)
|
||||
printIdentifiers(SemanticVersion::identifier_list const& list)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
@@ -61,10 +61,10 @@ chopUInt(int& value, int limit, std::string& input)
|
||||
if (input.empty())
|
||||
return false;
|
||||
|
||||
auto left_iter = std::ranges::find_if_not(
|
||||
auto leftIter = std::ranges::find_if_not(
|
||||
input, [](std::string::value_type c) { return std::isdigit(c, std::locale::classic()); });
|
||||
|
||||
std::string const item(input.begin(), left_iter);
|
||||
std::string const item(input.begin(), leftIter);
|
||||
|
||||
// Must not be empty
|
||||
if (item.empty())
|
||||
@@ -84,14 +84,14 @@ chopUInt(int& value, int limit, std::string& input)
|
||||
if (n < 0 || n > limit)
|
||||
return false;
|
||||
|
||||
input.erase(input.begin(), left_iter);
|
||||
input.erase(input.begin(), leftIter);
|
||||
value = n;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
extract_identifier(std::string& value, bool allowLeadingZeroes, std::string& input)
|
||||
extractIdentifier(std::string& value, bool allowLeadingZeroes, std::string& input)
|
||||
{
|
||||
// Must not be empty
|
||||
if (input.empty())
|
||||
@@ -114,7 +114,7 @@ extract_identifier(std::string& value, bool allowLeadingZeroes, std::string& inp
|
||||
}
|
||||
|
||||
bool
|
||||
extract_identifiers(
|
||||
extractIdentifiers(
|
||||
SemanticVersion::identifier_list& identifiers,
|
||||
bool allowLeadingZeroes,
|
||||
std::string& input)
|
||||
@@ -126,7 +126,7 @@ extract_identifiers(
|
||||
{
|
||||
std::string s;
|
||||
|
||||
if (!extract_identifier(s, allowLeadingZeroes, input))
|
||||
if (!extractIdentifier(s, allowLeadingZeroes, input))
|
||||
return false;
|
||||
identifiers.push_back(s);
|
||||
} while (chop(".", input));
|
||||
@@ -150,19 +150,19 @@ bool
|
||||
SemanticVersion::parse(std::string_view input)
|
||||
{
|
||||
// May not have leading or trailing whitespace
|
||||
auto left_iter = std::ranges::find_if_not(
|
||||
auto leftIter = std::ranges::find_if_not(
|
||||
input, [](std::string::value_type c) { return std::isspace(c, std::locale::classic()); });
|
||||
|
||||
auto right_iter =
|
||||
auto rightIter =
|
||||
std::ranges::find_if_not(std::ranges::reverse_view(input), [](std::string::value_type c) {
|
||||
return std::isspace(c, std::locale::classic());
|
||||
}).base();
|
||||
|
||||
// Must not be empty!
|
||||
if (left_iter >= right_iter)
|
||||
if (leftIter >= rightIter)
|
||||
return false;
|
||||
|
||||
std::string version(left_iter, right_iter);
|
||||
std::string version(leftIter, rightIter);
|
||||
|
||||
// May not have leading or trailing whitespace
|
||||
if (version != input)
|
||||
@@ -187,7 +187,7 @@ SemanticVersion::parse(std::string_view input)
|
||||
// May have pre-release identifier list
|
||||
if (chop("-", version))
|
||||
{
|
||||
if (!extract_identifiers(preReleaseIdentifiers, false, version))
|
||||
if (!extractIdentifiers(preReleaseIdentifiers, false, version))
|
||||
return false;
|
||||
|
||||
// Must not be empty
|
||||
@@ -198,7 +198,7 @@ SemanticVersion::parse(std::string_view input)
|
||||
// May have metadata identifier list
|
||||
if (chop("+", version))
|
||||
{
|
||||
if (!extract_identifiers(metaData, true, version))
|
||||
if (!extractIdentifiers(metaData, true, version))
|
||||
return false;
|
||||
|
||||
// Must not be empty
|
||||
@@ -220,13 +220,13 @@ SemanticVersion::print() const
|
||||
if (!preReleaseIdentifiers.empty())
|
||||
{
|
||||
s += "-";
|
||||
s += print_identifiers(preReleaseIdentifiers);
|
||||
s += printIdentifiers(preReleaseIdentifiers);
|
||||
}
|
||||
|
||||
if (!metaData.empty())
|
||||
{
|
||||
s += "+";
|
||||
s += print_identifiers(metaData);
|
||||
s += printIdentifiers(metaData);
|
||||
}
|
||||
|
||||
return s;
|
||||
|
||||
@@ -21,12 +21,12 @@ namespace detail {
|
||||
|
||||
class GroupImp : public std::enable_shared_from_this<GroupImp>, public Group
|
||||
{
|
||||
public:
|
||||
std::string const m_name;
|
||||
Collector::ptr m_collector;
|
||||
std::string const name_;
|
||||
Collector::ptr collector_;
|
||||
|
||||
GroupImp(std::string name_, Collector::ptr collector)
|
||||
: m_name(std::move(name_)), m_collector(std::move(collector))
|
||||
public:
|
||||
GroupImp(std::string name, Collector::ptr collector)
|
||||
: name_(std::move(name)), collector_(std::move(collector))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -35,43 +35,43 @@ public:
|
||||
std::string const&
|
||||
name() const override
|
||||
{
|
||||
return m_name;
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string
|
||||
make_name(std::string const& name)
|
||||
makeName(std::string const& name)
|
||||
{
|
||||
return m_name + "." + name;
|
||||
return name_ + "." + name;
|
||||
}
|
||||
|
||||
Hook
|
||||
make_hook(HookImpl::HandlerType const& handler) override
|
||||
makeHook(HookImpl::HandlerType const& handler) override
|
||||
{
|
||||
return m_collector->make_hook(handler);
|
||||
return collector_->makeHook(handler);
|
||||
}
|
||||
|
||||
Counter
|
||||
make_counter(std::string const& name) override
|
||||
makeCounter(std::string const& name) override
|
||||
{
|
||||
return m_collector->make_counter(make_name(name));
|
||||
return collector_->makeCounter(makeName(name));
|
||||
}
|
||||
|
||||
Event
|
||||
make_event(std::string const& name) override
|
||||
makeEvent(std::string const& name) override
|
||||
{
|
||||
return m_collector->make_event(make_name(name));
|
||||
return collector_->makeEvent(makeName(name));
|
||||
}
|
||||
|
||||
Gauge
|
||||
make_gauge(std::string const& name) override
|
||||
makeGauge(std::string const& name) override
|
||||
{
|
||||
return m_collector->make_gauge(make_name(name));
|
||||
return collector_->makeGauge(makeName(name));
|
||||
}
|
||||
|
||||
Meter
|
||||
make_meter(std::string const& name) override
|
||||
makeMeter(std::string const& name) override
|
||||
{
|
||||
return m_collector->make_meter(make_name(name));
|
||||
return collector_->makeMeter(makeName(name));
|
||||
}
|
||||
|
||||
GroupImp&
|
||||
@@ -83,12 +83,12 @@ public:
|
||||
class GroupsImp : public Groups
|
||||
{
|
||||
public:
|
||||
using Items = std::unordered_map<std::string, std::shared_ptr<Group>, uhash<>>;
|
||||
using Items = std::unordered_map<std::string, std::shared_ptr<Group>, Uhash<>>;
|
||||
|
||||
Collector::ptr m_collector;
|
||||
Items m_items;
|
||||
Collector::ptr collector;
|
||||
Items items;
|
||||
|
||||
explicit GroupsImp(Collector::ptr collector) : m_collector(std::move(collector))
|
||||
explicit GroupsImp(Collector::ptr collector) : collector(std::move(collector))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -97,10 +97,10 @@ public:
|
||||
Group::ptr const&
|
||||
get(std::string const& name) override
|
||||
{
|
||||
std::pair<Items::iterator, bool> const result(m_items.emplace(name, Group::ptr()));
|
||||
std::pair<Items::iterator, bool> const result(items.emplace(name, Group::ptr()));
|
||||
Group::ptr& group(result.first->second);
|
||||
if (result.second)
|
||||
group = std::make_shared<GroupImp>(name, m_collector);
|
||||
group = std::make_shared<GroupImp>(name, collector);
|
||||
return group;
|
||||
}
|
||||
};
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
Groups::~Groups() = default;
|
||||
|
||||
std::unique_ptr<Groups>
|
||||
make_Groups(Collector::ptr const& collector)
|
||||
makeGroups(Collector::ptr const& collector)
|
||||
{
|
||||
return std::make_unique<detail::GroupsImp>(collector);
|
||||
}
|
||||
|
||||
@@ -108,31 +108,31 @@ public:
|
||||
~NullCollectorImp() override = default;
|
||||
|
||||
Hook
|
||||
make_hook(HookImpl::HandlerType const&) override
|
||||
makeHook(HookImpl::HandlerType const&) override
|
||||
{
|
||||
return Hook(std::make_shared<detail::NullHookImpl>());
|
||||
}
|
||||
|
||||
Counter
|
||||
make_counter(std::string const&) override
|
||||
makeCounter(std::string const&) override
|
||||
{
|
||||
return Counter(std::make_shared<detail::NullCounterImpl>());
|
||||
}
|
||||
|
||||
Event
|
||||
make_event(std::string const&) override
|
||||
makeEvent(std::string const&) override
|
||||
{
|
||||
return Event(std::make_shared<detail::NullEventImpl>());
|
||||
}
|
||||
|
||||
Gauge
|
||||
make_gauge(std::string const&) override
|
||||
makeGauge(std::string const&) override
|
||||
{
|
||||
return Gauge(std::make_shared<detail::NullGaugeImpl>());
|
||||
}
|
||||
|
||||
Meter
|
||||
make_meter(std::string const&) override
|
||||
makeMeter(std::string const&) override
|
||||
{
|
||||
return Meter(std::make_shared<detail::NullMeterImpl>());
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::shared_ptr<Collector>
|
||||
NullCollector::New()
|
||||
NullCollector::make()
|
||||
{
|
||||
return std::make_shared<detail::NullCollectorImp>();
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ private:
|
||||
opentelemetry::nostd::shared_ptr<metrics_api::ObservableInstrument> m_gauge;
|
||||
|
||||
/** Owning collector, used to invoke hooks before reading gauge values. */
|
||||
std::shared_ptr<OTelCollectorImp> m_collector;
|
||||
std::shared_ptr<OTelCollectorImp> collector_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -578,9 +578,9 @@ OTelGaugeImpl::OTelGaugeImpl(
|
||||
std::string const& name,
|
||||
opentelemetry::nostd::shared_ptr<metrics_api::Meter> const& meter,
|
||||
std::shared_ptr<OTelCollectorImp> const& collector)
|
||||
: m_gauge(meter->CreateInt64ObservableGauge(name)), m_collector(collector)
|
||||
: m_gauge(meter->CreateInt64ObservableGauge(name)), collector_(collector)
|
||||
{
|
||||
m_collector->addGauge(this);
|
||||
collector_->addGauge(this);
|
||||
m_gauge->AddCallback(gaugeCallback, this);
|
||||
}
|
||||
|
||||
@@ -588,7 +588,7 @@ void
|
||||
OTelGaugeImpl::gaugeCallback(opentelemetry::metrics::ObserverResult result, void* state)
|
||||
{
|
||||
auto* self = static_cast<OTelGaugeImpl*>(state);
|
||||
self->m_collector->callHooks();
|
||||
self->collector_->callHooks();
|
||||
if (auto intResult = opentelemetry::nostd::get_if<
|
||||
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::ObserverResultT<int64_t>>>(
|
||||
&result))
|
||||
@@ -600,7 +600,7 @@ OTelGaugeImpl::gaugeCallback(opentelemetry::metrics::ObserverResult result, void
|
||||
OTelGaugeImpl::~OTelGaugeImpl()
|
||||
{
|
||||
m_gauge->RemoveCallback(gaugeCallback, this);
|
||||
m_collector->removeGauge(this);
|
||||
collector_->removeGauge(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -53,7 +53,7 @@ class StatsDMetricBase : public List<StatsDMetricBase>::Node
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
do_process() = 0;
|
||||
doProcess() = 0;
|
||||
virtual ~StatsDMetricBase() = default;
|
||||
StatsDMetricBase() = default;
|
||||
StatsDMetricBase(StatsDMetricBase const&) = delete;
|
||||
@@ -71,14 +71,14 @@ public:
|
||||
~StatsDHookImpl() override;
|
||||
|
||||
void
|
||||
do_process() override;
|
||||
doProcess() override;
|
||||
|
||||
StatsDHookImpl&
|
||||
operator=(StatsDHookImpl const&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
HandlerType m_handler;
|
||||
std::shared_ptr<StatsDCollectorImp> impl_;
|
||||
HandlerType handler_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -96,18 +96,18 @@ public:
|
||||
void
|
||||
flush();
|
||||
void
|
||||
do_increment(CounterImpl::value_type amount);
|
||||
doIncrement(CounterImpl::value_type amount);
|
||||
void
|
||||
do_process() override;
|
||||
doProcess() override;
|
||||
|
||||
StatsDCounterImpl&
|
||||
operator=(StatsDCounterImpl const&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
CounterImpl::value_type m_value{0};
|
||||
bool m_dirty{false};
|
||||
std::shared_ptr<StatsDCollectorImp> impl_;
|
||||
std::string name_;
|
||||
CounterImpl::value_type value_{0};
|
||||
bool dirty_{false};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -123,16 +123,16 @@ public:
|
||||
notify(EventImpl::value_type const& value) override;
|
||||
|
||||
void
|
||||
do_notify(EventImpl::value_type const& value);
|
||||
doNotify(EventImpl::value_type const& value);
|
||||
void
|
||||
do_process();
|
||||
doProcess();
|
||||
|
||||
private:
|
||||
StatsDEventImpl&
|
||||
operator=(StatsDEventImpl const&);
|
||||
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
std::shared_ptr<StatsDCollectorImp> impl_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -152,21 +152,21 @@ public:
|
||||
void
|
||||
flush();
|
||||
void
|
||||
do_set(GaugeImpl::value_type value);
|
||||
doSet(GaugeImpl::value_type value);
|
||||
void
|
||||
do_increment(GaugeImpl::difference_type amount);
|
||||
doIncrement(GaugeImpl::difference_type amount);
|
||||
void
|
||||
do_process() override;
|
||||
doProcess() override;
|
||||
|
||||
StatsDGaugeImpl&
|
||||
operator=(StatsDGaugeImpl const&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
GaugeImpl::value_type m_last_value{0};
|
||||
GaugeImpl::value_type m_value{0};
|
||||
bool m_dirty{true};
|
||||
std::shared_ptr<StatsDCollectorImp> impl_;
|
||||
std::string name_;
|
||||
GaugeImpl::value_type lastValue_{0};
|
||||
GaugeImpl::value_type value_{0};
|
||||
bool dirty_{true};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -184,18 +184,18 @@ public:
|
||||
void
|
||||
flush();
|
||||
void
|
||||
do_increment(MeterImpl::value_type amount);
|
||||
doIncrement(MeterImpl::value_type amount);
|
||||
void
|
||||
do_process() override;
|
||||
doProcess() override;
|
||||
|
||||
StatsDMeterImpl&
|
||||
operator=(StatsDMeterImpl const&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<StatsDCollectorImp> m_impl;
|
||||
std::string m_name;
|
||||
MeterImpl::value_type m_value{0};
|
||||
bool m_dirty{false};
|
||||
std::shared_ptr<StatsDCollectorImp> impl_;
|
||||
std::string name_;
|
||||
MeterImpl::value_type value_{0};
|
||||
bool dirty_{false};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -204,42 +204,39 @@ class StatsDCollectorImp : public StatsDCollector,
|
||||
public std::enable_shared_from_this<StatsDCollectorImp>
|
||||
{
|
||||
private:
|
||||
enum {
|
||||
// max_packet_size = 484
|
||||
max_packet_size = 1472
|
||||
};
|
||||
static constexpr auto kMaxPacketSize = 1472;
|
||||
|
||||
Journal m_journal;
|
||||
IP::Endpoint m_address;
|
||||
std::string m_prefix;
|
||||
boost::asio::io_context m_io_context;
|
||||
std::optional<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> m_work;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> m_strand;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
|
||||
boost::asio::ip::udp::socket m_socket;
|
||||
std::deque<std::string> m_data;
|
||||
Journal journal_;
|
||||
IP::Endpoint address_;
|
||||
std::string prefix_;
|
||||
boost::asio::io_context ioContext_;
|
||||
std::optional<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> work_;
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> timer_;
|
||||
boost::asio::ip::udp::socket socket_;
|
||||
std::deque<std::string> data_;
|
||||
std::recursive_mutex metricsLock_;
|
||||
List<StatsDMetricBase> metrics_;
|
||||
|
||||
// Must come last for order of init
|
||||
std::thread m_thread;
|
||||
std::thread thread_;
|
||||
|
||||
static boost::asio::ip::udp::endpoint
|
||||
to_endpoint(IP::Endpoint const& ep)
|
||||
toEndpoint(IP::Endpoint const& ep)
|
||||
{
|
||||
return boost::asio::ip::udp::endpoint(ep.address(), ep.port());
|
||||
}
|
||||
|
||||
public:
|
||||
StatsDCollectorImp(IP::Endpoint address, std::string prefix, Journal journal)
|
||||
: m_journal(journal)
|
||||
, m_address(std::move(address))
|
||||
, m_prefix(std::move(prefix))
|
||||
, m_work(boost::asio::make_work_guard(m_io_context))
|
||||
, m_strand(boost::asio::make_strand(m_io_context))
|
||||
, m_timer(m_io_context)
|
||||
, m_socket(m_io_context)
|
||||
, m_thread(&StatsDCollectorImp::run, this)
|
||||
: journal_(journal)
|
||||
, address_(std::move(address))
|
||||
, prefix_(std::move(prefix))
|
||||
, work_(boost::asio::make_work_guard(ioContext_))
|
||||
, strand_(boost::asio::make_strand(ioContext_))
|
||||
, timer_(ioContext_)
|
||||
, socket_(ioContext_)
|
||||
, thread_(&StatsDCollectorImp::run, this)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -247,43 +244,43 @@ public:
|
||||
{
|
||||
try
|
||||
{
|
||||
m_timer.cancel();
|
||||
timer_.cancel();
|
||||
}
|
||||
catch (boost::system::system_error const&) // NOLINT(bugprone-empty-catch)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
m_work.reset();
|
||||
m_thread.join();
|
||||
work_.reset();
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
Hook
|
||||
make_hook(HookImpl::HandlerType const& handler) override
|
||||
makeHook(HookImpl::HandlerType const& handler) override
|
||||
{
|
||||
return Hook(std::make_shared<detail::StatsDHookImpl>(handler, shared_from_this()));
|
||||
}
|
||||
|
||||
Counter
|
||||
make_counter(std::string const& name) override
|
||||
makeCounter(std::string const& name) override
|
||||
{
|
||||
return Counter(std::make_shared<detail::StatsDCounterImpl>(name, shared_from_this()));
|
||||
}
|
||||
|
||||
Event
|
||||
make_event(std::string const& name) override
|
||||
makeEvent(std::string const& name) override
|
||||
{
|
||||
return Event(std::make_shared<detail::StatsDEventImpl>(name, shared_from_this()));
|
||||
}
|
||||
|
||||
Gauge
|
||||
make_gauge(std::string const& name) override
|
||||
makeGauge(std::string const& name) override
|
||||
{
|
||||
return Gauge(std::make_shared<detail::StatsDGaugeImpl>(name, shared_from_this()));
|
||||
}
|
||||
|
||||
Meter
|
||||
make_meter(std::string const& name) override
|
||||
makeMeter(std::string const& name) override
|
||||
{
|
||||
return Meter(std::make_shared<detail::StatsDMeterImpl>(name, shared_from_this()));
|
||||
}
|
||||
@@ -293,50 +290,50 @@ public:
|
||||
void
|
||||
add(StatsDMetricBase& metric)
|
||||
{
|
||||
std::lock_guard const _(metricsLock_);
|
||||
metrics_.push_back(metric);
|
||||
std::scoped_lock const _(metricsLock_);
|
||||
metrics_.pushBack(metric);
|
||||
}
|
||||
|
||||
void
|
||||
remove(StatsDMetricBase& metric)
|
||||
{
|
||||
std::lock_guard const _(metricsLock_);
|
||||
metrics_.erase(metrics_.iterator_to(metric));
|
||||
std::scoped_lock const _(metricsLock_);
|
||||
metrics_.erase(metrics_.iteratorTo(metric));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
boost::asio::io_context&
|
||||
get_io_context()
|
||||
getIoContext()
|
||||
{
|
||||
return m_io_context;
|
||||
return ioContext_;
|
||||
}
|
||||
|
||||
std::string const&
|
||||
prefix() const
|
||||
{
|
||||
return m_prefix;
|
||||
return prefix_;
|
||||
}
|
||||
|
||||
void
|
||||
do_post_buffer(std::string const& buffer)
|
||||
doPostBuffer(std::string const& buffer)
|
||||
{
|
||||
m_data.emplace_back(buffer);
|
||||
data_.emplace_back(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
post_buffer(std::string&& buffer)
|
||||
postBuffer(std::string&& buffer)
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_io_context,
|
||||
ioContext_,
|
||||
boost::asio::bind_executor(
|
||||
m_strand, std::bind(&StatsDCollectorImp::do_post_buffer, this, std::move(buffer))));
|
||||
strand_, std::bind(&StatsDCollectorImp::doPostBuffer, this, std::move(buffer))));
|
||||
}
|
||||
|
||||
// The keepAlive parameter makes sure the buffers sent to
|
||||
// boost::asio::async_send do not go away until the call is finished
|
||||
void
|
||||
on_send(
|
||||
onSend(
|
||||
std::shared_ptr<std::deque<std::string>> /*keepAlive*/,
|
||||
boost::system::error_code ec,
|
||||
std::size_t)
|
||||
@@ -346,7 +343,7 @@ public:
|
||||
|
||||
if (ec)
|
||||
{
|
||||
if (auto stream = m_journal.error())
|
||||
if (auto stream = journal_.error())
|
||||
stream << "async_send failed: " << ec.message();
|
||||
return;
|
||||
}
|
||||
@@ -368,35 +365,35 @@ public:
|
||||
|
||||
// Send what we have
|
||||
void
|
||||
send_buffers()
|
||||
sendBuffers()
|
||||
{
|
||||
if (m_data.empty())
|
||||
if (data_.empty())
|
||||
return;
|
||||
|
||||
// Break up the array of strings into blocks
|
||||
// that each fit into one UDP packet.
|
||||
//
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.reserve(m_data.size());
|
||||
buffers.reserve(data_.size());
|
||||
std::size_t size(0);
|
||||
|
||||
auto keepAlive = std::make_shared<std::deque<std::string>>(std::move(m_data));
|
||||
m_data.clear();
|
||||
auto keepAlive = std::make_shared<std::deque<std::string>>(std::move(data_));
|
||||
data_.clear();
|
||||
|
||||
for (auto const& s : *keepAlive)
|
||||
{
|
||||
std::size_t const length(s.size());
|
||||
XRPL_ASSERT(
|
||||
!s.empty(),
|
||||
"beast::insight::detail::StatsDCollectorImp::send_buffers : "
|
||||
"beast::insight::detail::StatsDCollectorImp::sendBuffers : "
|
||||
"non-empty payload");
|
||||
if (!buffers.empty() && (size + length) > max_packet_size)
|
||||
if (!buffers.empty() && (size + length) > kMaxPacketSize)
|
||||
{
|
||||
log(buffers);
|
||||
m_socket.async_send(
|
||||
socket_.async_send(
|
||||
buffers,
|
||||
std::bind(
|
||||
&StatsDCollectorImp::on_send,
|
||||
&StatsDCollectorImp::onSend,
|
||||
this,
|
||||
keepAlive,
|
||||
std::placeholders::_1,
|
||||
@@ -412,10 +409,10 @@ public:
|
||||
if (!buffers.empty())
|
||||
{
|
||||
log(buffers);
|
||||
m_socket.async_send(
|
||||
socket_.async_send(
|
||||
buffers,
|
||||
std::bind(
|
||||
&StatsDCollectorImp::on_send,
|
||||
&StatsDCollectorImp::onSend,
|
||||
this,
|
||||
keepAlive,
|
||||
std::placeholders::_1,
|
||||
@@ -424,34 +421,34 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
set_timer()
|
||||
setTimer()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
m_timer.expires_after(1s);
|
||||
m_timer.async_wait(std::bind(&StatsDCollectorImp::on_timer, this, std::placeholders::_1));
|
||||
timer_.expires_after(1s);
|
||||
timer_.async_wait(std::bind(&StatsDCollectorImp::onTimer, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void
|
||||
on_timer(boost::system::error_code ec)
|
||||
onTimer(boost::system::error_code ec)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
if (ec)
|
||||
{
|
||||
if (auto stream = m_journal.error())
|
||||
stream << "on_timer failed: " << ec.message();
|
||||
if (auto stream = journal_.error())
|
||||
stream << "onTimer failed: " << ec.message();
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard const _(metricsLock_);
|
||||
std::scoped_lock const _(metricsLock_);
|
||||
|
||||
for (auto& m : metrics_)
|
||||
m.do_process();
|
||||
m.doProcess();
|
||||
|
||||
send_buffers();
|
||||
sendBuffers();
|
||||
|
||||
set_timer();
|
||||
setTimer();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -459,43 +456,43 @@ public:
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
if (m_socket.connect(to_endpoint(m_address), ec))
|
||||
if (socket_.connect(toEndpoint(address_), ec))
|
||||
{
|
||||
if (auto stream = m_journal.error())
|
||||
if (auto stream = journal_.error())
|
||||
stream << "Connect failed: " << ec.message();
|
||||
return;
|
||||
}
|
||||
|
||||
set_timer();
|
||||
setTimer();
|
||||
|
||||
m_io_context.run();
|
||||
ioContext_.run();
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
m_socket.shutdown(boost::asio::ip::udp::socket::shutdown_send, ec);
|
||||
socket_.shutdown(boost::asio::ip::udp::socket::shutdown_send, ec);
|
||||
|
||||
m_socket.close();
|
||||
socket_.close();
|
||||
|
||||
m_io_context.poll();
|
||||
ioContext_.poll();
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
StatsDHookImpl::StatsDHookImpl(HandlerType handler, std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_handler(std::move(handler))
|
||||
: impl_(impl), handler_(std::move(handler))
|
||||
{
|
||||
m_impl->add(*this);
|
||||
impl_->add(*this);
|
||||
}
|
||||
|
||||
StatsDHookImpl::~StatsDHookImpl()
|
||||
{
|
||||
m_impl->remove(*this);
|
||||
impl_->remove(*this);
|
||||
}
|
||||
|
||||
void
|
||||
StatsDHookImpl::do_process()
|
||||
StatsDHookImpl::doProcess()
|
||||
{
|
||||
m_handler();
|
||||
handler_();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -503,23 +500,23 @@ StatsDHookImpl::do_process()
|
||||
StatsDCounterImpl::StatsDCounterImpl(
|
||||
std::string name,
|
||||
std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(std::move(name))
|
||||
: impl_(impl), name_(std::move(name))
|
||||
{
|
||||
m_impl->add(*this);
|
||||
impl_->add(*this);
|
||||
}
|
||||
|
||||
StatsDCounterImpl::~StatsDCounterImpl()
|
||||
{
|
||||
m_impl->remove(*this);
|
||||
impl_->remove(*this);
|
||||
}
|
||||
|
||||
void
|
||||
StatsDCounterImpl::increment(CounterImpl::value_type amount)
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_impl->get_io_context(),
|
||||
impl_->getIoContext(),
|
||||
std::bind(
|
||||
&StatsDCounterImpl::do_increment,
|
||||
&StatsDCounterImpl::doIncrement,
|
||||
std::static_pointer_cast<StatsDCounterImpl>(shared_from_this()),
|
||||
amount));
|
||||
}
|
||||
@@ -527,26 +524,26 @@ StatsDCounterImpl::increment(CounterImpl::value_type amount)
|
||||
void
|
||||
StatsDCounterImpl::flush()
|
||||
{
|
||||
if (m_dirty)
|
||||
if (dirty_)
|
||||
{
|
||||
m_dirty = false;
|
||||
dirty_ = false;
|
||||
std::stringstream ss;
|
||||
ss << m_impl->prefix() << "." << m_name << ":" << m_value << "|c"
|
||||
ss << impl_->prefix() << "." << name_ << ":" << value_ << "|c"
|
||||
<< "\n";
|
||||
m_value = 0;
|
||||
m_impl->post_buffer(ss.str());
|
||||
value_ = 0;
|
||||
impl_->postBuffer(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StatsDCounterImpl::do_increment(CounterImpl::value_type amount)
|
||||
StatsDCounterImpl::doIncrement(CounterImpl::value_type amount)
|
||||
{
|
||||
m_value += amount;
|
||||
m_dirty = true;
|
||||
value_ += amount;
|
||||
dirty_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
StatsDCounterImpl::do_process()
|
||||
StatsDCounterImpl::doProcess()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
@@ -554,7 +551,7 @@ StatsDCounterImpl::do_process()
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
StatsDEventImpl::StatsDEventImpl(std::string name, std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(std::move(name))
|
||||
: impl_(impl), name_(std::move(name))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -562,45 +559,45 @@ void
|
||||
StatsDEventImpl::notify(EventImpl::value_type const& value)
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_impl->get_io_context(),
|
||||
impl_->getIoContext(),
|
||||
std::bind(
|
||||
&StatsDEventImpl::do_notify,
|
||||
&StatsDEventImpl::doNotify,
|
||||
std::static_pointer_cast<StatsDEventImpl>(shared_from_this()),
|
||||
value));
|
||||
}
|
||||
|
||||
void
|
||||
StatsDEventImpl::do_notify(EventImpl::value_type const& value)
|
||||
StatsDEventImpl::doNotify(EventImpl::value_type const& value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << m_impl->prefix() << "." << m_name << ":" << value.count() << "|ms"
|
||||
ss << impl_->prefix() << "." << name_ << ":" << value.count() << "|ms"
|
||||
<< "\n";
|
||||
m_impl->post_buffer(ss.str());
|
||||
impl_->postBuffer(ss.str());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
StatsDGaugeImpl::StatsDGaugeImpl(std::string name, std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(std::move(name))
|
||||
: impl_(impl), name_(std::move(name))
|
||||
{
|
||||
// Start dirty so the initial value (0) is emitted on the first flush.
|
||||
// Without this, gauges whose value never changes from 0 would never
|
||||
// appear in downstream metric stores (e.g. Prometheus via StatsD).
|
||||
m_impl->add(*this);
|
||||
impl_->add(*this);
|
||||
}
|
||||
|
||||
StatsDGaugeImpl::~StatsDGaugeImpl()
|
||||
{
|
||||
m_impl->remove(*this);
|
||||
impl_->remove(*this);
|
||||
}
|
||||
|
||||
void
|
||||
StatsDGaugeImpl::set(GaugeImpl::value_type value)
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_impl->get_io_context(),
|
||||
impl_->getIoContext(),
|
||||
std::bind(
|
||||
&StatsDGaugeImpl::do_set,
|
||||
&StatsDGaugeImpl::doSet,
|
||||
std::static_pointer_cast<StatsDGaugeImpl>(shared_from_this()),
|
||||
value));
|
||||
}
|
||||
@@ -609,9 +606,9 @@ void
|
||||
StatsDGaugeImpl::increment(GaugeImpl::difference_type amount)
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_impl->get_io_context(),
|
||||
impl_->getIoContext(),
|
||||
std::bind(
|
||||
&StatsDGaugeImpl::do_increment,
|
||||
&StatsDGaugeImpl::doIncrement,
|
||||
std::static_pointer_cast<StatsDGaugeImpl>(shared_from_this()),
|
||||
amount));
|
||||
}
|
||||
@@ -619,38 +616,38 @@ StatsDGaugeImpl::increment(GaugeImpl::difference_type amount)
|
||||
void
|
||||
StatsDGaugeImpl::flush()
|
||||
{
|
||||
if (m_dirty)
|
||||
if (dirty_)
|
||||
{
|
||||
m_dirty = false;
|
||||
dirty_ = false;
|
||||
std::stringstream ss;
|
||||
ss << m_impl->prefix() << "." << m_name << ":" << m_value << "|g"
|
||||
ss << impl_->prefix() << "." << name_ << ":" << value_ << "|g"
|
||||
<< "\n";
|
||||
m_impl->post_buffer(ss.str());
|
||||
impl_->postBuffer(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StatsDGaugeImpl::do_set(GaugeImpl::value_type value)
|
||||
StatsDGaugeImpl::doSet(GaugeImpl::value_type value)
|
||||
{
|
||||
m_value = value;
|
||||
value_ = value;
|
||||
|
||||
if (m_value != m_last_value)
|
||||
if (value_ != lastValue_)
|
||||
{
|
||||
m_last_value = m_value;
|
||||
m_dirty = true;
|
||||
lastValue_ = value_;
|
||||
dirty_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StatsDGaugeImpl::do_increment(GaugeImpl::difference_type amount)
|
||||
StatsDGaugeImpl::doIncrement(GaugeImpl::difference_type amount)
|
||||
{
|
||||
GaugeImpl::value_type value(m_value);
|
||||
GaugeImpl::value_type value(value_);
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
GaugeImpl::value_type const d(static_cast<GaugeImpl::value_type>(amount));
|
||||
value += (d >= std::numeric_limits<GaugeImpl::value_type>::max() - m_value)
|
||||
? std::numeric_limits<GaugeImpl::value_type>::max() - m_value
|
||||
value += (d >= std::numeric_limits<GaugeImpl::value_type>::max() - value_)
|
||||
? std::numeric_limits<GaugeImpl::value_type>::max() - value_
|
||||
: d;
|
||||
}
|
||||
else if (amount < 0)
|
||||
@@ -659,11 +656,11 @@ StatsDGaugeImpl::do_increment(GaugeImpl::difference_type amount)
|
||||
value = (d >= value) ? 0 : value - d;
|
||||
}
|
||||
|
||||
do_set(value);
|
||||
doSet(value);
|
||||
}
|
||||
|
||||
void
|
||||
StatsDGaugeImpl::do_process()
|
||||
StatsDGaugeImpl::doProcess()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
@@ -671,23 +668,23 @@ StatsDGaugeImpl::do_process()
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
StatsDMeterImpl::StatsDMeterImpl(std::string name, std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(std::move(name))
|
||||
: impl_(impl), name_(std::move(name))
|
||||
{
|
||||
m_impl->add(*this);
|
||||
impl_->add(*this);
|
||||
}
|
||||
|
||||
StatsDMeterImpl::~StatsDMeterImpl()
|
||||
{
|
||||
m_impl->remove(*this);
|
||||
impl_->remove(*this);
|
||||
}
|
||||
|
||||
void
|
||||
StatsDMeterImpl::increment(MeterImpl::value_type amount)
|
||||
{
|
||||
boost::asio::dispatch(
|
||||
m_impl->get_io_context(),
|
||||
impl_->getIoContext(),
|
||||
std::bind(
|
||||
&StatsDMeterImpl::do_increment,
|
||||
&StatsDMeterImpl::doIncrement,
|
||||
std::static_pointer_cast<StatsDMeterImpl>(shared_from_this()),
|
||||
amount));
|
||||
}
|
||||
@@ -695,26 +692,26 @@ StatsDMeterImpl::increment(MeterImpl::value_type amount)
|
||||
void
|
||||
StatsDMeterImpl::flush()
|
||||
{
|
||||
if (m_dirty)
|
||||
if (dirty_)
|
||||
{
|
||||
m_dirty = false;
|
||||
dirty_ = false;
|
||||
std::stringstream ss;
|
||||
ss << m_impl->prefix() << "." << m_name << ":" << m_value << "|m"
|
||||
ss << impl_->prefix() << "." << name_ << ":" << value_ << "|m"
|
||||
<< "\n";
|
||||
m_value = 0;
|
||||
m_impl->post_buffer(ss.str());
|
||||
value_ = 0;
|
||||
impl_->postBuffer(ss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StatsDMeterImpl::do_increment(MeterImpl::value_type amount)
|
||||
StatsDMeterImpl::doIncrement(MeterImpl::value_type amount)
|
||||
{
|
||||
m_value += amount;
|
||||
m_dirty = true;
|
||||
value_ += amount;
|
||||
dirty_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
StatsDMeterImpl::do_process()
|
||||
StatsDMeterImpl::doProcess()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
@@ -724,7 +721,7 @@ StatsDMeterImpl::do_process()
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::shared_ptr<StatsDCollector>
|
||||
StatsDCollector::New(IP::Endpoint const& address, std::string const& prefix, Journal journal)
|
||||
StatsDCollector::make(IP::Endpoint const& address, std::string const& prefix, Journal journal)
|
||||
{
|
||||
return std::make_shared<detail::StatsDCollectorImp>(address, prefix, journal);
|
||||
}
|
||||
|
||||
@@ -8,25 +8,25 @@
|
||||
namespace beast::IP {
|
||||
|
||||
Endpoint
|
||||
from_asio(boost::asio::ip::address const& address)
|
||||
fromAsio(boost::asio::ip::address const& address)
|
||||
{
|
||||
return Endpoint{address};
|
||||
}
|
||||
|
||||
Endpoint
|
||||
from_asio(boost::asio::ip::tcp::endpoint const& endpoint)
|
||||
fromAsio(boost::asio::ip::tcp::endpoint const& endpoint)
|
||||
{
|
||||
return Endpoint{endpoint.address(), endpoint.port()};
|
||||
}
|
||||
|
||||
boost::asio::ip::address
|
||||
to_asio_address(Endpoint const& endpoint)
|
||||
toAsioAddress(Endpoint const& endpoint)
|
||||
{
|
||||
return endpoint.address();
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::endpoint
|
||||
to_asio_endpoint(Endpoint const& endpoint)
|
||||
toAsioEndpoint(Endpoint const& endpoint)
|
||||
{
|
||||
return boost::asio::ip::tcp::endpoint{endpoint.address(), endpoint.port()};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace beast::IP {
|
||||
|
||||
bool
|
||||
is_private(AddressV4 const& addr)
|
||||
isPrivate(AddressV4 const& addr)
|
||||
{
|
||||
return ((addr.to_uint() & 0xff000000) == 0x0a000000) || // Prefix /8, 10. #.#.#
|
||||
((addr.to_uint() & 0xfff00000) == 0xac100000) || // Prefix /12 172. 16.#.# - 172.31.#.#
|
||||
@@ -12,16 +12,54 @@ is_private(AddressV4 const& addr)
|
||||
}
|
||||
|
||||
bool
|
||||
is_public(AddressV4 const& addr)
|
||||
isPublic(AddressV4 const& addr)
|
||||
{
|
||||
return !is_private(addr) && !addr.is_multicast();
|
||||
if (isPrivate(addr))
|
||||
return false;
|
||||
if (addr.is_multicast())
|
||||
return false;
|
||||
|
||||
auto const ip = addr.to_uint();
|
||||
|
||||
// 0.0.0.0/8 "This network"
|
||||
if ((ip & 0xff000000) == 0x00000000)
|
||||
return false;
|
||||
// 100.64.0.0/10 Shared Address Space (CGNAT) - RFC 6598
|
||||
if ((ip & 0xffc00000) == 0x64400000)
|
||||
return false;
|
||||
// 169.254.0.0/16 Link-local
|
||||
if ((ip & 0xffff0000) == 0xa9fe0000)
|
||||
return false;
|
||||
// 192.0.0.0/24 IETF Protocol Assignments - RFC 6890
|
||||
if ((ip & 0xffffff00) == 0xc0000000)
|
||||
return false;
|
||||
// 192.0.2.0/24 TEST-NET-1 (documentation) - RFC 5737
|
||||
if ((ip & 0xffffff00) == 0xc0000200)
|
||||
return false;
|
||||
// 192.88.99.0/24 6to4 Relay Anycast (deprecated) - RFC 7526
|
||||
if ((ip & 0xffffff00) == 0xc0586300)
|
||||
return false;
|
||||
// 198.18.0.0/15 Benchmarking - RFC 2544
|
||||
if ((ip & 0xfffe0000) == 0xc6120000)
|
||||
return false;
|
||||
// 198.51.100.0/24 TEST-NET-2 (documentation) - RFC 5737
|
||||
if ((ip & 0xffffff00) == 0xc6336400)
|
||||
return false;
|
||||
// 203.0.113.0/24 TEST-NET-3 (documentation) - RFC 5737
|
||||
if ((ip & 0xffffff00) == 0xcb007100)
|
||||
return false;
|
||||
// 240.0.0.0/4 Reserved for future use - RFC 1112
|
||||
if ((ip & 0xf0000000) == 0xf0000000)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char
|
||||
get_class(AddressV4 const& addr)
|
||||
getClass(AddressV4 const& addr)
|
||||
{
|
||||
static char const* table = "AAAABBCD"; // cspell:disable-line
|
||||
return table[(addr.to_uint() & 0xE0000000) >> 29];
|
||||
static char const* kTable = "AAAABBCD"; // cspell:disable-line
|
||||
return kTable[(addr.to_uint() & 0xE0000000) >> 29];
|
||||
}
|
||||
|
||||
} // namespace beast::IP
|
||||
|
||||
@@ -7,19 +7,55 @@
|
||||
namespace beast::IP {
|
||||
|
||||
bool
|
||||
is_private(AddressV6 const& addr)
|
||||
isPrivate(AddressV6 const& addr)
|
||||
{
|
||||
return (
|
||||
((addr.to_bytes()[0] & 0xfd) != 0) || // TODO fc00::/8 too ?
|
||||
(addr.is_v4_mapped() &&
|
||||
is_private(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr))));
|
||||
// fc00::/7 - Unique Local Address (ULA), covers fc00:: and fd00::
|
||||
if ((addr.to_bytes()[0] & 0xfe) == 0xfc)
|
||||
return true;
|
||||
if (addr.is_v4_mapped())
|
||||
return isPrivate(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
is_public(AddressV6 const& addr)
|
||||
isPublic(AddressV6 const& addr)
|
||||
{
|
||||
// TODO is this correct?
|
||||
return !is_private(addr) && !addr.is_multicast();
|
||||
if (addr.is_loopback())
|
||||
return false;
|
||||
if (addr.is_v4_mapped())
|
||||
return isPublic(boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, addr));
|
||||
if (isPrivate(addr))
|
||||
return false;
|
||||
if (addr.is_multicast())
|
||||
return false;
|
||||
if (addr.is_unspecified())
|
||||
return false;
|
||||
|
||||
auto const b = addr.to_bytes();
|
||||
|
||||
// fe80::/10 - Link-local
|
||||
if (b[0] == 0xfe && (b[1] & 0xc0) == 0x80)
|
||||
return false;
|
||||
// 100::/64 - Discard prefix (RFC 6666)
|
||||
if (b[0] == 0x01 && b[1] == 0x00 && b[2] == 0 && b[3] == 0 && b[4] == 0 && b[5] == 0 &&
|
||||
b[6] == 0 && b[7] == 0)
|
||||
return false;
|
||||
// 2001:db8::/32 - Documentation (RFC 3849)
|
||||
if (b[0] == 0x20 && b[1] == 0x01 && b[2] == 0x0d && b[3] == 0xb8)
|
||||
return false;
|
||||
// 2001::/32 - IETF Protocol Assignments / Teredo (RFC 4380)
|
||||
if (b[0] == 0x20 && b[1] == 0x01 && b[2] == 0x00 && b[3] == 0x00)
|
||||
return false;
|
||||
// 2001:20::/28 - ORCHIDv2 (RFC 7343)
|
||||
// 28-bit prefix: 0x2001002 => b[0]=0x20, b[1]=0x01, b[2]=0x00,
|
||||
// top nibble of b[3]=0x2
|
||||
if (b[0] == 0x20 && b[1] == 0x01 && b[2] == 0x00 && (b[3] & 0xf0) == 0x20)
|
||||
return false;
|
||||
// 2002::/16 - 6to4 (RFC 3056, deprecated by RFC 7526)
|
||||
if (b[0] == 0x20 && b[1] == 0x02)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace beast::IP
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
|
||||
namespace beast::IP {
|
||||
|
||||
Endpoint::Endpoint() : m_port(0)
|
||||
Endpoint::Endpoint() : port_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Endpoint::Endpoint(Address addr, Port port) : m_addr(std::move(addr)), m_port(port)
|
||||
Endpoint::Endpoint(Address addr, Port port) : addr_(std::move(addr)), port_(port)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<Endpoint>
|
||||
Endpoint::from_string_checked(std::string const& s)
|
||||
Endpoint::fromStringChecked(std::string const& s)
|
||||
{
|
||||
if (s.size() <= 64)
|
||||
{
|
||||
@@ -39,15 +39,15 @@ Endpoint::from_string_checked(std::string const& s)
|
||||
}
|
||||
|
||||
Endpoint
|
||||
Endpoint::from_string(std::string const& s)
|
||||
Endpoint::fromString(std::string const& s)
|
||||
{
|
||||
if (std::optional<Endpoint> const result = from_string_checked(s))
|
||||
if (std::optional<Endpoint> const result = fromStringChecked(s))
|
||||
return *result;
|
||||
return Endpoint{};
|
||||
}
|
||||
|
||||
std::string
|
||||
Endpoint::to_string() const
|
||||
Endpoint::toString() const
|
||||
{
|
||||
std::string s;
|
||||
s.reserve(
|
||||
|
||||
@@ -12,14 +12,14 @@ namespace beast {
|
||||
class NullJournalSink : public Journal::Sink
|
||||
{
|
||||
public:
|
||||
NullJournalSink() : Sink(severities::kDisabled, false)
|
||||
NullJournalSink() : Sink(Severity::Disabled, false)
|
||||
{
|
||||
}
|
||||
|
||||
~NullJournalSink() override = default;
|
||||
|
||||
[[nodiscard]] bool
|
||||
active(severities::Severity) const override
|
||||
active(Severity) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -35,24 +35,24 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] severities::Severity
|
||||
[[nodiscard]] Severity
|
||||
threshold() const override
|
||||
{
|
||||
return severities::kDisabled;
|
||||
return Severity::Disabled;
|
||||
}
|
||||
|
||||
void
|
||||
threshold(severities::Severity) override
|
||||
threshold(Severity) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(severities::Severity, std::string const&) override
|
||||
write(Severity, std::string const&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(severities::Severity, std::string const&) override
|
||||
writeAlways(Severity, std::string const&) override
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -62,13 +62,13 @@ public:
|
||||
Journal::Sink&
|
||||
Journal::getNullSink()
|
||||
{
|
||||
static NullJournalSink sink;
|
||||
return sink;
|
||||
static NullJournalSink kSink;
|
||||
return kSink;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Journal::Sink::Sink(Severity thresh, bool console) : thresh_(thresh), m_console(console)
|
||||
Journal::Sink::Sink(Severity thresh, bool console) : thresh_(thresh), console_(console)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -83,16 +83,16 @@ Journal::Sink::active(Severity level) const
|
||||
bool
|
||||
Journal::Sink::console() const
|
||||
{
|
||||
return m_console;
|
||||
return console_;
|
||||
}
|
||||
|
||||
void
|
||||
Journal::Sink::console(bool output)
|
||||
{
|
||||
m_console = output;
|
||||
console_ = output;
|
||||
}
|
||||
|
||||
severities::Severity
|
||||
Severity
|
||||
Journal::Sink::threshold() const
|
||||
{
|
||||
return thresh_;
|
||||
@@ -106,30 +106,30 @@ Journal::Sink::threshold(Severity thresh)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Journal::ScopedStream::ScopedStream(Sink& sink, Severity level) : m_sink(sink), m_level(level)
|
||||
Journal::ScopedStream::ScopedStream(Sink& sink, Severity level) : sink_(sink), level_(level)
|
||||
{
|
||||
// Modifiers applied from all ctors
|
||||
m_ostream << std::boolalpha << std::showbase;
|
||||
ostream_ << std::boolalpha << std::showbase;
|
||||
}
|
||||
|
||||
Journal::ScopedStream::ScopedStream(Stream const& stream, std::ostream& manip(std::ostream&))
|
||||
: ScopedStream(stream.sink(), stream.level())
|
||||
{
|
||||
m_ostream << manip;
|
||||
ostream_ << manip;
|
||||
}
|
||||
|
||||
Journal::ScopedStream::~ScopedStream()
|
||||
{
|
||||
std::string const& s(m_ostream.str());
|
||||
std::string const& s(ostream_.str());
|
||||
if (!s.empty())
|
||||
{
|
||||
if (s == "\n")
|
||||
{
|
||||
m_sink.write(m_level, "");
|
||||
sink_.write(level_, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sink.write(m_level, s);
|
||||
sink_.write(level_, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ Journal::ScopedStream::~ScopedStream()
|
||||
std::ostream&
|
||||
Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return m_ostream << manip;
|
||||
return ostream_ << manip;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace beast {
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PropertyStream::Item::Item(Source* source) : m_source(source)
|
||||
PropertyStream::Item::Item(Source* source) : source_(source)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyStream::Source&
|
||||
PropertyStream::Item::source() const
|
||||
{
|
||||
return *m_source;
|
||||
return *source_;
|
||||
}
|
||||
|
||||
PropertyStream::Source*
|
||||
@@ -44,25 +44,25 @@ PropertyStream::Item::operator*() const
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PropertyStream::Proxy::Proxy(Map const& map, std::string key) : m_map(&map), m_key(std::move(key))
|
||||
PropertyStream::Proxy::Proxy(Map const& map, std::string key) : map_(&map), key_(std::move(key))
|
||||
{
|
||||
}
|
||||
|
||||
PropertyStream::Proxy::Proxy(Proxy const& other) : m_map(other.m_map), m_key(other.m_key)
|
||||
PropertyStream::Proxy::Proxy(Proxy const& other) : map_(other.map_), key_(other.key_)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyStream::Proxy::~Proxy()
|
||||
{
|
||||
std::string const s(m_ostream.str());
|
||||
std::string const s(ostream_.str());
|
||||
if (!s.empty())
|
||||
m_map->add(m_key, s);
|
||||
map_->add(key_, s);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
PropertyStream::Proxy::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return m_ostream << manip;
|
||||
return ostream_ << manip;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -71,40 +71,40 @@ PropertyStream::Proxy::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PropertyStream::Map::Map(PropertyStream& stream) : m_stream(stream)
|
||||
PropertyStream::Map::Map(PropertyStream& stream) : stream_(stream)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyStream::Map::Map(Set& parent) : m_stream(parent.stream())
|
||||
PropertyStream::Map::Map(Set& parent) : stream_(parent.stream())
|
||||
{
|
||||
m_stream.map_begin();
|
||||
stream_.mapBegin();
|
||||
}
|
||||
|
||||
PropertyStream::Map::Map(std::string const& key, Map& map) : m_stream(map.stream())
|
||||
PropertyStream::Map::Map(std::string const& key, Map& map) : stream_(map.stream())
|
||||
{
|
||||
m_stream.map_begin(key);
|
||||
stream_.mapBegin(key);
|
||||
}
|
||||
|
||||
PropertyStream::Map::Map(std::string const& key, PropertyStream& stream) : m_stream(stream)
|
||||
PropertyStream::Map::Map(std::string const& key, PropertyStream& stream) : stream_(stream)
|
||||
{
|
||||
m_stream.map_begin(key);
|
||||
stream_.mapBegin(key);
|
||||
}
|
||||
|
||||
PropertyStream::Map::~Map()
|
||||
{
|
||||
m_stream.map_end();
|
||||
stream_.mapEnd();
|
||||
}
|
||||
|
||||
PropertyStream&
|
||||
PropertyStream::Map::stream()
|
||||
{
|
||||
return m_stream;
|
||||
return stream_;
|
||||
}
|
||||
|
||||
PropertyStream const&
|
||||
PropertyStream::Map::stream() const
|
||||
{
|
||||
return m_stream;
|
||||
return stream_;
|
||||
}
|
||||
|
||||
PropertyStream::Proxy
|
||||
@@ -119,31 +119,31 @@ PropertyStream::Map::operator[](std::string const& key)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PropertyStream::Set::Set(std::string const& key, Map& map) : m_stream(map.stream())
|
||||
PropertyStream::Set::Set(std::string const& key, Map& map) : stream_(map.stream())
|
||||
{
|
||||
m_stream.array_begin(key);
|
||||
stream_.arrayBegin(key);
|
||||
}
|
||||
|
||||
PropertyStream::Set::Set(std::string const& key, PropertyStream& stream) : m_stream(stream)
|
||||
PropertyStream::Set::Set(std::string const& key, PropertyStream& stream) : stream_(stream)
|
||||
{
|
||||
m_stream.array_begin(key);
|
||||
stream_.arrayBegin(key);
|
||||
}
|
||||
|
||||
PropertyStream::Set::~Set()
|
||||
{
|
||||
m_stream.array_end();
|
||||
stream_.arrayEnd();
|
||||
}
|
||||
|
||||
PropertyStream&
|
||||
PropertyStream::Set::stream()
|
||||
{
|
||||
return m_stream;
|
||||
return stream_;
|
||||
}
|
||||
|
||||
PropertyStream const&
|
||||
PropertyStream::Set::stream() const
|
||||
{
|
||||
return m_stream;
|
||||
return stream_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -152,13 +152,13 @@ PropertyStream::Set::stream() const
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PropertyStream::Source::Source(std::string name) : m_name(std::move(name)), item_(this)
|
||||
PropertyStream::Source::Source(std::string name) : name_(std::move(name)), item_(this)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyStream::Source::~Source()
|
||||
{
|
||||
std::lock_guard const _(lock_);
|
||||
std::scoped_lock const _(lock_);
|
||||
if (parent_ != nullptr)
|
||||
parent_->remove(*this);
|
||||
removeAll();
|
||||
@@ -167,42 +167,38 @@ PropertyStream::Source::~Source()
|
||||
std::string const&
|
||||
PropertyStream::Source::name() const
|
||||
{
|
||||
return m_name;
|
||||
return name_;
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::Source::add(Source& source)
|
||||
{
|
||||
std::lock(lock_, source.lock_);
|
||||
std::lock_guard const lk1(lock_, std::adopt_lock);
|
||||
std::lock_guard const lk2(source.lock_, std::adopt_lock);
|
||||
std::scoped_lock const lock(lock_, source.lock_);
|
||||
|
||||
XRPL_ASSERT(
|
||||
source.parent_ == nullptr, "beast::PropertyStream::Source::add : null source parent");
|
||||
children_.push_back(source.item_);
|
||||
children_.pushBack(source.item_);
|
||||
source.parent_ = this;
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::Source::remove(Source& child)
|
||||
{
|
||||
std::lock(lock_, child.lock_);
|
||||
std::lock_guard const lk1(lock_, std::adopt_lock);
|
||||
std::lock_guard const lk2(child.lock_, std::adopt_lock);
|
||||
std::scoped_lock const lock(lock_, child.lock_);
|
||||
|
||||
XRPL_ASSERT(
|
||||
child.parent_ == this, "beast::PropertyStream::Source::remove : child parent match");
|
||||
children_.erase(children_.iterator_to(child.item_));
|
||||
children_.erase(children_.iteratorTo(child.item_));
|
||||
child.parent_ = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::Source::removeAll()
|
||||
{
|
||||
std::lock_guard const _(lock_);
|
||||
std::scoped_lock const _(lock_);
|
||||
for (auto iter = children_.begin(); iter != children_.end();)
|
||||
{
|
||||
std::lock_guard const _cl((*iter)->lock_);
|
||||
std::scoped_lock const cl((*iter)->lock_);
|
||||
remove(*(*iter));
|
||||
}
|
||||
}
|
||||
@@ -210,19 +206,19 @@ PropertyStream::Source::removeAll()
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
PropertyStream::Source::write_one(PropertyStream& stream)
|
||||
PropertyStream::Source::writeOne(PropertyStream& stream)
|
||||
{
|
||||
Map map(m_name, stream);
|
||||
Map map(name_, stream);
|
||||
onWrite(map);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::Source::write(PropertyStream& stream)
|
||||
{
|
||||
Map map(m_name, stream);
|
||||
Map map(name_, stream);
|
||||
onWrite(map);
|
||||
|
||||
std::lock_guard const _(lock_);
|
||||
std::scoped_lock const _(lock_);
|
||||
|
||||
for (auto& child : children_)
|
||||
child.source().write(stream);
|
||||
@@ -242,32 +238,32 @@ PropertyStream::Source::write(PropertyStream& stream, std::string const& path)
|
||||
}
|
||||
else
|
||||
{
|
||||
result.first->write_one(stream);
|
||||
result.first->writeOne(stream);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<PropertyStream::Source*, bool>
|
||||
PropertyStream::Source::find(std::string path)
|
||||
{
|
||||
bool const deep(peel_trailing_slashstar(&path));
|
||||
bool const rooted(peel_leading_slash(&path));
|
||||
bool const deep(peelTrailingSlashstar(&path));
|
||||
bool const rooted(peelLeadingSlash(&path));
|
||||
Source* source(this);
|
||||
if (!path.empty())
|
||||
{
|
||||
if (!rooted)
|
||||
{
|
||||
std::string const name(peel_name(&path));
|
||||
source = find_one_deep(name);
|
||||
std::string const name(peelName(&path));
|
||||
source = findOneDeep(name);
|
||||
if (source == nullptr)
|
||||
return std::make_pair(nullptr, deep);
|
||||
}
|
||||
source = source->find_path(path);
|
||||
source = source->findPath(path);
|
||||
}
|
||||
return std::make_pair(source, deep);
|
||||
}
|
||||
|
||||
bool
|
||||
PropertyStream::Source::peel_leading_slash(std::string* path)
|
||||
PropertyStream::Source::peelLeadingSlash(std::string* path)
|
||||
{
|
||||
if (!path->empty() && path->front() == '/')
|
||||
{
|
||||
@@ -278,7 +274,7 @@ PropertyStream::Source::peel_leading_slash(std::string* path)
|
||||
}
|
||||
|
||||
bool
|
||||
PropertyStream::Source::peel_trailing_slashstar(std::string* path)
|
||||
PropertyStream::Source::peelTrailingSlashstar(std::string* path)
|
||||
{
|
||||
bool found(false);
|
||||
if (path->empty())
|
||||
@@ -294,7 +290,7 @@ PropertyStream::Source::peel_trailing_slashstar(std::string* path)
|
||||
}
|
||||
|
||||
std::string
|
||||
PropertyStream::Source::peel_name(std::string* path)
|
||||
PropertyStream::Source::peelName(std::string* path)
|
||||
{
|
||||
if (path->empty())
|
||||
return "";
|
||||
@@ -318,16 +314,16 @@ PropertyStream::Source::peel_name(std::string* path)
|
||||
|
||||
// Recursive search through the whole tree until name is found
|
||||
PropertyStream::Source*
|
||||
PropertyStream::Source::find_one_deep(std::string const& name)
|
||||
PropertyStream::Source::findOneDeep(std::string const& name)
|
||||
{
|
||||
Source* found = find_one(name); // NOLINT(misc-const-correctness)
|
||||
Source* found = findOne(name); // NOLINT TODO
|
||||
if (found != nullptr)
|
||||
return found;
|
||||
|
||||
std::lock_guard const _(lock_);
|
||||
std::scoped_lock const _(lock_);
|
||||
for (auto& s : children_)
|
||||
{
|
||||
found = s.source().find_one_deep(name);
|
||||
found = s.source().findOneDeep(name);
|
||||
if (found != nullptr)
|
||||
return found;
|
||||
}
|
||||
@@ -335,17 +331,17 @@ PropertyStream::Source::find_one_deep(std::string const& name)
|
||||
}
|
||||
|
||||
PropertyStream::Source*
|
||||
PropertyStream::Source::find_path(std::string path)
|
||||
PropertyStream::Source::findPath(std::string path)
|
||||
{
|
||||
if (path.empty())
|
||||
return this;
|
||||
Source* source(this);
|
||||
do
|
||||
{
|
||||
std::string const name(peel_name(&path));
|
||||
std::string const name(peelName(&path));
|
||||
if (name.empty())
|
||||
break;
|
||||
source = source->find_one(name);
|
||||
source = source->findOne(name);
|
||||
} while (source != nullptr);
|
||||
return source;
|
||||
}
|
||||
@@ -353,12 +349,12 @@ PropertyStream::Source::find_path(std::string path)
|
||||
// This function only looks at immediate children
|
||||
// If no immediate children match, then return nullptr
|
||||
PropertyStream::Source*
|
||||
PropertyStream::Source::find_one(std::string const& name)
|
||||
PropertyStream::Source::findOne(std::string const& name)
|
||||
{
|
||||
std::lock_guard const _(lock_);
|
||||
std::scoped_lock const _(lock_);
|
||||
for (auto& s : children_)
|
||||
{
|
||||
if (s.source().m_name == name)
|
||||
if (s.source().name_ == name)
|
||||
return &s.source();
|
||||
}
|
||||
return nullptr;
|
||||
@@ -391,85 +387,85 @@ PropertyStream::add(std::string const& key, bool value)
|
||||
void
|
||||
PropertyStream::add(std::string const& key, char value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, signed char value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, unsigned char value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, short value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, unsigned short value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, int value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, unsigned int value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, long value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, unsigned long value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, long long value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, unsigned long long value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, float value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, double value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(std::string const& key, long double value)
|
||||
{
|
||||
lexical_add(key, value);
|
||||
lexicalAdd(key, value);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -488,85 +484,85 @@ PropertyStream::add(bool value)
|
||||
void
|
||||
PropertyStream::add(char value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(signed char value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(unsigned char value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(short value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(unsigned short value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(int value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(unsigned int value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(long value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(unsigned long value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(long long value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(unsigned long long value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(float value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(double value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
void
|
||||
PropertyStream::add(long double value)
|
||||
{
|
||||
lexical_add(value);
|
||||
lexicalAdd(value);
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace detail {
|
||||
// ed25519Sha256 (4)
|
||||
// }
|
||||
|
||||
constexpr std::size_t fingerprintSize = 32;
|
||||
constexpr std::size_t kFingerprintSize = 32;
|
||||
|
||||
std::unique_ptr<Condition>
|
||||
loadSimpleSha256(Type type, Slice s, std::error_code& ec)
|
||||
@@ -66,19 +66,19 @@ loadSimpleSha256(Type type, Slice s, std::error_code& ec)
|
||||
|
||||
if (!isPrimitive(p) || !isContextSpecific(p))
|
||||
{
|
||||
ec = error::incorrect_encoding;
|
||||
ec = Error::IncorrectEncoding;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (p.tag != 0)
|
||||
{
|
||||
ec = error::unexpected_tag;
|
||||
ec = Error::UnexpectedTag;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (p.length != fingerprintSize)
|
||||
if (p.length != kFingerprintSize)
|
||||
{
|
||||
ec = error::fingerprint_size;
|
||||
ec = Error::FingerprintSize;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -94,13 +94,13 @@ loadSimpleSha256(Type type, Slice s, std::error_code& ec)
|
||||
|
||||
if (!isPrimitive(p) || !isContextSpecific(p))
|
||||
{
|
||||
ec = error::malformed_encoding;
|
||||
ec = Error::MalformedEncoding;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (p.tag != 1)
|
||||
{
|
||||
ec = error::unexpected_tag;
|
||||
ec = Error::UnexpectedTag;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -111,16 +111,16 @@ loadSimpleSha256(Type type, Slice s, std::error_code& ec)
|
||||
|
||||
if (!s.empty())
|
||||
{
|
||||
ec = error::trailing_garbage;
|
||||
ec = Error::TrailingGarbage;
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Type::preimageSha256:
|
||||
if (cost > PreimageSha256::maxPreimageLength)
|
||||
case Type::PreimageSha256:
|
||||
if (cost > PreimageSha256::kMaxPreimageLength)
|
||||
{
|
||||
ec = error::preimage_too_long;
|
||||
ec = Error::PreimageTooLong;
|
||||
return {};
|
||||
}
|
||||
break;
|
||||
@@ -149,7 +149,7 @@ Condition::deserialize(Slice s, std::error_code& ec)
|
||||
// }
|
||||
if (s.empty())
|
||||
{
|
||||
ec = error::buffer_empty;
|
||||
ec = Error::BufferEmpty;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -163,19 +163,19 @@ Condition::deserialize(Slice s, std::error_code& ec)
|
||||
// types
|
||||
if (!isConstructed(p) || !isContextSpecific(p))
|
||||
{
|
||||
ec = error::malformed_encoding;
|
||||
ec = Error::MalformedEncoding;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (p.length > s.size())
|
||||
{
|
||||
ec = error::buffer_underfull;
|
||||
ec = Error::BufferUnderfull;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (s.size() > maxSerializedCondition)
|
||||
if (s.size() > kMaxSerializedCondition)
|
||||
{
|
||||
ec = error::large_size;
|
||||
ec = Error::LargeSize;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -184,35 +184,35 @@ Condition::deserialize(Slice s, std::error_code& ec)
|
||||
switch (p.tag)
|
||||
{
|
||||
case 0: // PreimageSha256
|
||||
c = detail::loadSimpleSha256(Type::preimageSha256, Slice(s.data(), p.length), ec);
|
||||
c = detail::loadSimpleSha256(Type::PreimageSha256, Slice(s.data(), p.length), ec);
|
||||
if (!ec)
|
||||
s += p.length;
|
||||
break;
|
||||
|
||||
case 1: // PrefixSha256
|
||||
ec = error::unsupported_type;
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
case 2: // ThresholdSha256
|
||||
ec = error::unsupported_type;
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
case 3: // RsaSha256
|
||||
ec = error::unsupported_type;
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
case 4: // Ed25519Sha256
|
||||
ec = error::unsupported_type;
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
default:
|
||||
ec = error::unknown_type;
|
||||
ec = Error::UnknownType;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!s.empty())
|
||||
{
|
||||
ec = error::trailing_garbage;
|
||||
ec = Error::TrailingGarbage;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ Fulfillment::deserialize(Slice s, std::error_code& ec)
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
ec = error::buffer_empty;
|
||||
ec = Error::BufferEmpty;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -66,25 +66,25 @@ Fulfillment::deserialize(Slice s, std::error_code& ec)
|
||||
// All fulfillments are context-specific, constructed types
|
||||
if (!isConstructed(p) || !isContextSpecific(p))
|
||||
{
|
||||
ec = error::malformed_encoding;
|
||||
ec = Error::MalformedEncoding;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (p.length > s.size())
|
||||
{
|
||||
ec = error::buffer_underfull;
|
||||
ec = Error::BufferUnderfull;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (p.length < s.size())
|
||||
{
|
||||
ec = error::buffer_overfull;
|
||||
ec = Error::BufferOverfull;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (p.length > maxSerializedFulfillment)
|
||||
if (p.length > kMaxSerializedFulfillment)
|
||||
{
|
||||
ec = error::large_size;
|
||||
ec = Error::LargeSize;
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -93,40 +93,40 @@ Fulfillment::deserialize(Slice s, std::error_code& ec)
|
||||
using TagType = decltype(p.tag);
|
||||
switch (p.tag)
|
||||
{
|
||||
case safe_cast<TagType>(Type::preimageSha256):
|
||||
case safeCast<TagType>(Type::PreimageSha256):
|
||||
f = PreimageSha256::deserialize(Slice(s.data(), p.length), ec);
|
||||
if (ec)
|
||||
return {};
|
||||
s += p.length;
|
||||
break;
|
||||
|
||||
case safe_cast<TagType>(Type::prefixSha256):
|
||||
ec = error::unsupported_type;
|
||||
case safeCast<TagType>(Type::PrefixSha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
break;
|
||||
|
||||
case safe_cast<TagType>(Type::thresholdSha256):
|
||||
ec = error::unsupported_type;
|
||||
case safeCast<TagType>(Type::ThresholdSha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
break;
|
||||
|
||||
case safe_cast<TagType>(Type::rsaSha256):
|
||||
ec = error::unsupported_type;
|
||||
case safeCast<TagType>(Type::RsaSha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
break;
|
||||
|
||||
case safe_cast<TagType>(Type::ed25519Sha256):
|
||||
ec = error::unsupported_type;
|
||||
case safeCast<TagType>(Type::Ed25519Sha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
default:
|
||||
ec = error::unknown_type;
|
||||
ec = Error::UnknownType;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!s.empty())
|
||||
{
|
||||
ec = error::trailing_garbage;
|
||||
ec = Error::TrailingGarbage;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
namespace xrpl::cryptoconditions {
|
||||
namespace detail {
|
||||
|
||||
class cryptoconditions_error_category : public std::error_category
|
||||
class CryptoconditionsErrorCategory : public std::error_category
|
||||
{
|
||||
public:
|
||||
explicit cryptoconditions_error_category() = default;
|
||||
explicit CryptoconditionsErrorCategory() = default;
|
||||
|
||||
[[nodiscard]] char const*
|
||||
name() const noexcept override
|
||||
@@ -23,57 +23,57 @@ public:
|
||||
[[nodiscard]] std::string
|
||||
message(int ev) const override
|
||||
{
|
||||
switch (safe_cast<error>(ev))
|
||||
switch (safeCast<Error>(ev))
|
||||
{
|
||||
case error::unsupported_type:
|
||||
case Error::UnsupportedType:
|
||||
return "Specification: Requested type not supported.";
|
||||
|
||||
case error::unsupported_subtype:
|
||||
case Error::UnsupportedSubtype:
|
||||
return "Specification: Requested subtype not supported.";
|
||||
|
||||
case error::unknown_type:
|
||||
case Error::UnknownType:
|
||||
return "Specification: Requested type not recognized.";
|
||||
|
||||
case error::unknown_subtype:
|
||||
case Error::UnknownSubtype:
|
||||
return "Specification: Requested subtypes not recognized.";
|
||||
|
||||
case error::fingerprint_size:
|
||||
case Error::FingerprintSize:
|
||||
return "Specification: Incorrect fingerprint size.";
|
||||
|
||||
case error::incorrect_encoding:
|
||||
case Error::IncorrectEncoding:
|
||||
return "Specification: Incorrect encoding.";
|
||||
|
||||
case error::trailing_garbage:
|
||||
case Error::TrailingGarbage:
|
||||
return "Bad buffer: contains trailing garbage.";
|
||||
|
||||
case error::buffer_empty:
|
||||
case Error::BufferEmpty:
|
||||
return "Bad buffer: no data.";
|
||||
|
||||
case error::buffer_overfull:
|
||||
case Error::BufferOverfull:
|
||||
return "Bad buffer: overfull.";
|
||||
|
||||
case error::buffer_underfull:
|
||||
case Error::BufferUnderfull:
|
||||
return "Bad buffer: underfull.";
|
||||
|
||||
case error::malformed_encoding:
|
||||
case Error::MalformedEncoding:
|
||||
return "Malformed DER encoding.";
|
||||
|
||||
case error::unexpected_tag:
|
||||
case Error::UnexpectedTag:
|
||||
return "Malformed DER encoding: Unexpected tag.";
|
||||
|
||||
case error::short_preamble:
|
||||
case Error::ShortPreamble:
|
||||
return "Malformed DER encoding: Short preamble.";
|
||||
|
||||
case error::long_tag:
|
||||
case Error::LongTag:
|
||||
return "Implementation limit: Overlong tag.";
|
||||
|
||||
case error::large_size:
|
||||
case Error::LargeSize:
|
||||
return "Implementation limit: Large payload.";
|
||||
|
||||
case error::preimage_too_long:
|
||||
case Error::PreimageTooLong:
|
||||
return "Implementation limit: Specified preimage is too long.";
|
||||
|
||||
case error::generic:
|
||||
case Error::Generic:
|
||||
default:
|
||||
return "generic error";
|
||||
}
|
||||
@@ -99,20 +99,19 @@ public:
|
||||
};
|
||||
|
||||
inline std::error_category const&
|
||||
get_cryptoconditions_error_category()
|
||||
getCryptoconditionsErrorCategory()
|
||||
{
|
||||
static cryptoconditions_error_category const cat{};
|
||||
return cat;
|
||||
static CryptoconditionsErrorCategory const kCat{};
|
||||
return kCat;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
std::error_code
|
||||
make_error_code(error ev)
|
||||
make_error_code(Error ev)
|
||||
{
|
||||
return std::error_code{
|
||||
safe_cast<std::underlying_type_t<error>>(ev),
|
||||
detail::get_cryptoconditions_error_category()};
|
||||
safeCast<std::underlying_type_t<Error>>(ev), detail::getCryptoconditionsErrorCategory()};
|
||||
}
|
||||
|
||||
} // namespace xrpl::cryptoconditions
|
||||
|
||||
@@ -34,7 +34,7 @@ HashRouter::emplace(uint256 const& key) -> std::pair<Entry&, bool>
|
||||
void
|
||||
HashRouter::addSuppression(uint256 const& key)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
emplace(key);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ HashRouter::addSuppressionPeer(uint256 const& key, PeerShortID peer)
|
||||
std::pair<bool, std::optional<Stopwatch::time_point>>
|
||||
HashRouter::addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
auto result = emplace(key);
|
||||
result.first.addPeer(peer);
|
||||
@@ -58,7 +58,7 @@ HashRouter::addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer)
|
||||
bool
|
||||
HashRouter::addSuppressionPeer(uint256 const& key, PeerShortID peer, HashRouterFlags& flags)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
auto [s, created] = emplace(key);
|
||||
s.addPeer(peer);
|
||||
@@ -71,21 +71,21 @@ HashRouter::shouldProcess(
|
||||
uint256 const& key,
|
||||
PeerShortID peer,
|
||||
HashRouterFlags& flags,
|
||||
std::chrono::seconds tx_interval)
|
||||
std::chrono::seconds txInterval)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
auto result = emplace(key);
|
||||
auto& s = result.first;
|
||||
s.addPeer(peer);
|
||||
flags = s.getFlags();
|
||||
return s.shouldProcess(suppressionMap_.clock().now(), tx_interval);
|
||||
return s.shouldProcess(suppressionMap_.clock().now(), txInterval);
|
||||
}
|
||||
|
||||
HashRouterFlags
|
||||
HashRouter::getFlags(uint256 const& key)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
return emplace(key).first.getFlags();
|
||||
}
|
||||
@@ -95,7 +95,7 @@ HashRouter::setFlags(uint256 const& key, HashRouterFlags flags)
|
||||
{
|
||||
XRPL_ASSERT(static_cast<bool>(flags), "xrpl::HashRouter::setFlags : valid input");
|
||||
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
auto& s = emplace(key).first;
|
||||
|
||||
@@ -109,7 +109,7 @@ HashRouter::setFlags(uint256 const& key, HashRouterFlags flags)
|
||||
auto
|
||||
HashRouter::shouldRelay(uint256 const& key) -> std::optional<std::set<PeerShortID>>
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
auto& s = emplace(key).first;
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
Job::Job() : mType(jtINVALID), mJobIndex(0)
|
||||
Job::Job() : type_(JtInvalid), jobIndex_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Job::Job(JobType type, std::uint64_t index) : mType(type), mJobIndex(index)
|
||||
Job::Job(JobType type, std::uint64_t index) : type_(type), jobIndex_(index)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -25,83 +25,83 @@ Job::Job(
|
||||
std::uint64_t index,
|
||||
LoadMonitor& lm,
|
||||
std::function<void()> const& job)
|
||||
: mType(type), mJobIndex(index), mJob(job), mName(name), m_queue_time(clock_type::now())
|
||||
: type_(type), jobIndex_(index), job_(job), name_(name), queueTime_(clock_type::now())
|
||||
{
|
||||
m_loadEvent = std::make_shared<LoadEvent>(std::ref(lm), name, false);
|
||||
loadEvent_ = std::make_shared<LoadEvent>(std::ref(lm), name, false);
|
||||
}
|
||||
|
||||
JobType
|
||||
Job::getType() const
|
||||
{
|
||||
return mType;
|
||||
return type_;
|
||||
}
|
||||
|
||||
Job::clock_type::time_point const&
|
||||
Job::queue_time() const
|
||||
Job::queueTime() const
|
||||
{
|
||||
return m_queue_time;
|
||||
return queueTime_;
|
||||
}
|
||||
|
||||
void
|
||||
Job::doJob()
|
||||
{
|
||||
beast::setCurrentThreadName("j:" + mName);
|
||||
m_loadEvent->start();
|
||||
m_loadEvent->setName(mName);
|
||||
beast::setCurrentThreadName("j:" + name_);
|
||||
loadEvent_->start();
|
||||
loadEvent_->setName(name_);
|
||||
|
||||
mJob();
|
||||
job_();
|
||||
|
||||
// Destroy the lambda, otherwise we won't include
|
||||
// its duration in the time measurement
|
||||
mJob = nullptr;
|
||||
job_ = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
Job::operator>(Job const& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
if (type_ < j.type_)
|
||||
return true;
|
||||
|
||||
if (mType > j.mType)
|
||||
if (type_ > j.type_)
|
||||
return false;
|
||||
|
||||
return mJobIndex > j.mJobIndex;
|
||||
return jobIndex_ > j.jobIndex_;
|
||||
}
|
||||
|
||||
bool
|
||||
Job::operator>=(Job const& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
if (type_ < j.type_)
|
||||
return true;
|
||||
|
||||
if (mType > j.mType)
|
||||
if (type_ > j.type_)
|
||||
return false;
|
||||
|
||||
return mJobIndex >= j.mJobIndex;
|
||||
return jobIndex_ >= j.jobIndex_;
|
||||
}
|
||||
|
||||
bool
|
||||
Job::operator<(Job const& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
if (type_ < j.type_)
|
||||
return false;
|
||||
|
||||
if (mType > j.mType)
|
||||
if (type_ > j.type_)
|
||||
return true;
|
||||
|
||||
return mJobIndex < j.mJobIndex;
|
||||
return jobIndex_ < j.jobIndex_;
|
||||
}
|
||||
|
||||
bool
|
||||
Job::operator<=(Job const& j) const
|
||||
{
|
||||
if (mType < j.mType)
|
||||
if (type_ < j.type_)
|
||||
return false;
|
||||
|
||||
if (mType > j.mType)
|
||||
if (type_ > j.type_)
|
||||
return true;
|
||||
|
||||
return mJobIndex <= j.mJobIndex;
|
||||
return jobIndex_ <= j.jobIndex_;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -27,29 +27,29 @@ JobQueue::JobQueue(
|
||||
beast::Journal journal,
|
||||
Logs& logs,
|
||||
perf::PerfLog& perfLog)
|
||||
: m_journal(journal)
|
||||
, m_invalidJobData(JobTypes::instance().getInvalid(), collector, logs)
|
||||
, m_workers(*this, &perfLog, "JobQueue", threadCount)
|
||||
: journal_(journal)
|
||||
, invalidJobData_(JobTypes::instance().getInvalid(), collector, logs)
|
||||
, workers_(*this, &perfLog, "JobQueue", threadCount)
|
||||
, perfLog_(perfLog)
|
||||
, m_collector(collector)
|
||||
, collector_(collector)
|
||||
{
|
||||
JLOG(m_journal.info()) << "Using " << threadCount << " threads";
|
||||
JLOG(journal_.info()) << "Using " << threadCount << " threads";
|
||||
|
||||
hook = m_collector->make_hook(std::bind(&JobQueue::collect, this));
|
||||
job_count = m_collector->make_gauge("job_count");
|
||||
hook_ = collector_->makeHook(std::bind(&JobQueue::collect, this));
|
||||
jobCount_ = collector_->makeGauge("job_count");
|
||||
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
for (auto const& x : JobTypes::instance())
|
||||
{
|
||||
JobTypeInfo const& jt = x.second;
|
||||
|
||||
// And create dynamic information for all jobs
|
||||
auto const result(m_jobData.emplace(
|
||||
auto const result(jobData_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(jt.type()),
|
||||
std::forward_as_tuple(jt, m_collector, logs)));
|
||||
std::forward_as_tuple(jt, collector_, logs)));
|
||||
XRPL_ASSERT(result.second == true, "xrpl::JobQueue::JobQueue : jobs added");
|
||||
(void)result.second;
|
||||
}
|
||||
@@ -59,52 +59,52 @@ JobQueue::JobQueue(
|
||||
JobQueue::~JobQueue()
|
||||
{
|
||||
// Must unhook before destroying
|
||||
hook = beast::insight::Hook();
|
||||
hook_ = beast::insight::Hook();
|
||||
}
|
||||
|
||||
void
|
||||
JobQueue::collect()
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
job_count = m_jobSet.size();
|
||||
std::scoped_lock const lock(mutex_);
|
||||
jobCount_ = jobSet_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
JobQueue::addRefCountedJob(JobType type, std::string const& name, JobFunction const& func)
|
||||
{
|
||||
XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::addRefCountedJob : valid input job type");
|
||||
XRPL_ASSERT(type != JtInvalid, "xrpl::JobQueue::addRefCountedJob : valid input job type");
|
||||
|
||||
auto iter(m_jobData.find(type));
|
||||
auto iter(jobData_.find(type));
|
||||
XRPL_ASSERT(
|
||||
iter != m_jobData.end(), "xrpl::JobQueue::addRefCountedJob : job type found in jobs");
|
||||
if (iter == m_jobData.end())
|
||||
iter != jobData_.end(), "xrpl::JobQueue::addRefCountedJob : job type found in jobs");
|
||||
if (iter == jobData_.end())
|
||||
return false;
|
||||
|
||||
JLOG(m_journal.debug()) << __func__ << " : Adding job : " << name << " : " << type;
|
||||
JLOG(journal_.debug()) << __func__ << " : Adding job : " << name << " : " << type;
|
||||
JobTypeData& data(iter->second);
|
||||
|
||||
// FIXME: Workaround incorrect client shutdown ordering
|
||||
// do not add jobs to a queue with no threads
|
||||
XRPL_ASSERT(
|
||||
(type >= jtCLIENT && type <= jtCLIENT_WEBSOCKET) || m_workers.getNumberOfThreads() > 0,
|
||||
(type >= JtClient && type <= JtClientWebsocket) || workers_.getNumberOfThreads() > 0,
|
||||
"xrpl::JobQueue::addRefCountedJob : threads available or job "
|
||||
"requires no threads");
|
||||
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
auto result = m_jobSet.emplace(type, name, ++m_lastJob, data.load(), func);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto result = jobSet_.emplace(type, name, ++lastJob_, data.load(), func);
|
||||
auto const& job = *result.first;
|
||||
|
||||
JobType const type(job.getType());
|
||||
XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::addRefCountedJob : has valid job type");
|
||||
XRPL_ASSERT(m_jobSet.contains(job), "xrpl::JobQueue::addRefCountedJob : job found");
|
||||
XRPL_ASSERT(type != JtInvalid, "xrpl::JobQueue::addRefCountedJob : has valid job type");
|
||||
XRPL_ASSERT(jobSet_.contains(job), "xrpl::JobQueue::addRefCountedJob : job found");
|
||||
perfLog_.jobQueue(type);
|
||||
|
||||
JobTypeData& data(getJobTypeData(type));
|
||||
|
||||
if (data.waiting + data.running < getJobLimit(type))
|
||||
{
|
||||
m_workers.addTask();
|
||||
workers_.addTask();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,21 +119,21 @@ JobQueue::addRefCountedJob(JobType type, std::string const& name, JobFunction co
|
||||
int
|
||||
JobQueue::getJobCount(JobType t) const
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
JobDataMap::const_iterator const c = m_jobData.find(t);
|
||||
JobDataMap::const_iterator const c = jobData_.find(t);
|
||||
|
||||
return (c == m_jobData.end()) ? 0 : c->second.waiting;
|
||||
return (c == jobData_.end()) ? 0 : c->second.waiting;
|
||||
}
|
||||
|
||||
int
|
||||
JobQueue::getJobCountTotal(JobType t) const
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
JobDataMap::const_iterator const c = m_jobData.find(t);
|
||||
JobDataMap::const_iterator const c = jobData_.find(t);
|
||||
|
||||
return (c == m_jobData.end()) ? 0 : (c->second.waiting + c->second.running);
|
||||
return (c == jobData_.end()) ? 0 : (c->second.waiting + c->second.running);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -142,9 +142,9 @@ JobQueue::getJobCountGE(JobType t) const
|
||||
// return the number of jobs at this priority level or greater
|
||||
int ret = 0;
|
||||
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
for (auto const& x : m_jobData)
|
||||
for (auto const& x : jobData_)
|
||||
{
|
||||
if (x.first >= t)
|
||||
ret += x.second.waiting;
|
||||
@@ -156,10 +156,10 @@ JobQueue::getJobCountGE(JobType t) const
|
||||
std::unique_ptr<LoadEvent>
|
||||
JobQueue::makeLoadEvent(JobType t, std::string const& name)
|
||||
{
|
||||
JobDataMap::iterator const iter(m_jobData.find(t));
|
||||
XRPL_ASSERT(iter != m_jobData.end(), "xrpl::JobQueue::makeLoadEvent : valid job type input");
|
||||
JobDataMap::iterator const iter(jobData_.find(t));
|
||||
XRPL_ASSERT(iter != jobData_.end(), "xrpl::JobQueue::makeLoadEvent : valid job type input");
|
||||
|
||||
if (iter == m_jobData.end())
|
||||
if (iter == jobData_.end())
|
||||
return {};
|
||||
|
||||
return std::make_unique<LoadEvent>(iter->second.load(), name, true);
|
||||
@@ -169,36 +169,36 @@ void
|
||||
JobQueue::addLoadEvents(JobType t, int count, std::chrono::milliseconds elapsed)
|
||||
{
|
||||
if (isStopped())
|
||||
LogicError("JobQueue::addLoadEvents() called after JobQueue stopped");
|
||||
logicError("JobQueue::addLoadEvents() called after JobQueue stopped");
|
||||
|
||||
JobDataMap::iterator const iter(m_jobData.find(t));
|
||||
XRPL_ASSERT(iter != m_jobData.end(), "xrpl::JobQueue::addLoadEvents : valid job type input");
|
||||
JobDataMap::iterator const iter(jobData_.find(t));
|
||||
XRPL_ASSERT(iter != jobData_.end(), "xrpl::JobQueue::addLoadEvents : valid job type input");
|
||||
iter->second.load().addSamples(count, elapsed);
|
||||
}
|
||||
|
||||
bool
|
||||
JobQueue::isOverloaded()
|
||||
{
|
||||
return std::ranges::any_of(m_jobData, [](auto& entry) { return entry.second.load().isOver(); });
|
||||
return std::ranges::any_of(jobData_, [](auto& entry) { return entry.second.load().isOver(); });
|
||||
}
|
||||
|
||||
Json::Value
|
||||
json::Value
|
||||
JobQueue::getJson(int c)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
Json::Value ret(Json::objectValue);
|
||||
json::Value ret(json::ValueType::Object);
|
||||
|
||||
ret["threads"] = m_workers.getNumberOfThreads();
|
||||
ret["threads"] = workers_.getNumberOfThreads();
|
||||
|
||||
Json::Value priorities = Json::arrayValue;
|
||||
json::Value priorities = json::ValueType::Array;
|
||||
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
for (auto& x : m_jobData)
|
||||
for (auto& x : jobData_)
|
||||
{
|
||||
XRPL_ASSERT(x.first != jtINVALID, "xrpl::JobQueue::getJson : valid job type");
|
||||
XRPL_ASSERT(x.first != JtInvalid, "xrpl::JobQueue::getJson : valid job type");
|
||||
|
||||
if (x.first == jtGENERIC)
|
||||
if (x.first == JtGeneric)
|
||||
continue;
|
||||
|
||||
JobTypeData& data(x.second);
|
||||
@@ -210,7 +210,7 @@ JobQueue::getJson(int c)
|
||||
|
||||
if ((stats.count != 0) || (waiting != 0) || (stats.latencyPeak != 0ms) || (running != 0))
|
||||
{
|
||||
Json::Value& pri = priorities.append(Json::objectValue);
|
||||
json::Value& pri = priorities.append(json::ValueType::Object);
|
||||
|
||||
pri["job_type"] = data.name();
|
||||
|
||||
@@ -242,20 +242,20 @@ JobQueue::getJson(int c)
|
||||
void
|
||||
JobQueue::rendezvous()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
cv_.wait(lock, [this] { return m_processCount == 0 && m_jobSet.empty(); });
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock, [this] { return processCount_ == 0 && jobSet_.empty(); });
|
||||
}
|
||||
|
||||
JobTypeData&
|
||||
JobQueue::getJobTypeData(JobType type)
|
||||
{
|
||||
JobDataMap::iterator const c(m_jobData.find(type));
|
||||
XRPL_ASSERT(c != m_jobData.end(), "xrpl::JobQueue::getJobTypeData : valid job type input");
|
||||
JobDataMap::iterator const c(jobData_.find(type));
|
||||
XRPL_ASSERT(c != jobData_.end(), "xrpl::JobQueue::getJobTypeData : valid job type input");
|
||||
|
||||
// NIKB: This is ugly and I hate it. We must remove jtINVALID completely
|
||||
// NIKB: This is ugly and I hate it. We must remove JtInvalid completely
|
||||
// and use something sane.
|
||||
if (c == m_jobData.end())
|
||||
return m_invalidJobData;
|
||||
if (c == jobData_.end())
|
||||
return invalidJobData_;
|
||||
|
||||
return c->second;
|
||||
}
|
||||
@@ -265,17 +265,17 @@ JobQueue::stop()
|
||||
{
|
||||
stopping_ = true;
|
||||
using namespace std::chrono_literals;
|
||||
jobCounter_.join("JobQueue", 1s, m_journal);
|
||||
jobCounter_.join("JobQueue", 1s, journal_);
|
||||
{
|
||||
// After the JobCounter is joined, all jobs have finished executing
|
||||
// (i.e. returned from `Job::doJob`) and no more are being accepted,
|
||||
// but there may still be some threads between the return of
|
||||
// `Job::doJob` and the return of `JobQueue::processTask`. That is why
|
||||
// we must wait on the condition variable to make these assertions.
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
cv_.wait(lock, [this] { return m_processCount == 0 && m_jobSet.empty(); });
|
||||
XRPL_ASSERT(m_processCount == 0, "xrpl::JobQueue::stop : all processes completed");
|
||||
XRPL_ASSERT(m_jobSet.empty(), "xrpl::JobQueue::stop : all jobs completed");
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
cv_.wait(lock, [this] { return processCount_ == 0 && jobSet_.empty(); });
|
||||
XRPL_ASSERT(processCount_ == 0, "xrpl::JobQueue::stop : all processes completed");
|
||||
XRPL_ASSERT(jobSet_.empty(), "xrpl::JobQueue::stop : all jobs completed");
|
||||
XRPL_ASSERT(nSuspend_ == 0, "xrpl::JobQueue::stop : no coros suspended");
|
||||
stopped_ = true;
|
||||
}
|
||||
@@ -290,13 +290,13 @@ JobQueue::isStopped() const
|
||||
void
|
||||
JobQueue::getNextJob(Job& job)
|
||||
{
|
||||
XRPL_ASSERT(!m_jobSet.empty(), "xrpl::JobQueue::getNextJob : non-empty jobs");
|
||||
XRPL_ASSERT(!jobSet_.empty(), "xrpl::JobQueue::getNextJob : non-empty jobs");
|
||||
|
||||
std::set<Job>::const_iterator iter;
|
||||
for (iter = m_jobSet.begin(); iter != m_jobSet.end(); ++iter)
|
||||
for (iter = jobSet_.begin(); iter != jobSet_.end(); ++iter)
|
||||
{
|
||||
JobType const type = iter->getType();
|
||||
XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::getNextJob : valid job type");
|
||||
XRPL_ASSERT(type != JtInvalid, "xrpl::JobQueue::getNextJob : valid job type");
|
||||
|
||||
JobTypeData& data(getJobTypeData(type));
|
||||
XRPL_ASSERT(
|
||||
@@ -312,15 +312,15 @@ JobQueue::getNextJob(Job& job)
|
||||
}
|
||||
}
|
||||
|
||||
XRPL_ASSERT(iter != m_jobSet.end(), "xrpl::JobQueue::getNextJob : found next job");
|
||||
XRPL_ASSERT(iter != jobSet_.end(), "xrpl::JobQueue::getNextJob : found next job");
|
||||
job = *iter;
|
||||
m_jobSet.erase(iter);
|
||||
jobSet_.erase(iter);
|
||||
}
|
||||
|
||||
void
|
||||
JobQueue::finishJob(JobType type)
|
||||
{
|
||||
XRPL_ASSERT(type != jtINVALID, "xrpl::JobQueue::finishJob : valid input job type");
|
||||
XRPL_ASSERT(type != JtInvalid, "xrpl::JobQueue::finishJob : valid input job type");
|
||||
|
||||
JobTypeData& data = getJobTypeData(type);
|
||||
|
||||
@@ -332,7 +332,7 @@ JobQueue::finishJob(JobType type)
|
||||
"xrpl::JobQueue::finishJob : job limit");
|
||||
|
||||
--data.deferred;
|
||||
m_workers.addTask();
|
||||
workers_.addTask();
|
||||
}
|
||||
|
||||
--data.running;
|
||||
@@ -341,47 +341,47 @@ JobQueue::finishJob(JobType type)
|
||||
void
|
||||
JobQueue::processTask(int instance)
|
||||
{
|
||||
JobType type = jtINVALID;
|
||||
JobType type = JtInvalid;
|
||||
|
||||
{
|
||||
using namespace std::chrono;
|
||||
Job::clock_type::time_point const start_time(Job::clock_type::now());
|
||||
Job::clock_type::time_point const startTime(Job::clock_type::now());
|
||||
{
|
||||
Job job;
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
getNextJob(job);
|
||||
++m_processCount;
|
||||
++processCount_;
|
||||
}
|
||||
type = job.getType();
|
||||
JobTypeData const& data(getJobTypeData(type));
|
||||
JLOG(m_journal.trace()) << "Doing " << data.name() << "job";
|
||||
JLOG(journal_.trace()) << "Doing " << data.name() << "job";
|
||||
|
||||
// The amount of time that the job was in the queue
|
||||
auto const q_time = ceil<microseconds>(start_time - job.queue_time());
|
||||
perfLog_.jobStart(type, q_time, start_time, instance);
|
||||
auto const qTime = ceil<microseconds>(startTime - job.queueTime());
|
||||
perfLog_.jobStart(type, qTime, startTime, instance);
|
||||
|
||||
job.doJob();
|
||||
|
||||
// The amount of time it took to execute the job
|
||||
auto const x_time = ceil<microseconds>(Job::clock_type::now() - start_time);
|
||||
auto const xTime = ceil<microseconds>(Job::clock_type::now() - startTime);
|
||||
|
||||
if (x_time >= 10ms || q_time >= 10ms)
|
||||
if (xTime >= 10ms || qTime >= 10ms)
|
||||
{
|
||||
getJobTypeData(type).dequeue.notify(q_time);
|
||||
getJobTypeData(type).execute.notify(x_time);
|
||||
getJobTypeData(type).dequeue.notify(qTime);
|
||||
getJobTypeData(type).execute.notify(xTime);
|
||||
}
|
||||
perfLog_.jobFinish(type, x_time, instance);
|
||||
perfLog_.jobFinish(type, xTime, instance);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
// Job should be destroyed before stopping
|
||||
// otherwise destructors with side effects can access
|
||||
// parent objects that are already destroyed.
|
||||
finishJob(type);
|
||||
if (--m_processCount == 0 && m_jobSet.empty())
|
||||
if (--processCount_ == 0 && jobSet_.empty())
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ int
|
||||
JobQueue::getJobLimit(JobType type)
|
||||
{
|
||||
JobTypeInfo const& j(JobTypes::instance().get(type));
|
||||
XRPL_ASSERT(j.type() != jtINVALID, "xrpl::JobQueue::getJobLimit : valid job type");
|
||||
XRPL_ASSERT(j.type() != JtInvalid, "xrpl::JobQueue::getJobLimit : valid job type");
|
||||
|
||||
return j.limit();
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ LoadMonitor::Stats::Stats() : latencyAvg(0), latencyPeak(0)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
LoadMonitor::LoadMonitor(beast::Journal j)
|
||||
: mLatencyMSAvg(0)
|
||||
, mLatencyMSPeak(0)
|
||||
, mTargetLatencyAvg(0)
|
||||
, mTargetLatencyPk(0)
|
||||
, mLastUpdate(UptimeClock::now())
|
||||
: latencyMSAvg_(0)
|
||||
, latencyMSPeak_(0)
|
||||
, targetLatencyAvg_(0)
|
||||
, targetLatencyPk_(0)
|
||||
, lastUpdate_(UptimeClock::now())
|
||||
, j_(j)
|
||||
{
|
||||
}
|
||||
@@ -48,18 +48,18 @@ LoadMonitor::update()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
auto now = UptimeClock::now();
|
||||
if (now == mLastUpdate) // current
|
||||
if (now == lastUpdate_) // current
|
||||
return;
|
||||
|
||||
// VFALCO TODO Why 8?
|
||||
if ((now < mLastUpdate) || (now > (mLastUpdate + 8s)))
|
||||
if ((now < lastUpdate_) || (now > (lastUpdate_ + 8s)))
|
||||
{
|
||||
// way out of date
|
||||
mCounts = 0;
|
||||
mLatencyEvents = 0;
|
||||
mLatencyMSAvg = 0ms;
|
||||
mLatencyMSPeak = 0ms;
|
||||
mLastUpdate = now;
|
||||
counts_ = 0;
|
||||
latencyEvents_ = 0;
|
||||
latencyMSAvg_ = 0ms;
|
||||
latencyMSPeak_ = 0ms;
|
||||
lastUpdate_ = now;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -73,12 +73,12 @@ LoadMonitor::update()
|
||||
*/
|
||||
do
|
||||
{
|
||||
mLastUpdate += 1s;
|
||||
mCounts -= ((mCounts + 3) / 4);
|
||||
mLatencyEvents -= ((mLatencyEvents + 3) / 4);
|
||||
mLatencyMSAvg -= (mLatencyMSAvg / 4);
|
||||
mLatencyMSPeak -= (mLatencyMSPeak / 4);
|
||||
} while (mLastUpdate < now);
|
||||
lastUpdate_ += 1s;
|
||||
counts_ -= ((counts_ + 3) / 4);
|
||||
latencyEvents_ -= ((latencyEvents_ + 3) / 4);
|
||||
latencyMSAvg_ -= (latencyMSAvg_ / 4);
|
||||
latencyMSPeak_ -= (latencyMSPeak_ / 4);
|
||||
} while (lastUpdate_ < now);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -108,47 +108,47 @@ LoadMonitor::addLoadSample(LoadEvent const& s)
|
||||
void
|
||||
LoadMonitor::addSamples(int count, std::chrono::milliseconds latency)
|
||||
{
|
||||
std::lock_guard const sl(mutex_);
|
||||
std::scoped_lock const sl(mutex_);
|
||||
|
||||
update();
|
||||
mCounts += count;
|
||||
mLatencyEvents += count;
|
||||
mLatencyMSAvg += latency;
|
||||
mLatencyMSPeak += latency;
|
||||
counts_ += count;
|
||||
latencyEvents_ += count;
|
||||
latencyMSAvg_ += latency;
|
||||
latencyMSPeak_ += latency;
|
||||
|
||||
auto const latencyPeak = mLatencyEvents * latency * 4 / count;
|
||||
auto const latencyPeak = latencyEvents_ * latency * 4 / count;
|
||||
|
||||
if (mLatencyMSPeak < latencyPeak)
|
||||
mLatencyMSPeak = latencyPeak;
|
||||
if (latencyMSPeak_ < latencyPeak)
|
||||
latencyMSPeak_ = latencyPeak;
|
||||
}
|
||||
|
||||
void
|
||||
LoadMonitor::setTargetLatency(std::chrono::milliseconds avg, std::chrono::milliseconds pk)
|
||||
{
|
||||
mTargetLatencyAvg = avg;
|
||||
mTargetLatencyPk = pk;
|
||||
targetLatencyAvg_ = avg;
|
||||
targetLatencyPk_ = pk;
|
||||
}
|
||||
|
||||
bool
|
||||
LoadMonitor::isOverTarget(std::chrono::milliseconds avg, std::chrono::milliseconds peak)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
return (mTargetLatencyPk > 0ms && (peak > mTargetLatencyPk)) ||
|
||||
(mTargetLatencyAvg > 0ms && (avg > mTargetLatencyAvg));
|
||||
return (targetLatencyPk_ > 0ms && (peak > targetLatencyPk_)) ||
|
||||
(targetLatencyAvg_ > 0ms && (avg > targetLatencyAvg_));
|
||||
}
|
||||
|
||||
bool
|
||||
LoadMonitor::isOver()
|
||||
{
|
||||
std::lock_guard const sl(mutex_);
|
||||
std::scoped_lock const sl(mutex_);
|
||||
|
||||
update();
|
||||
|
||||
if (mLatencyEvents == 0)
|
||||
if (latencyEvents_ == 0)
|
||||
return false;
|
||||
|
||||
return isOverTarget(
|
||||
mLatencyMSAvg / (mLatencyEvents * 4), mLatencyMSPeak / (mLatencyEvents * 4));
|
||||
latencyMSAvg_ / (latencyEvents_ * 4), latencyMSPeak_ / (latencyEvents_ * 4));
|
||||
}
|
||||
|
||||
LoadMonitor::Stats
|
||||
@@ -157,21 +157,21 @@ LoadMonitor::getStats()
|
||||
using namespace std::chrono_literals;
|
||||
Stats stats;
|
||||
|
||||
std::lock_guard const sl(mutex_);
|
||||
std::scoped_lock const sl(mutex_);
|
||||
|
||||
update();
|
||||
|
||||
stats.count = mCounts / 4;
|
||||
stats.count = counts_ / 4;
|
||||
|
||||
if (mLatencyEvents == 0)
|
||||
if (latencyEvents_ == 0)
|
||||
{
|
||||
stats.latencyAvg = 0ms;
|
||||
stats.latencyPeak = 0ms;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.latencyAvg = mLatencyMSAvg / (mLatencyEvents * 4);
|
||||
stats.latencyPeak = mLatencyMSPeak / (mLatencyEvents * 4);
|
||||
stats.latencyAvg = latencyMSAvg_ / (latencyEvents_ * 4);
|
||||
stats.latencyPeak = latencyMSPeak_ / (latencyEvents_ * 4);
|
||||
}
|
||||
|
||||
stats.isOverloaded = isOverTarget(stats.latencyAvg, stats.latencyPeak);
|
||||
|
||||
@@ -15,13 +15,13 @@ Workers::Workers(
|
||||
perf::PerfLog* perfLog,
|
||||
std::string threadNames,
|
||||
int numberOfThreads)
|
||||
: m_callback(callback)
|
||||
: callback_(callback)
|
||||
, perfLog_(perfLog)
|
||||
, m_threadNames(std::move(threadNames))
|
||||
, m_semaphore(0)
|
||||
, m_activeCount(0)
|
||||
, m_pauseCount(0)
|
||||
, m_runningTaskCount(0)
|
||||
, threadNames_(std::move(threadNames))
|
||||
, semaphore_(0)
|
||||
, activeCount_(0)
|
||||
, pauseCount_(0)
|
||||
, runningTaskCount_(0)
|
||||
{
|
||||
setNumberOfThreads(numberOfThreads);
|
||||
}
|
||||
@@ -30,13 +30,13 @@ Workers::~Workers()
|
||||
{
|
||||
stop();
|
||||
|
||||
deleteWorkers(m_everyone);
|
||||
deleteWorkers(everyone_);
|
||||
}
|
||||
|
||||
int
|
||||
Workers::getNumberOfThreads() const noexcept
|
||||
{
|
||||
return m_numberOfThreads;
|
||||
return numberOfThreads_;
|
||||
}
|
||||
|
||||
// VFALCO NOTE if this function is called quickly to reduce then
|
||||
@@ -46,22 +46,22 @@ Workers::getNumberOfThreads() const noexcept
|
||||
void
|
||||
Workers::setNumberOfThreads(int numberOfThreads)
|
||||
{
|
||||
static int instance{0};
|
||||
if (m_numberOfThreads == numberOfThreads)
|
||||
static int kInstance{0};
|
||||
if (numberOfThreads_ == numberOfThreads)
|
||||
return;
|
||||
|
||||
if (perfLog_ != nullptr)
|
||||
perfLog_->resizeJobs(numberOfThreads);
|
||||
|
||||
if (numberOfThreads > m_numberOfThreads)
|
||||
if (numberOfThreads > numberOfThreads_)
|
||||
{
|
||||
// Increasing the number of working threads
|
||||
int const amount = numberOfThreads - m_numberOfThreads;
|
||||
int const amount = numberOfThreads - numberOfThreads_;
|
||||
|
||||
for (int i = 0; i < amount; ++i)
|
||||
{
|
||||
// See if we can reuse a paused worker
|
||||
Worker* worker = m_paused.pop_front();
|
||||
Worker* worker = paused_.popFront();
|
||||
|
||||
if (worker != nullptr)
|
||||
{
|
||||
@@ -72,26 +72,26 @@ Workers::setNumberOfThreads(int numberOfThreads)
|
||||
}
|
||||
else
|
||||
{
|
||||
worker = new Worker(*this, m_threadNames, instance++);
|
||||
m_everyone.push_front(worker);
|
||||
worker = new Worker(*this, threadNames_, kInstance++);
|
||||
everyone_.pushFront(worker);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Decreasing the number of working threads
|
||||
int const amount = m_numberOfThreads - numberOfThreads;
|
||||
int const amount = numberOfThreads_ - numberOfThreads;
|
||||
|
||||
for (int i = 0; i < amount; ++i)
|
||||
{
|
||||
++m_pauseCount;
|
||||
++pauseCount_;
|
||||
|
||||
// Pausing a thread counts as one "internal task"
|
||||
m_semaphore.notify();
|
||||
semaphore_.notify();
|
||||
}
|
||||
}
|
||||
|
||||
m_numberOfThreads = numberOfThreads;
|
||||
numberOfThreads_ = numberOfThreads;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -100,24 +100,24 @@ Workers::stop()
|
||||
setNumberOfThreads(0);
|
||||
|
||||
// Wait until all workers have paused AND no tasks are actively running.
|
||||
// Both conditions are needed because m_allPaused (mutex-protected) and
|
||||
// m_runningTaskCount (atomic) are not synchronized under the same lock,
|
||||
// so m_allPaused can momentarily be true while a task is still finishing.
|
||||
std::unique_lock<std::mutex> lk{m_mut};
|
||||
m_cv.wait(lk, [this] { return m_allPaused && numberOfCurrentlyRunningTasks() == 0; });
|
||||
// Both conditions are needed because allPaused_ (mutex-protected) and
|
||||
// runningTaskCount_ (atomic) are not synchronized under the same lock,
|
||||
// so allPaused_ can momentarily be true while a task is still finishing.
|
||||
std::unique_lock<std::mutex> lk{mut_};
|
||||
cv_.wait(lk, [this] { return allPaused_ && numberOfCurrentlyRunningTasks() == 0; });
|
||||
lk.unlock();
|
||||
}
|
||||
|
||||
void
|
||||
Workers::addTask()
|
||||
{
|
||||
m_semaphore.notify();
|
||||
semaphore_.notify();
|
||||
}
|
||||
|
||||
int
|
||||
Workers::numberOfCurrentlyRunningTasks() const noexcept
|
||||
{
|
||||
return m_runningTaskCount.load();
|
||||
return runningTaskCount_.load();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -125,7 +125,7 @@ Workers::deleteWorkers(beast::LockFreeStack<Worker>& stack)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
Worker const* const worker = stack.pop_front();
|
||||
Worker const* const worker = stack.popFront();
|
||||
|
||||
if (worker != nullptr)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ Workers::deleteWorkers(beast::LockFreeStack<Worker>& stack)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Workers::Worker::Worker(Workers& workers, std::string threadName, int const instance)
|
||||
: m_workers{workers}, threadName_{std::move(threadName)}, instance_{instance}
|
||||
: workers_{workers}, threadName_{std::move(threadName)}, instance_{instance}
|
||||
|
||||
{
|
||||
thread_ = std::thread{&Workers::Worker::run, this};
|
||||
@@ -151,7 +151,7 @@ Workers::Worker::Worker(Workers& workers, std::string threadName, int const inst
|
||||
Workers::Worker::~Worker()
|
||||
{
|
||||
{
|
||||
std::lock_guard const lock{mutex_};
|
||||
std::scoped_lock const lock{mutex_};
|
||||
++wakeCount_;
|
||||
shouldExit_ = true;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ Workers::Worker::~Worker()
|
||||
void
|
||||
Workers::Worker::notify()
|
||||
{
|
||||
std::lock_guard const lock{mutex_};
|
||||
std::scoped_lock const lock{mutex_};
|
||||
++wakeCount_;
|
||||
wakeup_.notify_one();
|
||||
}
|
||||
@@ -177,10 +177,10 @@ Workers::Worker::run()
|
||||
// Increment the count of active workers, and if
|
||||
// we are the first one then reset the "all paused" event
|
||||
//
|
||||
if (++m_workers.m_activeCount == 1)
|
||||
if (++workers_.activeCount_ == 1)
|
||||
{
|
||||
std::lock_guard const lk{m_workers.m_mut};
|
||||
m_workers.m_allPaused = false;
|
||||
std::scoped_lock const lk{workers_.mut_};
|
||||
workers_.allPaused_ = false;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
@@ -190,17 +190,17 @@ Workers::Worker::run()
|
||||
|
||||
// Acquire a task or "internal task."
|
||||
//
|
||||
m_workers.m_semaphore.wait();
|
||||
workers_.semaphore_.wait();
|
||||
|
||||
// See if there's a pause request. This
|
||||
// counts as an "internal task."
|
||||
//
|
||||
int pauseCount = m_workers.m_pauseCount.load();
|
||||
int pauseCount = workers_.pauseCount_.load();
|
||||
|
||||
if (pauseCount > 0)
|
||||
{
|
||||
// Try to decrement
|
||||
pauseCount = --m_workers.m_pauseCount;
|
||||
pauseCount = --workers_.pauseCount_;
|
||||
|
||||
if (pauseCount >= 0)
|
||||
{
|
||||
@@ -209,25 +209,25 @@ Workers::Worker::run()
|
||||
}
|
||||
|
||||
// Undo our decrement
|
||||
++m_workers.m_pauseCount;
|
||||
++workers_.pauseCount_;
|
||||
}
|
||||
|
||||
// We couldn't pause so we must have gotten
|
||||
// unblocked in order to process a task.
|
||||
//
|
||||
++m_workers.m_runningTaskCount;
|
||||
m_workers.m_callback.processTask(instance_);
|
||||
++workers_.runningTaskCount_;
|
||||
workers_.callback_.processTask(instance_);
|
||||
|
||||
// When the running task count drops to zero, wake stop() which
|
||||
// may be waiting for both m_allPaused and zero running tasks.
|
||||
// Locking m_mut before notify_all() prevents a lost wakeup:
|
||||
// may be waiting for both allPaused_ and zero running tasks.
|
||||
// Locking mut_ before notify_all() prevents a lost wakeup:
|
||||
// it serializes against the predicate check inside stop()'s
|
||||
// cv.wait(), ensuring the notification is not missed between
|
||||
// cv_.wait(), ensuring the notification is not missed between
|
||||
// the predicate evaluation and the actual sleep.
|
||||
if (--m_workers.m_runningTaskCount == 0)
|
||||
if (--workers_.runningTaskCount_ == 0)
|
||||
{
|
||||
std::lock_guard const lk{m_workers.m_mut};
|
||||
m_workers.m_cv.notify_all();
|
||||
std::scoped_lock const lk{workers_.mut_};
|
||||
workers_.cv_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,16 +235,16 @@ Workers::Worker::run()
|
||||
// guarantee that it will eventually block on its
|
||||
// event object.
|
||||
//
|
||||
m_workers.m_paused.push_front(this);
|
||||
workers_.paused_.pushFront(this);
|
||||
|
||||
// Decrement the count of active workers, and if we
|
||||
// are the last one then signal the "all paused" event.
|
||||
//
|
||||
if (--m_workers.m_activeCount == 0)
|
||||
if (--workers_.activeCount_ == 0)
|
||||
{
|
||||
std::lock_guard const lk{m_workers.m_mut};
|
||||
m_workers.m_allPaused = true;
|
||||
m_workers.m_cv.notify_all();
|
||||
std::scoped_lock const lk{workers_.mut_};
|
||||
workers_.allPaused_ = true;
|
||||
workers_.cv_.notify_all();
|
||||
}
|
||||
|
||||
// Set inactive thread name.
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace xrpl {
|
||||
// RFC 1751 code converted to C++/Boost.
|
||||
//
|
||||
|
||||
char const* RFC1751::s_dictionary[2048] = {
|
||||
char const* RFC1751::dictionary[2048] = {
|
||||
"A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", "AGO", "AID", "AIM", "AIR", "ALL",
|
||||
"ALP", "AM", "AMY", "AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT",
|
||||
"ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK",
|
||||
@@ -237,10 +237,10 @@ RFC1751::btoe(std::string& strHuman, std::string const& strData)
|
||||
|
||||
caBuffer[8] = char(p) << 6;
|
||||
|
||||
strHuman = std::string() + s_dictionary[extract(caBuffer, 0, 11)] + " " +
|
||||
s_dictionary[extract(caBuffer, 11, 11)] + " " + s_dictionary[extract(caBuffer, 22, 11)] +
|
||||
" " + s_dictionary[extract(caBuffer, 33, 11)] + " " +
|
||||
s_dictionary[extract(caBuffer, 44, 11)] + " " + s_dictionary[extract(caBuffer, 55, 11)];
|
||||
strHuman = std::string() + dictionary[extract(caBuffer, 0, 11)] + " " +
|
||||
dictionary[extract(caBuffer, 11, 11)] + " " + dictionary[extract(caBuffer, 22, 11)] + " " +
|
||||
dictionary[extract(caBuffer, 33, 11)] + " " + dictionary[extract(caBuffer, 44, 11)] + " " +
|
||||
dictionary[extract(caBuffer, 55, 11)];
|
||||
}
|
||||
|
||||
void
|
||||
@@ -314,7 +314,7 @@ RFC1751::wsrch(std::string const& strWord, int iMin, int iMax)
|
||||
{
|
||||
// Have a range to search.
|
||||
int const iMid = iMin + ((iMax - iMin) / 2);
|
||||
int const iDir = strWord.compare(s_dictionary[iMid]);
|
||||
int const iDir = strWord.compare(dictionary[iMid]);
|
||||
|
||||
if (iDir == 0)
|
||||
{
|
||||
@@ -447,7 +447,7 @@ RFC1751::getWordFromBlob(void const* blob, size_t bytes)
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
|
||||
return s_dictionary[hash % (sizeof(s_dictionary) / sizeof(s_dictionary[0]))];
|
||||
return dictionary[hash % (sizeof(dictionary) / sizeof(dictionary[0]))];
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
csprng_engine::csprng_engine()
|
||||
CsprngEngine::CsprngEngine()
|
||||
{
|
||||
// This is not strictly necessary
|
||||
if (RAND_poll() != 1)
|
||||
Throw<std::runtime_error>("CSPRNG: Initial polling failed");
|
||||
}
|
||||
|
||||
csprng_engine::~csprng_engine()
|
||||
CsprngEngine::~CsprngEngine()
|
||||
{
|
||||
// This cleanup function is not needed in newer versions of OpenSSL
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
@@ -29,7 +29,7 @@ csprng_engine::~csprng_engine()
|
||||
}
|
||||
|
||||
void
|
||||
csprng_engine::mix_entropy(void* buffer, std::size_t count)
|
||||
CsprngEngine::mixEntropy(void* buffer, std::size_t count)
|
||||
{
|
||||
std::array<std::random_device::result_type, 128> entropy{};
|
||||
|
||||
@@ -43,7 +43,7 @@ csprng_engine::mix_entropy(void* buffer, std::size_t count)
|
||||
e = rd();
|
||||
}
|
||||
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
// We add data to the pool, but we conservatively assume that
|
||||
// it contributes no actual entropy.
|
||||
@@ -54,13 +54,13 @@ csprng_engine::mix_entropy(void* buffer, std::size_t count)
|
||||
}
|
||||
|
||||
void
|
||||
csprng_engine::operator()(void* ptr, std::size_t count)
|
||||
CsprngEngine::operator()(void* ptr, std::size_t count)
|
||||
{
|
||||
// RAND_bytes is thread-safe on OpenSSL 1.1.0 and later when compiled
|
||||
// with thread support, so we don't need to grab a mutex.
|
||||
// https://mta.openssl.org/pipermail/openssl-users/2020-November/013146.html
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || !defined(OPENSSL_THREADS)
|
||||
std::lock_guard lock(mutex_);
|
||||
std::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
|
||||
auto const result = RAND_bytes(reinterpret_cast<unsigned char*>(ptr), count);
|
||||
@@ -69,19 +69,19 @@ csprng_engine::operator()(void* ptr, std::size_t count)
|
||||
Throw<std::runtime_error>("CSPRNG: Insufficient entropy");
|
||||
}
|
||||
|
||||
csprng_engine::result_type
|
||||
csprng_engine::operator()()
|
||||
CsprngEngine::result_type
|
||||
CsprngEngine::operator()()
|
||||
{
|
||||
result_type ret = 0;
|
||||
(*this)(&ret, sizeof(result_type));
|
||||
return ret;
|
||||
}
|
||||
|
||||
csprng_engine&
|
||||
crypto_prng()
|
||||
CsprngEngine&
|
||||
cryptoPrng()
|
||||
{
|
||||
static csprng_engine engine;
|
||||
return engine;
|
||||
static CsprngEngine kEngine;
|
||||
return kEngine;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
void
|
||||
secure_erase(void* dest, std::size_t bytes)
|
||||
secureErase(void* dest, std::size_t bytes)
|
||||
{
|
||||
OPENSSL_cleanse(dest, bytes);
|
||||
}
|
||||
|
||||
@@ -11,21 +11,21 @@
|
||||
|
||||
namespace xrpl::git {
|
||||
|
||||
static constexpr char kGIT_COMMIT_HASH[] = GIT_COMMIT_HASH;
|
||||
static constexpr char kGIT_BUILD_BRANCH[] = GIT_BUILD_BRANCH;
|
||||
static constexpr char kGitCommitHash[] = GIT_COMMIT_HASH;
|
||||
static constexpr char kGitBuildBranch[] = GIT_BUILD_BRANCH;
|
||||
|
||||
std::string const&
|
||||
getCommitHash()
|
||||
{
|
||||
static std::string const kVALUE = kGIT_COMMIT_HASH;
|
||||
return kVALUE;
|
||||
static std::string const kValue = kGitCommitHash;
|
||||
return kValue;
|
||||
}
|
||||
|
||||
std::string const&
|
||||
getBuildBranch()
|
||||
{
|
||||
static std::string const kVALUE = kGIT_BUILD_BRANCH;
|
||||
return kVALUE;
|
||||
static std::string const kValue = kGitBuildBranch;
|
||||
return kValue;
|
||||
}
|
||||
|
||||
} // namespace xrpl::git
|
||||
|
||||
@@ -6,160 +6,160 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
JsonPropertyStream::JsonPropertyStream() : m_top(Json::objectValue)
|
||||
JsonPropertyStream::JsonPropertyStream() : topValue(json::ValueType::Object)
|
||||
{
|
||||
m_stack.reserve(64);
|
||||
m_stack.push_back(&m_top);
|
||||
stack.reserve(64);
|
||||
stack.push_back(&topValue);
|
||||
}
|
||||
|
||||
Json::Value const&
|
||||
json::Value const&
|
||||
JsonPropertyStream::top() const
|
||||
{
|
||||
return m_top;
|
||||
return topValue;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::map_begin()
|
||||
JsonPropertyStream::mapBegin()
|
||||
{
|
||||
// top is array
|
||||
Json::Value& top(*m_stack.back());
|
||||
Json::Value& map(top.append(Json::objectValue));
|
||||
m_stack.push_back(&map);
|
||||
json::Value& top(*stack.back());
|
||||
json::Value& map(top.append(json::ValueType::Object));
|
||||
stack.push_back(&map);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::map_begin(std::string const& key)
|
||||
JsonPropertyStream::mapBegin(std::string const& key)
|
||||
{
|
||||
// top is a map
|
||||
Json::Value& top(*m_stack.back());
|
||||
Json::Value& map(top[key] = Json::objectValue);
|
||||
m_stack.push_back(&map);
|
||||
json::Value& top(*stack.back());
|
||||
json::Value& map(top[key] = json::ValueType::Object);
|
||||
stack.push_back(&map);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::map_end()
|
||||
JsonPropertyStream::mapEnd()
|
||||
{
|
||||
m_stack.pop_back();
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, short v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, unsigned short v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, int v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, unsigned int v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, long v)
|
||||
{
|
||||
(*m_stack.back())[key] = int(v);
|
||||
(*stack.back())[key] = int(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, float v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, double v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& key, std::string const& v)
|
||||
{
|
||||
(*m_stack.back())[key] = v;
|
||||
(*stack.back())[key] = v;
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::array_begin()
|
||||
JsonPropertyStream::arrayBegin()
|
||||
{
|
||||
// top is array
|
||||
Json::Value& top(*m_stack.back());
|
||||
Json::Value& vec(top.append(Json::arrayValue));
|
||||
m_stack.push_back(&vec);
|
||||
json::Value& top(*stack.back());
|
||||
json::Value& vec(top.append(json::ValueType::Array));
|
||||
stack.push_back(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::array_begin(std::string const& key)
|
||||
JsonPropertyStream::arrayBegin(std::string const& key)
|
||||
{
|
||||
// top is a map
|
||||
Json::Value& top(*m_stack.back());
|
||||
Json::Value& vec(top[key] = Json::arrayValue);
|
||||
m_stack.push_back(&vec);
|
||||
json::Value& top(*stack.back());
|
||||
json::Value& vec(top[key] = json::ValueType::Array);
|
||||
stack.push_back(&vec);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::array_end()
|
||||
JsonPropertyStream::arrayEnd()
|
||||
{
|
||||
m_stack.pop_back();
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(short v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(unsigned short v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(int v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(unsigned int v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(long v)
|
||||
{
|
||||
m_stack.back()->append(int(v));
|
||||
stack.back()->append(int(v));
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(float v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(double v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
void
|
||||
JsonPropertyStream::add(std::string const& v)
|
||||
{
|
||||
m_stack.back()->append(v);
|
||||
stack.back()->append(v);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -5,47 +5,47 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Json {
|
||||
namespace json {
|
||||
|
||||
namespace {
|
||||
|
||||
void
|
||||
outputJson(Json::Value const& value, Writer& writer)
|
||||
outputJson(Value const& value, Writer& writer)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
case Json::nullValue: {
|
||||
case ValueType::Null: {
|
||||
writer.output(nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::intValue: {
|
||||
case ValueType::Int: {
|
||||
writer.output(value.asInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::uintValue: {
|
||||
case ValueType::UInt: {
|
||||
writer.output(value.asUInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::realValue: {
|
||||
case ValueType::Real: {
|
||||
writer.output(value.asDouble());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::stringValue: {
|
||||
case ValueType::String: {
|
||||
writer.output(value.asString());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::booleanValue: {
|
||||
case ValueType::Boolean: {
|
||||
writer.output(value.asBool());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::arrayValue: {
|
||||
writer.startRoot(Writer::array);
|
||||
case ValueType::Array: {
|
||||
writer.startRoot(Writer::CollectionType::Array);
|
||||
for (auto const& i : value)
|
||||
{
|
||||
writer.rawAppend();
|
||||
@@ -55,8 +55,8 @@ outputJson(Json::Value const& value, Writer& writer)
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::objectValue: {
|
||||
writer.startRoot(Writer::object);
|
||||
case ValueType::Object: {
|
||||
writer.startRoot(Writer::CollectionType::Object);
|
||||
auto members = value.getMemberNames();
|
||||
for (auto const& tag : members)
|
||||
{
|
||||
@@ -72,14 +72,14 @@ outputJson(Json::Value const& value, Writer& writer)
|
||||
} // namespace
|
||||
|
||||
void
|
||||
outputJson(Json::Value const& value, Output const& out)
|
||||
outputJson(Value const& value, Output const& out)
|
||||
{
|
||||
Writer writer(out);
|
||||
outputJson(value, writer);
|
||||
}
|
||||
|
||||
std::string
|
||||
jsonAsString(Json::Value const& value)
|
||||
jsonAsString(Value const& value)
|
||||
{
|
||||
std::string s;
|
||||
Writer writer(stringOutput(s));
|
||||
@@ -87,4 +87,4 @@ jsonAsString(Json::Value const& value)
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
} // namespace json
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Json {
|
||||
namespace json {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<char, char const*> jsonSpecialCharacterEscape = {
|
||||
std::map<char, char const*> gJsonSpecialCharacterEscape = {
|
||||
{'"', "\\\""},
|
||||
{'\\', "\\\\"},
|
||||
{'/', "\\/"},
|
||||
@@ -26,18 +26,18 @@ std::map<char, char const*> jsonSpecialCharacterEscape = {
|
||||
{'\r', "\\r"},
|
||||
{'\t', "\\t"}};
|
||||
|
||||
size_t const jsonEscapeLength = 2;
|
||||
size_t const kJsonEscapeLength = 2;
|
||||
|
||||
// All other JSON punctuation.
|
||||
char const closeBrace = '}';
|
||||
char const closeBracket = ']';
|
||||
char const colon = ':';
|
||||
char const comma = ',';
|
||||
char const openBrace = '{';
|
||||
char const openBracket = '[';
|
||||
char const quote = '"';
|
||||
char const kCloseBrace = '}';
|
||||
char const kCloseBracket = ']';
|
||||
char const kColon = ':';
|
||||
char const kComma = ',';
|
||||
char const kOpenBrace = '{';
|
||||
char const kOpenBracket = '[';
|
||||
char const kQuote = '"';
|
||||
|
||||
auto const integralFloatsBecomeInts = false;
|
||||
auto const kIntegralFloatsBecomeInts = false;
|
||||
|
||||
size_t
|
||||
lengthWithoutTrailingZeros(std::string const& s)
|
||||
@@ -52,7 +52,7 @@ lengthWithoutTrailingZeros(std::string const& s)
|
||||
if (hasDecimals)
|
||||
return lastNonZero + 1;
|
||||
|
||||
if (integralFloatsBecomeInts || lastNonZero + 2 > s.size())
|
||||
if (kIntegralFloatsBecomeInts || lastNonZero + 2 > s.size())
|
||||
return lastNonZero;
|
||||
|
||||
return lastNonZero + 2;
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
void
|
||||
start(CollectionType ct)
|
||||
{
|
||||
char const ch = (ct == array) ? openBracket : openBrace;
|
||||
char const ch = (ct == CollectionType::Array) ? kOpenBracket : kOpenBrace;
|
||||
output({&ch, 1});
|
||||
stack_.emplace(Collection{.type = ct});
|
||||
}
|
||||
@@ -99,24 +99,24 @@ public:
|
||||
markStarted();
|
||||
std::size_t position = 0, writtenUntil = 0;
|
||||
|
||||
output_({"e, 1});
|
||||
output_({&kQuote, 1});
|
||||
auto data = bytes.data();
|
||||
for (; position < bytes.size(); ++position)
|
||||
{
|
||||
auto i = jsonSpecialCharacterEscape.find(data[position]);
|
||||
if (i != jsonSpecialCharacterEscape.end())
|
||||
auto i = gJsonSpecialCharacterEscape.find(data[position]);
|
||||
if (i != gJsonSpecialCharacterEscape.end())
|
||||
{
|
||||
if (writtenUntil < position)
|
||||
{
|
||||
output_({data + writtenUntil, position - writtenUntil});
|
||||
}
|
||||
output_({i->second, jsonEscapeLength});
|
||||
output_({i->second, kJsonEscapeLength});
|
||||
writtenUntil = position + 1;
|
||||
};
|
||||
}
|
||||
if (writtenUntil < position)
|
||||
output_({data + writtenUntil, position - writtenUntil});
|
||||
output_({"e, 1});
|
||||
output_({&kQuote, 1});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -134,7 +134,9 @@ public:
|
||||
auto t = stack_.top().type;
|
||||
if (t != type)
|
||||
{
|
||||
check(false, "Not an " + ((type == array ? "array: " : "object: ") + message));
|
||||
check(
|
||||
false,
|
||||
"Not an " + ((type == CollectionType::Array ? "array: " : "object: ") + message));
|
||||
}
|
||||
if (stack_.top().isFirst)
|
||||
{
|
||||
@@ -142,7 +144,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
output_({&comma, 1});
|
||||
output_({&kComma, 1});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ public:
|
||||
#endif
|
||||
|
||||
stringOutput(tag);
|
||||
output_({&colon, 1});
|
||||
output_({&kColon, 1});
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
@@ -171,8 +173,8 @@ public:
|
||||
{
|
||||
check(!empty(), "Empty stack in finish()");
|
||||
|
||||
auto isArray = stack_.top().type == array;
|
||||
auto ch = isArray ? closeBracket : closeBrace;
|
||||
auto isArray = stack_.top().type == CollectionType::Array;
|
||||
auto ch = isArray ? kCloseBracket : kCloseBrace;
|
||||
output_({&ch, 1});
|
||||
stack_.pop();
|
||||
}
|
||||
@@ -198,7 +200,7 @@ private:
|
||||
struct Collection
|
||||
{
|
||||
/** What type of collection are we in? */
|
||||
Writer::CollectionType type = Writer::CollectionType::array;
|
||||
Writer::CollectionType type = Writer::CollectionType::Array;
|
||||
|
||||
/** Is this the first entry in a collection?
|
||||
* If false, we have to emit a , before we write the next entry. */
|
||||
@@ -253,7 +255,7 @@ Writer::output(std::string const& s)
|
||||
}
|
||||
|
||||
void
|
||||
Writer::output(Json::Value const& value)
|
||||
Writer::output(json::Value const& value)
|
||||
{
|
||||
impl_->markStarted();
|
||||
outputJson(value, impl_->getOutput());
|
||||
@@ -301,7 +303,7 @@ Writer::finishAll()
|
||||
void
|
||||
Writer::rawAppend()
|
||||
{
|
||||
impl_->nextCollectionEntry(array, "append");
|
||||
impl_->nextCollectionEntry(CollectionType::Array, "append");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -309,7 +311,7 @@ Writer::rawSet(std::string const& tag)
|
||||
{
|
||||
check(!tag.empty(), "Tag can't be empty");
|
||||
|
||||
impl_->nextCollectionEntry(object, "set");
|
||||
impl_->nextCollectionEntry(CollectionType::Object, "set");
|
||||
impl_->writeObjectTag(tag);
|
||||
}
|
||||
|
||||
@@ -322,14 +324,14 @@ Writer::startRoot(CollectionType type)
|
||||
void
|
||||
Writer::startAppend(CollectionType type)
|
||||
{
|
||||
impl_->nextCollectionEntry(array, "startAppend");
|
||||
impl_->nextCollectionEntry(CollectionType::Array, "startAppend");
|
||||
impl_->start(type);
|
||||
}
|
||||
|
||||
void
|
||||
Writer::startSet(CollectionType type, std::string const& key)
|
||||
{
|
||||
impl_->nextCollectionEntry(object, "startSet");
|
||||
impl_->nextCollectionEntry(CollectionType::Object, "startSet");
|
||||
impl_->writeObjectTag(key);
|
||||
impl_->start(type);
|
||||
}
|
||||
@@ -341,4 +343,4 @@ Writer::finish()
|
||||
impl_->finish();
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
} // namespace json
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace Json {
|
||||
namespace json {
|
||||
// Implementation of class Reader
|
||||
// ////////////////////////////////
|
||||
|
||||
@@ -102,9 +102,9 @@ Reader::parse(char const* beginDoc, char const* endDoc, Value& root)
|
||||
{
|
||||
// Set error location to start of doc, ideally should be first token
|
||||
// found in doc
|
||||
token.type_ = tokenError;
|
||||
token.start_ = beginDoc;
|
||||
token.end_ = endDoc;
|
||||
token.type = TokenType::Error;
|
||||
token.start = beginDoc;
|
||||
token.end = endDoc;
|
||||
addError("A valid JSON document must be either an array or an object value.", token);
|
||||
return false;
|
||||
}
|
||||
@@ -117,41 +117,41 @@ Reader::readValue(unsigned depth)
|
||||
{
|
||||
Token token{};
|
||||
skipCommentTokens(token);
|
||||
if (depth > nest_limit)
|
||||
if (depth > kNestLimit)
|
||||
return addError("Syntax error: maximum nesting depth exceeded", token);
|
||||
bool successful = true;
|
||||
|
||||
switch (token.type_)
|
||||
switch (token.type)
|
||||
{
|
||||
case tokenObjectBegin:
|
||||
case TokenType::ObjectBegin:
|
||||
successful = readObject(token, depth);
|
||||
break;
|
||||
|
||||
case tokenArrayBegin:
|
||||
case TokenType::ArrayBegin:
|
||||
successful = readArray(token, depth);
|
||||
break;
|
||||
|
||||
case tokenInteger:
|
||||
case TokenType::Integer:
|
||||
successful = decodeNumber(token);
|
||||
break;
|
||||
|
||||
case tokenDouble:
|
||||
case TokenType::Double:
|
||||
successful = decodeDouble(token);
|
||||
break;
|
||||
|
||||
case tokenString:
|
||||
case TokenType::String:
|
||||
successful = decodeString(token);
|
||||
break;
|
||||
|
||||
case tokenTrue:
|
||||
case TokenType::True:
|
||||
currentValue() = true;
|
||||
break;
|
||||
|
||||
case tokenFalse:
|
||||
case TokenType::False:
|
||||
currentValue() = false;
|
||||
break;
|
||||
|
||||
case tokenNull:
|
||||
case TokenType::Null:
|
||||
currentValue() = Value();
|
||||
break;
|
||||
|
||||
@@ -168,7 +168,7 @@ Reader::skipCommentTokens(Token& token)
|
||||
do
|
||||
{
|
||||
readToken(token);
|
||||
} while (token.type_ == tokenComment);
|
||||
} while (token.type == TokenType::Comment);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -176,7 +176,7 @@ Reader::expectToken(TokenType type, Token& token, char const* message)
|
||||
{
|
||||
readToken(token);
|
||||
|
||||
if (token.type_ != type)
|
||||
if (token.type != type)
|
||||
return addError(message, token);
|
||||
|
||||
return true;
|
||||
@@ -186,35 +186,35 @@ bool
|
||||
Reader::readToken(Token& token)
|
||||
{
|
||||
skipSpaces();
|
||||
token.start_ = current_;
|
||||
token.start = current_;
|
||||
Char const c = getNextChar();
|
||||
bool ok = true;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '{':
|
||||
token.type_ = tokenObjectBegin;
|
||||
token.type = TokenType::ObjectBegin;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
token.type_ = tokenObjectEnd;
|
||||
token.type = TokenType::ObjectEnd;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
token.type_ = tokenArrayBegin;
|
||||
token.type = TokenType::ArrayBegin;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
token.type_ = tokenArrayEnd;
|
||||
token.type = TokenType::ArrayEnd;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
token.type_ = tokenString;
|
||||
token.type = TokenType::String;
|
||||
ok = readString();
|
||||
break;
|
||||
|
||||
case '/':
|
||||
token.type_ = tokenComment;
|
||||
token.type = TokenType::Comment;
|
||||
ok = readComment();
|
||||
break;
|
||||
|
||||
@@ -229,34 +229,34 @@ Reader::readToken(Token& token)
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
token.type_ = readNumber();
|
||||
token.type = readNumber();
|
||||
break;
|
||||
|
||||
case 't':
|
||||
token.type_ = tokenTrue;
|
||||
token.type = TokenType::True;
|
||||
ok = match("rue", 3);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
token.type_ = tokenFalse;
|
||||
token.type = TokenType::False;
|
||||
ok = match("alse", 4); // cspell:disable-line
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
token.type_ = tokenNull;
|
||||
token.type = TokenType::Null;
|
||||
ok = match("ull", 3);
|
||||
break;
|
||||
|
||||
case ',':
|
||||
token.type_ = tokenArraySeparator;
|
||||
token.type = TokenType::ArraySeparator;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
token.type_ = tokenMemberSeparator;
|
||||
token.type = TokenType::MemberSeparator;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
token.type_ = tokenEndOfStream;
|
||||
token.type = TokenType::EndOfStream;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -265,9 +265,9 @@ Reader::readToken(Token& token)
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
token.type_ = tokenError;
|
||||
token.type = TokenType::Error;
|
||||
|
||||
token.end_ = current_;
|
||||
token.end = current_;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -352,9 +352,9 @@ Reader::readCppStyleComment()
|
||||
Reader::TokenType
|
||||
Reader::readNumber()
|
||||
{
|
||||
static char const extended_tokens[] = {'.', 'e', 'E', '+', '-'};
|
||||
static char const kExtendedTokens[] = {'.', 'e', 'E', '+', '-'};
|
||||
|
||||
TokenType type = tokenInteger;
|
||||
TokenType type = TokenType::Integer;
|
||||
|
||||
if (current_ != end_)
|
||||
{
|
||||
@@ -365,12 +365,12 @@ Reader::readNumber()
|
||||
{
|
||||
if (std::isdigit(static_cast<unsigned char>(*current_)) == 0)
|
||||
{
|
||||
auto ret = std::ranges::find(extended_tokens, *current_);
|
||||
auto ret = std::ranges::find(kExtendedTokens, *current_);
|
||||
|
||||
if (ret == std::end(extended_tokens))
|
||||
if (ret == std::end(kExtendedTokens))
|
||||
break;
|
||||
|
||||
type = tokenDouble;
|
||||
type = TokenType::Double;
|
||||
}
|
||||
|
||||
++current_;
|
||||
@@ -407,35 +407,35 @@ Reader::readObject(Token& tokenStart, unsigned depth)
|
||||
{
|
||||
Token tokenName{};
|
||||
std::string name;
|
||||
currentValue() = Value(objectValue);
|
||||
currentValue() = Value(ValueType::Object);
|
||||
|
||||
while (readToken(tokenName))
|
||||
{
|
||||
bool initialTokenOk = true;
|
||||
|
||||
while (tokenName.type_ == tokenComment && initialTokenOk)
|
||||
while (tokenName.type == TokenType::Comment && initialTokenOk)
|
||||
initialTokenOk = readToken(tokenName);
|
||||
|
||||
if (!initialTokenOk)
|
||||
break;
|
||||
|
||||
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
|
||||
if (tokenName.type == TokenType::ObjectEnd && name.empty()) // empty object
|
||||
return true;
|
||||
|
||||
if (tokenName.type_ != tokenString)
|
||||
if (tokenName.type != TokenType::String)
|
||||
break;
|
||||
|
||||
name = "";
|
||||
|
||||
if (!decodeString(tokenName, name))
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
return recoverFromError(TokenType::ObjectEnd);
|
||||
|
||||
Token colon{};
|
||||
|
||||
if (!readToken(colon) || colon.type_ != tokenMemberSeparator)
|
||||
if (!readToken(colon) || colon.type != TokenType::MemberSeparator)
|
||||
{
|
||||
return addErrorAndRecover(
|
||||
"Missing ':' after object member name", colon, tokenObjectEnd);
|
||||
"Missing ':' after object member name", colon, TokenType::ObjectEnd);
|
||||
}
|
||||
|
||||
// Reject duplicate names
|
||||
@@ -448,34 +448,34 @@ Reader::readObject(Token& tokenStart, unsigned depth)
|
||||
nodes_.pop();
|
||||
|
||||
if (!ok) // error already set
|
||||
return recoverFromError(tokenObjectEnd);
|
||||
return recoverFromError(TokenType::ObjectEnd);
|
||||
|
||||
Token comma{};
|
||||
|
||||
if (!readToken(comma) ||
|
||||
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment))
|
||||
(comma.type != TokenType::ObjectEnd && comma.type != TokenType::ArraySeparator &&
|
||||
comma.type != TokenType::Comment))
|
||||
{
|
||||
return addErrorAndRecover(
|
||||
"Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
|
||||
"Missing ',' or '}' in object declaration", comma, TokenType::ObjectEnd);
|
||||
}
|
||||
|
||||
bool finalizeTokenOk = true;
|
||||
|
||||
while (comma.type_ == tokenComment && finalizeTokenOk)
|
||||
while (comma.type == TokenType::Comment && finalizeTokenOk)
|
||||
finalizeTokenOk = readToken(comma);
|
||||
|
||||
if (comma.type_ == tokenObjectEnd)
|
||||
if (comma.type == TokenType::ObjectEnd)
|
||||
return true;
|
||||
}
|
||||
|
||||
return addErrorAndRecover("Missing '}' or object member name", tokenName, tokenObjectEnd);
|
||||
return addErrorAndRecover("Missing '}' or object member name", tokenName, TokenType::ObjectEnd);
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::readArray(Token& tokenStart, unsigned depth)
|
||||
{
|
||||
currentValue() = Value(arrayValue);
|
||||
currentValue() = Value(ValueType::Array);
|
||||
skipSpaces();
|
||||
|
||||
if (*current_ == ']') // empty array
|
||||
@@ -495,27 +495,27 @@ Reader::readArray(Token& tokenStart, unsigned depth)
|
||||
nodes_.pop();
|
||||
|
||||
if (!ok) // error already set
|
||||
return recoverFromError(tokenArrayEnd);
|
||||
return recoverFromError(TokenType::ArrayEnd);
|
||||
|
||||
Token token{};
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readToken(token);
|
||||
|
||||
while (token.type_ == tokenComment && ok)
|
||||
while (token.type == TokenType::Comment && ok)
|
||||
{
|
||||
ok = readToken(token);
|
||||
}
|
||||
|
||||
bool const badTokenType =
|
||||
(token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
|
||||
(token.type != TokenType::ArraySeparator && token.type != TokenType::ArrayEnd);
|
||||
|
||||
if (!ok || badTokenType)
|
||||
{
|
||||
return addErrorAndRecover(
|
||||
"Missing ',' or ']' in array declaration", token, tokenArrayEnd);
|
||||
"Missing ',' or ']' in array declaration", token, TokenType::ArrayEnd);
|
||||
}
|
||||
|
||||
if (token.type_ == tokenArrayEnd)
|
||||
if (token.type == TokenType::ArrayEnd)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -525,16 +525,16 @@ Reader::readArray(Token& tokenStart, unsigned depth)
|
||||
bool
|
||||
Reader::decodeNumber(Token& token)
|
||||
{
|
||||
Location current = token.start_;
|
||||
Location current = token.start;
|
||||
bool const isNegative = *current == '-';
|
||||
|
||||
if (isNegative)
|
||||
++current;
|
||||
|
||||
if (current == token.end_)
|
||||
if (current == token.end)
|
||||
{
|
||||
return addError(
|
||||
"'" + std::string(token.start_, token.end_) + "' is not a valid number.", token);
|
||||
"'" + std::string(token.start, token.end) + "' is not a valid number.", token);
|
||||
}
|
||||
|
||||
// The existing Json integers are 32-bit so using a 64-bit value here avoids
|
||||
@@ -542,37 +542,37 @@ Reader::decodeNumber(Token& token)
|
||||
std::int64_t value = 0;
|
||||
|
||||
static_assert(
|
||||
sizeof(value) > sizeof(Value::maxUInt),
|
||||
sizeof(value) > sizeof(Value::kMaxUInt),
|
||||
"The JSON integer overflow logic will need to be reworked.");
|
||||
|
||||
while (current < token.end_ && (value <= Value::maxUInt))
|
||||
while (current < token.end && (value <= Value::kMaxUInt))
|
||||
{
|
||||
Char const c = *current++;
|
||||
|
||||
if (c < '0' || c > '9')
|
||||
{
|
||||
return addError(
|
||||
"'" + std::string(token.start_, token.end_) + "' is not a number.", token);
|
||||
"'" + std::string(token.start, token.end) + "' is not a number.", token);
|
||||
}
|
||||
|
||||
value = (value * 10) + (c - '0');
|
||||
}
|
||||
|
||||
// More tokens left -> input is larger than largest possible return value
|
||||
if (current != token.end_)
|
||||
if (current != token.end)
|
||||
{
|
||||
return addError(
|
||||
"'" + std::string(token.start_, token.end_) + "' exceeds the allowable range.", token);
|
||||
"'" + std::string(token.start, token.end) + "' exceeds the allowable range.", token);
|
||||
}
|
||||
|
||||
if (isNegative)
|
||||
{
|
||||
value = -value;
|
||||
|
||||
if (value < Value::minInt || value > Value::maxInt)
|
||||
if (value < Value::kMinInt || value > Value::kMaxInt)
|
||||
{
|
||||
return addError(
|
||||
"'" + std::string(token.start_, token.end_) + "' exceeds the allowable range.",
|
||||
"'" + std::string(token.start, token.end) + "' exceeds the allowable range.",
|
||||
token);
|
||||
}
|
||||
|
||||
@@ -580,15 +580,15 @@ Reader::decodeNumber(Token& token)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value > Value::maxUInt)
|
||||
if (value > Value::kMaxUInt)
|
||||
{
|
||||
return addError(
|
||||
"'" + std::string(token.start_, token.end_) + "' exceeds the allowable range.",
|
||||
"'" + std::string(token.start, token.end) + "' exceeds the allowable range.",
|
||||
token);
|
||||
}
|
||||
|
||||
// If it's representable as a signed integer, construct it as one.
|
||||
if (value <= Value::maxInt)
|
||||
if (value <= Value::kMaxInt)
|
||||
{
|
||||
currentValue() = static_cast<Value::Int>(value);
|
||||
}
|
||||
@@ -607,7 +607,7 @@ Reader::decodeDouble(Token& token)
|
||||
double value = 0;
|
||||
int const bufferSize = 32;
|
||||
int count = 0;
|
||||
int const length = int(token.end_ - token.start_);
|
||||
int const length = int(token.end - token.start);
|
||||
// Sanity check to avoid buffer overflow exploits.
|
||||
if (length < 0)
|
||||
{
|
||||
@@ -622,17 +622,17 @@ Reader::decodeDouble(Token& token)
|
||||
if (length <= bufferSize)
|
||||
{
|
||||
Char buffer[bufferSize + 1];
|
||||
memcpy(buffer, token.start_, length);
|
||||
memcpy(buffer, token.start, length);
|
||||
buffer[length] = 0;
|
||||
count = sscanf(buffer, format, &value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string const buffer(token.start_, token.end_);
|
||||
std::string const buffer(token.start, token.end);
|
||||
count = sscanf(buffer.c_str(), format, &value);
|
||||
}
|
||||
if (count != 1)
|
||||
return addError("'" + std::string(token.start_, token.end_) + "' is not a number.", token);
|
||||
return addError("'" + std::string(token.start, token.end) + "' is not a number.", token);
|
||||
currentValue() = value;
|
||||
return true;
|
||||
}
|
||||
@@ -652,9 +652,9 @@ Reader::decodeString(Token& token)
|
||||
bool
|
||||
Reader::decodeString(Token& token, std::string& decoded)
|
||||
{
|
||||
decoded.reserve(token.end_ - token.start_ - 2);
|
||||
Location current = token.start_ + 1; // skip '"'
|
||||
Location end = token.end_ - 1; // do not include '"'
|
||||
decoded.reserve(token.end - token.start - 2);
|
||||
Location current = token.start + 1; // skip '"'
|
||||
Location end = token.end - 1; // do not include '"'
|
||||
|
||||
while (current != end)
|
||||
{
|
||||
@@ -816,9 +816,9 @@ bool
|
||||
Reader::addError(std::string const& message, Token& token, Location extra)
|
||||
{
|
||||
ErrorInfo info;
|
||||
info.token_ = token;
|
||||
info.message_ = message;
|
||||
info.extra_ = extra;
|
||||
info.token = token;
|
||||
info.message = message;
|
||||
info.extra = extra;
|
||||
errors_.push_back(info);
|
||||
return false;
|
||||
}
|
||||
@@ -834,7 +834,7 @@ Reader::recoverFromError(TokenType skipUntilToken)
|
||||
if (!readToken(skip))
|
||||
errors_.resize(errorCount); // discard errors caused by recovery
|
||||
|
||||
if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
|
||||
if (skip.type == skipUntilToken || skip.type == TokenType::EndOfStream)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -911,11 +911,11 @@ Reader::getFormattedErrorMessages() const
|
||||
for (Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError)
|
||||
{
|
||||
ErrorInfo const& error = *itError;
|
||||
formattedMessage += "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
formattedMessage += "* " + getLocationLineAndColumn(error.token.start) + "\n";
|
||||
formattedMessage += " " + error.message + "\n";
|
||||
|
||||
if (error.extra_ != nullptr)
|
||||
formattedMessage += "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
|
||||
if (error.extra != nullptr)
|
||||
formattedMessage += "See " + getLocationLineAndColumn(error.extra) + " for detail.\n";
|
||||
}
|
||||
|
||||
return formattedMessage;
|
||||
@@ -924,14 +924,14 @@ Reader::getFormattedErrorMessages() const
|
||||
std::istream&
|
||||
operator>>(std::istream& sin, Value& root)
|
||||
{
|
||||
Json::Reader reader;
|
||||
json::Reader reader;
|
||||
bool const ok = reader.parse(sin, root);
|
||||
|
||||
// XRPL_ASSERT(ok, "Json::operator>>() : parse succeeded");
|
||||
// XRPL_ASSERT(ok, "json::operator>>() : parse succeeded");
|
||||
if (!ok)
|
||||
xrpl::Throw<std::runtime_error>(reader.getFormattedErrorMessages());
|
||||
|
||||
return sin;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
} // namespace json
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
namespace Json {
|
||||
namespace json {
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
@@ -89,12 +89,12 @@ ValueIteratorBase::key() const
|
||||
{
|
||||
Value::CZString const czString = (*current_).first;
|
||||
|
||||
if (czString.c_str() != nullptr)
|
||||
if (czString.cStr() != nullptr)
|
||||
{
|
||||
if (czString.isStaticString())
|
||||
return Value(StaticString(czString.c_str()));
|
||||
return Value(StaticString(czString.cStr()));
|
||||
|
||||
return Value(czString.c_str());
|
||||
return Value(czString.cStr());
|
||||
}
|
||||
|
||||
return Value(czString.index());
|
||||
@@ -105,7 +105,7 @@ ValueIteratorBase::index() const
|
||||
{
|
||||
Value::CZString const czString = (*current_).first;
|
||||
|
||||
if (czString.c_str() == nullptr)
|
||||
if (czString.cStr() == nullptr)
|
||||
return czString.index();
|
||||
|
||||
return Value::UInt(-1);
|
||||
@@ -114,7 +114,7 @@ ValueIteratorBase::index() const
|
||||
char const*
|
||||
ValueIteratorBase::memberName() const
|
||||
{
|
||||
char const* name = (*current_).first.c_str();
|
||||
char const* name = (*current_).first.cStr();
|
||||
return (name != nullptr) ? name : "";
|
||||
}
|
||||
|
||||
@@ -164,4 +164,4 @@ ValueIterator::operator=(SelfType const& other)
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
} // namespace json
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace Json {
|
||||
namespace json {
|
||||
|
||||
static bool
|
||||
isControlCharacter(char ch)
|
||||
@@ -59,7 +59,7 @@ valueToString(Int value)
|
||||
if (isNegative)
|
||||
*--current = '-';
|
||||
|
||||
XRPL_ASSERT(current >= buffer, "Json::valueToString(Int) : buffer check");
|
||||
XRPL_ASSERT(current >= buffer, "json::valueToString(Int) : buffer check");
|
||||
return current;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ valueToString(UInt value)
|
||||
char buffer[32];
|
||||
char* current = buffer + sizeof(buffer); // NOLINT(misc-const-correctness)
|
||||
uintToString(value, current);
|
||||
XRPL_ASSERT(current >= buffer, "Json::valueToString(UInt) : buffer check");
|
||||
XRPL_ASSERT(current >= buffer, "json::valueToString(UInt) : buffer check");
|
||||
return current;
|
||||
}
|
||||
|
||||
@@ -188,31 +188,31 @@ FastWriter::writeValue(Value const& value)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
case nullValue:
|
||||
case ValueType::Null:
|
||||
document_ += "null";
|
||||
break;
|
||||
|
||||
case intValue:
|
||||
case ValueType::Int:
|
||||
document_ += valueToString(value.asInt());
|
||||
break;
|
||||
|
||||
case uintValue:
|
||||
case ValueType::UInt:
|
||||
document_ += valueToString(value.asUInt());
|
||||
break;
|
||||
|
||||
case realValue:
|
||||
case ValueType::Real:
|
||||
document_ += valueToString(value.asDouble());
|
||||
break;
|
||||
|
||||
case stringValue:
|
||||
case ValueType::String:
|
||||
document_ += valueToQuotedString(value.asCString());
|
||||
break;
|
||||
|
||||
case booleanValue:
|
||||
case ValueType::Boolean:
|
||||
document_ += valueToString(value.asBool());
|
||||
break;
|
||||
|
||||
case arrayValue: {
|
||||
case ValueType::Array: {
|
||||
document_ += "[";
|
||||
int const size = value.size();
|
||||
|
||||
@@ -228,7 +228,7 @@ FastWriter::writeValue(Value const& value)
|
||||
}
|
||||
break;
|
||||
|
||||
case objectValue: {
|
||||
case ValueType::Object: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
document_ += "{";
|
||||
|
||||
@@ -271,35 +271,35 @@ StyledWriter::writeValue(Value const& value)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
case nullValue:
|
||||
case ValueType::Null:
|
||||
pushValue("null");
|
||||
break;
|
||||
|
||||
case intValue:
|
||||
case ValueType::Int:
|
||||
pushValue(valueToString(value.asInt()));
|
||||
break;
|
||||
|
||||
case uintValue:
|
||||
case ValueType::UInt:
|
||||
pushValue(valueToString(value.asUInt()));
|
||||
break;
|
||||
|
||||
case realValue:
|
||||
case ValueType::Real:
|
||||
pushValue(valueToString(value.asDouble()));
|
||||
break;
|
||||
|
||||
case stringValue:
|
||||
case ValueType::String:
|
||||
pushValue(valueToQuotedString(value.asCString()));
|
||||
break;
|
||||
|
||||
case booleanValue:
|
||||
case ValueType::Boolean:
|
||||
pushValue(valueToString(value.asBool()));
|
||||
break;
|
||||
|
||||
case arrayValue:
|
||||
case ValueType::Array:
|
||||
writeArrayValue(value);
|
||||
break;
|
||||
|
||||
case objectValue: {
|
||||
case ValueType::Object: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
|
||||
if (members.empty())
|
||||
@@ -381,7 +381,7 @@ StyledWriter::writeArrayValue(Value const& value)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
childValues_.size() == size,
|
||||
"Json::StyledWriter::writeArrayValue : child size match");
|
||||
"json::StyledWriter::writeArrayValue : child size match");
|
||||
document_ += "[ ";
|
||||
|
||||
for (unsigned index = 0; index < size; ++index)
|
||||
@@ -478,7 +478,7 @@ StyledWriter::unindent()
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
int(indentString_.size()) >= indentSize_,
|
||||
"Json::StyledWriter::unindent : maximum indent size");
|
||||
"json::StyledWriter::unindent : maximum indent size");
|
||||
indentString_.resize(indentString_.size() - indentSize_);
|
||||
}
|
||||
|
||||
@@ -506,35 +506,35 @@ StyledStreamWriter::writeValue(Value const& value)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
case nullValue:
|
||||
case ValueType::Null:
|
||||
pushValue("null");
|
||||
break;
|
||||
|
||||
case intValue:
|
||||
case ValueType::Int:
|
||||
pushValue(valueToString(value.asInt()));
|
||||
break;
|
||||
|
||||
case uintValue:
|
||||
case ValueType::UInt:
|
||||
pushValue(valueToString(value.asUInt()));
|
||||
break;
|
||||
|
||||
case realValue:
|
||||
case ValueType::Real:
|
||||
pushValue(valueToString(value.asDouble()));
|
||||
break;
|
||||
|
||||
case stringValue:
|
||||
case ValueType::String:
|
||||
pushValue(valueToQuotedString(value.asCString()));
|
||||
break;
|
||||
|
||||
case booleanValue:
|
||||
case ValueType::Boolean:
|
||||
pushValue(valueToString(value.asBool()));
|
||||
break;
|
||||
|
||||
case arrayValue:
|
||||
case ValueType::Array:
|
||||
writeArrayValue(value);
|
||||
break;
|
||||
|
||||
case objectValue: {
|
||||
case ValueType::Object: {
|
||||
Value::Members members(value.getMemberNames());
|
||||
|
||||
if (members.empty())
|
||||
@@ -616,7 +616,7 @@ StyledStreamWriter::writeArrayValue(Value const& value)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
childValues_.size() == size,
|
||||
"Json::StyledStreamWriter::writeArrayValue : child size match");
|
||||
"json::StyledStreamWriter::writeArrayValue : child size match");
|
||||
*document_ << "[ ";
|
||||
|
||||
for (unsigned index = 0; index < size; ++index)
|
||||
@@ -714,16 +714,16 @@ StyledStreamWriter::unindent()
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
indentString_.size() >= indentation_.size(),
|
||||
"Json::StyledStreamWriter::unindent : maximum indent size");
|
||||
"json::StyledStreamWriter::unindent : maximum indent size");
|
||||
indentString_.resize(indentString_.size() - indentation_.size());
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& sout, Value const& root)
|
||||
{
|
||||
Json::StyledStreamWriter writer;
|
||||
json::StyledStreamWriter writer;
|
||||
writer.write(sout, root);
|
||||
return sout;
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
} // namespace json
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Json {
|
||||
namespace json {
|
||||
|
||||
std::string
|
||||
to_string(Value const& value)
|
||||
@@ -18,4 +18,4 @@ pretty(Value const& value)
|
||||
return StyledWriter().write(value);
|
||||
}
|
||||
|
||||
} // namespace Json
|
||||
} // namespace json
|
||||
|
||||
@@ -25,35 +25,35 @@ AcceptedLedgerTx::AcceptedLedgerTx(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
std::shared_ptr<STTx const> const& txn,
|
||||
std::shared_ptr<STObject const> const& met)
|
||||
: mTxn(txn)
|
||||
, mMeta(txn->getTransactionID(), ledger->seq(), *met)
|
||||
, mAffected(mMeta.getAffectedAccounts())
|
||||
: txn_(txn)
|
||||
, meta_(txn->getTransactionID(), ledger->seq(), *met)
|
||||
, affected_(meta_.getAffectedAccounts())
|
||||
{
|
||||
XRPL_ASSERT(!ledger->open(), "xrpl::AcceptedLedgerTx::AcceptedLedgerTx : valid ledger state");
|
||||
|
||||
Serializer s;
|
||||
met->add(s);
|
||||
mRawMeta = std::move(s.modData());
|
||||
rawMeta_ = std::move(s.modData());
|
||||
|
||||
mJson = Json::objectValue;
|
||||
mJson[jss::transaction] = mTxn->getJson(JsonOptions::none);
|
||||
json_ = json::ValueType::Object;
|
||||
json_[jss::transaction] = txn_->getJson(JsonOptions::Values::None);
|
||||
|
||||
mJson[jss::meta] = mMeta.getJson(JsonOptions::none);
|
||||
mJson[jss::raw_meta] = strHex(mRawMeta);
|
||||
json_[jss::meta] = meta_.getJson(JsonOptions::Values::None);
|
||||
json_[jss::raw_meta] = strHex(rawMeta_);
|
||||
|
||||
mJson[jss::result] = transHuman(mMeta.getResultTER());
|
||||
json_[jss::result] = transHuman(meta_.getResultTER());
|
||||
|
||||
if (!mAffected.empty())
|
||||
if (!affected_.empty())
|
||||
{
|
||||
Json::Value& affected = (mJson[jss::affected] = Json::arrayValue);
|
||||
for (auto const& account : mAffected)
|
||||
json::Value& affected = (json_[jss::affected] = json::ValueType::Array);
|
||||
for (auto const& account : affected_)
|
||||
affected.append(toBase58(account));
|
||||
}
|
||||
|
||||
if (mTxn->getTxnType() == ttOFFER_CREATE)
|
||||
if (txn_->getTxnType() == ttOFFER_CREATE)
|
||||
{
|
||||
auto const& account = mTxn->getAccountID(sfAccount);
|
||||
auto const amount = mTxn->getFieldAmount(sfTakerGets);
|
||||
auto const& account = txn_->getAccountID(sfAccount);
|
||||
auto const amount = txn_->getFieldAmount(sfTakerGets);
|
||||
|
||||
// If the offer create is not self funded then add the owner balance
|
||||
if (account != amount.getIssuer())
|
||||
@@ -62,10 +62,10 @@ AcceptedLedgerTx::AcceptedLedgerTx(
|
||||
*ledger,
|
||||
account,
|
||||
amount,
|
||||
fhIGNORE_FREEZE,
|
||||
ahIGNORE_AUTH,
|
||||
FreezeHandling::IgnoreFreeze,
|
||||
AuthHandling::IgnoreAuth,
|
||||
beast::Journal{beast::Journal::getNullSink()});
|
||||
mJson[jss::transaction][jss::owner_funds] = ownerFunds.getText();
|
||||
json_[jss::transaction][jss::owner_funds] = ownerFunds.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,8 +73,8 @@ AcceptedLedgerTx::AcceptedLedgerTx(
|
||||
std::string
|
||||
AcceptedLedgerTx::getEscMeta() const
|
||||
{
|
||||
XRPL_ASSERT(!mRawMeta.empty(), "xrpl::AcceptedLedgerTx::getEscMeta : metadata is set");
|
||||
return sqlBlobLiteral(mRawMeta);
|
||||
XRPL_ASSERT(!rawMeta_.empty(), "xrpl::AcceptedLedgerTx::getEscMeta : metadata is set");
|
||||
return sqlBlobLiteral(rawMeta_);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -43,15 +43,15 @@ ApplyStateTable::apply(RawView& to) const
|
||||
auto const& sle = item.second.second;
|
||||
switch (item.second.first)
|
||||
{
|
||||
case Action::cache:
|
||||
case Action::Cache:
|
||||
break;
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
to.rawErase(sle);
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
to.rawInsert(sle);
|
||||
break;
|
||||
case Action::modify:
|
||||
case Action::Modify:
|
||||
to.rawReplace(sle);
|
||||
break;
|
||||
};
|
||||
@@ -66,9 +66,9 @@ ApplyStateTable::size() const
|
||||
{
|
||||
switch (item.second.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
case Action::Erase:
|
||||
case Action::Insert:
|
||||
case Action::Modify:
|
||||
++ret;
|
||||
default:
|
||||
break;
|
||||
@@ -90,15 +90,15 @@ ApplyStateTable::visit(
|
||||
{
|
||||
switch (item.second.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
func(item.first, true, to.read(keylet::unchecked(item.first)), item.second.second);
|
||||
break;
|
||||
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
func(item.first, false, nullptr, item.second.second);
|
||||
break;
|
||||
|
||||
case Action::modify:
|
||||
case Action::Modify:
|
||||
func(item.first, false, to.read(keylet::unchecked(item.first)), item.second.second);
|
||||
break;
|
||||
|
||||
@@ -137,15 +137,15 @@ ApplyStateTable::apply(
|
||||
switch (item.second.first)
|
||||
{
|
||||
default:
|
||||
case Action::cache:
|
||||
case Action::Cache:
|
||||
continue;
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
type = &sfDeletedNode;
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
type = &sfCreatedNode;
|
||||
break;
|
||||
case Action::modify:
|
||||
case Action::Modify:
|
||||
type = &sfModifiedNode;
|
||||
break;
|
||||
}
|
||||
@@ -169,24 +169,24 @@ ApplyStateTable::apply(
|
||||
{
|
||||
// go through the original node for
|
||||
// modified fields saved on modification
|
||||
if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) &&
|
||||
if (obj.getFName().shouldMeta(SField::kSmdChangeOrig) &&
|
||||
!curNode->hasMatchingEntry(obj))
|
||||
prevs.emplace_back(obj);
|
||||
prevs.emplaceBack(obj);
|
||||
}
|
||||
|
||||
if (!prevs.empty())
|
||||
meta.getAffectedNode(item.first).emplace_back(std::move(prevs));
|
||||
meta.getAffectedNode(item.first).emplaceBack(std::move(prevs));
|
||||
|
||||
STObject finals(sfFinalFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
// go through the final node for final fields
|
||||
if (obj.getFName().shouldMeta(SField::sMD_Always | SField::sMD_DeleteFinal))
|
||||
finals.emplace_back(obj);
|
||||
if (obj.getFName().shouldMeta(SField::kSmdAlways | SField::kSmdDeleteFinal))
|
||||
finals.emplaceBack(obj);
|
||||
}
|
||||
|
||||
if (!finals.empty())
|
||||
meta.getAffectedNode(item.first).emplace_back(std::move(finals));
|
||||
meta.getAffectedNode(item.first).emplaceBack(std::move(finals));
|
||||
}
|
||||
else if (type == &sfModifiedNode)
|
||||
{
|
||||
@@ -205,24 +205,24 @@ ApplyStateTable::apply(
|
||||
for (auto const& obj : *origNode)
|
||||
{
|
||||
// search the original node for values saved on modify
|
||||
if (obj.getFName().shouldMeta(SField::sMD_ChangeOrig) &&
|
||||
if (obj.getFName().shouldMeta(SField::kSmdChangeOrig) &&
|
||||
!curNode->hasMatchingEntry(obj))
|
||||
prevs.emplace_back(obj);
|
||||
prevs.emplaceBack(obj);
|
||||
}
|
||||
|
||||
if (!prevs.empty())
|
||||
meta.getAffectedNode(item.first).emplace_back(std::move(prevs));
|
||||
meta.getAffectedNode(item.first).emplaceBack(std::move(prevs));
|
||||
|
||||
STObject finals(sfFinalFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
// search the final node for values saved always
|
||||
if (obj.getFName().shouldMeta(SField::sMD_Always | SField::sMD_ChangeNew))
|
||||
finals.emplace_back(obj);
|
||||
if (obj.getFName().shouldMeta(SField::kSmdAlways | SField::kSmdChangeNew))
|
||||
finals.emplaceBack(obj);
|
||||
}
|
||||
|
||||
if (!finals.empty())
|
||||
meta.getAffectedNode(item.first).emplace_back(std::move(finals));
|
||||
meta.getAffectedNode(item.first).emplaceBack(std::move(finals));
|
||||
}
|
||||
else if (type == &sfCreatedNode) // if created, thread to owner(s)
|
||||
{
|
||||
@@ -240,12 +240,12 @@ ApplyStateTable::apply(
|
||||
{
|
||||
// save non-default values
|
||||
if (!obj.isDefault() &&
|
||||
obj.getFName().shouldMeta(SField::sMD_Create | SField::sMD_Always))
|
||||
news.emplace_back(obj);
|
||||
obj.getFName().shouldMeta(SField::kSmdCreate | SField::kSmdAlways))
|
||||
news.emplaceBack(obj);
|
||||
}
|
||||
|
||||
if (!news.empty())
|
||||
meta.getAffectedNode(item.first).emplace_back(std::move(news));
|
||||
meta.getAffectedNode(item.first).emplaceBack(std::move(news));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -269,7 +269,7 @@ ApplyStateTable::apply(
|
||||
|
||||
// VFALCO For diagnostics do we want to show
|
||||
// metadata even when the base view is open?
|
||||
JLOG(j.trace()) << "metadata " << meta.getJson(JsonOptions::none);
|
||||
JLOG(j.trace()) << "metadata " << meta.getJson(JsonOptions::Values::None);
|
||||
|
||||
metadata = meta;
|
||||
}
|
||||
@@ -294,11 +294,11 @@ ApplyStateTable::exists(ReadView const& base, Keylet const& k) const
|
||||
auto const& sle = item.second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
return false;
|
||||
case Action::cache:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
case Action::Cache:
|
||||
case Action::Insert:
|
||||
case Action::Modify:
|
||||
break;
|
||||
}
|
||||
return k.check(*sle);
|
||||
@@ -320,11 +320,11 @@ ApplyStateTable::succ(
|
||||
if (!next)
|
||||
break;
|
||||
iter = items_.find(*next);
|
||||
} while (iter != items_.end() && iter->second.first == Action::erase);
|
||||
} while (iter != items_.end() && iter->second.first == Action::Erase);
|
||||
// Find non-deleted successor in our list
|
||||
for (iter = items_.upper_bound(key); iter != items_.end(); ++iter)
|
||||
{
|
||||
if (iter->second.first != Action::erase)
|
||||
if (iter->second.first != Action::Erase)
|
||||
{
|
||||
// Found both, return the lower key
|
||||
if (!next || next > iter->first)
|
||||
@@ -349,11 +349,11 @@ ApplyStateTable::read(ReadView const& base, Keylet const& k) const
|
||||
auto const& sle = item.second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
return nullptr;
|
||||
case Action::cache:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
case Action::Cache:
|
||||
case Action::Insert:
|
||||
case Action::Modify:
|
||||
break;
|
||||
};
|
||||
if (!k.check(*sle))
|
||||
@@ -376,18 +376,18 @@ ApplyStateTable::peek(ReadView const& base, Keylet const& k)
|
||||
iter,
|
||||
piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::cache, make_shared<SLE>(*sle)));
|
||||
forward_as_tuple(Action::Cache, make_shared<SLE>(*sle)));
|
||||
return iter->second.second;
|
||||
}
|
||||
auto const& item = iter->second;
|
||||
auto const& sle = item.second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
return nullptr;
|
||||
case Action::cache:
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
case Action::Cache:
|
||||
case Action::Insert:
|
||||
case Action::Modify:
|
||||
break;
|
||||
};
|
||||
if (!k.check(*sle))
|
||||
@@ -406,15 +406,15 @@ ApplyStateTable::erase(ReadView const& base, std::shared_ptr<SLE> const& sle)
|
||||
Throw<std::logic_error>("ApplyStateTable::erase: unknown SLE");
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
Throw<std::logic_error>("ApplyStateTable::erase: double erase");
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
items_.erase(iter);
|
||||
break;
|
||||
case Action::cache:
|
||||
case Action::modify:
|
||||
item.first = Action::erase;
|
||||
case Action::Cache:
|
||||
case Action::Modify:
|
||||
item.first = Action::Erase;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -424,21 +424,21 @@ ApplyStateTable::rawErase(ReadView const& base, std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
using namespace std;
|
||||
auto const result = items_.emplace(
|
||||
piecewise_construct, forward_as_tuple(sle->key()), forward_as_tuple(Action::erase, sle));
|
||||
piecewise_construct, forward_as_tuple(sle->key()), forward_as_tuple(Action::Erase, sle));
|
||||
if (result.second)
|
||||
return;
|
||||
auto& item = result.first->second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
Throw<std::logic_error>("ApplyStateTable::rawErase: double erase");
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
items_.erase(result.first);
|
||||
break;
|
||||
case Action::cache:
|
||||
case Action::modify:
|
||||
item.first = Action::erase;
|
||||
case Action::Cache:
|
||||
case Action::Modify:
|
||||
item.first = Action::Erase;
|
||||
item.second = sle;
|
||||
break;
|
||||
}
|
||||
@@ -455,22 +455,22 @@ ApplyStateTable::insert(ReadView const& base, std::shared_ptr<SLE> const& sle)
|
||||
iter,
|
||||
piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::insert, sle));
|
||||
forward_as_tuple(Action::Insert, sle));
|
||||
return;
|
||||
}
|
||||
auto& item = iter->second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::cache:
|
||||
case Action::Cache:
|
||||
Throw<std::logic_error>("ApplyStateTable::insert: already cached");
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
Throw<std::logic_error>("ApplyStateTable::insert: already inserted");
|
||||
case Action::modify:
|
||||
case Action::Modify:
|
||||
Throw<std::logic_error>("ApplyStateTable::insert: already modified");
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
break;
|
||||
}
|
||||
item.first = Action::modify;
|
||||
item.first = Action::Modify;
|
||||
item.second = sle;
|
||||
}
|
||||
|
||||
@@ -485,19 +485,19 @@ ApplyStateTable::replace(ReadView const& base, std::shared_ptr<SLE> const& sle)
|
||||
iter,
|
||||
piecewise_construct,
|
||||
forward_as_tuple(sle->key()),
|
||||
forward_as_tuple(Action::modify, sle));
|
||||
forward_as_tuple(Action::Modify, sle));
|
||||
return;
|
||||
}
|
||||
auto& item = iter->second;
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
Throw<std::logic_error>("ApplyStateTable::replace: already erased");
|
||||
case Action::cache:
|
||||
item.first = Action::modify;
|
||||
case Action::Cache:
|
||||
item.first = Action::Modify;
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
case Action::Insert:
|
||||
case Action::Modify:
|
||||
break;
|
||||
}
|
||||
item.second = sle;
|
||||
@@ -514,14 +514,14 @@ ApplyStateTable::update(ReadView const& base, std::shared_ptr<SLE> const& sle)
|
||||
Throw<std::logic_error>("ApplyStateTable::update: unknown SLE");
|
||||
switch (item.first)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
Throw<std::logic_error>("ApplyStateTable::update: erased");
|
||||
break;
|
||||
case Action::cache:
|
||||
item.first = Action::modify;
|
||||
case Action::Cache:
|
||||
item.first = Action::Modify;
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::modify:
|
||||
case Action::Insert:
|
||||
case Action::Modify:
|
||||
break;
|
||||
};
|
||||
}
|
||||
@@ -584,7 +584,7 @@ ApplyStateTable::getForMod(ReadView const& base, key_type const& key, Mods& mods
|
||||
if (iter != items_.end())
|
||||
{
|
||||
auto const& item = iter->second;
|
||||
if (item.first == Action::erase)
|
||||
if (item.first == Action::Erase)
|
||||
{
|
||||
// The Destination of an Escrow or a PayChannel may have been
|
||||
// deleted. In that case the account we're threading to will
|
||||
@@ -592,7 +592,7 @@ ApplyStateTable::getForMod(ReadView const& base, key_type const& key, Mods& mods
|
||||
JLOG(j.warn()) << "Trying to thread to deleted node";
|
||||
return nullptr;
|
||||
}
|
||||
if (item.first != Action::cache)
|
||||
if (item.first != Action::Cache)
|
||||
return item.second;
|
||||
|
||||
// If it's only cached, then the node is being modified only by
|
||||
|
||||
@@ -38,7 +38,7 @@ createRoot(
|
||||
describe(newRoot);
|
||||
|
||||
STVector256 v;
|
||||
v.push_back(key);
|
||||
v.pushBack(key);
|
||||
newRoot->setFieldV256(sfIndexes, v);
|
||||
|
||||
view.insert(newRoot);
|
||||
@@ -80,7 +80,7 @@ insertKey(
|
||||
if (std::ranges::find(indexes, key) != indexes.end())
|
||||
Throw<std::logic_error>("dirInsert: double insertion"); // LCOV_EXCL_LINE
|
||||
|
||||
indexes.push_back(key);
|
||||
indexes.pushBack(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -125,7 +125,7 @@ insertPage(
|
||||
// Check whether we're out of pages.
|
||||
if (page == 0)
|
||||
return std::nullopt;
|
||||
if (!view.rules().enabled(fixDirectoryLimit) && page >= dirNodeMaxPages) // Old pages limit
|
||||
if (!view.rules().enabled(fixDirectoryLimit) && page >= kDirNodeMaxPages) // Old pages limit
|
||||
return std::nullopt;
|
||||
|
||||
// We are about to create a new node; we'll link it to
|
||||
@@ -138,7 +138,7 @@ insertPage(
|
||||
|
||||
// Insert the new key:
|
||||
STVector256 indexes;
|
||||
indexes.push_back(key);
|
||||
indexes.pushBack(key);
|
||||
|
||||
node = std::make_shared<SLE>(keylet::page(directory, page));
|
||||
node->setFieldH256(sfRootIndex, directory.key);
|
||||
@@ -179,7 +179,7 @@ ApplyView::dirAdd(
|
||||
auto [page, node, indexes] = directory::findPreviousPage(*this, directory, root);
|
||||
|
||||
// If there's space, we use it:
|
||||
if (indexes.size() < dirNodeMaxEntries)
|
||||
if (indexes.size() < kDirNodeMaxEntries)
|
||||
{
|
||||
return directory::insertKey(*this, node, page, preserveOrder, indexes, key);
|
||||
}
|
||||
@@ -208,19 +208,19 @@ ApplyView::emptyDirDelete(Keylet const& directory)
|
||||
if (!node->getFieldV256(sfIndexes).empty())
|
||||
return false;
|
||||
|
||||
std::uint64_t constexpr rootPage = 0;
|
||||
static constexpr std::uint64_t kRootPage = 0;
|
||||
auto prevPage = node->getFieldU64(sfIndexPrevious);
|
||||
auto nextPage = node->getFieldU64(sfIndexNext);
|
||||
|
||||
if (nextPage == rootPage && prevPage != rootPage)
|
||||
if (nextPage == kRootPage && prevPage != kRootPage)
|
||||
Throw<std::logic_error>("Directory chain: fwd link broken"); // LCOV_EXCL_LINE
|
||||
|
||||
if (prevPage == rootPage && nextPage != rootPage)
|
||||
if (prevPage == kRootPage && nextPage != kRootPage)
|
||||
Throw<std::logic_error>("Directory chain: rev link broken"); // LCOV_EXCL_LINE
|
||||
|
||||
// Older versions of the code would, in some cases, allow the last page to
|
||||
// be empty. Remove such pages:
|
||||
if (nextPage == prevPage && nextPage != rootPage)
|
||||
// Older versions of the code would, in some cases, allow the last
|
||||
// page to be empty. Remove such pages:
|
||||
if (nextPage == prevPage && nextPage != kRootPage)
|
||||
{
|
||||
auto last = peek(keylet::page(directory, nextPage));
|
||||
|
||||
@@ -230,21 +230,23 @@ ApplyView::emptyDirDelete(Keylet const& directory)
|
||||
if (!last->getFieldV256(sfIndexes).empty())
|
||||
return false;
|
||||
|
||||
// Update the first page's linked list and mark it as updated.
|
||||
node->setFieldU64(sfIndexNext, rootPage);
|
||||
node->setFieldU64(sfIndexPrevious, rootPage);
|
||||
// Update the first page's linked list and
|
||||
// mark it as updated.
|
||||
node->setFieldU64(sfIndexNext, kRootPage);
|
||||
node->setFieldU64(sfIndexPrevious, kRootPage);
|
||||
update(node);
|
||||
|
||||
// And erase the empty last page:
|
||||
erase(last);
|
||||
|
||||
// Make sure our local values reflect the updated information:
|
||||
nextPage = rootPage;
|
||||
prevPage = rootPage;
|
||||
// Make sure our local values reflect the
|
||||
// updated information:
|
||||
nextPage = kRootPage;
|
||||
prevPage = kRootPage;
|
||||
}
|
||||
|
||||
// If there are no other pages, erase the root:
|
||||
if (nextPage == rootPage && prevPage == rootPage)
|
||||
if (nextPage == kRootPage && prevPage == kRootPage)
|
||||
erase(node);
|
||||
|
||||
return true;
|
||||
@@ -258,7 +260,7 @@ ApplyView::dirRemove(Keylet const& directory, std::uint64_t page, uint256 const&
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
std::uint64_t constexpr rootPage = 0;
|
||||
static constexpr std::uint64_t kRootPage = 0;
|
||||
|
||||
{
|
||||
auto entries = node->getFieldV256(sfIndexes);
|
||||
@@ -283,10 +285,11 @@ ApplyView::dirRemove(Keylet const& directory, std::uint64_t page, uint256 const&
|
||||
auto prevPage = node->getFieldU64(sfIndexPrevious);
|
||||
auto nextPage = node->getFieldU64(sfIndexNext);
|
||||
|
||||
// The first page is the directory's root node and is treated specially: it
|
||||
// can never be deleted even if it is empty, unless we plan on removing the
|
||||
// entire directory.
|
||||
if (page == rootPage)
|
||||
// The first page is the directory's root node and is
|
||||
// treated specially: it can never be deleted even if
|
||||
// it is empty, unless we plan on removing the entire
|
||||
// directory.
|
||||
if (page == kRootPage)
|
||||
{
|
||||
if (nextPage == page && prevPage != page)
|
||||
Throw<std::logic_error>("Directory chain: fwd link broken"); // LCOV_EXCL_LINE
|
||||
@@ -355,32 +358,32 @@ ApplyView::dirRemove(Keylet const& directory, std::uint64_t page, uint256 const&
|
||||
// The page is no longer linked. Delete it.
|
||||
erase(node);
|
||||
|
||||
// Check whether the next page is the last page and, if so, whether it's
|
||||
// empty. If it is, delete it.
|
||||
if (nextPage != rootPage && next->getFieldU64(sfIndexNext) == rootPage &&
|
||||
// Check whether the next page is the last page and, if
|
||||
// so, whether it's empty. If it is, delete it.
|
||||
if (nextPage != kRootPage && next->getFieldU64(sfIndexNext) == kRootPage &&
|
||||
next->getFieldV256(sfIndexes).empty())
|
||||
{
|
||||
// Since next doesn't point to the root, it can't be pointing to prev.
|
||||
erase(next);
|
||||
|
||||
// The previous page is now the last page:
|
||||
prev->setFieldU64(sfIndexNext, rootPage);
|
||||
prev->setFieldU64(sfIndexNext, kRootPage);
|
||||
update(prev);
|
||||
|
||||
// And the root points to the last page:
|
||||
auto root = peek(keylet::page(directory, rootPage));
|
||||
auto root = peek(keylet::page(directory, kRootPage));
|
||||
if (!root)
|
||||
Throw<std::logic_error>("Directory chain: root link broken."); // LCOV_EXCL_LINE
|
||||
|
||||
root->setFieldU64(sfIndexPrevious, prevPage);
|
||||
update(root);
|
||||
|
||||
nextPage = rootPage;
|
||||
nextPage = kRootPage;
|
||||
}
|
||||
|
||||
// If we're not keeping the root, then check to see if it's left empty.
|
||||
// If so, delete it as well.
|
||||
if (!keepRoot && nextPage == rootPage && prevPage == rootPage)
|
||||
// If we're not keeping the root, then check to see if
|
||||
// it's left empty. If so, delete it as well.
|
||||
if (!keepRoot && nextPage == kRootPage && prevPage == kRootPage)
|
||||
{
|
||||
if (prev->getFieldV256(sfIndexes).empty())
|
||||
erase(prev);
|
||||
|
||||
@@ -65,31 +65,31 @@ ApplyViewBase::read(Keylet const& k) const
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::slesBegin() const -> std::unique_ptr<sles_type::iter_base>
|
||||
ApplyViewBase::slesBegin() const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return base_->slesBegin();
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::slesEnd() const -> std::unique_ptr<sles_type::iter_base>
|
||||
ApplyViewBase::slesEnd() const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return base_->slesEnd();
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::slesUpperBound(uint256 const& key) const -> std::unique_ptr<sles_type::iter_base>
|
||||
ApplyViewBase::slesUpperBound(uint256 const& key) const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return base_->slesUpperBound(key);
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::txsBegin() const -> std::unique_ptr<txs_type::iter_base>
|
||||
ApplyViewBase::txsBegin() const -> std::unique_ptr<TxsType::iter_base>
|
||||
{
|
||||
return base_->txsBegin();
|
||||
}
|
||||
|
||||
auto
|
||||
ApplyViewBase::txsEnd() const -> std::unique_ptr<txs_type::iter_base>
|
||||
ApplyViewBase::txsEnd() const -> std::unique_ptr<TxsType::iter_base>
|
||||
{
|
||||
return base_->txsEnd();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <xrpl/ledger/BookDirs.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
@@ -15,11 +14,11 @@ namespace xrpl {
|
||||
BookDirs::BookDirs(ReadView const& view, Book const& book)
|
||||
: view_(&view)
|
||||
, root_(keylet::page(getBookBase(book)).key)
|
||||
, next_quality_(getQualityNext(root_))
|
||||
, key_(view_->succ(root_, next_quality_).value_or(beast::zero))
|
||||
, nextQuality_(getQualityNext(root_))
|
||||
, key_(view_->succ(root_, nextQuality_).value_or(beast::kZero))
|
||||
{
|
||||
XRPL_ASSERT(root_ != beast::zero, "xrpl::BookDirs::BookDirs : nonzero root");
|
||||
if (key_ != beast::zero)
|
||||
XRPL_ASSERT(root_ != beast::kZero, "xrpl::BookDirs::BookDirs : nonzero root");
|
||||
if (key_ != beast::kZero)
|
||||
{
|
||||
if (!cdirFirst(*view_, key_, sle_, entry_, index_))
|
||||
{
|
||||
@@ -34,9 +33,9 @@ auto
|
||||
BookDirs::begin() const -> BookDirs::const_iterator
|
||||
{
|
||||
auto it = BookDirs::const_iterator(*view_, root_, key_);
|
||||
if (key_ != beast::zero)
|
||||
if (key_ != beast::kZero)
|
||||
{
|
||||
it.next_quality_ = next_quality_;
|
||||
it.nextQuality_ = nextQuality_;
|
||||
it.sle_ = sle_;
|
||||
it.entry_ = entry_;
|
||||
it.index_ = index_;
|
||||
@@ -50,8 +49,6 @@ BookDirs::end() const -> BookDirs::const_iterator
|
||||
return BookDirs::const_iterator(*view_, root_, key_);
|
||||
}
|
||||
|
||||
beast::Journal BookDirs::const_iterator::j_ = beast::Journal{beast::Journal::getNullSink()};
|
||||
|
||||
bool
|
||||
BookDirs::const_iterator::operator==(BookDirs::const_iterator const& other) const
|
||||
{
|
||||
@@ -62,13 +59,14 @@ BookDirs::const_iterator::operator==(BookDirs::const_iterator const& other) cons
|
||||
view_ == other.view_ && root_ == other.root_,
|
||||
"xrpl::BookDirs::const_iterator::operator== : views and roots are "
|
||||
"matching");
|
||||
return entry_ == other.entry_ && cur_key_ == other.cur_key_ && index_ == other.index_;
|
||||
return entry_ == other.entry_ && curKey_ == other.curKey_ && index_ == other.index_;
|
||||
}
|
||||
|
||||
BookDirs::const_iterator::reference
|
||||
BookDirs::const_iterator::operator*() const
|
||||
{
|
||||
XRPL_ASSERT(index_ != beast::zero, "xrpl::BookDirs::const_iterator::operator* : nonzero index");
|
||||
XRPL_ASSERT(
|
||||
index_ != beast::kZero, "xrpl::BookDirs::const_iterator::operator* : nonzero index");
|
||||
if (!cache_)
|
||||
cache_ = view_->read(keylet::offer(index_));
|
||||
return *cache_;
|
||||
@@ -77,21 +75,21 @@ BookDirs::const_iterator::operator*() const
|
||||
BookDirs::const_iterator&
|
||||
BookDirs::const_iterator::operator++()
|
||||
{
|
||||
using beast::zero;
|
||||
using beast::kZero;
|
||||
|
||||
XRPL_ASSERT(index_ != zero, "xrpl::BookDirs::const_iterator::operator++ : nonzero index");
|
||||
if (!cdirNext(*view_, cur_key_, sle_, entry_, index_))
|
||||
XRPL_ASSERT(index_ != kZero, "xrpl::BookDirs::const_iterator::operator++ : nonzero index");
|
||||
if (!cdirNext(*view_, curKey_, sle_, entry_, index_))
|
||||
{
|
||||
if (index_ == 0)
|
||||
cur_key_ = view_->succ(++cur_key_, next_quality_).value_or(zero);
|
||||
curKey_ = view_->succ(++curKey_, nextQuality_).value_or(kZero);
|
||||
|
||||
if (index_ != 0 || cur_key_ == zero)
|
||||
if (index_ != 0 || curKey_ == kZero)
|
||||
{
|
||||
cur_key_ = key_;
|
||||
curKey_ = key_;
|
||||
entry_ = 0;
|
||||
index_ = zero;
|
||||
index_ = kZero;
|
||||
}
|
||||
else if (!cdirFirst(*view_, cur_key_, sle_, entry_, index_))
|
||||
else if (!cdirFirst(*view_, curKey_, sle_, entry_, index_))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::BookDirs::const_iterator::operator++ : directory is empty");
|
||||
@@ -107,7 +105,7 @@ BookDirs::const_iterator
|
||||
BookDirs::const_iterator::operator++(int)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
index_ != beast::zero, "xrpl::BookDirs::const_iterator::operator++(int) : nonzero index");
|
||||
index_ != beast::kZero, "xrpl::BookDirs::const_iterator::operator++(int) : nonzero index");
|
||||
const_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
|
||||
@@ -13,24 +13,24 @@ namespace xrpl {
|
||||
void
|
||||
BookListeners::addSubscriber(InfoSub::ref sub)
|
||||
{
|
||||
std::lock_guard const sl(mLock);
|
||||
mListeners[sub->getSeq()] = sub;
|
||||
std::scoped_lock const sl(lock_);
|
||||
listeners_[sub->getSeq()] = sub;
|
||||
}
|
||||
|
||||
void
|
||||
BookListeners::removeSubscriber(std::uint64_t seq)
|
||||
{
|
||||
std::lock_guard const sl(mLock);
|
||||
mListeners.erase(seq);
|
||||
std::scoped_lock const sl(lock_);
|
||||
listeners_.erase(seq);
|
||||
}
|
||||
|
||||
void
|
||||
BookListeners::publish(MultiApiJson const& jvObj, hash_set<std::uint64_t>& havePublished)
|
||||
{
|
||||
std::lock_guard const sl(mLock);
|
||||
auto it = mListeners.cbegin();
|
||||
std::scoped_lock const sl(lock_);
|
||||
auto it = listeners_.cbegin();
|
||||
|
||||
while (it != mListeners.cend())
|
||||
while (it != listeners_.cend())
|
||||
{
|
||||
InfoSub::pointer p = it->second.lock();
|
||||
|
||||
@@ -41,13 +41,13 @@ BookListeners::publish(MultiApiJson const& jvObj, hash_set<std::uint64_t>& haveP
|
||||
{
|
||||
jvObj.visit(
|
||||
p->getApiVersion(), //
|
||||
[&](Json::Value const& jv) { p->send(jv, true); });
|
||||
[&](json::Value const& jv) { p->send(jv, true); });
|
||||
}
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = mListeners.erase(it);
|
||||
it = listeners_.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,15 +22,15 @@ CachedViewImpl::exists(Keylet const& k) const
|
||||
std::shared_ptr<SLE const>
|
||||
CachedViewImpl::read(Keylet const& k) const
|
||||
{
|
||||
static CountedObjects::Counter hits{"CachedView::hit"};
|
||||
static CountedObjects::Counter hitsexpired{"CachedView::hitExpired"};
|
||||
static CountedObjects::Counter misses{"CachedView::miss"};
|
||||
static CountedObjects::Counter kHits{"CachedView::hit"};
|
||||
static CountedObjects::Counter kHitsExpired{"CachedView::hitExpired"};
|
||||
static CountedObjects::Counter kMisses{"CachedView::miss"};
|
||||
bool cacheHit = false;
|
||||
bool baseRead = false;
|
||||
|
||||
auto const digest = [&]() -> std::optional<uint256> {
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto const iter = map_.find(k.key);
|
||||
if (iter != map_.end())
|
||||
{
|
||||
@@ -50,15 +50,15 @@ CachedViewImpl::read(Keylet const& k) const
|
||||
XRPL_ASSERT(sle || baseRead, "xrpl::CachedView::read : null SLE result from base");
|
||||
if (cacheHit && baseRead)
|
||||
{
|
||||
hitsexpired.increment();
|
||||
kHitsExpired.increment();
|
||||
}
|
||||
else if (cacheHit)
|
||||
{
|
||||
hits.increment();
|
||||
kHits.increment();
|
||||
}
|
||||
else
|
||||
{
|
||||
misses.increment();
|
||||
kMisses.increment();
|
||||
}
|
||||
|
||||
if (!cacheHit)
|
||||
@@ -66,7 +66,7 @@ CachedViewImpl::read(Keylet const& k) const
|
||||
// Avoid acquiring this lock unless necessary. It is only necessary if
|
||||
// the key was not found in the map_. The lock is needed to add the key
|
||||
// and digest.
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
map_.emplace(k.key, *digest);
|
||||
}
|
||||
if (!sle || !k.check(*sle))
|
||||
|
||||
@@ -33,7 +33,7 @@ operator<(CanonicalTXSet::Key const& lhs, CanonicalTXSet::Key const& rhs)
|
||||
uint256
|
||||
CanonicalTXSet::accountKey(AccountID const& account)
|
||||
{
|
||||
uint256 ret = beast::zero;
|
||||
uint256 ret = beast::kZero;
|
||||
memcpy(ret.begin(), account.begin(), account.size());
|
||||
ret ^= salt_;
|
||||
return ret;
|
||||
@@ -68,7 +68,7 @@ CanonicalTXSet::popAcctTransaction(std::shared_ptr<STTx const> const& tx)
|
||||
uint256 const effectiveAccount{accountKey(tx->getAccountID(sfAccount))};
|
||||
|
||||
auto const seqProxy = tx->getSeqProxy();
|
||||
Key const after(effectiveAccount, seqProxy, beast::zero);
|
||||
Key const after(effectiveAccount, seqProxy, beast::kZero);
|
||||
auto const itrNext{map_.lower_bound(after)};
|
||||
if (itrNext != map_.end() && itrNext->first.getAccount() == effectiveAccount &&
|
||||
(!itrNext->second->getSeqProxy().isSeq() ||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using const_iterator = Dir::const_iterator;
|
||||
using const_iterator = Dir::ConstIterator;
|
||||
|
||||
Dir::Dir(ReadView const& view, Keylet const& key)
|
||||
: view_(&view), root_(key), sle_(view_->read(root_))
|
||||
@@ -23,9 +23,9 @@ Dir::Dir(ReadView const& view, Keylet const& key)
|
||||
}
|
||||
|
||||
auto
|
||||
Dir::begin() const -> const_iterator
|
||||
Dir::begin() const -> ConstIterator
|
||||
{
|
||||
auto it = const_iterator(*view_, root_, root_);
|
||||
auto it = ConstIterator(*view_, root_, root_);
|
||||
if (sle_ != nullptr)
|
||||
{
|
||||
it.sle_ = sle_;
|
||||
@@ -41,27 +41,27 @@ Dir::begin() const -> const_iterator
|
||||
}
|
||||
|
||||
auto
|
||||
Dir::end() const -> const_iterator
|
||||
Dir::end() const -> ConstIterator
|
||||
{
|
||||
return const_iterator(*view_, root_, root_);
|
||||
return ConstIterator(*view_, root_, root_);
|
||||
}
|
||||
|
||||
bool
|
||||
const_iterator::operator==(const_iterator const& other) const
|
||||
const_iterator::operator==(ConstIterator const& other) const
|
||||
{
|
||||
if (view_ == nullptr || other.view_ == nullptr)
|
||||
return false;
|
||||
|
||||
XRPL_ASSERT(
|
||||
view_ == other.view_ && root_.key == other.root_.key,
|
||||
"xrpl::const_iterator::operator== : views and roots are matching");
|
||||
"xrpl::Dir::ConstIterator::operator== : views and roots are matching");
|
||||
return page_.key == other.page_.key && index_ == other.index_;
|
||||
}
|
||||
|
||||
const_iterator::reference
|
||||
const_iterator::operator*() const
|
||||
{
|
||||
XRPL_ASSERT(index_ != beast::zero, "xrpl::const_iterator::operator* : nonzero index");
|
||||
XRPL_ASSERT(index_ != beast::kZero, "xrpl::Dir::ConstIterator::operator* : nonzero index");
|
||||
if (!cache_)
|
||||
cache_ = view_->read(keylet::child(index_));
|
||||
return *cache_;
|
||||
@@ -70,7 +70,7 @@ const_iterator::operator*() const
|
||||
const_iterator&
|
||||
const_iterator::operator++()
|
||||
{
|
||||
XRPL_ASSERT(index_ != beast::zero, "xrpl::const_iterator::operator++ : nonzero index");
|
||||
XRPL_ASSERT(index_ != beast::kZero, "xrpl::Dir::ConstIterator::operator++ : nonzero index");
|
||||
if (++it_ != std::end(*indexes_))
|
||||
{
|
||||
index_ = *it_;
|
||||
@@ -78,36 +78,37 @@ const_iterator::operator++()
|
||||
return *this;
|
||||
}
|
||||
|
||||
return next_page();
|
||||
return nextPage();
|
||||
}
|
||||
|
||||
const_iterator
|
||||
const_iterator::operator++(int)
|
||||
{
|
||||
XRPL_ASSERT(index_ != beast::zero, "xrpl::const_iterator::operator++(int) : nonzero index");
|
||||
const_iterator tmp(*this);
|
||||
XRPL_ASSERT(
|
||||
index_ != beast::kZero, "xrpl::Dir::ConstIterator::operator++(int) : nonzero index");
|
||||
ConstIterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const_iterator&
|
||||
const_iterator::next_page()
|
||||
const_iterator::nextPage()
|
||||
{
|
||||
auto const next = sle_->getFieldU64(sfIndexNext);
|
||||
if (next == 0)
|
||||
{
|
||||
page_.key = root_.key;
|
||||
index_ = beast::zero;
|
||||
index_ = beast::kZero;
|
||||
}
|
||||
else
|
||||
{
|
||||
page_ = keylet::page(root_, next);
|
||||
sle_ = view_->read(page_);
|
||||
XRPL_ASSERT(sle_, "xrpl::const_iterator::next_page : non-null SLE");
|
||||
XRPL_ASSERT(sle_, "xrpl::Dir::ConstIterator::nextPage : non-null SLE");
|
||||
indexes_ = &sle_->getFieldV256(sfIndexes);
|
||||
if (indexes_->empty())
|
||||
{
|
||||
index_ = beast::zero;
|
||||
index_ = beast::kZero;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -120,7 +121,7 @@ const_iterator::next_page()
|
||||
}
|
||||
|
||||
std::size_t
|
||||
const_iterator::page_size()
|
||||
const_iterator::pageSize()
|
||||
{
|
||||
return indexes_->size();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/KeyType.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
@@ -31,7 +30,6 @@
|
||||
#include <xrpl/protocol/Seed.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/shamap/Family.h>
|
||||
#include <xrpl/shamap/SHAMap.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
@@ -43,42 +41,41 @@
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
create_genesis_t const create_genesis{};
|
||||
CreateGenesisT const kCreateGenesis{};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Ledger::sles_iter_impl : public sles_type::iter_base
|
||||
class Ledger::SlesIterImpl : public SlesType::iter_base
|
||||
{
|
||||
private:
|
||||
SHAMap::const_iterator iter_;
|
||||
SHAMap::ConstIterator iter_;
|
||||
|
||||
public:
|
||||
sles_iter_impl() = delete;
|
||||
sles_iter_impl&
|
||||
operator=(sles_iter_impl const&) = delete;
|
||||
SlesIterImpl() = delete;
|
||||
SlesIterImpl&
|
||||
operator=(SlesIterImpl const&) = delete;
|
||||
|
||||
sles_iter_impl(sles_iter_impl const&) = default;
|
||||
SlesIterImpl(SlesIterImpl const&) = default;
|
||||
|
||||
sles_iter_impl(SHAMap::const_iterator iter) : iter_(iter)
|
||||
SlesIterImpl(SHAMap::ConstIterator iter) : iter_(iter)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<base_type>
|
||||
copy() const override
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(*this);
|
||||
return std::make_unique<SlesIterImpl>(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
equal(base_type const& impl) const override
|
||||
{
|
||||
if (auto const p = dynamic_cast<sles_iter_impl const*>(&impl))
|
||||
if (auto const p = dynamic_cast<SlesIterImpl const*>(&impl))
|
||||
return iter_ == p->iter_;
|
||||
return false;
|
||||
}
|
||||
@@ -89,7 +86,7 @@ public:
|
||||
++iter_;
|
||||
}
|
||||
|
||||
[[nodiscard]] sles_type::value_type
|
||||
[[nodiscard]] SlesType::value_type
|
||||
dereference() const override
|
||||
{
|
||||
SerialIter sit(iter_->slice());
|
||||
@@ -99,33 +96,33 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Ledger::txs_iter_impl : public txs_type::iter_base
|
||||
class Ledger::TxsIterImpl : public TxsType::iter_base
|
||||
{
|
||||
private:
|
||||
bool metadata_;
|
||||
SHAMap::const_iterator iter_;
|
||||
SHAMap::ConstIterator iter_;
|
||||
|
||||
public:
|
||||
txs_iter_impl() = delete;
|
||||
txs_iter_impl&
|
||||
operator=(txs_iter_impl const&) = delete;
|
||||
TxsIterImpl() = delete;
|
||||
TxsIterImpl&
|
||||
operator=(TxsIterImpl const&) = delete;
|
||||
|
||||
txs_iter_impl(txs_iter_impl const&) = default;
|
||||
TxsIterImpl(TxsIterImpl const&) = default;
|
||||
|
||||
txs_iter_impl(bool metadata, SHAMap::const_iterator iter) : metadata_(metadata), iter_(iter)
|
||||
TxsIterImpl(bool metadata, SHAMap::ConstIterator iter) : metadata_(metadata), iter_(iter)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<base_type>
|
||||
copy() const override
|
||||
{
|
||||
return std::make_unique<txs_iter_impl>(*this);
|
||||
return std::make_unique<TxsIterImpl>(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
equal(base_type const& impl) const override
|
||||
{
|
||||
if (auto const p = dynamic_cast<txs_iter_impl const*>(&impl))
|
||||
if (auto const p = dynamic_cast<TxsIterImpl const*>(&impl))
|
||||
return iter_ == p->iter_;
|
||||
return false;
|
||||
}
|
||||
@@ -136,7 +133,7 @@ public:
|
||||
++iter_;
|
||||
}
|
||||
|
||||
[[nodiscard]] txs_type::value_type
|
||||
[[nodiscard]] TxsType::value_type
|
||||
dereference() const override
|
||||
{
|
||||
auto const& item = *iter_;
|
||||
@@ -149,12 +146,12 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Ledger::Ledger(
|
||||
create_genesis_t,
|
||||
CreateGenesisT,
|
||||
Rules rules,
|
||||
Fees const& fees,
|
||||
std::vector<uint256> const& amendments,
|
||||
Family& family)
|
||||
: mImmutable(false)
|
||||
: immutable_(false)
|
||||
, txMap_(SHAMapType::TRANSACTION, family)
|
||||
, stateMap_(SHAMapType::STATE, family)
|
||||
, fees_(fees)
|
||||
@@ -162,15 +159,15 @@ Ledger::Ledger(
|
||||
, j_(beast::Journal(beast::Journal::getNullSink()))
|
||||
{
|
||||
header_.seq = 1;
|
||||
header_.drops = INITIAL_XRP;
|
||||
header_.closeTimeResolution = ledgerGenesisTimeResolution;
|
||||
header_.drops = kInitialXrp;
|
||||
header_.closeTimeResolution = kLedgerGenesisTimeResolution;
|
||||
|
||||
static auto const id =
|
||||
calcAccountID(generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")).first);
|
||||
static auto const kID =
|
||||
calcAccountID(generateKeyPair(KeyType::Secp256k1, generateSeed("masterpassphrase")).first);
|
||||
{
|
||||
auto const sle = std::make_shared<SLE>(keylet::account(id));
|
||||
auto const sle = std::make_shared<SLE>(keylet::account(kID));
|
||||
sle->setFieldU32(sfSequence, 1);
|
||||
sle->setAccountID(sfAccount, id);
|
||||
sle->setAccountID(sfAccount, kID);
|
||||
sle->setFieldAmount(sfBalance, header_.drops);
|
||||
rawInsert(sle);
|
||||
}
|
||||
@@ -199,12 +196,12 @@ Ledger::Ledger(
|
||||
sle->at(sfReserveBase) = *f;
|
||||
if (auto const f = fees.increment.dropsAs<std::uint32_t>())
|
||||
sle->at(sfReserveIncrement) = *f;
|
||||
sle->at(sfReferenceFeeUnits) = FEE_UNITS_DEPRECATED;
|
||||
sle->at(sfReferenceFeeUnits) = kFeeUnitsDeprecated;
|
||||
}
|
||||
rawInsert(sle);
|
||||
}
|
||||
|
||||
stateMap_.flushDirty(hotACCOUNT_NODE);
|
||||
stateMap_.flushDirty(NodeObjectType::AccountNode);
|
||||
setImmutable();
|
||||
}
|
||||
|
||||
@@ -216,7 +213,7 @@ Ledger::Ledger(
|
||||
Fees const& fees,
|
||||
Family& family,
|
||||
beast::Journal j)
|
||||
: mImmutable(true)
|
||||
: immutable_(true)
|
||||
, txMap_(SHAMapType::TRANSACTION, info.txHash, family)
|
||||
, stateMap_(SHAMapType::STATE, info.accountHash, family)
|
||||
, fees_(fees)
|
||||
@@ -255,7 +252,7 @@ Ledger::Ledger(
|
||||
|
||||
// Create a new ledger that follows this one
|
||||
Ledger::Ledger(Ledger const& prevLedger, NetClock::time_point closeTime)
|
||||
: mImmutable(false)
|
||||
: immutable_(false)
|
||||
, txMap_(SHAMapType::TRANSACTION, prevLedger.txMap_.family())
|
||||
, stateMap_(prevLedger.stateMap_, true)
|
||||
, fees_(prevLedger.fees_)
|
||||
@@ -282,7 +279,7 @@ Ledger::Ledger(Ledger const& prevLedger, NetClock::time_point closeTime)
|
||||
}
|
||||
|
||||
Ledger::Ledger(LedgerHeader const& info, Rules rules, Family& family)
|
||||
: mImmutable(true)
|
||||
: immutable_(true)
|
||||
, txMap_(SHAMapType::TRANSACTION, info.txHash, family)
|
||||
, stateMap_(SHAMapType::STATE, info.accountHash, family)
|
||||
, rules_(std::move(rules))
|
||||
@@ -298,7 +295,7 @@ Ledger::Ledger(
|
||||
Rules rules,
|
||||
Fees const& fees,
|
||||
Family& family)
|
||||
: mImmutable(false)
|
||||
: immutable_(false)
|
||||
, txMap_(SHAMapType::TRANSACTION, family)
|
||||
, stateMap_(SHAMapType::STATE, family)
|
||||
, fees_(fees)
|
||||
@@ -307,7 +304,7 @@ Ledger::Ledger(
|
||||
{
|
||||
header_.seq = ledgerSeq;
|
||||
header_.closeTime = closeTime;
|
||||
header_.closeTimeResolution = ledgerDefaultTimeResolution;
|
||||
header_.closeTimeResolution = kLedgerDefaultTimeResolution;
|
||||
setup();
|
||||
}
|
||||
|
||||
@@ -316,16 +313,16 @@ Ledger::setImmutable(bool rehash)
|
||||
{
|
||||
// Force update, since this is the only
|
||||
// place the hash transitions to valid
|
||||
if (!mImmutable && rehash)
|
||||
if (!immutable_ && rehash)
|
||||
{
|
||||
header_.txHash = txMap_.getHash().as_uint256();
|
||||
header_.accountHash = stateMap_.getHash().as_uint256();
|
||||
header_.txHash = txMap_.getHash().asUInt256();
|
||||
header_.accountHash = stateMap_.getHash().asUInt256();
|
||||
}
|
||||
|
||||
if (rehash)
|
||||
header_.hash = calculateLedgerHash(header_);
|
||||
|
||||
mImmutable = true;
|
||||
immutable_ = true;
|
||||
txMap_.setImmutable();
|
||||
stateMap_.setImmutable();
|
||||
setup();
|
||||
@@ -342,7 +339,7 @@ Ledger::setAccepted(
|
||||
|
||||
header_.closeTime = closeTime;
|
||||
header_.closeTimeResolution = closeResolution;
|
||||
header_.closeFlags = correctCloseTime ? 0 : sLCF_NoConsensusTime;
|
||||
header_.closeFlags = correctCloseTime ? 0 : kSLcfNoConsensusTime;
|
||||
setImmutable();
|
||||
}
|
||||
|
||||
@@ -350,8 +347,7 @@ bool
|
||||
Ledger::addSLE(SLE const& sle)
|
||||
{
|
||||
auto const s = sle.getSerializer();
|
||||
return stateMap_.addItem(
|
||||
SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle.key(), s.slice()));
|
||||
return stateMap_.addItem(SHAMapNodeType::TnAccountState, makeShamapitem(sle.key(), s.slice()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -397,7 +393,7 @@ Ledger::exists(uint256 const& key) const
|
||||
std::optional<uint256>
|
||||
Ledger::succ(uint256 const& key, std::optional<uint256> const& last) const
|
||||
{
|
||||
auto item = stateMap_.upper_bound(key);
|
||||
auto item = stateMap_.upperBound(key);
|
||||
if (item == stateMap_.end())
|
||||
return std::nullopt;
|
||||
if (last && item->key() >= last)
|
||||
@@ -408,7 +404,7 @@ Ledger::succ(uint256 const& key, std::optional<uint256> const& last) const
|
||||
std::shared_ptr<SLE const>
|
||||
Ledger::read(Keylet const& k) const
|
||||
{
|
||||
if (k.key == beast::zero)
|
||||
if (k.key == beast::kZero)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::Ledger::read : zero key");
|
||||
@@ -427,33 +423,33 @@ Ledger::read(Keylet const& k) const
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
auto
|
||||
Ledger::slesBegin() const -> std::unique_ptr<sles_type::iter_base>
|
||||
Ledger::slesBegin() const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(stateMap_.begin());
|
||||
return std::make_unique<SlesIterImpl>(stateMap_.begin());
|
||||
}
|
||||
|
||||
auto
|
||||
Ledger::slesEnd() const -> std::unique_ptr<sles_type::iter_base>
|
||||
Ledger::slesEnd() const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(stateMap_.end());
|
||||
return std::make_unique<SlesIterImpl>(stateMap_.end());
|
||||
}
|
||||
|
||||
auto
|
||||
Ledger::slesUpperBound(uint256 const& key) const -> std::unique_ptr<sles_type::iter_base>
|
||||
Ledger::slesUpperBound(uint256 const& key) const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(stateMap_.upper_bound(key));
|
||||
return std::make_unique<SlesIterImpl>(stateMap_.upperBound(key));
|
||||
}
|
||||
|
||||
auto
|
||||
Ledger::txsBegin() const -> std::unique_ptr<txs_type::iter_base>
|
||||
Ledger::txsBegin() const -> std::unique_ptr<TxsType::iter_base>
|
||||
{
|
||||
return std::make_unique<txs_iter_impl>(!open(), txMap_.begin());
|
||||
return std::make_unique<TxsIterImpl>(!open(), txMap_.begin());
|
||||
}
|
||||
|
||||
auto
|
||||
Ledger::txsEnd() const -> std::unique_ptr<txs_type::iter_base>
|
||||
Ledger::txsEnd() const -> std::unique_ptr<TxsType::iter_base>
|
||||
{
|
||||
return std::make_unique<txs_iter_impl>(!open(), txMap_.end());
|
||||
return std::make_unique<TxsIterImpl>(!open(), txMap_.end());
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -484,7 +480,7 @@ Ledger::digest(key_type const& key) const -> std::optional<digest_type>
|
||||
// from the NodeStore needlessly.
|
||||
if (!stateMap_.peekItem(key, digest))
|
||||
return std::nullopt;
|
||||
return digest.as_uint256();
|
||||
return digest.asUInt256();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -493,14 +489,14 @@ void
|
||||
Ledger::rawErase(std::shared_ptr<SLE> const& sle)
|
||||
{
|
||||
if (!stateMap_.delItem(sle->key()))
|
||||
Throw<std::logic_error>("Ledger::rawErase: key not found");
|
||||
logicError("Ledger::rawErase: key not found");
|
||||
}
|
||||
|
||||
void
|
||||
Ledger::rawErase(uint256 const& key)
|
||||
{
|
||||
if (!stateMap_.delItem(key))
|
||||
Throw<std::logic_error>("Ledger::rawErase: key not found");
|
||||
logicError("Ledger::rawErase: key not found");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -509,8 +505,10 @@ Ledger::rawInsert(std::shared_ptr<SLE> const& sle)
|
||||
Serializer ss;
|
||||
sle->add(ss);
|
||||
if (!stateMap_.addGiveItem(
|
||||
SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle->key(), ss.slice())))
|
||||
Throw<std::logic_error>("Ledger::rawInsert: key already exists");
|
||||
SHAMapNodeType::TnAccountState, makeShamapitem(sle->key(), ss.slice())))
|
||||
{
|
||||
logicError("Ledger::rawInsert: key already exists");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -519,8 +517,10 @@ Ledger::rawReplace(std::shared_ptr<SLE> const& sle)
|
||||
Serializer ss;
|
||||
sle->add(ss);
|
||||
if (!stateMap_.updateGiveItem(
|
||||
SHAMapNodeType::tnACCOUNT_STATE, make_shamapitem(sle->key(), ss.slice())))
|
||||
Throw<std::logic_error>("Ledger::rawReplace: key not found");
|
||||
SHAMapNodeType::TnAccountState, makeShamapitem(sle->key(), ss.slice())))
|
||||
{
|
||||
logicError("Ledger::rawReplace: key not found");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -535,28 +535,8 @@ Ledger::rawTxInsert(
|
||||
Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
|
||||
s.addVL(txn->peekData());
|
||||
s.addVL(metaData->peekData());
|
||||
if (!txMap_.addGiveItem(SHAMapNodeType::tnTRANSACTION_MD, make_shamapitem(key, s.slice())))
|
||||
Throw<std::logic_error>("duplicate_tx: " + to_string(key));
|
||||
}
|
||||
|
||||
uint256
|
||||
Ledger::rawTxInsertWithHash(
|
||||
uint256 const& key,
|
||||
std::shared_ptr<Serializer const> const& txn,
|
||||
std::shared_ptr<Serializer const> const& metaData)
|
||||
{
|
||||
XRPL_ASSERT(metaData, "xrpl::Ledger::rawTxInsertWithHash : non-null metadata input");
|
||||
|
||||
// low-level - just add to table
|
||||
Serializer s(txn->getDataLength() + metaData->getDataLength() + 16);
|
||||
s.addVL(txn->peekData());
|
||||
s.addVL(metaData->peekData());
|
||||
auto item = make_shamapitem(key, s.slice());
|
||||
auto hash = sha512Half(HashPrefix::txNode, item->slice(), item->key());
|
||||
if (!txMap_.addGiveItem(SHAMapNodeType::tnTRANSACTION_MD, std::move(item)))
|
||||
Throw<std::logic_error>("duplicate_tx: " + to_string(key));
|
||||
|
||||
return hash;
|
||||
if (!txMap_.addGiveItem(SHAMapNodeType::TnTransactionMd, makeShamapitem(key, s.slice())))
|
||||
logicError("duplicate_tx: " + to_string(key));
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -575,7 +555,7 @@ Ledger::setup()
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
|
||||
Rethrow();
|
||||
rethrow();
|
||||
}
|
||||
|
||||
try
|
||||
@@ -637,7 +617,7 @@ Ledger::setup()
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
JLOG(j_.error()) << "Exception in " << __func__ << ": " << ex.what();
|
||||
Rethrow();
|
||||
rethrow();
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -730,13 +710,13 @@ Ledger::updateNegativeUNL()
|
||||
if (hasToReEnable && v.isFieldPresent(sfPublicKey) &&
|
||||
v.getFieldVL(sfPublicKey) == sle->getFieldVL(sfValidatorToReEnable))
|
||||
continue;
|
||||
newNUnl.push_back(v);
|
||||
newNUnl.pushBack(v);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasToDisable)
|
||||
{
|
||||
newNUnl.push_back(STObject::makeInnerObject(sfDisabledValidator));
|
||||
newNUnl.pushBack(STObject::makeInnerObject(sfDisabledValidator));
|
||||
newNUnl.back().setFieldVL(sfPublicKey, sle->getFieldVL(sfValidatorToDisable));
|
||||
newNUnl.back().setFieldU32(sfFirstLedgerSequence, seq());
|
||||
}
|
||||
@@ -815,9 +795,9 @@ Ledger::isSensible() const
|
||||
return false;
|
||||
if (header_.accountHash.isZero())
|
||||
return false;
|
||||
if (header_.accountHash != stateMap_.getHash().as_uint256())
|
||||
if (header_.accountHash != stateMap_.getHash().asUInt256())
|
||||
return false;
|
||||
if (header_.txHash != txMap_.getHash().as_uint256())
|
||||
if (header_.txHash != txMap_.getHash().asUInt256())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class OpenView::txs_iter_impl : public txs_type::iter_base
|
||||
class OpenView::TxsIterImpl : public TxsType::iter_base
|
||||
{
|
||||
private:
|
||||
bool metadata_;
|
||||
txs_map::const_iterator iter_;
|
||||
|
||||
public:
|
||||
explicit txs_iter_impl(bool metadata, txs_map::const_iterator iter)
|
||||
explicit TxsIterImpl(bool metadata, txs_map::const_iterator iter)
|
||||
: metadata_(metadata), iter_(iter)
|
||||
{
|
||||
}
|
||||
@@ -39,13 +39,13 @@ public:
|
||||
[[nodiscard]] std::unique_ptr<base_type>
|
||||
copy() const override
|
||||
{
|
||||
return std::make_unique<txs_iter_impl>(metadata_, iter_);
|
||||
return std::make_unique<TxsIterImpl>(metadata_, iter_);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
equal(base_type const& impl) const override
|
||||
{
|
||||
if (auto const p = dynamic_cast<txs_iter_impl const*>(&impl))
|
||||
if (auto const p = dynamic_cast<TxsIterImpl const*>(&impl))
|
||||
return iter_ == p->iter_;
|
||||
return false;
|
||||
}
|
||||
@@ -78,9 +78,9 @@ public:
|
||||
OpenView::OpenView(OpenView const& rhs)
|
||||
: ReadView(rhs)
|
||||
, TxsRawView(rhs)
|
||||
, monotonic_resource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
|
||||
initialBufferSize)}
|
||||
, txs_{rhs.txs_, monotonic_resource_.get()}
|
||||
, monotonicResource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
|
||||
kInitialBufferSize)}
|
||||
, txs_{rhs.txs_, monotonicResource_.get()}
|
||||
, rules_{rhs.rules_}
|
||||
, header_{rhs.header_}
|
||||
, base_{rhs.base_}
|
||||
@@ -88,14 +88,10 @@ OpenView::OpenView(OpenView const& rhs)
|
||||
, hold_{rhs.hold_}
|
||||
, open_{rhs.open_} {};
|
||||
|
||||
OpenView::OpenView(
|
||||
open_ledger_t,
|
||||
ReadView const* base,
|
||||
Rules rules,
|
||||
std::shared_ptr<void const> hold)
|
||||
: monotonic_resource_{
|
||||
std::make_unique<boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)}
|
||||
, txs_{monotonic_resource_.get()}
|
||||
OpenView::OpenView(OpenLedgerT, ReadView const* base, Rules rules, std::shared_ptr<void const> hold)
|
||||
: monotonicResource_{
|
||||
std::make_unique<boost::container::pmr::monotonic_buffer_resource>(kInitialBufferSize)}
|
||||
, txs_{monotonicResource_.get()}
|
||||
, rules_(std::move(rules))
|
||||
, header_(base->header())
|
||||
, base_(base)
|
||||
@@ -109,9 +105,9 @@ OpenView::OpenView(
|
||||
}
|
||||
|
||||
OpenView::OpenView(ReadView const* base, std::shared_ptr<void const> hold)
|
||||
: monotonic_resource_{
|
||||
std::make_unique<boost::container::pmr::monotonic_buffer_resource>(initialBufferSize)}
|
||||
, txs_{monotonic_resource_.get()}
|
||||
: monotonicResource_{
|
||||
std::make_unique<boost::container::pmr::monotonic_buffer_resource>(kInitialBufferSize)}
|
||||
, txs_{monotonicResource_.get()}
|
||||
, rules_(base->rules())
|
||||
, header_(base->header())
|
||||
, base_(base)
|
||||
@@ -174,33 +170,33 @@ OpenView::read(Keylet const& k) const
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::slesBegin() const -> std::unique_ptr<sles_type::iter_base>
|
||||
OpenView::slesBegin() const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return items_.slesBegin(*base_);
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::slesEnd() const -> std::unique_ptr<sles_type::iter_base>
|
||||
OpenView::slesEnd() const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return items_.slesEnd(*base_);
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::slesUpperBound(uint256 const& key) const -> std::unique_ptr<sles_type::iter_base>
|
||||
OpenView::slesUpperBound(uint256 const& key) const -> std::unique_ptr<SlesType::iter_base>
|
||||
{
|
||||
return items_.slesUpperBound(*base_, key);
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::txsBegin() const -> std::unique_ptr<txs_type::iter_base>
|
||||
OpenView::txsBegin() const -> std::unique_ptr<TxsType::iter_base>
|
||||
{
|
||||
return std::make_unique<txs_iter_impl>(!open(), txs_.cbegin());
|
||||
return std::make_unique<TxsIterImpl>(!open(), txs_.cbegin());
|
||||
}
|
||||
|
||||
auto
|
||||
OpenView::txsEnd() const -> std::unique_ptr<txs_type::iter_base>
|
||||
OpenView::txsEnd() const -> std::unique_ptr<TxsType::iter_base>
|
||||
{
|
||||
return std::make_unique<txs_iter_impl>(!open(), txs_.cend());
|
||||
return std::make_unique<TxsIterImpl>(!open(), txs_.cend());
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -321,7 +321,7 @@ PaymentSandbox::balanceHookIOU(
|
||||
auto adjustedAmt = std::min({amount, lastBal - delta, minBal});
|
||||
adjustedAmt.get<Issue>().account = amount.getIssuer();
|
||||
|
||||
if (isXRP(issuer) && adjustedAmt < beast::zero)
|
||||
if (isXRP(issuer) && adjustedAmt < beast::kZero)
|
||||
{
|
||||
// A calculated negative XRP balance is not an error case. Consider a
|
||||
// payment snippet that credits a large XRP amount and then debits the
|
||||
|
||||
@@ -17,24 +17,24 @@
|
||||
|
||||
namespace xrpl::detail {
|
||||
|
||||
class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base
|
||||
class RawStateTable::SlesIterImpl : public ReadView::SlesType::iter_base
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<SLE const> sle0_;
|
||||
ReadView::sles_type::iterator iter0_;
|
||||
ReadView::sles_type::iterator end0_;
|
||||
ReadView::SlesType::Iterator iter0_;
|
||||
ReadView::SlesType::Iterator end0_;
|
||||
std::shared_ptr<SLE const> sle1_;
|
||||
items_t::const_iterator iter1_;
|
||||
items_t::const_iterator end1_;
|
||||
|
||||
public:
|
||||
sles_iter_impl(sles_iter_impl const&) = default;
|
||||
SlesIterImpl(SlesIterImpl const&) = default;
|
||||
|
||||
sles_iter_impl(
|
||||
SlesIterImpl(
|
||||
items_t::const_iterator iter1,
|
||||
items_t::const_iterator end1,
|
||||
ReadView::sles_type::iterator iter0,
|
||||
ReadView::sles_type::iterator end0)
|
||||
ReadView::SlesType::Iterator iter0,
|
||||
ReadView::SlesType::Iterator end0)
|
||||
: iter0_(std::move(iter0)), end0_(std::move(end0)), iter1_(iter1), end1_(end1)
|
||||
{
|
||||
if (iter0_ != end0_)
|
||||
@@ -49,13 +49,13 @@ public:
|
||||
std::unique_ptr<base_type>
|
||||
copy() const override
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(*this);
|
||||
return std::make_unique<SlesIterImpl>(*this);
|
||||
}
|
||||
|
||||
bool
|
||||
equal(base_type const& impl) const override
|
||||
{
|
||||
if (auto const p = dynamic_cast<sles_iter_impl const*>(&impl))
|
||||
if (auto const p = dynamic_cast<SlesIterImpl const*>(&impl))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
end1_ == p->end1_ && end0_ == p->end0_,
|
||||
@@ -151,7 +151,7 @@ private:
|
||||
void
|
||||
skip()
|
||||
{
|
||||
while (iter1_ != end1_ && iter1_->second.action == Action::erase &&
|
||||
while (iter1_ != end1_ && iter1_->second.action == Action::Erase &&
|
||||
sle0_->key() == sle1_->key())
|
||||
{
|
||||
inc1();
|
||||
@@ -175,13 +175,13 @@ RawStateTable::apply(RawView& to) const
|
||||
auto const& item = elem.second;
|
||||
switch (item.action)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
to.rawErase(item.sle);
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
to.rawInsert(item.sle);
|
||||
break;
|
||||
case Action::replace:
|
||||
case Action::Replace:
|
||||
to.rawReplace(item.sle);
|
||||
break;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ RawStateTable::exists(ReadView const& base, Keylet const& k) const
|
||||
if (iter == items_.end())
|
||||
return base.exists(k);
|
||||
auto const& item = iter->second;
|
||||
if (item.action == Action::erase)
|
||||
if (item.action == Action::Erase)
|
||||
return false;
|
||||
if (!k.check(*item.sle))
|
||||
return false;
|
||||
@@ -221,11 +221,11 @@ RawStateTable::succ(ReadView const& base, key_type const& key, std::optional<key
|
||||
if (!next)
|
||||
break;
|
||||
iter = items_.find(*next);
|
||||
} while (iter != items_.end() && iter->second.action == Action::erase);
|
||||
} while (iter != items_.end() && iter->second.action == Action::Erase);
|
||||
// Find non-deleted successor in our list
|
||||
for (iter = items_.upper_bound(key); iter != items_.end(); ++iter)
|
||||
{
|
||||
if (iter->second.action != Action::erase)
|
||||
if (iter->second.action != Action::Erase)
|
||||
{
|
||||
// Found both, return the lower key
|
||||
if (!next || next > iter->first)
|
||||
@@ -247,20 +247,20 @@ RawStateTable::erase(std::shared_ptr<SLE> const& sle)
|
||||
auto const result = items_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(sle->key()),
|
||||
std::forward_as_tuple(Action::erase, sle));
|
||||
std::forward_as_tuple(Action::Erase, sle));
|
||||
if (result.second)
|
||||
return;
|
||||
auto& item = result.first->second;
|
||||
switch (item.action)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
Throw<std::logic_error>("RawStateTable::erase: already erased");
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
items_.erase(result.first);
|
||||
break;
|
||||
case Action::replace:
|
||||
item.action = Action::erase;
|
||||
case Action::Replace:
|
||||
item.action = Action::Erase;
|
||||
item.sle = sle;
|
||||
break;
|
||||
}
|
||||
@@ -272,20 +272,20 @@ RawStateTable::insert(std::shared_ptr<SLE> const& sle)
|
||||
auto const result = items_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(sle->key()),
|
||||
std::forward_as_tuple(Action::insert, sle));
|
||||
std::forward_as_tuple(Action::Insert, sle));
|
||||
if (result.second)
|
||||
return;
|
||||
auto& item = result.first->second;
|
||||
switch (item.action)
|
||||
{
|
||||
case Action::erase:
|
||||
item.action = Action::replace;
|
||||
case Action::Erase:
|
||||
item.action = Action::Replace;
|
||||
item.sle = sle;
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::Insert:
|
||||
Throw<std::logic_error>("RawStateTable::insert: already inserted");
|
||||
break;
|
||||
case Action::replace:
|
||||
case Action::Replace:
|
||||
Throw<std::logic_error>("RawStateTable::insert: already exists");
|
||||
break;
|
||||
}
|
||||
@@ -297,17 +297,17 @@ RawStateTable::replace(std::shared_ptr<SLE> const& sle)
|
||||
auto const result = items_.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(sle->key()),
|
||||
std::forward_as_tuple(Action::replace, sle));
|
||||
std::forward_as_tuple(Action::Replace, sle));
|
||||
if (result.second)
|
||||
return;
|
||||
auto& item = result.first->second;
|
||||
switch (item.action)
|
||||
{
|
||||
case Action::erase:
|
||||
case Action::Erase:
|
||||
Throw<std::logic_error>("RawStateTable::replace: was erased");
|
||||
break;
|
||||
case Action::insert:
|
||||
case Action::replace:
|
||||
case Action::Insert:
|
||||
case Action::Replace:
|
||||
item.sle = sle;
|
||||
break;
|
||||
}
|
||||
@@ -320,7 +320,7 @@ RawStateTable::read(ReadView const& base, Keylet const& k) const
|
||||
if (iter == items_.end())
|
||||
return base.read(k);
|
||||
auto const& item = iter->second;
|
||||
if (item.action == Action::erase)
|
||||
if (item.action == Action::Erase)
|
||||
return nullptr;
|
||||
// Convert to SLE const
|
||||
std::shared_ptr<SLE const> sle = item.sle;
|
||||
@@ -335,25 +335,25 @@ RawStateTable::destroyXRP(XRPAmount const& fee)
|
||||
dropsDestroyed_ += fee;
|
||||
}
|
||||
|
||||
std::unique_ptr<ReadView::sles_type::iter_base>
|
||||
std::unique_ptr<ReadView::SlesType::iter_base>
|
||||
RawStateTable::slesBegin(ReadView const& base) const
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(
|
||||
return std::make_unique<SlesIterImpl>(
|
||||
items_.begin(), items_.end(), base.sles.begin(), base.sles.end());
|
||||
}
|
||||
|
||||
std::unique_ptr<ReadView::sles_type::iter_base>
|
||||
std::unique_ptr<ReadView::SlesType::iter_base>
|
||||
RawStateTable::slesEnd(ReadView const& base) const
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(
|
||||
return std::make_unique<SlesIterImpl>(
|
||||
items_.end(), items_.end(), base.sles.end(), base.sles.end());
|
||||
}
|
||||
|
||||
std::unique_ptr<ReadView::sles_type::iter_base>
|
||||
std::unique_ptr<ReadView::SlesType::iter_base>
|
||||
RawStateTable::slesUpperBound(ReadView const& base, uint256 const& key) const
|
||||
{
|
||||
return std::make_unique<sles_iter_impl>(
|
||||
items_.upper_bound(key), items_.end(), base.sles.upper_bound(key), base.sles.end());
|
||||
return std::make_unique<SlesIterImpl>(
|
||||
items_.upper_bound(key), items_.end(), base.sles.upperBound(key), base.sles.end());
|
||||
}
|
||||
|
||||
} // namespace xrpl::detail
|
||||
|
||||
@@ -13,48 +13,48 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
ReadView::sles_type::sles_type(ReadView const& view) : ReadViewFwdRange(view)
|
||||
ReadView::SlesType::SlesType(ReadView const& view) : ReadViewFwdRange(view)
|
||||
{
|
||||
}
|
||||
|
||||
auto
|
||||
ReadView::sles_type::begin() const -> iterator
|
||||
ReadView::SlesType::begin() const -> Iterator
|
||||
{
|
||||
return iterator(view_, view_->slesBegin());
|
||||
return Iterator(view_, view_->slesBegin());
|
||||
}
|
||||
|
||||
auto
|
||||
ReadView::sles_type::end() const -> iterator
|
||||
ReadView::SlesType::end() const -> Iterator
|
||||
{
|
||||
return iterator(view_, view_->slesEnd());
|
||||
return Iterator(view_, view_->slesEnd());
|
||||
}
|
||||
|
||||
auto
|
||||
ReadView::sles_type::upper_bound(key_type const& key) const -> iterator
|
||||
ReadView::SlesType::upperBound(key_type const& key) const -> Iterator
|
||||
{
|
||||
return iterator(view_, view_->slesUpperBound(key));
|
||||
return Iterator(view_, view_->slesUpperBound(key));
|
||||
}
|
||||
|
||||
ReadView::txs_type::txs_type(ReadView const& view) : ReadViewFwdRange(view)
|
||||
ReadView::TxsType::TxsType(ReadView const& view) : ReadViewFwdRange(view)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ReadView::txs_type::empty() const
|
||||
ReadView::TxsType::empty() const
|
||||
{
|
||||
return begin() == end();
|
||||
}
|
||||
|
||||
auto
|
||||
ReadView::txs_type::begin() const -> iterator
|
||||
ReadView::TxsType::begin() const -> Iterator
|
||||
{
|
||||
return iterator(view_, view_->txsBegin());
|
||||
return Iterator(view_, view_->txsBegin());
|
||||
}
|
||||
|
||||
auto
|
||||
ReadView::txs_type::end() const -> iterator
|
||||
ReadView::TxsType::end() const -> Iterator
|
||||
{
|
||||
return iterator(view_, view_->txsEnd());
|
||||
return Iterator(view_, view_->txsEnd());
|
||||
}
|
||||
|
||||
Rules
|
||||
@@ -66,7 +66,7 @@ makeRulesGivenLedger(DigestAwareReadView const& ledger, Rules const& current)
|
||||
Rules
|
||||
makeRulesGivenLedger(
|
||||
DigestAwareReadView const& ledger,
|
||||
std::unordered_set<uint256, beast::uhash<>> const& presets)
|
||||
std::unordered_set<uint256, beast::Uhash<>> const& presets)
|
||||
{
|
||||
Keylet const k = keylet::amendments();
|
||||
std::optional const digest = ledger.digest(k.key);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -57,19 +58,45 @@ isVaultPseudoAccountFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
MPTIssue const& mptShare,
|
||||
int depth)
|
||||
std::uint8_t depth)
|
||||
{
|
||||
if (!view.rules().enabled(featureSingleAssetVault))
|
||||
return false;
|
||||
|
||||
if (depth >= maxAssetCheckDepth)
|
||||
return true; // LCOV_EXCL_LINE
|
||||
if (depth >= kMaxAssetCheckDepth)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::View::isVaultPseudoAccountFrozen : reached asset check depth");
|
||||
return true;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const mptIssuance = view.read(keylet::mptIssuance(mptShare.getMptID()));
|
||||
if (mptIssuance == nullptr)
|
||||
return false; // zero MPToken won't block deletion of MPTokenIssuance
|
||||
|
||||
auto const issuer = mptIssuance->getAccountID(sfIssuer);
|
||||
|
||||
// Post-fixCleanup3_2_0: vault shares carry sfReferenceHolding pointing
|
||||
// to the vault pseudo's MPToken or RippleState for the underlying.
|
||||
// Read it to derive the underlying asset and recurse, skipping the
|
||||
// issuer-account-then-vault chain. Pre-amendment shares (no field)
|
||||
// fall back to the chain lookup below.
|
||||
if (mptIssuance->isFieldPresent(sfReferenceHolding))
|
||||
{
|
||||
auto const sleHolding =
|
||||
view.read(keylet::unchecked(mptIssuance->getFieldH256(sfReferenceHolding)));
|
||||
if (!sleHolding)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : dangling sfReferenceHolding");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
return isAnyFrozen(
|
||||
view, {issuer, account}, assetOfHolding(*mptIssuance, *sleHolding), depth + 1);
|
||||
}
|
||||
|
||||
auto const mptIssuer = view.read(keylet::account(issuer));
|
||||
if (mptIssuer == nullptr)
|
||||
{
|
||||
@@ -350,7 +377,7 @@ withdrawToDestExceedsLimit(
|
||||
[&](Issue const& issue) -> TER {
|
||||
auto const& currency = issue.currency;
|
||||
auto const owed = creditBalance(view, to, issuer, currency);
|
||||
if (owed <= beast::zero)
|
||||
if (owed <= beast::kZero)
|
||||
{
|
||||
auto const limit = creditLimit(view, to, issuer, currency);
|
||||
if (-owed >= limit || amount > (limit + owed))
|
||||
@@ -437,8 +464,8 @@ doWithdraw(
|
||||
view,
|
||||
sourceAcct,
|
||||
amount.asset(),
|
||||
FreezeHandling::fhIGNORE_FREEZE,
|
||||
AuthHandling::ahIGNORE_AUTH,
|
||||
FreezeHandling::IgnoreFreeze,
|
||||
AuthHandling::IgnoreAuth,
|
||||
j) < amount)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
@@ -463,7 +490,7 @@ cleanupOnAccountDelete(
|
||||
// Delete all the entries in the account directory.
|
||||
std::shared_ptr<SLE> sleDirNode{};
|
||||
unsigned int uDirEntry{0};
|
||||
uint256 dirEntry{beast::zero};
|
||||
uint256 dirEntry{beast::kZero};
|
||||
std::uint32_t deleted = 0;
|
||||
|
||||
if (view.exists(ownerDirKeylet) &&
|
||||
@@ -487,7 +514,7 @@ cleanupOnAccountDelete(
|
||||
}
|
||||
|
||||
LedgerEntryType const nodeType{
|
||||
safe_cast<LedgerEntryType>(sleItem->getFieldU16(sfLedgerEntryType))};
|
||||
safeCast<LedgerEntryType>(sleItem->getFieldU16(sfLedgerEntryType))};
|
||||
|
||||
// Deleter handles the details of specific account-owned object
|
||||
// deletion
|
||||
|
||||
@@ -46,7 +46,8 @@ STAmount
|
||||
ammLPTokens(STAmount const& asset1, STAmount const& asset2, Asset const& lptIssue)
|
||||
{
|
||||
// AMM invariant: sqrt(asset1 * asset2) >= LPTokensBalance
|
||||
auto const rounding = isFeatureEnabled(fixAMMv1_3) ? Number::downward : Number::getround();
|
||||
auto const rounding =
|
||||
isFeatureEnabled(fixAMMv1_3) ? Number::RoundingMode::Downward : Number::getround();
|
||||
NumberRoundModeGuard const g(rounding);
|
||||
auto const tokens = root2(asset1 * asset2);
|
||||
return toSTAmount(lptIssue, tokens);
|
||||
@@ -77,7 +78,7 @@ lpTokensOut(
|
||||
|
||||
// minimize tokens out
|
||||
auto const frac = (r - c) / (1 + c);
|
||||
return multiply(lptAMMBalance, frac, Number::downward);
|
||||
return multiply(lptAMMBalance, frac, Number::RoundingMode::Downward);
|
||||
}
|
||||
|
||||
/* Equation 4 solves equation 3 for b:
|
||||
@@ -113,7 +114,7 @@ ammAssetIn(
|
||||
|
||||
// maximize deposit
|
||||
auto const frac = solveQuadraticEq(a, b, c);
|
||||
return multiply(asset1Balance, frac, Number::upward);
|
||||
return multiply(asset1Balance, frac, Number::RoundingMode::Upward);
|
||||
}
|
||||
|
||||
/* Equation 7:
|
||||
@@ -138,7 +139,7 @@ lpTokensIn(
|
||||
|
||||
// maximize tokens in
|
||||
auto const frac = (c - root2(c * c - 4 * fr)) / 2;
|
||||
return multiply(lptAMMBalance, frac, Number::upward);
|
||||
return multiply(lptAMMBalance, frac, Number::RoundingMode::Upward);
|
||||
}
|
||||
|
||||
/* Equation 8 solves equation 7 for b:
|
||||
@@ -168,7 +169,7 @@ ammAssetOut(
|
||||
|
||||
// minimize withdraw
|
||||
auto const frac = (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1);
|
||||
return multiply(assetBalance, frac, Number::downward);
|
||||
return multiply(assetBalance, frac, Number::RoundingMode::Downward);
|
||||
}
|
||||
|
||||
Number
|
||||
@@ -182,7 +183,7 @@ adjustLPTokens(STAmount const& lptAMMBalance, STAmount const& lpTokens, IsDeposi
|
||||
{
|
||||
// Force rounding downward to ensure adjusted tokens are less or equal
|
||||
// to requested tokens.
|
||||
saveNumberRoundMode const rm(Number::setround(Number::rounding_mode::downward));
|
||||
SaveNumberRoundMode const rm(Number::setround(Number::RoundingMode::Downward));
|
||||
if (isDeposit == IsDeposit::Yes)
|
||||
return (lptAMMBalance + lpTokens) - lptAMMBalance;
|
||||
return (lpTokens - lptAMMBalance) + lptAMMBalance;
|
||||
@@ -204,7 +205,7 @@ adjustAmountsByLPTokens(
|
||||
|
||||
auto const lpTokensActual = adjustLPTokens(lptAMMBalance, lpTokens, isDeposit);
|
||||
|
||||
if (lpTokensActual == beast::zero)
|
||||
if (lpTokensActual == beast::kZero)
|
||||
{
|
||||
auto const amount2Opt = amount2 ? std::make_optional(STAmount{}) : std::nullopt;
|
||||
return std::make_tuple(STAmount{}, amount2Opt, lpTokensActual);
|
||||
@@ -289,7 +290,7 @@ solveQuadraticEqSmallest(Number const& a, Number const& b, Number const& c)
|
||||
}
|
||||
|
||||
STAmount
|
||||
multiply(STAmount const& amount, Number const& frac, Number::rounding_mode rm)
|
||||
multiply(STAmount const& amount, Number const& frac, Number::RoundingMode rm)
|
||||
{
|
||||
NumberRoundModeGuard const g(rm);
|
||||
auto const t = amount * frac;
|
||||
@@ -570,7 +571,7 @@ getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account)
|
||||
"xrpl::getTradingFee : auction present");
|
||||
if (ammSle.isFieldPresent(sfAuctionSlot))
|
||||
{
|
||||
auto const& auctionSlot = safe_downcast<STObject const&>(ammSle.peekAtField(sfAuctionSlot));
|
||||
auto const& auctionSlot = safeDowncast<STObject const&>(ammSle.peekAtField(sfAuctionSlot));
|
||||
// Not expired
|
||||
if (auto const expiration = auctionSlot[~sfExpiration];
|
||||
duration_cast<seconds>(view.header().parentCloseTime.time_since_epoch()).count() <
|
||||
@@ -643,7 +644,7 @@ deleteAMMTrustLines(
|
||||
if (nodeType == ltRIPPLE_STATE)
|
||||
{
|
||||
// Trustlines must have zero balance
|
||||
if (sleItem->getFieldAmount(sfBalance) != beast::zero)
|
||||
if (sleItem->getFieldAmount(sfBalance) != beast::kZero)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.error()) << "deleteAMMObjects: deleting trustline with "
|
||||
@@ -680,7 +681,7 @@ deleteAMMMPTokens(Sandbox& sb, AccountID const& ammAccountID, beast::Journal j)
|
||||
{
|
||||
// MPT must have zero balance
|
||||
if (sleItem->getFieldU64(sfMPTAmount) != 0 ||
|
||||
(*sleItem)[~sfLockedAmount].value_or(0) != 0)
|
||||
(*sleItem)[~sfLockedAmount].valueOr(0) != 0)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.error()) << "deleteAMMObjects: deleting MPT with "
|
||||
@@ -731,7 +732,7 @@ deleteAMMAccount(Sandbox& sb, Asset const& asset, Asset const& asset2, beast::Jo
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
if (auto const ter = deleteAMMTrustLines(sb, ammAccountID, maxDeletableAMMTrustLines, j);
|
||||
if (auto const ter = deleteAMMTrustLines(sb, ammAccountID, kMaxDeletableAmmTrustLines, j);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
@@ -778,9 +779,9 @@ initializeFeeAuctionVote(
|
||||
STObject voteEntry = STObject::makeInnerObject(sfVoteEntry);
|
||||
if (tfee != 0)
|
||||
voteEntry.setFieldU16(sfTradingFee, tfee);
|
||||
voteEntry.setFieldU32(sfVoteWeight, VOTE_WEIGHT_SCALE_FACTOR);
|
||||
voteEntry.setFieldU32(sfVoteWeight, kVoteWeightScaleFactor);
|
||||
voteEntry.setAccountID(sfAccount, account);
|
||||
voteSlots.push_back(voteEntry);
|
||||
voteSlots.pushBack(voteEntry);
|
||||
ammSle->setFieldArray(sfVoteSlots, voteSlots);
|
||||
// AMM creator gets the auction slot for free.
|
||||
// AuctionSlot is created on AMMCreate and updated on AMMDeposit
|
||||
@@ -796,7 +797,7 @@ initializeFeeAuctionVote(
|
||||
auto const expiration = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
view.header().parentCloseTime.time_since_epoch())
|
||||
.count() +
|
||||
TOTAL_TIME_SLOT_SECS;
|
||||
kTotalTimeSlotSecs;
|
||||
auctionSlot.setFieldU32(sfExpiration, expiration);
|
||||
auctionSlot.setFieldAmount(sfPrice, STAmount{lptAsset, 0});
|
||||
// Set the fee
|
||||
@@ -808,7 +809,7 @@ initializeFeeAuctionVote(
|
||||
{
|
||||
ammSle->makeFieldAbsent(sfTradingFee); // LCOV_EXCL_LINE
|
||||
}
|
||||
if (auto const dfee = tfee / AUCTION_SLOT_DISCOUNTED_FEE_FRACTION)
|
||||
if (auto const dfee = tfee / kAuctionSlotDiscountedFeeFraction)
|
||||
{
|
||||
auctionSlot.setFieldU16(sfDiscountedFee, dfee);
|
||||
}
|
||||
@@ -816,6 +817,9 @@ initializeFeeAuctionVote(
|
||||
{
|
||||
auctionSlot.makeFieldAbsent(sfDiscountedFee); // LCOV_EXCL_LINE
|
||||
}
|
||||
// Clear stale auth accounts from any previous auction slot holder.
|
||||
if (rules.enabled(fixCleanup3_2_0) && auctionSlot.isFieldPresent(sfAuthAccounts))
|
||||
auctionSlot.makeFieldAbsent(sfAuthAccounts);
|
||||
}
|
||||
|
||||
Expected<bool, TER>
|
||||
|
||||
@@ -88,7 +88,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
|
||||
{
|
||||
auto const sle = view.read(keylet::account(id));
|
||||
if (sle == nullptr)
|
||||
return beast::zero;
|
||||
return beast::kZero;
|
||||
|
||||
// Return balance minus reserve
|
||||
std::uint32_t const ownerCount =
|
||||
@@ -121,7 +121,7 @@ transferRate(ReadView const& view, AccountID const& issuer)
|
||||
if (sle && sle->isFieldPresent(sfTransferRate))
|
||||
return Rate{sle->getFieldU32(sfTransferRate)};
|
||||
|
||||
return parityRate;
|
||||
return kParityRate;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -146,17 +146,17 @@ AccountID
|
||||
pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
|
||||
{
|
||||
// This number must not be changed without an amendment
|
||||
constexpr std::uint16_t maxAccountAttempts = 256;
|
||||
for (std::uint16_t i = 0; i < maxAccountAttempts; ++i)
|
||||
static constexpr std::uint16_t kMaxAccountAttempts = 256;
|
||||
for (std::uint16_t i = 0; i < kMaxAccountAttempts; ++i)
|
||||
{
|
||||
ripesha_hasher rsh;
|
||||
RipeshaHasher rsh;
|
||||
auto const hash = sha512Half(i, view.header().parentHash, pseudoOwnerKey);
|
||||
rsh(hash.data(), hash.size());
|
||||
AccountID const ret{static_cast<ripesha_hasher::result_type>(rsh)};
|
||||
AccountID const ret = AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
|
||||
if (!view.read(keylet::account(ret)))
|
||||
return ret;
|
||||
}
|
||||
return beast::zero;
|
||||
return beast::kZero;
|
||||
}
|
||||
|
||||
// Pseudo-account designator fields MUST be maintained by including the
|
||||
@@ -168,7 +168,7 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
|
||||
[[nodiscard]] std::vector<SField const*> const&
|
||||
getPseudoAccountFields()
|
||||
{
|
||||
static std::vector<SField const*> const pseudoFields = []() {
|
||||
static std::vector<SField const*> const kPseudoFields = []() {
|
||||
auto const ar = LedgerFormats::getInstance().findByType(ltACCOUNT_ROOT);
|
||||
if (!ar)
|
||||
{
|
||||
@@ -183,12 +183,12 @@ getPseudoAccountFields()
|
||||
std::vector<SField const*> pseudoFields;
|
||||
for (auto const& field : soTemplate)
|
||||
{
|
||||
if (field.sField().shouldMeta(SField::sMD_PseudoAccount))
|
||||
if (field.sField().shouldMeta(SField::kSmdPseudoAccount))
|
||||
pseudoFields.emplace_back(&field.sField());
|
||||
}
|
||||
return pseudoFields;
|
||||
}();
|
||||
return pseudoFields;
|
||||
return kPseudoFields;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
@@ -221,7 +221,7 @@ createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const
|
||||
"xrpl::createPseudoAccount : valid owner field");
|
||||
|
||||
auto const accountId = pseudoAccountAddress(view, pseudoOwnerKey);
|
||||
if (accountId == beast::zero)
|
||||
if (accountId == beast::kZero)
|
||||
return Unexpected(tecDUPLICATE);
|
||||
|
||||
// Create pseudo-account.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
@@ -9,6 +10,7 @@
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
@@ -33,15 +35,16 @@ namespace xrpl {
|
||||
namespace credentials {
|
||||
|
||||
bool
|
||||
checkExpired(std::shared_ptr<SLE const> const& sleCredential, NetClock::time_point const& closed)
|
||||
checkExpired(SLE const& sleCredential, NetClock::time_point const& closed)
|
||||
{
|
||||
std::uint32_t const exp =
|
||||
(*sleCredential)[~sfExpiration].value_or(std::numeric_limits<std::uint32_t>::max());
|
||||
sleCredential[~sfExpiration].value_or(std::numeric_limits<std::uint32_t>::max());
|
||||
std::uint32_t const now = closed.time_since_epoch().count();
|
||||
return now > exp;
|
||||
}
|
||||
|
||||
bool
|
||||
[[nodiscard]]
|
||||
static Expected<bool, TER>
|
||||
removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j)
|
||||
{
|
||||
auto const closeTime = view.header().parentCloseTime;
|
||||
@@ -53,11 +56,13 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j)
|
||||
auto const k = keylet::credential(h);
|
||||
auto const sleCred = view.peek(k);
|
||||
|
||||
if (sleCred && checkExpired(sleCred, closeTime))
|
||||
if (sleCred && checkExpired(*sleCred, closeTime))
|
||||
{
|
||||
JLOG(j.trace()) << "Credentials are expired. Cred: " << sleCred->getText();
|
||||
// delete expired credentials even if the transaction failed
|
||||
deleteSLE(view, sleCred, j);
|
||||
auto const err = deleteSLE(view, sleCred, j);
|
||||
if (view.rules().enabled(fixCleanup3_1_3) && !isTesSuccess(err))
|
||||
return Unexpected(err);
|
||||
foundExpired = true;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +105,7 @@ deleteSLE(ApplyView& view, std::shared_ptr<SLE> const& sleCredential, beast::Jou
|
||||
|
||||
auto const issuer = sleCredential->getAccountID(sfIssuer);
|
||||
auto const subject = sleCredential->getAccountID(sfSubject);
|
||||
bool const accepted = (sleCredential->getFlags() & lsfAccepted) != 0u;
|
||||
bool const accepted = sleCredential->isFlag(lsfAccepted);
|
||||
|
||||
auto err = delSLE(issuer, sfIssuerNode, !accepted || (subject == issuer));
|
||||
if (!isTesSuccess(err))
|
||||
@@ -126,7 +131,7 @@ checkFields(STTx const& tx, beast::Journal j)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const& credentials = tx.getFieldV256(sfCredentialIDs);
|
||||
if (credentials.empty() || (credentials.size() > maxCredentialsArraySize))
|
||||
if (credentials.empty() || (credentials.size() > kMaxCredentialsArraySize))
|
||||
{
|
||||
JLOG(j.trace()) << "Malformed transaction: Credentials array size is invalid: "
|
||||
<< credentials.size();
|
||||
@@ -169,7 +174,7 @@ valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal
|
||||
return tecBAD_CREDENTIALS;
|
||||
}
|
||||
|
||||
if ((sleCred->getFlags() & lsfAccepted) == 0u)
|
||||
if (!sleCred->isFlag(lsfAccepted))
|
||||
{
|
||||
JLOG(j.trace()) << "Credential isn't accepted. Cred: " << h;
|
||||
return tecBAD_CREDENTIALS;
|
||||
@@ -205,12 +210,12 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject)
|
||||
// allows expired credentials to be deleted by any transaction.
|
||||
if (sleCredential)
|
||||
{
|
||||
if (checkExpired(sleCredential, closeTime))
|
||||
if (checkExpired(*sleCredential, closeTime))
|
||||
{
|
||||
foundExpired = true;
|
||||
continue;
|
||||
}
|
||||
if ((sleCredential->getFlags() & lsfAccepted) != 0u)
|
||||
if (sleCredential->isFlag(lsfAccepted))
|
||||
{
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -283,7 +288,7 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j)
|
||||
}
|
||||
|
||||
auto const ct = credential[sfCredentialType];
|
||||
if (ct.empty() || (ct.size() > maxCredentialTypeLength))
|
||||
if (ct.empty() || (ct.size() > kMaxCredentialTypeLength))
|
||||
{
|
||||
JLOG(j.trace()) << "Malformed transaction: "
|
||||
"Invalid credentialType size: "
|
||||
@@ -321,21 +326,24 @@ verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, b
|
||||
auto const type = h.getFieldVL(sfCredentialType);
|
||||
auto const keyletCredential = keylet::credential(account, issuer, makeSlice(type));
|
||||
if (view.exists(keyletCredential))
|
||||
credentials.push_back(keyletCredential.key);
|
||||
credentials.pushBack(keyletCredential.key);
|
||||
}
|
||||
|
||||
bool const foundExpired = credentials::removeExpired(view, credentials, j);
|
||||
auto const foundExpired = credentials::removeExpired(view, credentials, j);
|
||||
if (!foundExpired.has_value())
|
||||
return foundExpired.error();
|
||||
|
||||
for (auto const& h : credentials)
|
||||
{
|
||||
auto sleCredential = view.read(keylet::credential(h));
|
||||
if (!sleCredential)
|
||||
continue; // expired, i.e. deleted in credentials::removeExpired
|
||||
|
||||
if ((sleCredential->getFlags() & lsfAccepted) != 0u)
|
||||
if (sleCredential->isFlag(lsfAccepted))
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
return foundExpired ? tecEXPIRED : tecNO_PERMISSION;
|
||||
return *foundExpired ? tecEXPIRED : tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -355,10 +363,17 @@ verifyDepositPreauth(
|
||||
|
||||
bool const credentialsPresent = tx.isFieldPresent(sfCredentialIDs);
|
||||
|
||||
if (credentialsPresent && credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j))
|
||||
return tecEXPIRED;
|
||||
if (credentialsPresent)
|
||||
{
|
||||
auto const foundExpired =
|
||||
credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j);
|
||||
if (!foundExpired.has_value())
|
||||
return foundExpired.error();
|
||||
if (*foundExpired)
|
||||
return tecEXPIRED;
|
||||
}
|
||||
|
||||
if (sleDst && ((sleDst->getFlags() & lsfDepositAuth) != 0u))
|
||||
if (sleDst && sleDst->isFlag(lsfDepositAuth))
|
||||
{
|
||||
if (src != dst)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,6 @@
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
@@ -55,7 +54,11 @@ isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue cons
|
||||
}
|
||||
|
||||
bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth)
|
||||
isFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
MPTIssue const& mptIssue,
|
||||
std::uint8_t depth)
|
||||
{
|
||||
return isGlobalFrozen(view, mptIssue) || isIndividualFrozen(view, account, mptIssue) ||
|
||||
isVaultPseudoAccountFrozen(view, account, mptIssue, depth);
|
||||
@@ -66,7 +69,7 @@ isAnyFrozen(
|
||||
ReadView const& view,
|
||||
std::initializer_list<AccountID> const& accounts,
|
||||
MPTIssue const& mptIssue,
|
||||
int depth)
|
||||
std::uint8_t depth)
|
||||
{
|
||||
if (isGlobalFrozen(view, mptIssue))
|
||||
return true;
|
||||
@@ -96,11 +99,11 @@ transferRate(ReadView const& view, MPTID const& issuanceID)
|
||||
sle && sle->isFieldPresent(sfTransferFee))
|
||||
{
|
||||
auto const fee = sle->getFieldU16(sfTransferFee);
|
||||
XRPL_ASSERT(fee <= maxTransferFee, "xrpl::transferRate : fee is too large");
|
||||
XRPL_ASSERT(fee <= kMaxTransferFee, "xrpl::transferRate : fee is too large");
|
||||
return Rate{1'000'000'000u + (10'000 * fee)};
|
||||
}
|
||||
|
||||
return parityRate;
|
||||
return kParityRate;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
@@ -169,8 +172,8 @@ authorizeMPToken(
|
||||
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
|
||||
auto const sleMpt = view.peek(mptokenKey);
|
||||
if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0 ||
|
||||
(view.rules().enabled(fixSecurity3_1_3) &&
|
||||
(*sleMpt)[~sfLockedAmount].value_or(0) != 0))
|
||||
(view.rules().enabled(fixCleanup3_1_3) &&
|
||||
(*sleMpt)[~sfLockedAmount].valueOr(0) != 0))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!view.dirRemove(
|
||||
@@ -194,7 +197,7 @@ authorizeMPToken(
|
||||
// items. This is similar to the reserve requirements of trust lines.
|
||||
std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount);
|
||||
XRPAmount const reserveCreate(
|
||||
(uOwnerCount < 2) ? XRPAmount(beast::zero)
|
||||
(uOwnerCount < 2) ? XRPAmount(beast::kZero)
|
||||
: view.fees().accountReserve(uOwnerCount + 1));
|
||||
|
||||
if (priorBalance < reserveCreate)
|
||||
@@ -284,7 +287,7 @@ removeEmptyHolding(
|
||||
// accounting out of balance, so fail. Since this should be impossible
|
||||
// anyway, I'm not going to put any effort into it.
|
||||
if (mptoken->at(sfMPTAmount) != 0 ||
|
||||
(view.rules().enabled(fixSecurity3_1_3) && (*mptoken)[~sfLockedAmount].value_or(0) != 0))
|
||||
(view.rules().enabled(fixCleanup3_1_3) && (*mptoken)[~sfLockedAmount].valueOr(0) != 0))
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
return authorizeMPToken(
|
||||
@@ -303,7 +306,7 @@ requireAuth(
|
||||
MPTIssue const& mptIssue,
|
||||
AccountID const& account,
|
||||
AuthType authType,
|
||||
int depth)
|
||||
std::uint8_t depth)
|
||||
{
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto const sleIssuance = view.read(mptID);
|
||||
@@ -320,8 +323,13 @@ requireAuth(
|
||||
|
||||
if (featureSAVEnabled)
|
||||
{
|
||||
if (depth >= maxAssetCheckDepth)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
if (depth >= kMaxAssetCheckDepth)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::MPTokenHelpers::requireAuth : reached asset check depth");
|
||||
return tecINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
// requireAuth is recursive if the issuer is a vault pseudo-account
|
||||
auto const sleIssuer = view.read(keylet::account(mptIssuer));
|
||||
@@ -358,7 +366,7 @@ requireAuth(
|
||||
if (maybeDomainID)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth,
|
||||
sleIssuance->isFlag(lsfMPTRequireAuth),
|
||||
"xrpl::requireAuth : issuance requires authorization");
|
||||
// ter = tefINTERNAL | tecOBJECT_NOT_FOUND | tecNO_AUTH | tecEXPIRED
|
||||
auto const ter = credentials::validDomain(view, *maybeDomainID, account);
|
||||
@@ -374,10 +382,11 @@ requireAuth(
|
||||
// belong to someone who is explicitly authorized e.g. a vault owner.
|
||||
}
|
||||
|
||||
if (featureSAVEnabled)
|
||||
bool const featureMPTV2Enabled = view.rules().enabled(featureMPTokensV2);
|
||||
if (featureSAVEnabled || featureMPTV2Enabled)
|
||||
{
|
||||
// Implicitly authorize Vault and LoanBroker pseudo-accounts
|
||||
if (isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID}))
|
||||
// Implicitly authorize Vault, LoanBroker, and AMM pseudo-accounts
|
||||
if (isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID, &sfAMMID}))
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -489,28 +498,88 @@ enforceMPTokenAuthorization(
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
[[nodiscard]] Asset
|
||||
assetOfHolding(SLE const& sleShareIssuance, SLE const& sleHolding)
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
sleHolding.getType() == ltRIPPLE_STATE || sleHolding.getType() == ltMPTOKEN,
|
||||
"xrpl::assetOfHolding",
|
||||
"unexpected holding type");
|
||||
XRPL_ASSERT_PARTS(
|
||||
sleShareIssuance.getType() == ltMPTOKEN_ISSUANCE,
|
||||
"xrpl::assetOfHolding",
|
||||
"not SLE MPTokenIssuance");
|
||||
|
||||
if (sleHolding.getType() == ltMPTOKEN)
|
||||
return MPTIssue{sleHolding.getFieldH192(sfMPTokenIssuanceID)};
|
||||
|
||||
auto const vaultPseudo = sleShareIssuance.at(sfIssuer);
|
||||
auto const lowLimit = sleHolding.getFieldAmount(sfLowLimit);
|
||||
auto const highLimit = sleHolding.getFieldAmount(sfHighLimit);
|
||||
auto const& iouIssuer =
|
||||
(lowLimit.getIssuer() != vaultPseudo) ? lowLimit.getIssuer() : highLimit.getIssuer();
|
||||
return Issue{lowLimit.get<Issue>().currency, iouIssuer};
|
||||
}
|
||||
|
||||
TER
|
||||
canTransfer(
|
||||
ReadView const& view,
|
||||
MPTIssue const& mptIssue,
|
||||
AccountID const& from,
|
||||
AccountID const& to)
|
||||
AccountID const& to,
|
||||
WaiveMPTCanTransfer waive,
|
||||
std::uint8_t depth)
|
||||
{
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto const sleIssuance = view.read(mptID);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
auto const issuer = (*sleIssuance)[sfIssuer];
|
||||
if (waive == WaiveMPTCanTransfer::Yes || from == issuer || to == issuer)
|
||||
return tesSUCCESS;
|
||||
|
||||
if (!sleIssuance->isFlag(lsfMPTCanTransfer))
|
||||
return TER{tecNO_AUTH};
|
||||
|
||||
// Post-fixCleanup3_2_0: vault shares carry sfReferenceHolding pointing
|
||||
// to the vault pseudo's MPToken or RippleState for the underlying asset.
|
||||
// Third-party transfers inherit the underlying's transferability.
|
||||
// Issuer-involving transfers and waived callers returned tesSUCCESS above.
|
||||
//
|
||||
// The recursive call always passes WaiveMPTCanTransfer::No so that
|
||||
// a waived outer caller does not transitively unlock the underlying.
|
||||
if (view.rules().enabled(fixCleanup3_2_0) && sleIssuance->isFieldPresent(sfReferenceHolding))
|
||||
{
|
||||
if (from != (*sleIssuance)[sfIssuer] && to != (*sleIssuance)[sfIssuer])
|
||||
return TER{tecNO_AUTH};
|
||||
// Defensive depth bound on the inheritance recursion. Unreachable
|
||||
// in practice (vault-of-vault-shares is forbidden at VaultCreate).
|
||||
if (depth >= kMaxAssetCheckDepth)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::MPTokenHelpers::canTransfer : reached asset check depth");
|
||||
return tecINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const sleHolding =
|
||||
view.read(keylet::unchecked(sleIssuance->getFieldH256(sfReferenceHolding)));
|
||||
if (!sleHolding)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return canTransfer(
|
||||
view,
|
||||
assetOfHolding(*sleIssuance, *sleHolding),
|
||||
from,
|
||||
to,
|
||||
WaiveMPTCanTransfer::No,
|
||||
depth + 1);
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
canTrade(ReadView const& view, Asset const& asset)
|
||||
canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth)
|
||||
{
|
||||
return asset.visit(
|
||||
[&](Issue const&) -> TER { return tesSUCCESS; },
|
||||
@@ -520,10 +589,51 @@ canTrade(ReadView const& view, Asset const& asset)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
if (!sleIssuance->isFlag(lsfMPTCanTrade))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Post-fixCleanup3_2_0: vault shares inherit the underlying
|
||||
// asset's tradability. A share whose underlying has been
|
||||
// removed from trading cannot itself be placed on the DEX.
|
||||
if (view.rules().enabled(fixCleanup3_2_0) &&
|
||||
sleIssuance->isFieldPresent(sfReferenceHolding))
|
||||
{
|
||||
// Defensive depth bound on the inheritance recursion.
|
||||
// Unreachable in practice (vault-of-vault-shares
|
||||
// forbidden at VaultCreate).
|
||||
if (depth >= kMaxAssetCheckDepth)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::MPTokenHelpers::canTrade : reached asset check depth");
|
||||
return tecINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
auto const sleHolding =
|
||||
view.read(keylet::unchecked(sleIssuance->getFieldH256(sfReferenceHolding)));
|
||||
if (!sleHolding)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return canTrade(view, assetOfHolding(*sleIssuance, *sleHolding), depth + 1);
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
TER
|
||||
canMPTTradeAndTransfer(
|
||||
ReadView const& view,
|
||||
Asset const& asset,
|
||||
AccountID const& from,
|
||||
AccountID const& to)
|
||||
{
|
||||
if (!asset.holds<MPTIssue>())
|
||||
return tesSUCCESS;
|
||||
|
||||
if (auto const ter = canTrade(view, asset); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
return canTransfer(view, asset, from, to);
|
||||
}
|
||||
|
||||
TER
|
||||
lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount, beast::Journal j)
|
||||
{
|
||||
@@ -567,7 +677,7 @@ lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount,
|
||||
(*sle)[sfMPTAmount] = amt - pay;
|
||||
|
||||
// Overflow check for addition
|
||||
uint64_t const locked = (*sle)[~sfLockedAmount].value_or(0);
|
||||
uint64_t const locked = (*sle)[~sfLockedAmount].valueOr(0);
|
||||
|
||||
if (!canAdd(STAmount(mptIssue, locked), STAmount(mptIssue, pay)))
|
||||
{ // LCOV_EXCL_START
|
||||
@@ -591,7 +701,7 @@ lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount,
|
||||
// 1. Increase the Issuance EscrowedAmount
|
||||
// 2. DO NOT change the Issuance OutstandingAmount
|
||||
{
|
||||
uint64_t const issuanceEscrowed = (*sleIssuance)[~sfLockedAmount].value_or(0);
|
||||
uint64_t const issuanceEscrowed = (*sleIssuance)[~sfLockedAmount].valueOr(0);
|
||||
auto const pay = amount.mpt().value();
|
||||
|
||||
// Overflow check for addition
|
||||
@@ -839,7 +949,7 @@ checkCreateMPT(
|
||||
std::int64_t
|
||||
maxMPTAmount(SLE const& sleIssuance)
|
||||
{
|
||||
return sleIssuance[~sfMaximumAmount].value_or(maxMPTokenAmount);
|
||||
return sleIssuance[~sfMaximumAmount].value_or(kMaxMpTokenAmount);
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
@@ -891,65 +1001,4 @@ issuerSelfDebitHookMPT(ApplyView& view, MPTIssue const& issue, std::uint64_t amo
|
||||
view.issuerSelfDebitHookMPT(issue, amount, available);
|
||||
}
|
||||
|
||||
static TER
|
||||
checkMPTAllowed(ReadView const& view, TxType txType, Asset const& asset, AccountID const& accountID)
|
||||
{
|
||||
if (!asset.holds<MPTIssue>())
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const& issuanceID = asset.get<MPTIssue>().getMptID();
|
||||
auto const validTx = txType == ttAMM_CREATE || txType == ttAMM_DEPOSIT ||
|
||||
txType == ttAMM_WITHDRAW || txType == ttOFFER_CREATE || txType == ttCHECK_CREATE ||
|
||||
txType == ttCHECK_CASH || txType == ttPAYMENT;
|
||||
XRPL_ASSERT(validTx, "xrpl::checkMPTAllowed : all MPT tx or DEX");
|
||||
if (!validTx)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const& issuer = asset.getIssuer();
|
||||
if (!view.exists(keylet::account(issuer)))
|
||||
return tecNO_ISSUER; // LCOV_EXCL_LINE
|
||||
|
||||
auto const issuanceKey = keylet::mptIssuance(issuanceID);
|
||||
auto const issuanceSle = view.read(issuanceKey);
|
||||
if (!issuanceSle)
|
||||
return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE
|
||||
|
||||
auto const flags = issuanceSle->getFlags();
|
||||
|
||||
if ((flags & lsfMPTLocked) != 0u)
|
||||
return tecLOCKED; // LCOV_EXCL_LINE
|
||||
// Offer crossing and Payment
|
||||
if ((flags & lsfMPTCanTrade) == 0)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
if (accountID != issuer)
|
||||
{
|
||||
if ((flags & lsfMPTCanTransfer) == 0)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
auto const mptSle = view.read(keylet::mptoken(issuanceKey.key, accountID));
|
||||
// Allow to succeed since some tx create MPToken if it doesn't exist.
|
||||
// Tx's have their own check for missing MPToken.
|
||||
if (!mptSle)
|
||||
return tesSUCCESS;
|
||||
|
||||
if (mptSle->isFlag(lsfMPTLocked))
|
||||
return tecLOCKED;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
checkMPTTxAllowed(
|
||||
ReadView const& view,
|
||||
TxType txType,
|
||||
Asset const& asset,
|
||||
AccountID const& accountID)
|
||||
{
|
||||
// use isDEXAllowed for payment/offer crossing
|
||||
XRPL_ASSERT(txType != ttPAYMENT, "xrpl::checkMPTTxAllowed : not payment");
|
||||
return checkMPTAllowed(view, txType, asset, accountID);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFlags.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/protocol/nft.h>
|
||||
#include <xrpl/protocol/nftPageMask.h>
|
||||
@@ -43,8 +44,8 @@ namespace xrpl::nft {
|
||||
static std::shared_ptr<SLE const>
|
||||
locatePage(ReadView const& view, AccountID const& owner, uint256 const& id)
|
||||
{
|
||||
auto const first = keylet::nftpage(keylet::nftpage_min(owner), id);
|
||||
auto const last = keylet::nftpage_max(owner);
|
||||
auto const first = keylet::nftpage(keylet::nftpageMin(owner), id);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
// This NFT can only be found in the first page with a key that's strictly
|
||||
// greater than `first`, so look for that, up until the maximum possible
|
||||
@@ -56,8 +57,8 @@ locatePage(ReadView const& view, AccountID const& owner, uint256 const& id)
|
||||
static std::shared_ptr<SLE>
|
||||
locatePage(ApplyView& view, AccountID const& owner, uint256 const& id)
|
||||
{
|
||||
auto const first = keylet::nftpage(keylet::nftpage_min(owner), id);
|
||||
auto const last = keylet::nftpage_max(owner);
|
||||
auto const first = keylet::nftpage(keylet::nftpageMin(owner), id);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
// This NFT can only be found in the first page with a key that's strictly
|
||||
// greater than `first`, so look for that, up until the maximum possible
|
||||
@@ -73,9 +74,9 @@ getPageForToken(
|
||||
uint256 const& id,
|
||||
std::function<void(ApplyView&, AccountID const&)> const& createCallback)
|
||||
{
|
||||
auto const base = keylet::nftpage_min(owner);
|
||||
auto const base = keylet::nftpageMin(owner);
|
||||
auto const first = keylet::nftpage(base, id);
|
||||
auto const last = keylet::nftpage_max(owner);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
// This NFT can only be found in the first page with a key that's strictly
|
||||
// greater than `first`, so look for that, up until the maximum possible
|
||||
@@ -97,7 +98,7 @@ getPageForToken(
|
||||
STArray narr = cp->getFieldArray(sfNFTokens);
|
||||
|
||||
// The right page still has space: we're good.
|
||||
if (narr.size() != dirMaxTokensPerPage)
|
||||
if (narr.size() != kDirMaxTokensPerPage)
|
||||
return cp;
|
||||
|
||||
// We need to split the page in two: the first half of the items in this
|
||||
@@ -114,13 +115,13 @@ getPageForToken(
|
||||
// any additional equivalent NFTs maximum room for expansion.
|
||||
// Round up the boundary until there's a non-equivalent entry.
|
||||
uint256 const cmp =
|
||||
narr[(dirMaxTokensPerPage / 2) - 1].getFieldH256(sfNFTokenID) & nft::pageMask;
|
||||
narr[(kDirMaxTokensPerPage / 2) - 1].getFieldH256(sfNFTokenID) & nft::kPageMask;
|
||||
|
||||
// Note that the calls to find_if_not() and (later) find_if()
|
||||
// rely on the fact that narr is kept in sorted order.
|
||||
auto splitIter = std::find_if_not(
|
||||
narr.begin() + (dirMaxTokensPerPage / 2), narr.end(), [&cmp](STObject const& obj) {
|
||||
return (obj.getFieldH256(sfNFTokenID) & nft::pageMask) == cmp;
|
||||
narr.begin() + (kDirMaxTokensPerPage / 2), narr.end(), [&cmp](STObject const& obj) {
|
||||
return (obj.getFieldH256(sfNFTokenID) & nft::kPageMask) == cmp;
|
||||
});
|
||||
|
||||
// If we get all the way from the middle to the end with only
|
||||
@@ -129,7 +130,7 @@ getPageForToken(
|
||||
if (splitIter == narr.end())
|
||||
{
|
||||
splitIter = std::ranges::find_if(narr, [&cmp](STObject const& obj) {
|
||||
return (obj.getFieldH256(sfNFTokenID) & nft::pageMask) == cmp;
|
||||
return (obj.getFieldH256(sfNFTokenID) & nft::kPageMask) == cmp;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -142,7 +143,7 @@ getPageForToken(
|
||||
// equivalent tokens. This requires special handling.
|
||||
if (splitIter == narr.begin())
|
||||
{
|
||||
auto const relation{(id & nft::pageMask) <=> cmp};
|
||||
auto const relation{(id & nft::kPageMask) <=> cmp};
|
||||
if (relation == 0)
|
||||
{
|
||||
// If the passed in id belongs exactly on this (full) page
|
||||
@@ -177,8 +178,8 @@ getPageForToken(
|
||||
// less than the low 96-bits of the enclosing page's index. In order to
|
||||
// accommodate that requirement we use an index one higher than the
|
||||
// largest NFT in the page.
|
||||
uint256 const tokenIDForNewPage = narr.size() == dirMaxTokensPerPage
|
||||
? narr[dirMaxTokensPerPage - 1].getFieldH256(sfNFTokenID).next()
|
||||
uint256 const tokenIDForNewPage = narr.size() == kDirMaxTokensPerPage
|
||||
? narr[kDirMaxTokensPerPage - 1].getFieldH256(sfNFTokenID).next()
|
||||
: carr[0].getFieldH256(sfNFTokenID);
|
||||
|
||||
auto np = std::make_shared<SLE>(keylet::nftpage(base, tokenIDForNewPage));
|
||||
@@ -216,7 +217,7 @@ compareTokens(uint256 const& a, uint256 const& b)
|
||||
// 96-bits are identical we still need a fully deterministic sort.
|
||||
// So we sort on the low 96-bits first. If those are equal we sort on
|
||||
// the whole thing.
|
||||
if (auto const lowBitsCmp{(a & nft::pageMask) <=> (b & nft::pageMask)}; lowBitsCmp != 0)
|
||||
if (auto const lowBitsCmp{(a & nft::kPageMask) <=> (b & nft::kPageMask)}; lowBitsCmp != 0)
|
||||
return lowBitsCmp < 0;
|
||||
|
||||
return a < b;
|
||||
@@ -280,7 +281,7 @@ insertToken(ApplyView& view, AccountID owner, STObject&& nft)
|
||||
|
||||
{
|
||||
auto arr = page->getFieldArray(sfNFTokens);
|
||||
arr.push_back(std::move(nft));
|
||||
arr.pushBack(std::move(nft));
|
||||
|
||||
arr.sort([](STObject const& o1, STObject const& o2) {
|
||||
return compareTokens(o1.getFieldH256(sfNFTokenID), o2.getFieldH256(sfNFTokenID));
|
||||
@@ -313,7 +314,7 @@ mergePages(ApplyView& view, std::shared_ptr<SLE> const& p1, std::shared_ptr<SLE>
|
||||
// this it would mean that one of them can be deleted as a result of
|
||||
// the merge.
|
||||
|
||||
if (p1arr.size() + p2arr.size() > dirMaxTokensPerPage)
|
||||
if (p1arr.size() + p2arr.size() > kDirMaxTokensPerPage)
|
||||
return false;
|
||||
|
||||
STArray x(p1arr.size() + p2arr.size());
|
||||
@@ -444,7 +445,7 @@ removeToken(
|
||||
// 3. Fix up the owner count.
|
||||
// 4. Erase the previous page.
|
||||
if (view.rules().enabled(fixNFTokenPageLinks) &&
|
||||
((curr->key() & nft::pageMask) == pageMask))
|
||||
((curr->key() & nft::kPageMask) == kPageMask))
|
||||
{
|
||||
// Copy all relevant information from prev to curr.
|
||||
curr->peekFieldArray(sfNFTokens) = prev->peekFieldArray(sfNFTokens);
|
||||
@@ -635,8 +636,8 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr<SLE> const& offer)
|
||||
auto const nftokenID = (*offer)[sfNFTokenID];
|
||||
|
||||
if (!view.dirRemove(
|
||||
(((*offer)[sfFlags] & lsfSellNFToken) != 0u) ? keylet::nft_sells(nftokenID)
|
||||
: keylet::nft_buys(nftokenID),
|
||||
offer->isFlag(lsfSellNFToken) ? keylet::nftSells(nftokenID)
|
||||
: keylet::nftBuys(nftokenID),
|
||||
(*offer)[sfNFTokenOfferNode],
|
||||
offer->key(),
|
||||
false))
|
||||
@@ -654,11 +655,11 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner)
|
||||
{
|
||||
bool didRepair = false;
|
||||
|
||||
auto const last = keylet::nftpage_max(owner);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
std::shared_ptr<SLE> page = view.peek(Keylet(
|
||||
ltNFTOKEN_PAGE,
|
||||
view.succ(keylet::nftpage_min(owner).key, last.key.next()).value_or(last.key)));
|
||||
view.succ(keylet::nftpageMin(owner).key, last.key.next()).value_or(last.key)));
|
||||
|
||||
if (!page)
|
||||
return didRepair;
|
||||
@@ -787,7 +788,7 @@ tokenOfferCreatePreflight(
|
||||
|
||||
if (!isXRP(amount))
|
||||
{
|
||||
if ((nftFlags & nft::flagOnlyXRP) != 0)
|
||||
if ((nftFlags & nft::kFlagOnlyXrp) != 0)
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (!amount)
|
||||
@@ -832,7 +833,7 @@ tokenOfferCreatePreclaim(
|
||||
std::optional<AccountID> const& owner,
|
||||
std::uint32_t txFlags)
|
||||
{
|
||||
if (((nftFlags & nft::flagCreateTrustLines) == 0) && !amount.native() && (xferFee != 0u))
|
||||
if (((nftFlags & nft::kFlagCreateTrustLines) == 0) && !amount.native() && (xferFee != 0u))
|
||||
{
|
||||
if (!view.exists(keylet::account(nftIssuer)))
|
||||
return tecNO_ISSUER;
|
||||
@@ -854,7 +855,7 @@ tokenOfferCreatePreclaim(
|
||||
return tecFROZEN;
|
||||
}
|
||||
|
||||
if (nftIssuer != acctID && ((nftFlags & nft::flagTransferable) == 0))
|
||||
if (nftIssuer != acctID && ((nftFlags & nft::kFlagTransferable) == 0))
|
||||
{
|
||||
auto const root = view.read(keylet::account(nftIssuer));
|
||||
XRPL_ASSERT(root, "xrpl::nft::tokenOfferCreatePreclaim : non-null account");
|
||||
@@ -873,7 +874,7 @@ tokenOfferCreatePreclaim(
|
||||
{
|
||||
// We allow an IOU issuer to make a buy offer
|
||||
// using their own currency.
|
||||
if (accountFunds(view, acctID, amount, FreezeHandling::fhZERO_IF_FROZEN, j).signum() <= 0)
|
||||
if (accountFunds(view, acctID, amount, FreezeHandling::ZeroIfFrozen, j).signum() <= 0)
|
||||
return tecUNFUNDED_OFFER;
|
||||
}
|
||||
|
||||
@@ -887,7 +888,7 @@ tokenOfferCreatePreclaim(
|
||||
return tecNO_DST;
|
||||
|
||||
// check if the destination has disallowed incoming offers
|
||||
if ((sleDst->getFlags() & lsfDisallowIncomingNFTokenOffer) != 0u)
|
||||
if (sleDst->isFlag(lsfDisallowIncomingNFTokenOffer))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
@@ -900,7 +901,7 @@ tokenOfferCreatePreclaim(
|
||||
if (!sleOwner)
|
||||
return tecNO_TARGET;
|
||||
|
||||
if ((sleOwner->getFlags() & lsfDisallowIncomingNFTokenOffer) != 0u)
|
||||
if (sleOwner->isFlag(lsfDisallowIncomingNFTokenOffer))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
@@ -953,7 +954,7 @@ tokenOfferCreateApply(
|
||||
// Token offers are also added to the token's buy or sell offer
|
||||
// directory
|
||||
auto const offerNode = view.dirInsert(
|
||||
isSellOffer ? keylet::nft_sells(nftokenID) : keylet::nft_buys(nftokenID),
|
||||
isSellOffer ? keylet::nftSells(nftokenID) : keylet::nftBuys(nftokenID),
|
||||
offerID,
|
||||
[&nftokenID, isSellOffer](std::shared_ptr<SLE> const& sle) {
|
||||
(*sle)[sfFlags] = isSellOffer ? lsfNFTokenSellOffers : lsfNFTokenBuyOffers;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STArray.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/CredentialHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -19,6 +21,16 @@ namespace xrpl::permissioned_dex {
|
||||
bool
|
||||
accountInDomain(ReadView const& view, AccountID const& account, Domain const& domainID)
|
||||
{
|
||||
// Avoid constructing a zero-key PermissionedDomain keylet.
|
||||
// keylet::permissionedDomain(uint256) uses the DomainID as the ledger key.
|
||||
if (view.rules().enabled(fixCleanup3_2_0) && domainID == beast::kZero)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::permissioned_dex::accountInDomain : domainID is zero");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const sleDomain = view.read(keylet::permissionedDomain(domainID));
|
||||
if (!sleDomain)
|
||||
return false;
|
||||
@@ -35,7 +47,7 @@ accountInDomain(ReadView const& view, AccountID const& account, Domain const& do
|
||||
if (!sleCred || !sleCred->isFlag(lsfAccepted))
|
||||
return false;
|
||||
|
||||
return !credentials::checkExpired(sleCred, view.header().parentCloseTime);
|
||||
return !credentials::checkExpired(*sleCred, view.header().parentCloseTime);
|
||||
});
|
||||
|
||||
return inDomain;
|
||||
@@ -60,9 +72,9 @@ offerInDomain(
|
||||
if (sleOffer->getFieldH256(sfDomainID) != domainID)
|
||||
return false; // LCOV_EXCL_LINE
|
||||
|
||||
if (view.rules().enabled(fixSecurity3_1_3))
|
||||
if (view.rules().enabled(fixCleanup3_1_3))
|
||||
{
|
||||
// post-fixSecurity3_1_3: a valid hybrid offer must have
|
||||
// post-fixCleanup3_1_3: a valid hybrid offer must have
|
||||
// sfAdditionalBooks present with exactly 1 entry
|
||||
if (sleOffer->isFlag(lsfHybrid) &&
|
||||
(!sleOffer->isFieldPresent(sfAdditionalBooks) ||
|
||||
@@ -75,7 +87,7 @@ offerInDomain(
|
||||
}
|
||||
else
|
||||
{
|
||||
// pre-fixSecurity3_1_3: a valid hybrid offer must have
|
||||
// pre-fixCleanup3_1_3: a valid hybrid offer must have
|
||||
// sfAdditionalBooks present (size is not checked)
|
||||
if (sleOffer->isFlag(lsfHybrid) && !sleOffer->isFieldPresent(sfAdditionalBooks))
|
||||
{
|
||||
|
||||
@@ -183,15 +183,15 @@ trustCreate(
|
||||
bool const bSrcHigh,
|
||||
AccountID const& uSrcAccountID,
|
||||
AccountID const& uDstAccountID,
|
||||
uint256 const& uIndex, // --> ripple state entry
|
||||
SLE::ref sleAccount, // --> the account being set.
|
||||
bool const bAuth, // --> authorize account.
|
||||
bool const bNoRipple, // --> others cannot ripple through
|
||||
bool const bFreeze, // --> funds cannot leave
|
||||
bool bDeepFreeze, // --> can neither receive nor send funds
|
||||
STAmount const& saBalance, // --> balance of account being set.
|
||||
uint256 const& uIndex, // ripple state entry
|
||||
SLE::ref sleAccount, // the account being set.
|
||||
bool const bAuth, // authorize account.
|
||||
bool const bNoRipple, // others cannot ripple through
|
||||
bool const bFreeze, // funds cannot leave
|
||||
bool bDeepFreeze, // can neither receive nor send funds
|
||||
STAmount const& saBalance, // balance of account being set.
|
||||
// Issuer should be noAccount()
|
||||
STAmount const& saLimit, // --> limit for account being set.
|
||||
STAmount const& saLimit, // limit for account being set.
|
||||
// Issuer should be the account being set.
|
||||
std::uint32_t uQualityIn,
|
||||
std::uint32_t uQualityOut,
|
||||
@@ -274,7 +274,7 @@ trustCreate(
|
||||
uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
|
||||
}
|
||||
|
||||
if ((slePeer->getFlags() & lsfDefaultRipple) == 0)
|
||||
if (!slePeer->isFlag(lsfDefaultRipple))
|
||||
{
|
||||
// The other side's default is no rippling
|
||||
uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
|
||||
@@ -341,22 +341,25 @@ updateTrustLine(
|
||||
{
|
||||
if (!state)
|
||||
return false;
|
||||
std::uint32_t const flags(state->getFieldU32(sfFlags));
|
||||
|
||||
auto sle = view.peek(keylet::account(sender));
|
||||
if (!sle)
|
||||
return false;
|
||||
|
||||
auto const senderReserveFlag = bSenderHigh ? lsfHighReserve : lsfLowReserve;
|
||||
auto const senderNoRippleFlag = bSenderHigh ? lsfHighNoRipple : lsfLowNoRipple;
|
||||
auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
|
||||
auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
|
||||
|
||||
// YYY Could skip this if rippling in reverse.
|
||||
if (before > beast::zero
|
||||
if (before > beast::kZero
|
||||
// Sender balance was positive.
|
||||
&& after <= beast::zero
|
||||
&& after <= beast::kZero
|
||||
// Sender is zero or negative.
|
||||
&& ((flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) != 0u)
|
||||
&& state->isFlag(senderReserveFlag)
|
||||
// Sender reserve is set.
|
||||
&& static_cast<bool>(flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
|
||||
static_cast<bool>(sle->getFlags() & lsfDefaultRipple) &&
|
||||
((flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) == 0u) &&
|
||||
&& state->isFlag(senderNoRippleFlag) != sle->isFlag(lsfDefaultRipple) &&
|
||||
!state->isFlag(senderFreezeFlag) &&
|
||||
!state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
|
||||
// Sender trust limit is 0.
|
||||
&& (state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) == 0u)
|
||||
@@ -369,11 +372,10 @@ updateTrustLine(
|
||||
adjustOwnerCount(view, sle, -1, j);
|
||||
|
||||
// Clear reserve flag.
|
||||
state->setFieldU32(sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
|
||||
state->clearFlag(senderReserveFlag);
|
||||
|
||||
// Balance is zero, receiver reserve is clear.
|
||||
if (!after // Balance is zero.
|
||||
&& ((flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)) == 0u))
|
||||
if (!after && !state->isFlag(receiverReserveFlag))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -405,28 +407,28 @@ issueIOU(
|
||||
|
||||
if (auto state = view.peek(index))
|
||||
{
|
||||
STAmount final_balance = state->getFieldAmount(sfBalance);
|
||||
STAmount finalBalance = state->getFieldAmount(sfBalance);
|
||||
|
||||
if (bSenderHigh)
|
||||
final_balance.negate(); // Put balance in sender terms.
|
||||
finalBalance.negate(); // Put balance in sender terms.
|
||||
|
||||
STAmount const start_balance = final_balance;
|
||||
STAmount const startBalance = finalBalance;
|
||||
|
||||
final_balance -= amount;
|
||||
finalBalance -= amount;
|
||||
|
||||
auto const must_delete = updateTrustLine(
|
||||
view, state, bSenderHigh, issue.account, start_balance, final_balance, j);
|
||||
auto const mustDelete =
|
||||
updateTrustLine(view, state, bSenderHigh, issue.account, startBalance, finalBalance, j);
|
||||
|
||||
view.creditHookIOU(issue.account, account, amount, start_balance);
|
||||
view.creditHookIOU(issue.account, account, amount, startBalance);
|
||||
|
||||
if (bSenderHigh)
|
||||
final_balance.negate();
|
||||
finalBalance.negate();
|
||||
|
||||
// Adjust the balance on the trust line if necessary. We do this even
|
||||
// if we are going to delete the line to reflect the correct balance
|
||||
// at the time of deletion.
|
||||
state->setFieldAmount(sfBalance, final_balance);
|
||||
if (must_delete)
|
||||
state->setFieldAmount(sfBalance, finalBalance);
|
||||
if (mustDelete)
|
||||
{
|
||||
return trustDelete(
|
||||
view,
|
||||
@@ -445,15 +447,15 @@ issueIOU(
|
||||
// this is unnecessarily inefficient as copying which could be avoided
|
||||
// is now required. Consider available options.
|
||||
STAmount const limit(Issue{issue.currency, account});
|
||||
STAmount final_balance = amount;
|
||||
STAmount finalBalance = amount;
|
||||
|
||||
final_balance.get<Issue>().account = noAccount();
|
||||
finalBalance.get<Issue>().account = noAccount();
|
||||
|
||||
auto const receiverAccount = view.peek(keylet::account(account));
|
||||
if (!receiverAccount)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
bool const noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
|
||||
bool const noRipple = !receiverAccount->isFlag(lsfDefaultRipple);
|
||||
|
||||
return trustCreate(
|
||||
view,
|
||||
@@ -466,7 +468,7 @@ issueIOU(
|
||||
noRipple,
|
||||
false,
|
||||
false,
|
||||
final_balance,
|
||||
finalBalance,
|
||||
limit,
|
||||
0,
|
||||
0,
|
||||
@@ -497,29 +499,29 @@ redeemIOU(
|
||||
|
||||
if (auto state = view.peek(keylet::line(account, issue.account, issue.currency)))
|
||||
{
|
||||
STAmount final_balance = state->getFieldAmount(sfBalance);
|
||||
STAmount finalBalance = state->getFieldAmount(sfBalance);
|
||||
|
||||
if (bSenderHigh)
|
||||
final_balance.negate(); // Put balance in sender terms.
|
||||
finalBalance.negate(); // Put balance in sender terms.
|
||||
|
||||
STAmount const start_balance = final_balance;
|
||||
STAmount const startBalance = finalBalance;
|
||||
|
||||
final_balance -= amount;
|
||||
finalBalance -= amount;
|
||||
|
||||
auto const must_delete =
|
||||
updateTrustLine(view, state, bSenderHigh, account, start_balance, final_balance, j);
|
||||
auto const mustDelete =
|
||||
updateTrustLine(view, state, bSenderHigh, account, startBalance, finalBalance, j);
|
||||
|
||||
view.creditHookIOU(account, issue.account, amount, start_balance);
|
||||
view.creditHookIOU(account, issue.account, amount, startBalance);
|
||||
|
||||
if (bSenderHigh)
|
||||
final_balance.negate();
|
||||
finalBalance.negate();
|
||||
|
||||
// Adjust the balance on the trust line if necessary. We do this even
|
||||
// if we are going to delete the line to reflect the correct balance
|
||||
// at the time of deletion.
|
||||
state->setFieldAmount(sfBalance, final_balance);
|
||||
state->setFieldAmount(sfBalance, finalBalance);
|
||||
|
||||
if (must_delete)
|
||||
if (mustDelete)
|
||||
{
|
||||
return trustDelete(
|
||||
view,
|
||||
@@ -564,12 +566,11 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
|
||||
// If this is a weak or legacy check, or if the account has a line, fail if
|
||||
// auth is required and not set on the line
|
||||
if (auto const issuerAccount = view.read(keylet::account(issue.account));
|
||||
issuerAccount && (((*issuerAccount)[sfFlags] & lsfRequireAuth) != 0u))
|
||||
issuerAccount && issuerAccount->isFlag(lsfRequireAuth))
|
||||
{
|
||||
if (trustLine)
|
||||
{
|
||||
return (((*trustLine)[sfFlags] &
|
||||
((account > issue.account) ? lsfLowAuth : lsfHighAuth)) != 0u)
|
||||
return trustLine->isFlag((account > issue.account) ? lsfLowAuth : lsfHighAuth)
|
||||
? tesSUCCESS
|
||||
: TER{tecNO_AUTH};
|
||||
}
|
||||
@@ -698,7 +699,7 @@ removeEmptyHolding(
|
||||
auto const line = view.peek(keylet::line(accountID, issue));
|
||||
if (!line)
|
||||
return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND;
|
||||
if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::zero)
|
||||
if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::kZero)
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
// Adjust the owner count(s)
|
||||
@@ -774,7 +775,7 @@ deleteAMMTrustLine(
|
||||
}
|
||||
|
||||
auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
|
||||
if ((sleState->getFlags() & uFlags) == 0u)
|
||||
if (!sleState->isFlag(uFlags))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
adjustOwnerCount(view, !ammLow ? sleLow : sleHigh, -1, j);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
@@ -55,6 +56,14 @@ isGlobalFrozen(ReadView const& view, Asset const& asset)
|
||||
[&](MPTIssue const& issue) { return isGlobalFrozen(view, issue); });
|
||||
}
|
||||
|
||||
TER
|
||||
checkGlobalFrozen(ReadView const& view, Asset const& asset)
|
||||
{
|
||||
if (isGlobalFrozen(view, asset))
|
||||
return asset.holds<MPTIssue>() ? tecLOCKED : tecFROZEN;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset)
|
||||
{
|
||||
@@ -62,8 +71,16 @@ isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const&
|
||||
[&](auto const& issue) { return isIndividualFrozen(view, account, issue); }, asset.value());
|
||||
}
|
||||
|
||||
TER
|
||||
checkIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset)
|
||||
{
|
||||
if (isIndividualFrozen(view, account, asset))
|
||||
return asset.holds<MPTIssue>() ? tecLOCKED : tecFROZEN;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth)
|
||||
isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, std::uint8_t depth)
|
||||
{
|
||||
return std::visit(
|
||||
[&](auto const& issue) { return isFrozen(view, account, issue, depth); }, asset.value());
|
||||
@@ -107,7 +124,7 @@ isAnyFrozen(
|
||||
ReadView const& view,
|
||||
std::initializer_list<AccountID> const& accounts,
|
||||
Asset const& asset,
|
||||
int depth)
|
||||
std::uint8_t depth)
|
||||
{
|
||||
return asset.visit(
|
||||
[&](Issue const& issue) { return isAnyFrozen(view, accounts, issue); },
|
||||
@@ -115,7 +132,11 @@ isAnyFrozen(
|
||||
}
|
||||
|
||||
bool
|
||||
isDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth)
|
||||
isDeepFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
MPTIssue const& mptIssue,
|
||||
std::uint8_t depth)
|
||||
{
|
||||
// Unlike IOUs, frozen / locked MPTs are not allowed to send or receive
|
||||
// funds, so checking "deep frozen" is the same as checking "frozen".
|
||||
@@ -123,7 +144,7 @@ isDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mpt
|
||||
}
|
||||
|
||||
bool
|
||||
isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth)
|
||||
isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, std::uint8_t depth)
|
||||
{
|
||||
return std::visit(
|
||||
[&](auto const& issue) { return isDeepFrozen(view, account, issue, depth); },
|
||||
@@ -165,7 +186,7 @@ getLineIfUsable(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (zeroIfFrozen == fhZERO_IF_FROZEN)
|
||||
if (zeroIfFrozen == FreezeHandling::ZeroIfFrozen)
|
||||
{
|
||||
if (isFrozen(view, account, currency, issuer) ||
|
||||
isDeepFrozen(view, account, currency, issuer))
|
||||
@@ -252,12 +273,12 @@ accountHolds(
|
||||
return {xrpLiquid(view, account, 0, j)};
|
||||
}
|
||||
|
||||
bool const returnSpendable = (includeFullBalance == shFULL_BALANCE);
|
||||
bool const returnSpendable = (includeFullBalance == SpendableHandling::FullBalance);
|
||||
if (returnSpendable && account == issuer)
|
||||
{
|
||||
// If the account is the issuer, then their limit is effectively
|
||||
// infinite
|
||||
return STAmount{Issue{currency, issuer}, STAmount::cMaxValue, STAmount::cMaxOffset};
|
||||
return STAmount{Issue{currency, issuer}, STAmount::kMaxValue, STAmount::kMaxOffset};
|
||||
}
|
||||
|
||||
// IOU: Return balance on trust line modulo freeze
|
||||
@@ -290,7 +311,7 @@ accountHolds(
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance)
|
||||
{
|
||||
bool const returnSpendable = (includeFullBalance == shFULL_BALANCE);
|
||||
bool const returnSpendable = (includeFullBalance == SpendableHandling::FullBalance);
|
||||
STAmount amount{mptIssue};
|
||||
auto const& issuer = mptIssue.getIssuer();
|
||||
bool const mptokensV2 = view.rules().enabled(featureMPTokensV2);
|
||||
@@ -317,7 +338,7 @@ accountHolds(
|
||||
{
|
||||
amount.clear(mptIssue);
|
||||
}
|
||||
else if (zeroIfFrozen == fhZERO_IF_FROZEN && isFrozen(view, account, mptIssue))
|
||||
else if (zeroIfFrozen == FreezeHandling::ZeroIfFrozen && isFrozen(view, account, mptIssue))
|
||||
{
|
||||
amount.clear(mptIssue);
|
||||
}
|
||||
@@ -327,14 +348,14 @@ accountHolds(
|
||||
|
||||
// Only if auth check is needed, as it needs to do an additional read
|
||||
// operation. Note featureSingleAssetVault will affect error codes.
|
||||
if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED &&
|
||||
if (zeroIfUnauthorized == AuthHandling::ZeroIfUnauthorized &&
|
||||
view.rules().enabled(featureSingleAssetVault))
|
||||
{
|
||||
if (auto const err = requireAuth(view, mptIssue, account, AuthType::StrongAuth);
|
||||
!isTesSuccess(err))
|
||||
amount.clear(mptIssue);
|
||||
}
|
||||
else if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED)
|
||||
else if (zeroIfUnauthorized == AuthHandling::ZeroIfUnauthorized)
|
||||
{
|
||||
auto const sleIssuance = view.read(keylet::mptIssuance(mptIssue.getMptID()));
|
||||
|
||||
@@ -401,7 +422,13 @@ accountFunds(
|
||||
[&](Issue const&) { return accountFunds(view, id, saDefault, freezeHandling, j); },
|
||||
[&](MPTIssue const&) {
|
||||
return accountHolds(
|
||||
view, id, saDefault.asset(), freezeHandling, authHandling, j, shFULL_BALANCE);
|
||||
view,
|
||||
id,
|
||||
saDefault.asset(),
|
||||
freezeHandling,
|
||||
authHandling,
|
||||
j,
|
||||
SpendableHandling::FullBalance);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -487,20 +514,26 @@ TER
|
||||
requireAuth(ReadView const& view, Asset const& asset, AccountID const& account, AuthType authType)
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue_) {
|
||||
return requireAuth(view, issue_, account, authType);
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) {
|
||||
return requireAuth(view, issue, account, authType);
|
||||
},
|
||||
asset.value());
|
||||
}
|
||||
|
||||
TER
|
||||
canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, AccountID const& to)
|
||||
canTransfer(
|
||||
ReadView const& view,
|
||||
Asset const& asset,
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
WaiveMPTCanTransfer waive,
|
||||
std::uint8_t depth)
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
|
||||
return canTransfer(view, issue, from, to);
|
||||
return asset.visit(
|
||||
[&](MPTIssue const& issue) -> TER {
|
||||
return canTransfer(view, issue, from, to, waive, depth);
|
||||
},
|
||||
asset.value());
|
||||
[&](Issue const& issue) -> TER { return canTransfer(view, issue, from, to); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -563,39 +596,41 @@ directSendNoFeeIOU(
|
||||
<< " amount=" << saAmount.getFullText()
|
||||
<< " after=" << saBalance.getFullText();
|
||||
|
||||
std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags));
|
||||
bool bDelete = false;
|
||||
|
||||
auto const senderReserveFlag = bSenderHigh ? lsfHighReserve : lsfLowReserve;
|
||||
auto const senderNoRippleFlag = bSenderHigh ? lsfHighNoRipple : lsfLowNoRipple;
|
||||
auto const senderFreezeFlag = bSenderHigh ? lsfHighFreeze : lsfLowFreeze;
|
||||
auto const receiverReserveFlag = bSenderHigh ? lsfLowReserve : lsfHighReserve;
|
||||
|
||||
// FIXME This NEEDS to be cleaned up and simplified. It's impossible
|
||||
// for anyone to understand.
|
||||
if (saBefore > beast::zero
|
||||
if (saBefore > beast::kZero
|
||||
// Sender balance was positive.
|
||||
&& saBalance <= beast::zero
|
||||
&& saBalance <= beast::kZero
|
||||
// Sender is zero or negative.
|
||||
&& ((uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) != 0u)
|
||||
&& sleRippleState->isFlag(senderReserveFlag)
|
||||
// Sender reserve is set.
|
||||
&& static_cast<bool>(uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
|
||||
static_cast<bool>(
|
||||
view.read(keylet::account(uSenderID))->getFlags() & lsfDefaultRipple) &&
|
||||
((uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) == 0u) &&
|
||||
!sleRippleState->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
|
||||
&& sleRippleState->isFlag(senderNoRippleFlag) !=
|
||||
view.read(keylet::account(uSenderID))->isFlag(lsfDefaultRipple) &&
|
||||
!sleRippleState->isFlag(senderFreezeFlag) &&
|
||||
!sleRippleState->getFieldAmount(bSenderHigh ? sfHighLimit : sfLowLimit)
|
||||
// Sender trust limit is 0.
|
||||
&& (sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) == 0u)
|
||||
&& (sleRippleState->getFieldU32(bSenderHigh ? sfHighQualityIn : sfLowQualityIn) == 0u)
|
||||
// Sender quality in is 0.
|
||||
&&
|
||||
(sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut) == 0u))
|
||||
(sleRippleState->getFieldU32(bSenderHigh ? sfHighQualityOut : sfLowQualityOut) == 0u))
|
||||
// Sender quality out is 0.
|
||||
{
|
||||
// Clear the reserve of the sender, possibly delete the line!
|
||||
adjustOwnerCount(view, view.peek(keylet::account(uSenderID)), -1, j);
|
||||
|
||||
// Clear reserve flag.
|
||||
sleRippleState->setFieldU32(
|
||||
sfFlags, uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
|
||||
sleRippleState->clearFlag(senderReserveFlag);
|
||||
|
||||
// Balance is zero, receiver reserve is clear.
|
||||
bDelete = !saBalance // Balance is zero.
|
||||
&& ((uFlags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)) == 0u);
|
||||
&& !sleRippleState->isFlag(receiverReserveFlag);
|
||||
// Receiver reserve is clear.
|
||||
}
|
||||
|
||||
@@ -612,7 +647,7 @@ directSendNoFeeIOU(
|
||||
view,
|
||||
sleRippleState,
|
||||
bSenderHigh ? uReceiverID : uSenderID,
|
||||
!bSenderHigh ? uReceiverID : uSenderID,
|
||||
bSenderHigh ? uSenderID : uReceiverID,
|
||||
j);
|
||||
}
|
||||
|
||||
@@ -634,7 +669,7 @@ directSendNoFeeIOU(
|
||||
if (!sleAccount)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0;
|
||||
bool const noRipple = !sleAccount->isFlag(lsfDefaultRipple);
|
||||
|
||||
return trustCreate(
|
||||
view,
|
||||
@@ -789,7 +824,7 @@ accountSendIOU(
|
||||
{
|
||||
if (view.rules().enabled(fixAMMv1_1))
|
||||
{
|
||||
if (saAmount < beast::zero || saAmount.holds<MPTIssue>())
|
||||
if (saAmount < beast::kZero || saAmount.holds<MPTIssue>())
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
@@ -798,7 +833,7 @@ accountSendIOU(
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
XRPL_ASSERT(
|
||||
saAmount >= beast::zero && !saAmount.holds<MPTIssue>(),
|
||||
saAmount >= beast::kZero && !saAmount.holds<MPTIssue>(),
|
||||
"xrpl::accountSendIOU : minimum amount and not MPT");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
@@ -827,24 +862,23 @@ accountSendIOU(
|
||||
TER terResult(tesSUCCESS);
|
||||
|
||||
SLE::pointer const sender =
|
||||
uSenderID != beast::zero ? view.peek(keylet::account(uSenderID)) : SLE::pointer();
|
||||
uSenderID != beast::kZero ? view.peek(keylet::account(uSenderID)) : SLE::pointer();
|
||||
SLE::pointer const receiver =
|
||||
uReceiverID != beast::zero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer();
|
||||
uReceiverID != beast::kZero ? view.peek(keylet::account(uReceiverID)) : SLE::pointer();
|
||||
|
||||
if (auto stream = j.trace())
|
||||
{
|
||||
std::string sender_bal("-");
|
||||
std::string receiver_bal("-");
|
||||
std::string senderBal("-");
|
||||
std::string receiverBal("-");
|
||||
|
||||
if (sender)
|
||||
sender_bal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
senderBal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
if (receiver)
|
||||
receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
receiverBal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
stream << "accountSendIOU> " << to_string(uSenderID) << " (" << sender_bal << ") -> "
|
||||
<< to_string(uReceiverID) << " (" << receiver_bal
|
||||
<< ") : " << saAmount.getFullText();
|
||||
stream << "accountSendIOU> " << to_string(uSenderID) << " (" << senderBal << ") -> "
|
||||
<< to_string(uReceiverID) << " (" << receiverBal << ") : " << saAmount.getFullText();
|
||||
}
|
||||
|
||||
if (sender)
|
||||
@@ -880,18 +914,17 @@ accountSendIOU(
|
||||
|
||||
if (auto stream = j.trace())
|
||||
{
|
||||
std::string sender_bal("-");
|
||||
std::string receiver_bal("-");
|
||||
std::string senderBal("-");
|
||||
std::string receiverBal("-");
|
||||
|
||||
if (sender)
|
||||
sender_bal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
senderBal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
if (receiver)
|
||||
receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
receiverBal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
stream << "accountSendIOU< " << to_string(uSenderID) << " (" << sender_bal << ") -> "
|
||||
<< to_string(uReceiverID) << " (" << receiver_bal
|
||||
<< ") : " << saAmount.getFullText();
|
||||
stream << "accountSendIOU< " << to_string(uSenderID) << " (" << senderBal << ") -> "
|
||||
<< to_string(uReceiverID) << " (" << receiverBal << ") : " << saAmount.getFullText();
|
||||
}
|
||||
|
||||
return terResult;
|
||||
@@ -925,16 +958,16 @@ accountSendMultiIOU(
|
||||
*/
|
||||
|
||||
SLE::pointer const sender =
|
||||
senderID != beast::zero ? view.peek(keylet::account(senderID)) : SLE::pointer();
|
||||
senderID != beast::kZero ? view.peek(keylet::account(senderID)) : SLE::pointer();
|
||||
|
||||
if (auto stream = j.trace())
|
||||
{
|
||||
std::string sender_bal("-");
|
||||
std::string senderBal("-");
|
||||
|
||||
if (sender)
|
||||
sender_bal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
senderBal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
stream << "accountSendMultiIOU> " << to_string(senderID) << " (" << sender_bal << ") -> "
|
||||
stream << "accountSendMultiIOU> " << to_string(senderID) << " (" << senderBal << ") -> "
|
||||
<< receivers.size() << " receivers.";
|
||||
}
|
||||
|
||||
@@ -945,7 +978,7 @@ accountSendMultiIOU(
|
||||
auto const& receiverID = r.first;
|
||||
STAmount const amount{issue, r.second};
|
||||
|
||||
if (amount < beast::zero)
|
||||
if (amount < beast::kZero)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
@@ -957,17 +990,17 @@ accountSendMultiIOU(
|
||||
continue;
|
||||
|
||||
SLE::pointer const receiver =
|
||||
receiverID != beast::zero ? view.peek(keylet::account(receiverID)) : SLE::pointer();
|
||||
receiverID != beast::kZero ? view.peek(keylet::account(receiverID)) : SLE::pointer();
|
||||
|
||||
if (auto stream = j.trace())
|
||||
{
|
||||
std::string receiver_bal("-");
|
||||
std::string receiverBal("-");
|
||||
|
||||
if (receiver)
|
||||
receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
receiverBal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
stream << "accountSendMultiIOU> " << to_string(senderID) << " -> "
|
||||
<< to_string(receiverID) << " (" << receiver_bal
|
||||
<< to_string(receiverID) << " (" << receiverBal
|
||||
<< ") : " << amount.getFullText();
|
||||
}
|
||||
|
||||
@@ -986,13 +1019,13 @@ accountSendMultiIOU(
|
||||
|
||||
if (auto stream = j.trace())
|
||||
{
|
||||
std::string receiver_bal("-");
|
||||
std::string receiverBal("-");
|
||||
|
||||
if (receiver)
|
||||
receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
receiverBal = receiver->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
stream << "accountSendMultiIOU< " << to_string(senderID) << " -> "
|
||||
<< to_string(receiverID) << " (" << receiver_bal
|
||||
<< to_string(receiverID) << " (" << receiverBal
|
||||
<< ") : " << amount.getFullText();
|
||||
}
|
||||
}
|
||||
@@ -1013,12 +1046,12 @@ accountSendMultiIOU(
|
||||
|
||||
if (auto stream = j.trace())
|
||||
{
|
||||
std::string sender_bal("-");
|
||||
std::string senderBal("-");
|
||||
|
||||
if (sender)
|
||||
sender_bal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
senderBal = sender->getFieldAmount(sfBalance).getFullText();
|
||||
|
||||
stream << "accountSendMultiIOU< " << to_string(senderID) << " (" << sender_bal << ") -> "
|
||||
stream << "accountSendMultiIOU< " << to_string(senderID) << " (" << senderBal << ") -> "
|
||||
<< receivers.size() << " receivers.";
|
||||
}
|
||||
return tesSUCCESS;
|
||||
@@ -1089,6 +1122,13 @@ directSendNoFeeMPT(
|
||||
auto const mptokenID = keylet::mptoken(mptID.key, uReceiverID);
|
||||
if (auto sle = view.peek(mptokenID))
|
||||
{
|
||||
if (view.rules().enabled(featureMPTokensV2))
|
||||
{
|
||||
if ((*sle)[sfMPTAmount] > (std::numeric_limits<std::uint64_t>::max() - amt))
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
view.creditHookMPT(uSenderID, uReceiverID, saAmount, (*sle)[sfMPTAmount], available);
|
||||
(*sle)[sfMPTAmount] += amt;
|
||||
view.update(sle);
|
||||
@@ -1185,9 +1225,9 @@ directSendNoLimitMultiMPT(
|
||||
// Use uint64_t, not STAmount, to keep MaximumAmount comparisons in exact
|
||||
// integer arithmetic. STAmount implicitly converts to Number, whose
|
||||
// small-scale mantissa (~16 digits) can lose precision for values near
|
||||
// maxMPTokenAmount (19 digits).
|
||||
// kMaxMpTokenAmount (19 digits).
|
||||
std::uint64_t totalSendAmount{0};
|
||||
std::uint64_t const maximumAmount = sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount);
|
||||
std::uint64_t const maximumAmount = sle->at(~sfMaximumAmount).value_or(kMaxMpTokenAmount);
|
||||
std::uint64_t const outstandingAmount = sle->getFieldU64(sfOutstandingAmount);
|
||||
|
||||
// actual accumulates the total cost to the sender (includes transfer
|
||||
@@ -1201,7 +1241,7 @@ directSendNoLimitMultiMPT(
|
||||
{
|
||||
STAmount const amount{mptIssue, amt};
|
||||
|
||||
if (amount < beast::zero)
|
||||
if (amount < beast::kZero)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (!amount || senderID == receiverID)
|
||||
@@ -1212,15 +1252,15 @@ directSendNoLimitMultiMPT(
|
||||
if (senderID == issuer)
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
takeFromSender == beast::zero,
|
||||
takeFromSender == beast::kZero,
|
||||
"xrpl::directSendNoLimitMultiMPT",
|
||||
"sender == issuer, takeFromSender == zero");
|
||||
|
||||
std::uint64_t const sendAmount = amount.mpt().value();
|
||||
|
||||
if (view.rules().enabled(fixSecurity3_1_3))
|
||||
if (view.rules().enabled(fixCleanup3_1_3))
|
||||
{
|
||||
// Post-fixSecurity3_1_3: aggregate MaximumAmount
|
||||
// Post-fixCleanup3_1_3: aggregate MaximumAmount
|
||||
// check. WARNING: the order of conditions is
|
||||
// critical — each guards the subtraction in the
|
||||
// next against unsigned underflow. Do not reorder.
|
||||
@@ -1238,7 +1278,7 @@ directSendNoLimitMultiMPT(
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pre-fixSecurity3_1_3: per-iteration MaximumAmount
|
||||
// Pre-fixCleanup3_1_3: per-iteration MaximumAmount
|
||||
// check. Reads sfOutstandingAmount from a stale
|
||||
// view.read() snapshot — incorrect for multi-destination
|
||||
// sends but retained for ledger replay compatibility.
|
||||
@@ -1294,7 +1334,7 @@ accountSendMPT(
|
||||
AllowMPTOverflow allowOverflow)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
saAmount >= beast::zero && saAmount.holds<MPTIssue>(),
|
||||
saAmount >= beast::kZero && saAmount.holds<MPTIssue>(),
|
||||
"xrpl::accountSendMPT : minimum amount and MPT");
|
||||
|
||||
/* If we aren't sending anything or if the sender is the same as the
|
||||
@@ -1396,8 +1436,8 @@ transferXRP(
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
XRPL_ASSERT(from != beast::zero, "xrpl::transferXRP : nonzero from account");
|
||||
XRPL_ASSERT(to != beast::zero, "xrpl::transferXRP : nonzero to account");
|
||||
XRPL_ASSERT(from != beast::kZero, "xrpl::transferXRP : nonzero from account");
|
||||
XRPL_ASSERT(to != beast::kZero, "xrpl::transferXRP : nonzero to account");
|
||||
XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver");
|
||||
XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP");
|
||||
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
@@ -70,7 +75,8 @@ assetsToSharesWithdraw(
|
||||
std::shared_ptr<SLE const> const& vault,
|
||||
std::shared_ptr<SLE const> const& issuance,
|
||||
STAmount const& assets,
|
||||
TruncateShares truncate)
|
||||
TruncateShares truncate,
|
||||
WaiveUnrealizedLoss waive)
|
||||
{
|
||||
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesWithdraw : non-negative assets");
|
||||
XRPL_ASSERT(
|
||||
@@ -80,13 +86,14 @@ assetsToSharesWithdraw(
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
Number assetTotal = vault->at(sfAssetsTotal);
|
||||
assetTotal -= vault->at(sfLossUnrealized);
|
||||
if (waive == WaiveUnrealizedLoss::No)
|
||||
assetTotal -= vault->at(sfLossUnrealized);
|
||||
STAmount shares{vault->at(sfShareMPTID)};
|
||||
if (assetTotal == 0)
|
||||
return shares;
|
||||
Number const shareTotal = issuance->at(sfOutstandingAmount);
|
||||
Number result = (shareTotal * assets) / assetTotal;
|
||||
if (truncate == TruncateShares::yes)
|
||||
if (truncate == TruncateShares::Yes)
|
||||
result = result.truncate();
|
||||
shares = result;
|
||||
return shares;
|
||||
@@ -96,7 +103,8 @@ assetsToSharesWithdraw(
|
||||
sharesToAssetsWithdraw(
|
||||
std::shared_ptr<SLE const> const& vault,
|
||||
std::shared_ptr<SLE const> const& issuance,
|
||||
STAmount const& shares)
|
||||
STAmount const& shares,
|
||||
WaiveUnrealizedLoss waive)
|
||||
{
|
||||
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsWithdraw : non-negative shares");
|
||||
XRPL_ASSERT(
|
||||
@@ -106,7 +114,8 @@ sharesToAssetsWithdraw(
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
Number assetTotal = vault->at(sfAssetsTotal);
|
||||
assetTotal -= vault->at(sfLossUnrealized);
|
||||
if (waive == WaiveUnrealizedLoss::No)
|
||||
assetTotal -= vault->at(sfLossUnrealized);
|
||||
STAmount assets{vault->at(sfAsset)};
|
||||
if (assetTotal == 0)
|
||||
return assets;
|
||||
@@ -115,4 +124,24 @@ sharesToAssetsWithdraw(
|
||||
return assets;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE,
|
||||
"xrpl::isSoleShareholder : valid issuance SLE");
|
||||
|
||||
std::uint64_t const outstanding = issuance->at(sfOutstandingAmount);
|
||||
if (outstanding == 0)
|
||||
return false;
|
||||
|
||||
auto const shareMPTID =
|
||||
makeMptID(issuance->getFieldU32(sfSequence), issuance->getAccountID(sfIssuer));
|
||||
auto const sleToken = view.read(keylet::mptoken(shareMPTID, account));
|
||||
if (!sleToken)
|
||||
return false; // LCOV_EXCL_LINE
|
||||
|
||||
return sleToken->getFieldU64(sfMPTAmount) == outstanding;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
static std::optional<HTTPClientSSLContext> httpClientSSLContext;
|
||||
static std::optional<HTTPClientSSLContext> gHttpClientSslContext;
|
||||
|
||||
void
|
||||
HTTPClient::initializeSSLContext(
|
||||
@@ -42,13 +42,13 @@ HTTPClient::initializeSSLContext(
|
||||
bool sslVerify,
|
||||
beast::Journal j)
|
||||
{
|
||||
httpClientSSLContext.emplace(sslVerifyDir, sslVerifyFile, sslVerify, j);
|
||||
gHttpClientSslContext.emplace(sslVerifyDir, sslVerifyFile, sslVerify, j);
|
||||
}
|
||||
|
||||
void
|
||||
HTTPClient::cleanupSSLContext()
|
||||
{
|
||||
httpClientSSLContext.reset();
|
||||
gHttpClientSslContext.reset();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -61,18 +61,18 @@ class HTTPClientImp : public std::enable_shared_from_this<HTTPClientImp>, public
|
||||
{
|
||||
public:
|
||||
HTTPClientImp(
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::io_context& ioContext,
|
||||
unsigned short const port,
|
||||
std::size_t maxResponseSize,
|
||||
beast::Journal& j)
|
||||
: mSocket(
|
||||
io_context,
|
||||
httpClientSSLContext->context()) // NOLINT(bugprone-unchecked-optional-access)
|
||||
, mResolver(io_context)
|
||||
, mHeader(maxClientHeaderBytes)
|
||||
, mPort(port)
|
||||
: socket_(
|
||||
ioContext,
|
||||
gHttpClientSslContext->context()) // NOLINT(bugprone-unchecked-optional-access)
|
||||
, resolver_(ioContext)
|
||||
, header_(kMaxClientHeaderBytes)
|
||||
, port_(port)
|
||||
, maxResponseSize_(maxResponseSize)
|
||||
, mDeadline(io_context)
|
||||
, deadline_(ioContext)
|
||||
, j_(j)
|
||||
{
|
||||
}
|
||||
@@ -107,11 +107,11 @@ public:
|
||||
int iStatus,
|
||||
std::string const& strData)> complete)
|
||||
{
|
||||
mSSL = bSSL;
|
||||
mDeqSites = deqSites;
|
||||
mBuild = build;
|
||||
mComplete = complete;
|
||||
mTimeout = timeout;
|
||||
ssl_ = bSSL;
|
||||
deqSites_ = deqSites;
|
||||
build_ = build;
|
||||
complete_ = complete;
|
||||
timeout_ = timeout;
|
||||
|
||||
httpsNext();
|
||||
}
|
||||
@@ -128,8 +128,8 @@ public:
|
||||
int iStatus,
|
||||
std::string const& strData)> complete)
|
||||
{
|
||||
mComplete = complete;
|
||||
mTimeout = timeout;
|
||||
complete_ = complete;
|
||||
timeout_ = timeout;
|
||||
|
||||
request(
|
||||
bSSL,
|
||||
@@ -149,36 +149,36 @@ public:
|
||||
void
|
||||
httpsNext()
|
||||
{
|
||||
JLOG(j_.trace()) << "Fetch: " << mDeqSites[0];
|
||||
JLOG(j_.trace()) << "Fetch: " << deqSites_[0];
|
||||
|
||||
auto query = std::make_shared<Query>(
|
||||
mDeqSites[0],
|
||||
std::to_string(mPort),
|
||||
deqSites_[0],
|
||||
std::to_string(port_),
|
||||
boost::asio::ip::resolver_query_base::numeric_service);
|
||||
mQuery = query;
|
||||
query_ = query;
|
||||
|
||||
try
|
||||
{
|
||||
mDeadline.expires_after(mTimeout);
|
||||
deadline_.expires_after(timeout_);
|
||||
}
|
||||
catch (boost::system::system_error const& e)
|
||||
{
|
||||
mShutdown = e.code();
|
||||
shutdown_ = e.code();
|
||||
|
||||
JLOG(j_.trace()) << "expires_after: " << mShutdown.message();
|
||||
mDeadline.async_wait(
|
||||
JLOG(j_.trace()) << "expires_after: " << shutdown_.message();
|
||||
deadline_.async_wait(
|
||||
std::bind(
|
||||
&HTTPClientImp::handleDeadline, shared_from_this(), std::placeholders::_1));
|
||||
}
|
||||
|
||||
if (!mShutdown)
|
||||
if (!shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Resolving: " << mDeqSites[0];
|
||||
JLOG(j_.trace()) << "Resolving: " << deqSites_[0];
|
||||
|
||||
mResolver.async_resolve(
|
||||
mQuery->host,
|
||||
mQuery->port,
|
||||
mQuery->flags,
|
||||
resolver_.async_resolve(
|
||||
query_->host,
|
||||
query_->port,
|
||||
query_->flags,
|
||||
std::bind(
|
||||
&HTTPClientImp::handleResolve,
|
||||
shared_from_this(),
|
||||
@@ -186,8 +186,8 @@ public:
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
if (mShutdown)
|
||||
invokeComplete(mShutdown);
|
||||
if (shutdown_)
|
||||
invokeComplete(shutdown_);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
}
|
||||
else if (ecResult)
|
||||
{
|
||||
JLOG(j_.trace()) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message();
|
||||
JLOG(j_.trace()) << "Deadline error: " << deqSites_[0] << ": " << ecResult.message();
|
||||
|
||||
// Can't do anything sound.
|
||||
std::abort();
|
||||
@@ -213,14 +213,14 @@ public:
|
||||
|
||||
// Mark us as shutting down.
|
||||
// XXX Use our own error code.
|
||||
mShutdown = boost::system::error_code{
|
||||
shutdown_ = boost::system::error_code{
|
||||
boost::system::errc::bad_address, boost::system::system_category()};
|
||||
|
||||
// Cancel any resolving.
|
||||
mResolver.cancel();
|
||||
resolver_.cancel();
|
||||
|
||||
// Stop the transaction.
|
||||
mSocket.async_shutdown(
|
||||
socket_.asyncShutdown(
|
||||
std::bind(
|
||||
&HTTPClientImp::handleShutdown, shared_from_this(), std::placeholders::_1));
|
||||
}
|
||||
@@ -231,7 +231,7 @@ public:
|
||||
{
|
||||
if (ecResult)
|
||||
{
|
||||
JLOG(j_.trace()) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message();
|
||||
JLOG(j_.trace()) << "Shutdown error: " << deqSites_[0] << ": " << ecResult.message();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,27 +240,27 @@ public:
|
||||
boost::system::error_code const& ecResult,
|
||||
boost::asio::ip::tcp::resolver::results_type result)
|
||||
{
|
||||
if (!mShutdown)
|
||||
if (!shutdown_)
|
||||
{
|
||||
mShutdown = ecResult
|
||||
shutdown_ = ecResult
|
||||
? ecResult
|
||||
// httpClientSSLContext always initialized before use
|
||||
// gHttpClientSslContext always initialized before use
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
: httpClientSSLContext->preConnectVerify(mSocket.SSLSocket(), mDeqSites[0]);
|
||||
: gHttpClientSslContext->preConnectVerify(socket_.sslSocket(), deqSites_[0]);
|
||||
}
|
||||
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message();
|
||||
JLOG(j_.trace()) << "Resolve error: " << deqSites_[0] << ": " << shutdown_.message();
|
||||
|
||||
invokeComplete(mShutdown);
|
||||
invokeComplete(shutdown_);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j_.trace()) << "Resolve complete.";
|
||||
|
||||
boost::asio::async_connect(
|
||||
mSocket.lowest_layer(),
|
||||
socket_.lowestLayer(),
|
||||
result,
|
||||
std::bind(
|
||||
&HTTPClientImp::handleConnect, shared_from_this(), std::placeholders::_1));
|
||||
@@ -270,36 +270,36 @@ public:
|
||||
void
|
||||
handleConnect(boost::system::error_code const& ecResult)
|
||||
{
|
||||
if (!mShutdown)
|
||||
mShutdown = ecResult;
|
||||
if (!shutdown_)
|
||||
shutdown_ = ecResult;
|
||||
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Connect error: " << mShutdown.message();
|
||||
JLOG(j_.trace()) << "Connect error: " << shutdown_.message();
|
||||
}
|
||||
|
||||
if (!mShutdown)
|
||||
if (!shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Connected.";
|
||||
|
||||
// httpClientSSLContext always initialized before use
|
||||
// gHttpClientSslContext always initialized before use
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
mShutdown = httpClientSSLContext->postConnectVerify(mSocket.SSLSocket(), mDeqSites[0]);
|
||||
shutdown_ = gHttpClientSslContext->postConnectVerify(socket_.sslSocket(), deqSites_[0]);
|
||||
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "postConnectVerify: " << mDeqSites[0] << ": "
|
||||
<< mShutdown.message();
|
||||
JLOG(j_.trace()) << "postConnectVerify: " << deqSites_[0] << ": "
|
||||
<< shutdown_.message();
|
||||
}
|
||||
}
|
||||
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
invokeComplete(mShutdown);
|
||||
invokeComplete(shutdown_);
|
||||
}
|
||||
else if (mSSL)
|
||||
else if (ssl_)
|
||||
{
|
||||
mSocket.async_handshake(
|
||||
socket_.asyncHandshake(
|
||||
AutoSocket::ssl_socket::client,
|
||||
std::bind(
|
||||
&HTTPClientImp::handleRequest, shared_from_this(), std::placeholders::_1));
|
||||
@@ -313,23 +313,23 @@ public:
|
||||
void
|
||||
handleRequest(boost::system::error_code const& ecResult)
|
||||
{
|
||||
if (!mShutdown)
|
||||
mShutdown = ecResult;
|
||||
if (!shutdown_)
|
||||
shutdown_ = ecResult;
|
||||
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Handshake error:" << mShutdown.message();
|
||||
JLOG(j_.trace()) << "Handshake error:" << shutdown_.message();
|
||||
|
||||
invokeComplete(mShutdown);
|
||||
invokeComplete(shutdown_);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j_.trace()) << "Session started.";
|
||||
|
||||
mBuild(mRequest, mDeqSites[0]);
|
||||
build_(request_, deqSites_[0]);
|
||||
|
||||
mSocket.async_write(
|
||||
mRequest,
|
||||
socket_.asyncWrite(
|
||||
request_,
|
||||
std::bind(
|
||||
&HTTPClientImp::handleWrite,
|
||||
shared_from_this(),
|
||||
@@ -339,23 +339,23 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
handleWrite(boost::system::error_code const& ecResult, std::size_t bytes_transferred)
|
||||
handleWrite(boost::system::error_code const& ecResult, std::size_t bytesTransferred)
|
||||
{
|
||||
if (!mShutdown)
|
||||
mShutdown = ecResult;
|
||||
if (!shutdown_)
|
||||
shutdown_ = ecResult;
|
||||
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Write error: " << mShutdown.message();
|
||||
JLOG(j_.trace()) << "Write error: " << shutdown_.message();
|
||||
|
||||
invokeComplete(mShutdown);
|
||||
invokeComplete(shutdown_);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j_.trace()) << "Wrote.";
|
||||
|
||||
mSocket.async_read_until(
|
||||
mHeader,
|
||||
socket_.asyncReadUntil(
|
||||
header_,
|
||||
"\r\n\r\n",
|
||||
std::bind(
|
||||
&HTTPClientImp::handleHeader,
|
||||
@@ -366,20 +366,20 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
handleHeader(boost::system::error_code const& ecResult, std::size_t bytes_transferred)
|
||||
handleHeader(boost::system::error_code const& ecResult, std::size_t bytesTransferred)
|
||||
{
|
||||
std::string strHeader{
|
||||
{std::istreambuf_iterator<char>(&mHeader)}, std::istreambuf_iterator<char>()};
|
||||
{std::istreambuf_iterator<char>(&header_)}, std::istreambuf_iterator<char>()};
|
||||
JLOG(j_.trace()) << "Header: \"" << strHeader << "\"";
|
||||
|
||||
static boost::regex const reStatus{"\\`HTTP/1\\S+ (\\d{3}) .*\\'"}; // HTTP/1.1 200 OK
|
||||
static boost::regex const reSize{
|
||||
static boost::regex const kReStatus{"\\`HTTP/1\\S+ (\\d{3}) .*\\'"}; // HTTP/1.1 200 OK
|
||||
static boost::regex const kReSize{
|
||||
"\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'", boost::regex::icase};
|
||||
static boost::regex const reBody{"\\`.*\\r\\n\\r\\n(.*)\\'"};
|
||||
static boost::regex const kReBody{"\\`.*\\r\\n\\r\\n(.*)\\'"};
|
||||
|
||||
boost::smatch smMatch;
|
||||
// Match status code.
|
||||
if (!boost::regex_match(strHeader, smMatch, reStatus))
|
||||
if (!boost::regex_match(strHeader, smMatch, kReStatus))
|
||||
{
|
||||
// XXX Use our own error code.
|
||||
JLOG(j_.trace()) << "No status code";
|
||||
@@ -389,13 +389,13 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
mStatus = beast::lexicalCastThrow<int>(std::string(smMatch[1]));
|
||||
status_ = beast::lexicalCastThrow<int>(std::string(smMatch[1]));
|
||||
|
||||
if (boost::regex_match(strHeader, smMatch, reBody)) // we got some body
|
||||
mBody = smMatch[1];
|
||||
if (boost::regex_match(strHeader, smMatch, kReBody)) // we got some body
|
||||
body_ = smMatch[1];
|
||||
|
||||
std::size_t const responseSize = [&] {
|
||||
if (boost::regex_match(strHeader, smMatch, reSize))
|
||||
if (boost::regex_match(strHeader, smMatch, kReSize))
|
||||
return beast::lexicalCast<std::size_t>(std::string(smMatch[1]), maxResponseSize_);
|
||||
return maxResponseSize_;
|
||||
}();
|
||||
@@ -412,17 +412,17 @@ public:
|
||||
if (responseSize == 0)
|
||||
{
|
||||
// no body wanted or available
|
||||
invokeComplete(ecResult, mStatus);
|
||||
invokeComplete(ecResult, status_);
|
||||
}
|
||||
else if (mBody.size() >= responseSize)
|
||||
else if (body_.size() >= responseSize)
|
||||
{
|
||||
// we got the whole thing
|
||||
invokeComplete(ecResult, mStatus, mBody);
|
||||
invokeComplete(ecResult, status_, body_);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSocket.async_read(
|
||||
mResponse.prepare(responseSize - mBody.size()),
|
||||
socket_.asyncRead(
|
||||
response_.prepare(responseSize - body_.size()),
|
||||
boost::asio::transfer_all(),
|
||||
std::bind(
|
||||
&HTTPClientImp::handleData,
|
||||
@@ -433,29 +433,29 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
handleData(boost::system::error_code const& ecResult, std::size_t bytes_transferred)
|
||||
handleData(boost::system::error_code const& ecResult, std::size_t bytesTransferred)
|
||||
{
|
||||
if (!mShutdown)
|
||||
mShutdown = ecResult;
|
||||
if (!shutdown_)
|
||||
shutdown_ = ecResult;
|
||||
|
||||
if (mShutdown && mShutdown != boost::asio::error::eof)
|
||||
if (shutdown_ && shutdown_ != boost::asio::error::eof)
|
||||
{
|
||||
JLOG(j_.trace()) << "Read error: " << mShutdown.message();
|
||||
JLOG(j_.trace()) << "Read error: " << shutdown_.message();
|
||||
|
||||
invokeComplete(mShutdown);
|
||||
invokeComplete(shutdown_);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mShutdown)
|
||||
if (shutdown_)
|
||||
{
|
||||
JLOG(j_.trace()) << "Complete.";
|
||||
}
|
||||
else
|
||||
{
|
||||
mResponse.commit(bytes_transferred);
|
||||
response_.commit(bytesTransferred);
|
||||
std::string const strBody{
|
||||
{std::istreambuf_iterator<char>(&mResponse)}, std::istreambuf_iterator<char>()};
|
||||
invokeComplete(ecResult, mStatus, mBody + strBody);
|
||||
{std::istreambuf_iterator<char>(&response_)}, std::istreambuf_iterator<char>()};
|
||||
invokeComplete(ecResult, status_, body_ + strBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -470,7 +470,7 @@ public:
|
||||
boost::system::error_code ecCancel;
|
||||
try
|
||||
{
|
||||
mDeadline.cancel();
|
||||
deadline_.cancel();
|
||||
}
|
||||
catch (boost::system::system_error const& e)
|
||||
{
|
||||
@@ -478,24 +478,24 @@ public:
|
||||
ecCancel = e.code();
|
||||
}
|
||||
|
||||
JLOG(j_.debug()) << "invokeComplete: Deadline popping: " << mDeqSites.size();
|
||||
JLOG(j_.debug()) << "invokeComplete: Deadline popping: " << deqSites_.size();
|
||||
|
||||
if (!mDeqSites.empty())
|
||||
if (!deqSites_.empty())
|
||||
{
|
||||
mDeqSites.pop_front();
|
||||
deqSites_.pop_front();
|
||||
}
|
||||
|
||||
bool bAgain = true;
|
||||
|
||||
if (mDeqSites.empty() || !ecResult)
|
||||
if (deqSites_.empty() || !ecResult)
|
||||
{
|
||||
// ecResult: !0 = had an error, last entry
|
||||
// iStatus: result, if no error
|
||||
// strData: data, if no error
|
||||
bAgain = mComplete && mComplete(ecResult ? ecResult : ecCancel, iStatus, strData);
|
||||
bAgain = complete_ && complete_(ecResult ? ecResult : ecCancel, iStatus, strData);
|
||||
}
|
||||
|
||||
if (!mDeqSites.empty() && bAgain)
|
||||
if (!deqSites_.empty() && bAgain)
|
||||
{
|
||||
httpsNext();
|
||||
}
|
||||
@@ -504,9 +504,9 @@ public:
|
||||
private:
|
||||
using pointer = std::shared_ptr<HTTPClient>;
|
||||
|
||||
bool mSSL{};
|
||||
AutoSocket mSocket;
|
||||
boost::asio::ip::tcp::resolver mResolver;
|
||||
bool ssl_{};
|
||||
AutoSocket socket_;
|
||||
boost::asio::ip::tcp::resolver resolver_;
|
||||
|
||||
struct Query
|
||||
{
|
||||
@@ -514,27 +514,27 @@ private:
|
||||
std::string port;
|
||||
boost::asio::ip::resolver_query_base::flags flags;
|
||||
};
|
||||
std::shared_ptr<Query> mQuery;
|
||||
std::shared_ptr<Query> query_;
|
||||
|
||||
boost::asio::streambuf mRequest;
|
||||
boost::asio::streambuf mHeader;
|
||||
boost::asio::streambuf mResponse;
|
||||
std::string mBody;
|
||||
unsigned short const mPort;
|
||||
boost::asio::streambuf request_;
|
||||
boost::asio::streambuf header_;
|
||||
boost::asio::streambuf response_;
|
||||
std::string body_;
|
||||
unsigned short const port_;
|
||||
std::size_t const maxResponseSize_;
|
||||
int mStatus{};
|
||||
std::function<void(boost::asio::streambuf& sb, std::string const& strHost)> mBuild;
|
||||
int status_{};
|
||||
std::function<void(boost::asio::streambuf& sb, std::string const& strHost)> build_;
|
||||
std::function<
|
||||
bool(boost::system::error_code const& ecResult, int iStatus, std::string const& strData)>
|
||||
mComplete;
|
||||
complete_;
|
||||
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> mDeadline;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> deadline_;
|
||||
|
||||
// If not success, we are shutting down.
|
||||
boost::system::error_code mShutdown;
|
||||
boost::system::error_code shutdown_;
|
||||
|
||||
std::deque<std::string> mDeqSites;
|
||||
std::chrono::seconds mTimeout{};
|
||||
std::deque<std::string> deqSites_;
|
||||
std::chrono::seconds timeout_{};
|
||||
beast::Journal j_;
|
||||
};
|
||||
|
||||
@@ -543,7 +543,7 @@ private:
|
||||
void
|
||||
HTTPClient::get(
|
||||
bool bSSL,
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::io_context& ioContext,
|
||||
std::deque<std::string> deqSites,
|
||||
unsigned short const port,
|
||||
std::string const& strPath,
|
||||
@@ -554,14 +554,14 @@ HTTPClient::get(
|
||||
complete,
|
||||
beast::Journal& j)
|
||||
{
|
||||
auto client = std::make_shared<HTTPClientImp>(io_context, port, responseMax, j);
|
||||
auto client = std::make_shared<HTTPClientImp>(ioContext, port, responseMax, j);
|
||||
client->get(bSSL, deqSites, strPath, timeout, complete);
|
||||
}
|
||||
|
||||
void
|
||||
HTTPClient::get(
|
||||
bool bSSL,
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::io_context& ioContext,
|
||||
std::string strSite,
|
||||
unsigned short const port,
|
||||
std::string const& strPath,
|
||||
@@ -574,14 +574,14 @@ HTTPClient::get(
|
||||
{
|
||||
std::deque<std::string> const deqSites(1, strSite);
|
||||
|
||||
auto client = std::make_shared<HTTPClientImp>(io_context, port, responseMax, j);
|
||||
auto client = std::make_shared<HTTPClientImp>(ioContext, port, responseMax, j);
|
||||
client->get(bSSL, deqSites, strPath, timeout, complete);
|
||||
}
|
||||
|
||||
void
|
||||
HTTPClient::request(
|
||||
bool bSSL,
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::io_context& ioContext,
|
||||
std::string strSite,
|
||||
unsigned short const port,
|
||||
std::function<void(boost::asio::streambuf& sb, std::string const& strHost)> setRequest,
|
||||
@@ -594,7 +594,7 @@ HTTPClient::request(
|
||||
{
|
||||
std::deque<std::string> const deqSites(1, strSite);
|
||||
|
||||
auto client = std::make_shared<HTTPClientImp>(io_context, port, responseMax, j);
|
||||
auto client = std::make_shared<HTTPClientImp>(ioContext, port, responseMax, j);
|
||||
client->request(bSSL, deqSites, setRequest, timeout, complete);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
namespace xrpl::NodeStore {
|
||||
|
||||
BatchWriter::BatchWriter(Callback& callback, Scheduler& scheduler)
|
||||
: m_callback(callback), m_scheduler(scheduler)
|
||||
: callback_(callback), scheduler_(scheduler)
|
||||
{
|
||||
mWriteSet.reserve(batchWritePreallocationSize);
|
||||
writeSet_.reserve(kBatchWritePreallocationSize);
|
||||
}
|
||||
|
||||
BatchWriter::~BatchWriter()
|
||||
@@ -27,29 +27,29 @@ BatchWriter::~BatchWriter()
|
||||
void
|
||||
BatchWriter::store(std::shared_ptr<NodeObject> const& object)
|
||||
{
|
||||
std::unique_lock<decltype(mWriteMutex)> sl(mWriteMutex);
|
||||
std::unique_lock<decltype(writeMutex_)> sl(writeMutex_);
|
||||
|
||||
// If the batch has reached its limit, we wait
|
||||
// until the batch writer is finished
|
||||
while (mWriteSet.size() >= batchWriteLimitSize)
|
||||
mWriteCondition.wait(sl);
|
||||
while (writeSet_.size() >= kBatchWritePreallocationSize)
|
||||
writeCondition_.wait(sl);
|
||||
|
||||
mWriteSet.push_back(object);
|
||||
writeSet_.push_back(object);
|
||||
|
||||
if (!mWritePending)
|
||||
if (!writePending_)
|
||||
{
|
||||
mWritePending = true;
|
||||
writePending_ = true;
|
||||
|
||||
m_scheduler.scheduleTask(*this);
|
||||
scheduler_.scheduleTask(*this);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
BatchWriter::getWriteLoad()
|
||||
{
|
||||
std::lock_guard const sl(mWriteMutex);
|
||||
std::scoped_lock const sl(writeMutex_);
|
||||
|
||||
return std::max(mWriteLoad, static_cast<int>(mWriteSet.size()));
|
||||
return std::max(writeLoad_, static_cast<int>(writeSet_.size()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -65,20 +65,20 @@ BatchWriter::writeBatch()
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> set;
|
||||
|
||||
set.reserve(batchWritePreallocationSize);
|
||||
set.reserve(kBatchWritePreallocationSize);
|
||||
|
||||
{
|
||||
std::lock_guard const sl(mWriteMutex);
|
||||
std::scoped_lock const sl(writeMutex_);
|
||||
|
||||
mWriteSet.swap(set);
|
||||
writeSet_.swap(set);
|
||||
XRPL_ASSERT(
|
||||
mWriteSet.empty(), "xrpl::NodeStore::BatchWriter::writeBatch : writes not set");
|
||||
mWriteLoad = set.size();
|
||||
writeSet_.empty(), "xrpl::NodeStore::BatchWriter::writeBatch : writes not set");
|
||||
writeLoad_ = set.size();
|
||||
|
||||
if (set.empty())
|
||||
{
|
||||
mWritePending = false;
|
||||
mWriteCondition.notify_all();
|
||||
writePending_ = false;
|
||||
writeCondition_.notify_all();
|
||||
|
||||
// VFALCO NOTE Fix this function to not return from the middle
|
||||
return;
|
||||
@@ -89,22 +89,22 @@ BatchWriter::writeBatch()
|
||||
report.writeCount = set.size();
|
||||
auto const before = std::chrono::steady_clock::now();
|
||||
|
||||
m_callback.writeBatch(set);
|
||||
callback_.writeBatch(set);
|
||||
|
||||
report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - before);
|
||||
|
||||
m_scheduler.onBatchWrite(report);
|
||||
scheduler_.onBatchWrite(report);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BatchWriter::waitForWriting()
|
||||
{
|
||||
std::unique_lock<decltype(mWriteMutex)> sl(mWriteMutex);
|
||||
std::unique_lock<decltype(writeMutex_)> sl(writeMutex_);
|
||||
|
||||
while (mWritePending)
|
||||
mWriteCondition.wait(sl);
|
||||
while (writePending_)
|
||||
writeCondition_.wait(sl);
|
||||
}
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -38,7 +38,7 @@ Database::Database(
|
||||
beast::Journal journal)
|
||||
: j_(journal)
|
||||
, scheduler_(scheduler)
|
||||
, earliestLedgerSeq_(get<std::uint32_t>(config, "earliest_seq", XRP_LEDGER_EARLIEST_SEQ))
|
||||
, earliestLedgerSeq_(get<std::uint32_t>(config, "earliest_seq", kXrpLedgerEarliestSeq))
|
||||
, requestBundle_(get<int>(config, "rq_bundle", 4))
|
||||
, readThreads_(std::max(1, readThreads))
|
||||
{
|
||||
@@ -95,7 +95,7 @@ Database::Database(
|
||||
auto const& data = it->second;
|
||||
auto const seqn = data[0].first;
|
||||
|
||||
auto obj = fetchNodeObject(hash, seqn, FetchType::async);
|
||||
auto obj = fetchNodeObject(hash, seqn, FetchType::Async);
|
||||
|
||||
// This could be further optimized: if there are
|
||||
// multiple requests for sequence numbers mapping to
|
||||
@@ -107,7 +107,7 @@ Database::Database(
|
||||
req.second(
|
||||
(seqn == req.first) || isSameDB(req.first, seqn)
|
||||
? obj
|
||||
: fetchNodeObject(hash, req.first, FetchType::async));
|
||||
: fetchNodeObject(hash, req.first, FetchType::Async));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ void
|
||||
Database::stop()
|
||||
{
|
||||
{
|
||||
std::lock_guard const lock(readLock_);
|
||||
std::scoped_lock const lock(readLock_);
|
||||
|
||||
if (!readStopping_.exchange(true, std::memory_order_relaxed))
|
||||
{
|
||||
@@ -179,7 +179,7 @@ Database::asyncFetch(
|
||||
std::uint32_t ledgerSeq,
|
||||
std::function<void(std::shared_ptr<NodeObject> const&)>&& cb)
|
||||
{
|
||||
std::lock_guard const lock(readLock_);
|
||||
std::scoped_lock const lock(readLock_);
|
||||
|
||||
if (!isStopping())
|
||||
{
|
||||
@@ -192,7 +192,7 @@ void
|
||||
Database::importInternal(Backend& dstBackend, Database& srcDB)
|
||||
{
|
||||
Batch batch;
|
||||
batch.reserve(batchWritePreallocationSize);
|
||||
batch.reserve(kBatchWritePreallocationSize);
|
||||
auto storeBatch = [&, fname = __func__]() {
|
||||
try
|
||||
{
|
||||
@@ -211,13 +211,13 @@ Database::importInternal(Backend& dstBackend, Database& srcDB)
|
||||
batch.clear();
|
||||
};
|
||||
|
||||
srcDB.for_each([&](std::shared_ptr<NodeObject> nodeObject) {
|
||||
srcDB.forEach([&](std::shared_ptr<NodeObject> nodeObject) {
|
||||
XRPL_ASSERT(nodeObject, "xrpl::NodeStore::Database::importInternal : non-null node");
|
||||
if (!nodeObject) // This should never happen
|
||||
return;
|
||||
|
||||
batch.emplace_back(std::move(nodeObject));
|
||||
if (batch.size() >= batchWritePreallocationSize)
|
||||
if (batch.size() >= kBatchWritePreallocationSize)
|
||||
storeBatch();
|
||||
});
|
||||
|
||||
@@ -254,13 +254,13 @@ Database::fetchNodeObject(
|
||||
}
|
||||
|
||||
void
|
||||
Database::getCountsJson(Json::Value& obj)
|
||||
Database::getCountsJson(json::Value& obj)
|
||||
{
|
||||
XRPL_ASSERT(obj.isObject(), "xrpl::NodeStore::Database::getCountsJson : valid input type");
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> const lock(readLock_);
|
||||
obj["read_queue"] = static_cast<Json::UInt>(read_.size());
|
||||
obj["read_queue"] = static_cast<json::UInt>(read_.size());
|
||||
}
|
||||
|
||||
obj["read_threads_total"] = readThreads_.load();
|
||||
|
||||
@@ -4,21 +4,16 @@
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/strHex.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
#include <xrpl/nodestore/Types.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::NodeStore {
|
||||
|
||||
@@ -29,6 +24,13 @@ DatabaseNodeImp::store(NodeObjectType type, Blob&& data, uint256 const& hash, st
|
||||
|
||||
auto obj = NodeObject::createObject(type, std::move(data), hash);
|
||||
backend_->store(obj);
|
||||
if (cache_)
|
||||
{
|
||||
// After the store, replace a negative cache entry if there is one
|
||||
cache_->canonicalize(hash, obj, [](std::shared_ptr<NodeObject> const& n) {
|
||||
return n->getType() == NodeObjectType::Dummy;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -37,9 +39,25 @@ DatabaseNodeImp::asyncFetch(
|
||||
std::uint32_t ledgerSeq,
|
||||
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback)
|
||||
{
|
||||
if (cache_)
|
||||
{
|
||||
std::shared_ptr<NodeObject> const obj = cache_->fetch(hash);
|
||||
if (obj)
|
||||
{
|
||||
callback(obj->getType() == NodeObjectType::Dummy ? nullptr : obj);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Database::asyncFetch(hash, ledgerSeq, std::move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseNodeImp::sweep()
|
||||
{
|
||||
if (cache_)
|
||||
cache_->sweep();
|
||||
}
|
||||
|
||||
std::shared_ptr<NodeObject>
|
||||
DatabaseNodeImp::fetchNodeObject(
|
||||
uint256 const& hash,
|
||||
@@ -47,32 +65,58 @@ DatabaseNodeImp::fetchNodeObject(
|
||||
FetchReport& fetchReport,
|
||||
bool duplicate)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nodeObject = nullptr;
|
||||
Status status = ok;
|
||||
std::shared_ptr<NodeObject> nodeObject = cache_ ? cache_->fetch(hash) : nullptr;
|
||||
if (!nodeObject)
|
||||
{
|
||||
JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record not "
|
||||
<< (cache_ ? "cached" : "found");
|
||||
|
||||
try
|
||||
{
|
||||
status = backend_->fetch(hash, &nodeObject);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash
|
||||
<< ": Exception fetching from backend: " << e.what();
|
||||
Rethrow();
|
||||
}
|
||||
Status status = Status::Ok;
|
||||
try
|
||||
{
|
||||
status = backend_->fetch(hash, &nodeObject);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash
|
||||
<< ": Exception fetching from backend: " << e.what();
|
||||
rethrow();
|
||||
}
|
||||
|
||||
switch (status)
|
||||
switch (status)
|
||||
{
|
||||
case Status::Ok:
|
||||
if (cache_)
|
||||
{
|
||||
if (nodeObject)
|
||||
{
|
||||
cache_->canonicalizeReplaceClient(hash, nodeObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto notFound = NodeObject::createObject(NodeObjectType::Dummy, {}, hash);
|
||||
cache_->canonicalizeReplaceClient(hash, notFound);
|
||||
if (notFound->getType() != NodeObjectType::Dummy)
|
||||
nodeObject = notFound;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Status::NotFound:
|
||||
break;
|
||||
case Status::DataCorrupt:
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted";
|
||||
break;
|
||||
default:
|
||||
JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result "
|
||||
<< static_cast<int>(status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
case ok:
|
||||
case notFound:
|
||||
break;
|
||||
case dataCorrupt:
|
||||
JLOG(j_.fatal()) << "fetchNodeObject " << hash << ": nodestore data is corrupted";
|
||||
break;
|
||||
default:
|
||||
JLOG(j_.warn()) << "fetchNodeObject " << hash << ": backend returns unknown result "
|
||||
<< status;
|
||||
break;
|
||||
JLOG(j_.trace()) << "fetchNodeObject " << hash << ": record found in cache";
|
||||
if (nodeObject->getType() == NodeObjectType::Dummy)
|
||||
nodeObject.reset();
|
||||
}
|
||||
|
||||
if (nodeObject)
|
||||
@@ -81,33 +125,4 @@ DatabaseNodeImp::fetchNodeObject(
|
||||
return nodeObject;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<NodeObject>>
|
||||
DatabaseNodeImp::fetchBatch(std::vector<uint256> const& hashes)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
auto const before = steady_clock::now();
|
||||
|
||||
// Get the node objects that match the hashes from the backend. To protect
|
||||
// against the backends returning fewer or more results than expected, the
|
||||
// container is resized to the number of hashes.
|
||||
auto results = backend_->fetchBatch(hashes).first;
|
||||
XRPL_ASSERT(
|
||||
results.size() == hashes.size() || results.empty(),
|
||||
"number of output objects either matches number of input hashes or is empty");
|
||||
results.resize(hashes.size());
|
||||
for (size_t i = 0; i < results.size(); ++i)
|
||||
{
|
||||
if (!results[i])
|
||||
{
|
||||
JLOG(j_.error()) << "fetchBatch - "
|
||||
<< "record not found in db. hash = " << strHex(hashes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
auto fetchDurationUs =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(steady_clock::now() - before).count();
|
||||
updateFetchMetrics(hashes.size(), 0, fetchDurationUs);
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -53,7 +53,7 @@ DatabaseRotatingImp::rotate(
|
||||
// deleted.
|
||||
std::shared_ptr<NodeStore::Backend> oldArchiveBackend;
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
|
||||
archiveBackend_->setDeletePath();
|
||||
oldArchiveBackend = std::move(archiveBackend_);
|
||||
@@ -70,14 +70,14 @@ DatabaseRotatingImp::rotate(
|
||||
std::string
|
||||
DatabaseRotatingImp::getName() const
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return writableBackend_->getName();
|
||||
}
|
||||
|
||||
std::int32_t
|
||||
DatabaseRotatingImp::getWriteLoad() const
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return writableBackend_->getWriteLoad();
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ void
|
||||
DatabaseRotatingImp::importDatabase(Database& source)
|
||||
{
|
||||
auto const backend = [&] {
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return writableBackend_;
|
||||
}();
|
||||
|
||||
@@ -95,7 +95,7 @@ DatabaseRotatingImp::importDatabase(Database& source)
|
||||
void
|
||||
DatabaseRotatingImp::sync()
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
writableBackend_->sync();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ DatabaseRotatingImp::store(NodeObjectType type, Blob&& data, uint256 const& hash
|
||||
auto nObj = NodeObject::createObject(type, std::move(data), hash);
|
||||
|
||||
auto const backend = [&] {
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return writableBackend_;
|
||||
}();
|
||||
|
||||
@@ -113,6 +113,12 @@ DatabaseRotatingImp::store(NodeObjectType type, Blob&& data, uint256 const& hash
|
||||
storeStats(1, nObj->getData().size());
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseRotatingImp::sweep()
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
std::shared_ptr<NodeObject>
|
||||
DatabaseRotatingImp::fetchNodeObject(
|
||||
uint256 const& hash,
|
||||
@@ -121,7 +127,7 @@ DatabaseRotatingImp::fetchNodeObject(
|
||||
bool duplicate)
|
||||
{
|
||||
auto fetch = [&](std::shared_ptr<Backend> const& backend) {
|
||||
Status status = ok;
|
||||
Status status = Status::Ok;
|
||||
std::shared_ptr<NodeObject> nodeObject;
|
||||
try
|
||||
{
|
||||
@@ -130,19 +136,19 @@ DatabaseRotatingImp::fetchNodeObject(
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.fatal()) << "Exception, " << e.what();
|
||||
Rethrow();
|
||||
rethrow();
|
||||
}
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case ok:
|
||||
case notFound:
|
||||
case Status::Ok:
|
||||
case Status::NotFound:
|
||||
break;
|
||||
case dataCorrupt:
|
||||
case Status::DataCorrupt:
|
||||
JLOG(j_.fatal()) << "Corrupt NodeObject #" << hash;
|
||||
break;
|
||||
default:
|
||||
JLOG(j_.warn()) << "Unknown status=" << status;
|
||||
JLOG(j_.warn()) << "Unknown status=" << static_cast<int>(status);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -153,7 +159,7 @@ DatabaseRotatingImp::fetchNodeObject(
|
||||
std::shared_ptr<NodeObject> nodeObject;
|
||||
|
||||
auto [writable, archive] = [&] {
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return std::make_pair(writableBackend_, archiveBackend_);
|
||||
}();
|
||||
|
||||
@@ -167,7 +173,7 @@ DatabaseRotatingImp::fetchNodeObject(
|
||||
{
|
||||
{
|
||||
// Refresh the writable backend pointer
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
writable = writableBackend_;
|
||||
}
|
||||
|
||||
@@ -184,18 +190,18 @@ DatabaseRotatingImp::fetchNodeObject(
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseRotatingImp::for_each(std::function<void(std::shared_ptr<NodeObject>)> f)
|
||||
DatabaseRotatingImp::forEach(std::function<void(std::shared_ptr<NodeObject>)> f)
|
||||
{
|
||||
auto [writable, archive] = [&] {
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return std::make_pair(writableBackend_, archiveBackend_);
|
||||
}();
|
||||
|
||||
// Iterate the writable backend
|
||||
writable->for_each(f);
|
||||
writable->forEach(f);
|
||||
|
||||
// Iterate the archive backend
|
||||
archive->for_each(f);
|
||||
archive->forEach(f);
|
||||
}
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -23,34 +23,34 @@ DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes)
|
||||
9...end The body of the object data
|
||||
*/
|
||||
|
||||
m_success = false;
|
||||
m_key = key;
|
||||
m_objectType = hotUNKNOWN;
|
||||
m_objectData = nullptr;
|
||||
m_dataBytes = std::max(0, valueBytes - 9);
|
||||
success_ = false;
|
||||
key_ = key;
|
||||
objectType_ = NodeObjectType::Unknown;
|
||||
objectData_ = nullptr;
|
||||
dataBytes_ = std::max(0, valueBytes - 9);
|
||||
|
||||
// VFALCO NOTE What about bytes 4 through 7 inclusive?
|
||||
|
||||
if (valueBytes > 8)
|
||||
{
|
||||
unsigned char const* byte = static_cast<unsigned char const*>(value);
|
||||
m_objectType = safe_cast<NodeObjectType>(byte[8]);
|
||||
objectType_ = safeCast<NodeObjectType>(byte[8]);
|
||||
}
|
||||
|
||||
if (valueBytes > 9)
|
||||
{
|
||||
m_objectData = static_cast<unsigned char const*>(value) + 9;
|
||||
objectData_ = static_cast<unsigned char const*>(value) + 9;
|
||||
|
||||
switch (m_objectType)
|
||||
switch (objectType_)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case hotUNKNOWN:
|
||||
case hotLEDGER:
|
||||
case hotACCOUNT_NODE:
|
||||
case hotTRANSACTION_NODE:
|
||||
m_success = true;
|
||||
case NodeObjectType::Unknown:
|
||||
case NodeObjectType::Ledger:
|
||||
case NodeObjectType::AccountNode:
|
||||
case NodeObjectType::TransactionNode:
|
||||
success_ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -59,15 +59,15 @@ DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes)
|
||||
std::shared_ptr<NodeObject>
|
||||
DecodedBlob::createObject()
|
||||
{
|
||||
XRPL_ASSERT(m_success, "xrpl::NodeStore::DecodedBlob::createObject : valid object type");
|
||||
XRPL_ASSERT(success_, "xrpl::NodeStore::DecodedBlob::createObject : valid object type");
|
||||
|
||||
std::shared_ptr<NodeObject> object;
|
||||
|
||||
if (m_success)
|
||||
if (success_)
|
||||
{
|
||||
Blob data(m_objectData, m_objectData + m_dataBytes);
|
||||
Blob data(objectData_, objectData_ + dataBytes_);
|
||||
|
||||
object = NodeObject::createObject(m_objectType, std::move(data), uint256::fromVoid(m_key));
|
||||
object = NodeObject::createObject(objectType_, std::move(data), uint256::fromVoid(key_));
|
||||
}
|
||||
|
||||
return object;
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace xrpl::NodeStore {
|
||||
ManagerImp&
|
||||
ManagerImp::instance()
|
||||
{
|
||||
static ManagerImp _;
|
||||
return _;
|
||||
static ManagerImp kInst;
|
||||
return kInst;
|
||||
}
|
||||
|
||||
void
|
||||
ManagerImp::missing_backend()
|
||||
ManagerImp::missingBackend()
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"Your xrpld.cfg is missing a [node_db] entry, "
|
||||
@@ -60,7 +60,7 @@ ManagerImp::ManagerImp()
|
||||
}
|
||||
|
||||
std::unique_ptr<Backend>
|
||||
ManagerImp::make_Backend(
|
||||
ManagerImp::makeBackend(
|
||||
Section const& parameters,
|
||||
std::size_t burstSize,
|
||||
Scheduler& scheduler,
|
||||
@@ -68,26 +68,27 @@ ManagerImp::make_Backend(
|
||||
{
|
||||
std::string const type{get(parameters, "type")};
|
||||
if (type.empty())
|
||||
missing_backend();
|
||||
missingBackend();
|
||||
|
||||
auto factory{find(type)};
|
||||
if (factory == nullptr)
|
||||
{
|
||||
missing_backend();
|
||||
missingBackend();
|
||||
}
|
||||
|
||||
return factory->createInstance(NodeObject::keyBytes, parameters, burstSize, scheduler, journal);
|
||||
return factory->createInstance(
|
||||
NodeObject::kKeyBytes, parameters, burstSize, scheduler, journal);
|
||||
}
|
||||
|
||||
std::unique_ptr<Database>
|
||||
ManagerImp::make_Database(
|
||||
ManagerImp::makeDatabase(
|
||||
std::size_t burstSize,
|
||||
Scheduler& scheduler,
|
||||
int readThreads,
|
||||
Section const& config,
|
||||
beast::Journal journal)
|
||||
{
|
||||
auto backend{make_Backend(config, burstSize, scheduler, journal)};
|
||||
auto backend{makeBackend(config, burstSize, scheduler, journal)};
|
||||
backend->open();
|
||||
return std::make_unique<DatabaseNodeImp>(
|
||||
scheduler, readThreads, std::move(backend), config, journal);
|
||||
@@ -96,14 +97,14 @@ ManagerImp::make_Database(
|
||||
void
|
||||
ManagerImp::insert(Factory& factory)
|
||||
{
|
||||
std::lock_guard const _(mutex_);
|
||||
std::scoped_lock const _(mutex_);
|
||||
list_.push_back(&factory);
|
||||
}
|
||||
|
||||
void
|
||||
ManagerImp::erase(Factory& factory)
|
||||
{
|
||||
std::lock_guard const _(mutex_);
|
||||
std::scoped_lock const _(mutex_);
|
||||
auto const iter =
|
||||
std::ranges::find_if(list_, [&factory](Factory* other) { return other == &factory; });
|
||||
XRPL_ASSERT(iter != list_.end(), "xrpl::NodeStore::ManagerImp::erase : valid input");
|
||||
@@ -113,7 +114,7 @@ ManagerImp::erase(Factory& factory)
|
||||
Factory*
|
||||
ManagerImp::find(std::string const& name)
|
||||
{
|
||||
std::lock_guard const _(mutex_);
|
||||
std::scoped_lock const _(mutex_);
|
||||
auto const iter = std::ranges::find_if(
|
||||
list_, [&name](Factory* other) { return boost::iequals(name, other->getName()); });
|
||||
if (iter == list_.end())
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace xrpl {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
NodeObject::NodeObject(NodeObjectType type, Blob&& data, uint256 const& hash, PrivateAccess)
|
||||
: mType(type), mHash(hash), mData(std::move(data))
|
||||
: type_(type), hash_(hash), data_(std::move(data))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,19 +24,19 @@ NodeObject::createObject(NodeObjectType type, Blob&& data, uint256 const& hash)
|
||||
NodeObjectType
|
||||
NodeObject::getType() const
|
||||
{
|
||||
return mType;
|
||||
return type_;
|
||||
}
|
||||
|
||||
uint256 const&
|
||||
NodeObject::getHash() const
|
||||
{
|
||||
return mHash;
|
||||
return hash_;
|
||||
}
|
||||
|
||||
Blob const&
|
||||
NodeObject::getData() const
|
||||
{
|
||||
return mData;
|
||||
return data_;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::NodeStore {
|
||||
|
||||
@@ -59,7 +58,7 @@ public:
|
||||
MemoryDB&
|
||||
open(std::string const& path)
|
||||
{
|
||||
std::lock_guard const _(mutex_);
|
||||
std::scoped_lock const _(mutex_);
|
||||
auto const result =
|
||||
map_.emplace(std::piecewise_construct, std::make_tuple(path), std::make_tuple());
|
||||
MemoryDB& db = result.first->second;
|
||||
@@ -69,13 +68,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
MemoryFactory* memoryFactory = nullptr;
|
||||
MemoryFactory* gMemoryFactory = nullptr;
|
||||
|
||||
void
|
||||
registerMemoryFactory(Manager& manager)
|
||||
{
|
||||
static MemoryFactory instance{manager};
|
||||
memoryFactory = &instance;
|
||||
static MemoryFactory kInstance{manager};
|
||||
gMemoryFactory = &kInstance;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -112,7 +111,7 @@ public:
|
||||
void
|
||||
open(bool) override
|
||||
{
|
||||
db_ = &memoryFactory->open(name_);
|
||||
db_ = &gMemoryFactory->open(name_);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -134,45 +133,23 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::fetch : non-null database");
|
||||
|
||||
std::lock_guard const _(db_->mutex);
|
||||
std::scoped_lock const _(db_->mutex);
|
||||
|
||||
Map::iterator const iter = db_->table.find(hash);
|
||||
if (iter == db_->table.end())
|
||||
{
|
||||
pObject->reset();
|
||||
return notFound;
|
||||
return Status::NotFound;
|
||||
}
|
||||
*pObject = iter->second;
|
||||
return ok;
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> results;
|
||||
results.reserve(hashes.size());
|
||||
for (auto const& h : hashes)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nObj;
|
||||
Status const status = fetch(h, &nObj);
|
||||
if (status != ok)
|
||||
{
|
||||
results.push_back({});
|
||||
}
|
||||
else
|
||||
{
|
||||
results.push_back(nObj);
|
||||
}
|
||||
}
|
||||
|
||||
return {results, ok};
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
void
|
||||
store(std::shared_ptr<NodeObject> const& object) override
|
||||
{
|
||||
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::store : non-null database");
|
||||
std::lock_guard const _(db_->mutex);
|
||||
std::scoped_lock const _(db_->mutex);
|
||||
db_->table.emplace(object->getHash(), object);
|
||||
}
|
||||
|
||||
@@ -189,9 +166,9 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
for_each(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
{
|
||||
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::for_each : non-null database");
|
||||
XRPL_ASSERT(db_, "xrpl::NodeStore::MemoryBackend::forEach : non-null database");
|
||||
for (auto const& e : db_->table)
|
||||
f(e.second);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::NodeStore {
|
||||
|
||||
@@ -53,16 +52,16 @@ public:
|
||||
// NuDB database. We used it to identify shard databases before that code
|
||||
// was removed. For now, its only use is a sanity check that the database
|
||||
// was created by xrpld.
|
||||
static constexpr std::uint64_t appnum = 1;
|
||||
static constexpr std::uint64_t kAppNum = 1;
|
||||
|
||||
beast::Journal const j_;
|
||||
size_t const keyBytes_;
|
||||
std::size_t const burstSize_;
|
||||
std::string const name_;
|
||||
std::size_t const blockSize_;
|
||||
nudb::store db_;
|
||||
std::atomic<bool> deletePath_;
|
||||
Scheduler& scheduler_;
|
||||
beast::Journal const j;
|
||||
size_t const keyBytes;
|
||||
std::size_t const burstSize;
|
||||
std::string const name;
|
||||
std::size_t const blockSize;
|
||||
nudb::store db;
|
||||
std::atomic<bool> deletePath;
|
||||
Scheduler& scheduler;
|
||||
|
||||
NuDBBackend(
|
||||
size_t keyBytes,
|
||||
@@ -70,15 +69,15 @@ public:
|
||||
std::size_t burstSize,
|
||||
Scheduler& scheduler,
|
||||
beast::Journal journal)
|
||||
: j_(journal)
|
||||
, keyBytes_(keyBytes)
|
||||
, burstSize_(burstSize)
|
||||
, name_(get(keyValues, "path"))
|
||||
, blockSize_(parseBlockSize(name_, keyValues, journal))
|
||||
, deletePath_(false)
|
||||
, scheduler_(scheduler)
|
||||
: j(journal)
|
||||
, keyBytes(keyBytes)
|
||||
, burstSize(burstSize)
|
||||
, name(get(keyValues, "path"))
|
||||
, blockSize(parseBlockSize(name, keyValues, journal))
|
||||
, deletePath(false)
|
||||
, scheduler(scheduler)
|
||||
{
|
||||
if (name_.empty())
|
||||
if (name.empty())
|
||||
Throw<std::runtime_error>("nodestore: Missing path in NuDB backend");
|
||||
}
|
||||
|
||||
@@ -89,16 +88,16 @@ public:
|
||||
Scheduler& scheduler,
|
||||
nudb::context& context,
|
||||
beast::Journal journal)
|
||||
: j_(journal)
|
||||
, keyBytes_(keyBytes)
|
||||
, burstSize_(burstSize)
|
||||
, name_(get(keyValues, "path"))
|
||||
, blockSize_(parseBlockSize(name_, keyValues, journal))
|
||||
, db_(context)
|
||||
, deletePath_(false)
|
||||
, scheduler_(scheduler)
|
||||
: j(journal)
|
||||
, keyBytes(keyBytes)
|
||||
, burstSize(burstSize)
|
||||
, name(get(keyValues, "path"))
|
||||
, blockSize(parseBlockSize(name, keyValues, journal))
|
||||
, db(context)
|
||||
, deletePath(false)
|
||||
, scheduler(scheduler)
|
||||
{
|
||||
if (name_.empty())
|
||||
if (name.empty())
|
||||
Throw<std::runtime_error>("nodestore: Missing path in NuDB backend");
|
||||
}
|
||||
|
||||
@@ -119,30 +118,30 @@ public:
|
||||
std::string
|
||||
getName() override
|
||||
{
|
||||
return name_;
|
||||
return name;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::size_t>
|
||||
getBlockSize() const override
|
||||
{
|
||||
return blockSize_;
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
void
|
||||
open(bool createIfMissing, uint64_t appType, uint64_t uid, uint64_t salt) override
|
||||
{
|
||||
using namespace boost::filesystem;
|
||||
if (db_.is_open())
|
||||
if (db.is_open())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"xrpl::NodeStore::NuDBBackend::open : database is already "
|
||||
"open");
|
||||
JLOG(j_.error()) << "database is already open";
|
||||
JLOG(j.error()) << "database is already open";
|
||||
return;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
auto const folder = path(name_);
|
||||
auto const folder = path(name);
|
||||
auto const dp = (folder / "nudb.dat").string();
|
||||
auto const kp = (folder / "nudb.key").string();
|
||||
auto const lp = (folder / "nudb.log").string();
|
||||
@@ -151,54 +150,54 @@ public:
|
||||
{
|
||||
create_directories(folder);
|
||||
nudb::create<nudb::xxhasher>(
|
||||
dp, kp, lp, appType, uid, salt, keyBytes_, blockSize_, 0.50, ec);
|
||||
dp, kp, lp, appType, uid, salt, keyBytes, blockSize, 0.50, ec);
|
||||
if (ec == nudb::errc::file_exists)
|
||||
ec = {};
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
db_.open(dp, kp, lp, ec);
|
||||
db.open(dp, kp, lp, ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
|
||||
if (db_.appnum() != appnum)
|
||||
if (db.appnum() != kAppNum)
|
||||
Throw<std::runtime_error>("nodestore: unknown appnum");
|
||||
db_.set_burst(burstSize_);
|
||||
db.set_burst(burstSize);
|
||||
}
|
||||
|
||||
bool
|
||||
isOpen() override
|
||||
{
|
||||
return db_.is_open();
|
||||
return db.is_open();
|
||||
}
|
||||
|
||||
void
|
||||
open(bool createIfMissing) override
|
||||
{
|
||||
open(createIfMissing, appnum, nudb::make_uid(), nudb::make_salt());
|
||||
open(createIfMissing, kAppNum, nudb::make_uid(), nudb::make_salt());
|
||||
}
|
||||
|
||||
void
|
||||
close() override
|
||||
{
|
||||
if (db_.is_open())
|
||||
if (db.is_open())
|
||||
{
|
||||
nudb::error_code ec;
|
||||
db_.close(ec);
|
||||
db.close(ec);
|
||||
if (ec)
|
||||
{
|
||||
// Log to make sure the nature of the error gets to the user.
|
||||
JLOG(j_.fatal()) << "NuBD close() failed: " << ec.message();
|
||||
JLOG(j.fatal()) << "NuBD close() failed: " << ec.message();
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
|
||||
if (deletePath_)
|
||||
if (deletePath)
|
||||
{
|
||||
boost::filesystem::remove_all(name_, ec);
|
||||
boost::filesystem::remove_all(name, ec);
|
||||
if (ec)
|
||||
{
|
||||
JLOG(j_.fatal())
|
||||
<< "Filesystem remove_all of " << name_ << " failed with: " << ec.message();
|
||||
JLOG(j.fatal())
|
||||
<< "Filesystem remove_all of " << name << " failed with: " << ec.message();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,61 +206,39 @@ public:
|
||||
Status
|
||||
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pno) override
|
||||
{
|
||||
Status status = ok;
|
||||
Status status = Status::Ok;
|
||||
pno->reset();
|
||||
nudb::error_code ec;
|
||||
db_.fetch(
|
||||
db.fetch(
|
||||
hash.data(),
|
||||
[&hash, pno, &status](void const* data, std::size_t size) {
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobject_decompress(data, size, bf);
|
||||
auto const result = nodeobjectDecompress(data, size, bf);
|
||||
DecodedBlob decoded(hash.data(), result.first, result.second);
|
||||
if (!decoded.wasOk())
|
||||
{
|
||||
status = dataCorrupt;
|
||||
status = Status::DataCorrupt;
|
||||
return;
|
||||
}
|
||||
*pno = decoded.createObject();
|
||||
status = ok;
|
||||
status = Status::Ok;
|
||||
},
|
||||
ec);
|
||||
if (ec == nudb::error::key_not_found)
|
||||
return notFound;
|
||||
return Status::NotFound;
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
return status;
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> results;
|
||||
results.reserve(hashes.size());
|
||||
for (auto const& h : hashes)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nObj;
|
||||
Status const status = fetch(h, &nObj);
|
||||
if (status != ok)
|
||||
{
|
||||
results.push_back({});
|
||||
}
|
||||
else
|
||||
{
|
||||
results.push_back(nObj);
|
||||
}
|
||||
}
|
||||
|
||||
return {results, ok};
|
||||
}
|
||||
|
||||
void
|
||||
do_insert(std::shared_ptr<NodeObject> const& no)
|
||||
doInsert(std::shared_ptr<NodeObject> const& no)
|
||||
{
|
||||
EncodedBlob const e(no);
|
||||
nudb::error_code ec;
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobject_compress(e.getData(), e.getSize(), bf);
|
||||
db_.insert(e.getKey(), result.first, result.second, ec);
|
||||
auto const result = nodeobjectCompress(e.getData(), e.getSize(), bf);
|
||||
db.insert(e.getKey(), result.first, result.second, ec);
|
||||
if (ec && ec != nudb::error::key_exists)
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
@@ -272,10 +249,10 @@ public:
|
||||
BatchWriteReport report{};
|
||||
report.writeCount = 1;
|
||||
auto const start = std::chrono::steady_clock::now();
|
||||
do_insert(no);
|
||||
doInsert(no);
|
||||
report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
scheduler_.onBatchWrite(report);
|
||||
scheduler.onBatchWrite(report);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -285,10 +262,10 @@ public:
|
||||
report.writeCount = batch.size();
|
||||
auto const start = std::chrono::steady_clock::now();
|
||||
for (auto const& e : batch)
|
||||
do_insert(e);
|
||||
doInsert(e);
|
||||
report.elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
scheduler_.onBatchWrite(report);
|
||||
scheduler.onBatchWrite(report);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -297,25 +274,25 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
for_each(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
{
|
||||
auto const dp = db_.dat_path();
|
||||
auto const kp = db_.key_path();
|
||||
auto const lp = db_.log_path();
|
||||
auto const dp = db.dat_path();
|
||||
auto const kp = db.key_path();
|
||||
auto const lp = db.log_path();
|
||||
// auto const appnum = db_.appnum();
|
||||
nudb::error_code ec;
|
||||
db_.close(ec);
|
||||
db.close(ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
nudb::visit(
|
||||
dp,
|
||||
[&](void const* key,
|
||||
std::size_t key_bytes,
|
||||
std::size_t keyBytes,
|
||||
void const* data,
|
||||
std::size_t size,
|
||||
nudb::error_code&) {
|
||||
nudb::detail::buffer bf;
|
||||
auto const result = nodeobject_decompress(data, size, bf);
|
||||
auto const result = nodeobjectDecompress(data, size, bf);
|
||||
DecodedBlob decoded(key, result.first, result.second);
|
||||
if (!decoded.wasOk())
|
||||
{
|
||||
@@ -328,7 +305,7 @@ public:
|
||||
ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
db_.open(dp, kp, lp, ec);
|
||||
db.open(dp, kp, lp, ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
@@ -342,24 +319,24 @@ public:
|
||||
void
|
||||
setDeletePath() override
|
||||
{
|
||||
deletePath_ = true;
|
||||
deletePath = true;
|
||||
}
|
||||
|
||||
void
|
||||
verify() override
|
||||
{
|
||||
auto const dp = db_.dat_path();
|
||||
auto const kp = db_.key_path();
|
||||
auto const lp = db_.log_path();
|
||||
auto const dp = db.dat_path();
|
||||
auto const kp = db.key_path();
|
||||
auto const lp = db.log_path();
|
||||
nudb::error_code ec;
|
||||
db_.close(ec);
|
||||
db.close(ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
nudb::verify_info vi;
|
||||
nudb::verify<nudb::xxhasher>(vi, dp, kp, 0, nudb::no_progress{}, ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
db_.open(dp, kp, lp, ec);
|
||||
db.open(dp, kp, lp, ec);
|
||||
if (ec)
|
||||
Throw<nudb::system_error>(ec);
|
||||
}
|
||||
@@ -382,7 +359,7 @@ private:
|
||||
std::size_t const blockSize = defaultSize;
|
||||
std::string blockSizeStr;
|
||||
|
||||
if (!get_if_exists(keyValues, "nudb_block_size", blockSizeStr))
|
||||
if (!getIfExists(keyValues, "nudb_block_size", blockSizeStr))
|
||||
{
|
||||
return blockSize; // Early return with default
|
||||
}
|
||||
@@ -460,7 +437,7 @@ public:
|
||||
void
|
||||
registerNuDBFactory(Manager& manager)
|
||||
{
|
||||
static NuDBFactory const instance{manager};
|
||||
static NuDBFactory const kInstance{manager};
|
||||
}
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl::NodeStore {
|
||||
|
||||
@@ -49,13 +47,7 @@ public:
|
||||
Status
|
||||
fetch(uint256 const&, std::shared_ptr<NodeObject>*) override
|
||||
{
|
||||
return notFound;
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
{
|
||||
return {};
|
||||
return Status::NotFound;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -74,7 +66,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
for_each(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
{
|
||||
}
|
||||
|
||||
@@ -128,7 +120,7 @@ public:
|
||||
void
|
||||
registerNullFactory(Manager& manager)
|
||||
{
|
||||
static NullFactory const instance{manager};
|
||||
static NullFactory const kInstance{manager};
|
||||
}
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if XRPL_ROCKSDB_AVAILABLE
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
@@ -57,7 +55,7 @@ public:
|
||||
|
||||
struct ThreadParams
|
||||
{
|
||||
ThreadParams(void (*f_)(void*), void* a_) : f(f_), a(a_)
|
||||
ThreadParams(void (*f)(void*), void* a) : f(f), a(a)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -66,7 +64,7 @@ public:
|
||||
};
|
||||
|
||||
static void
|
||||
thread_entry(void* ptr)
|
||||
threadEntry(void* ptr)
|
||||
{
|
||||
ThreadParams const* const p(reinterpret_cast<ThreadParams*>(ptr));
|
||||
auto const f = p->f;
|
||||
@@ -74,8 +72,8 @@ public:
|
||||
void* a(p->a);
|
||||
delete p;
|
||||
|
||||
static std::atomic<std::size_t> n;
|
||||
std::size_t const id(++n);
|
||||
static std::atomic<std::size_t> kN;
|
||||
std::size_t const id(++kN);
|
||||
beast::setCurrentThreadName("rocksdb #" + std::to_string(id));
|
||||
|
||||
f(a);
|
||||
@@ -85,7 +83,7 @@ public:
|
||||
StartThread(void (*f)(void*), void* a) override
|
||||
{
|
||||
ThreadParams* const p(new ThreadParams(f, a));
|
||||
EnvWrapper::StartThread(&RocksDBEnv::thread_entry, p);
|
||||
EnvWrapper::StartThread(&RocksDBEnv::threadEntry, p);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,16 +92,16 @@ public:
|
||||
class RocksDBBackend : public Backend, public BatchWriter::Callback
|
||||
{
|
||||
private:
|
||||
std::atomic<bool> m_deletePath;
|
||||
std::atomic<bool> deletePath_;
|
||||
|
||||
public:
|
||||
beast::Journal m_journal;
|
||||
size_t const m_keyBytes;
|
||||
BatchWriter m_batch;
|
||||
std::string m_name;
|
||||
std::unique_ptr<rocksdb::DB> m_db;
|
||||
int fdRequired_ = 2048;
|
||||
rocksdb::Options m_options;
|
||||
beast::Journal journal;
|
||||
size_t const keyBytes;
|
||||
BatchWriter batch;
|
||||
std::string name;
|
||||
std::unique_ptr<rocksdb::DB> db;
|
||||
int fdMinRequired = 2048;
|
||||
rocksdb::Options options;
|
||||
|
||||
RocksDBBackend(
|
||||
int keyBytes,
|
||||
@@ -111,90 +109,89 @@ public:
|
||||
Scheduler& scheduler,
|
||||
beast::Journal journal,
|
||||
RocksDBEnv* env)
|
||||
: m_deletePath(false), m_journal(journal), m_keyBytes(keyBytes), m_batch(*this, scheduler)
|
||||
: deletePath_(false), journal(journal), keyBytes(keyBytes), batch(*this, scheduler)
|
||||
{
|
||||
if (!get_if_exists(keyValues, "path", m_name))
|
||||
if (!getIfExists(keyValues, "path", name))
|
||||
Throw<std::runtime_error>("Missing path in RocksDBFactory backend");
|
||||
|
||||
rocksdb::BlockBasedTableOptions table_options;
|
||||
m_options.env = env;
|
||||
rocksdb::BlockBasedTableOptions tableOptions;
|
||||
options.env = env;
|
||||
|
||||
bool const hard_set = keyValues.exists("hard_set") && get<bool>(keyValues, "hard_set");
|
||||
bool const hardSet = keyValues.exists("hard_set") && get<bool>(keyValues, "hard_set");
|
||||
|
||||
if (keyValues.exists("cache_mb"))
|
||||
{
|
||||
auto size = get<int>(keyValues, "cache_mb");
|
||||
|
||||
if (!hard_set && size == 256)
|
||||
if (!hardSet && size == 256)
|
||||
size = 1024;
|
||||
|
||||
table_options.block_cache = rocksdb::NewLRUCache(megabytes(size));
|
||||
tableOptions.block_cache = rocksdb::NewLRUCache(megabytes(size));
|
||||
}
|
||||
|
||||
if (auto const v = get<int>(keyValues, "filter_bits"))
|
||||
{
|
||||
bool const filter_blocks =
|
||||
bool const filterBlocks =
|
||||
!keyValues.exists("filter_full") || (get<int>(keyValues, "filter_full") == 0);
|
||||
table_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(v, filter_blocks));
|
||||
tableOptions.filter_policy.reset(rocksdb::NewBloomFilterPolicy(v, filterBlocks));
|
||||
}
|
||||
|
||||
if (get_if_exists(keyValues, "open_files", m_options.max_open_files))
|
||||
if (getIfExists(keyValues, "open_files", options.max_open_files))
|
||||
{
|
||||
if (!hard_set && m_options.max_open_files == 2000)
|
||||
m_options.max_open_files = 8000;
|
||||
if (!hardSet && options.max_open_files == 2000)
|
||||
options.max_open_files = 8000;
|
||||
|
||||
fdRequired_ = m_options.max_open_files + 128;
|
||||
fdMinRequired = options.max_open_files + 128;
|
||||
}
|
||||
|
||||
if (keyValues.exists("file_size_mb"))
|
||||
{
|
||||
auto file_size_mb = get<int>(keyValues, "file_size_mb");
|
||||
auto fileSizeMb = get<int>(keyValues, "file_size_mb");
|
||||
|
||||
if (!hard_set && file_size_mb == 8)
|
||||
file_size_mb = 256;
|
||||
if (!hardSet && fileSizeMb == 8)
|
||||
fileSizeMb = 256;
|
||||
|
||||
m_options.target_file_size_base = megabytes(file_size_mb);
|
||||
m_options.max_bytes_for_level_base = 5 * m_options.target_file_size_base;
|
||||
m_options.write_buffer_size = 2 * m_options.target_file_size_base;
|
||||
options.target_file_size_base = megabytes(fileSizeMb);
|
||||
options.max_bytes_for_level_base = 5 * options.target_file_size_base;
|
||||
options.write_buffer_size = 2 * options.target_file_size_base;
|
||||
}
|
||||
|
||||
get_if_exists(keyValues, "file_size_mult", m_options.target_file_size_multiplier);
|
||||
getIfExists(keyValues, "file_size_mult", options.target_file_size_multiplier);
|
||||
|
||||
if (keyValues.exists("bg_threads"))
|
||||
{
|
||||
m_options.env->SetBackgroundThreads(
|
||||
get<int>(keyValues, "bg_threads"), rocksdb::Env::LOW);
|
||||
options.env->SetBackgroundThreads(get<int>(keyValues, "bg_threads"), rocksdb::Env::LOW);
|
||||
}
|
||||
|
||||
if (keyValues.exists("high_threads"))
|
||||
{
|
||||
auto const highThreads = get<int>(keyValues, "high_threads");
|
||||
m_options.env->SetBackgroundThreads(highThreads, rocksdb::Env::HIGH);
|
||||
options.env->SetBackgroundThreads(highThreads, rocksdb::Env::HIGH);
|
||||
|
||||
// If we have high-priority threads, presumably we want to
|
||||
// use them for background flushes
|
||||
if (highThreads > 0)
|
||||
m_options.max_background_flushes = highThreads;
|
||||
options.max_background_flushes = highThreads;
|
||||
}
|
||||
|
||||
m_options.compression = rocksdb::kSnappyCompression;
|
||||
options.compression = rocksdb::kSnappyCompression;
|
||||
|
||||
get_if_exists(keyValues, "block_size", table_options.block_size);
|
||||
getIfExists(keyValues, "block_size", tableOptions.block_size);
|
||||
|
||||
if (keyValues.exists("universal_compaction") &&
|
||||
(get<int>(keyValues, "universal_compaction") != 0))
|
||||
{
|
||||
m_options.compaction_style = rocksdb::kCompactionStyleUniversal;
|
||||
m_options.min_write_buffer_number_to_merge = 2;
|
||||
m_options.max_write_buffer_number = 6;
|
||||
m_options.write_buffer_size = 6 * m_options.target_file_size_base;
|
||||
options.compaction_style = rocksdb::kCompactionStyleUniversal;
|
||||
options.min_write_buffer_number_to_merge = 2;
|
||||
options.max_write_buffer_number = 6;
|
||||
options.write_buffer_size = 6 * options.target_file_size_base;
|
||||
}
|
||||
|
||||
if (keyValues.exists("bbt_options"))
|
||||
{
|
||||
rocksdb::ConfigOptions const config_options;
|
||||
rocksdb::ConfigOptions const configOptions;
|
||||
auto const s = rocksdb::GetBlockBasedTableOptionsFromString(
|
||||
config_options, table_options, get(keyValues, "bbt_options"), &table_options);
|
||||
configOptions, tableOptions, get(keyValues, "bbt_options"), &tableOptions);
|
||||
if (!s.ok())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
@@ -202,12 +199,12 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
m_options.table_factory.reset(NewBlockBasedTableFactory(table_options));
|
||||
options.table_factory.reset(NewBlockBasedTableFactory(tableOptions));
|
||||
|
||||
if (keyValues.exists("options"))
|
||||
{
|
||||
auto const s =
|
||||
rocksdb::GetOptionsFromString(m_options, get(keyValues, "options"), &m_options);
|
||||
rocksdb::GetOptionsFromString(options, get(keyValues, "options"), &options);
|
||||
if (!s.ok())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
@@ -216,10 +213,10 @@ public:
|
||||
}
|
||||
|
||||
std::string s1, s2;
|
||||
rocksdb::GetStringFromDBOptions(&s1, m_options, "; ");
|
||||
rocksdb::GetStringFromColumnFamilyOptions(&s2, m_options, "; ");
|
||||
JLOG(m_journal.debug()) << "RocksDB DBOptions: " << s1;
|
||||
JLOG(m_journal.debug()) << "RocksDB CFOptions: " << s2;
|
||||
rocksdb::GetStringFromDBOptions(&s1, options, "; ");
|
||||
rocksdb::GetStringFromColumnFamilyOptions(&s2, options, "; ");
|
||||
JLOG(journal.debug()) << "RocksDB DBOptions: " << s1;
|
||||
JLOG(journal.debug()) << "RocksDB CFOptions: " << s2;
|
||||
}
|
||||
|
||||
~RocksDBBackend() override
|
||||
@@ -230,42 +227,42 @@ public:
|
||||
void
|
||||
open(bool createIfMissing) override
|
||||
{
|
||||
if (m_db)
|
||||
if (db)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"xrpl::NodeStore::RocksDBBackend::open : database is already "
|
||||
"open");
|
||||
JLOG(m_journal.error()) << "database is already open";
|
||||
JLOG(journal.error()) << "database is already open";
|
||||
return;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
rocksdb::DB* db = nullptr;
|
||||
m_options.create_if_missing = createIfMissing;
|
||||
rocksdb::Status const status = rocksdb::DB::Open(m_options, m_name, &db);
|
||||
if (!status.ok() || (db == nullptr))
|
||||
rocksdb::DB* localDb = nullptr;
|
||||
options.create_if_missing = createIfMissing;
|
||||
rocksdb::Status const status = rocksdb::DB::Open(options, name, &localDb);
|
||||
if (!status.ok() || (localDb == nullptr))
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
std::string("Unable to open/create RocksDB: ") + status.ToString());
|
||||
}
|
||||
m_db.reset(db);
|
||||
db.reset(localDb);
|
||||
}
|
||||
|
||||
bool
|
||||
isOpen() override
|
||||
{
|
||||
return static_cast<bool>(m_db);
|
||||
return static_cast<bool>(db);
|
||||
}
|
||||
|
||||
void
|
||||
close() override
|
||||
{
|
||||
if (m_db)
|
||||
if (db)
|
||||
{
|
||||
m_db.reset();
|
||||
if (m_deletePath)
|
||||
db.reset();
|
||||
if (deletePath_)
|
||||
{
|
||||
boost::filesystem::path const dir = m_name;
|
||||
boost::filesystem::path const dir = name;
|
||||
boost::filesystem::remove_all(dir);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +271,7 @@ public:
|
||||
std::string
|
||||
getName() override
|
||||
{
|
||||
return m_name;
|
||||
return name;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -282,17 +279,17 @@ public:
|
||||
Status
|
||||
fetch(uint256 const& hash, std::shared_ptr<NodeObject>* pObject) override
|
||||
{
|
||||
XRPL_ASSERT(m_db, "xrpl::NodeStore::RocksDBBackend::fetch : non-null database");
|
||||
XRPL_ASSERT(db, "xrpl::NodeStore::RocksDBBackend::fetch : non-null database");
|
||||
pObject->reset();
|
||||
|
||||
Status status(ok);
|
||||
Status status = Status::Ok;
|
||||
|
||||
rocksdb::ReadOptions const options;
|
||||
rocksdb::Slice const slice(std::bit_cast<char const*>(hash.data()), m_keyBytes);
|
||||
rocksdb::Slice const slice(std::bit_cast<char const*>(hash.data()), keyBytes);
|
||||
|
||||
std::string string;
|
||||
|
||||
rocksdb::Status const getStatus = m_db->Get(options, slice, &string);
|
||||
rocksdb::Status const getStatus = db->Get(options, slice, &string);
|
||||
|
||||
if (getStatus.ok())
|
||||
{
|
||||
@@ -306,63 +303,42 @@ public:
|
||||
{
|
||||
// Decoding failed, probably corrupted!
|
||||
//
|
||||
status = dataCorrupt;
|
||||
status = Status::DataCorrupt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getStatus.IsCorruption())
|
||||
{
|
||||
status = dataCorrupt;
|
||||
status = Status::DataCorrupt;
|
||||
}
|
||||
else if (getStatus.IsNotFound())
|
||||
{
|
||||
status = notFound;
|
||||
status = Status::NotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = Status(customCode + unsafe_cast<int>(getStatus.code()));
|
||||
status = static_cast<Status>(
|
||||
static_cast<int>(Status::CustomCode) + unsafeCast<int>(getStatus.code()));
|
||||
|
||||
JLOG(m_journal.error()) << getStatus.ToString();
|
||||
JLOG(journal.error()) << getStatus.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::shared_ptr<NodeObject>>, Status>
|
||||
fetchBatch(std::vector<uint256> const& hashes) override
|
||||
{
|
||||
std::vector<std::shared_ptr<NodeObject>> results;
|
||||
results.reserve(hashes.size());
|
||||
for (auto const& h : hashes)
|
||||
{
|
||||
std::shared_ptr<NodeObject> nObj;
|
||||
Status const status = fetch(h, &nObj);
|
||||
if (status != ok)
|
||||
{
|
||||
results.push_back({});
|
||||
}
|
||||
else
|
||||
{
|
||||
results.push_back(nObj);
|
||||
}
|
||||
}
|
||||
|
||||
return {results, ok};
|
||||
}
|
||||
|
||||
void
|
||||
store(std::shared_ptr<NodeObject> const& object) override
|
||||
{
|
||||
m_batch.store(object);
|
||||
batch.store(object);
|
||||
}
|
||||
|
||||
void
|
||||
storeBatch(Batch const& batch) override
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
m_db,
|
||||
db,
|
||||
"xrpl::NodeStore::RocksDBBackend::storeBatch : non-null "
|
||||
"database");
|
||||
rocksdb::WriteBatch wb;
|
||||
@@ -372,13 +348,13 @@ public:
|
||||
EncodedBlob const encoded(e);
|
||||
|
||||
wb.Put(
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getKey()), m_keyBytes),
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getKey()), keyBytes),
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getData()), encoded.getSize()));
|
||||
}
|
||||
|
||||
rocksdb::WriteOptions const options;
|
||||
|
||||
auto ret = m_db->Write(options, &wb);
|
||||
auto ret = db->Write(options, &wb);
|
||||
|
||||
if (!ret.ok())
|
||||
Throw<std::runtime_error>("storeBatch failed: " + ret.ToString());
|
||||
@@ -390,16 +366,16 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
for_each(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
forEach(std::function<void(std::shared_ptr<NodeObject>)> f) override
|
||||
{
|
||||
XRPL_ASSERT(m_db, "xrpl::NodeStore::RocksDBBackend::for_each : non-null database");
|
||||
XRPL_ASSERT(db, "xrpl::NodeStore::RocksDBBackend::forEach : non-null database");
|
||||
rocksdb::ReadOptions const options;
|
||||
|
||||
std::unique_ptr<rocksdb::Iterator> it(m_db->NewIterator(options));
|
||||
std::unique_ptr<rocksdb::Iterator> it(db->NewIterator(options));
|
||||
|
||||
for (it->SeekToFirst(); it->Valid(); it->Next())
|
||||
{
|
||||
if (it->key().size() == m_keyBytes)
|
||||
if (it->key().size() == keyBytes)
|
||||
{
|
||||
DecodedBlob decoded(it->key().data(), it->value().data(), it->value().size());
|
||||
|
||||
@@ -410,14 +386,14 @@ public:
|
||||
else
|
||||
{
|
||||
// Uh oh, corrupted data!
|
||||
JLOG(m_journal.fatal()) << "Corrupt NodeObject #" << it->key().ToString(true);
|
||||
JLOG(journal.fatal()) << "Corrupt NodeObject #" << it->key().ToString(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// VFALCO NOTE What does it mean to find an
|
||||
// incorrectly sized key? Corruption?
|
||||
JLOG(m_journal.fatal()) << "Bad key size = " << it->key().size();
|
||||
JLOG(journal.fatal()) << "Bad key size = " << it->key().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,13 +401,13 @@ public:
|
||||
int
|
||||
getWriteLoad() override
|
||||
{
|
||||
return m_batch.getWriteLoad();
|
||||
return batch.getWriteLoad();
|
||||
}
|
||||
|
||||
void
|
||||
setDeletePath() override
|
||||
{
|
||||
m_deletePath = true;
|
||||
deletePath_ = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -446,7 +422,7 @@ public:
|
||||
[[nodiscard]] int
|
||||
fdRequired() const override
|
||||
{
|
||||
return fdRequired_;
|
||||
return fdMinRequired;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -458,7 +434,7 @@ private:
|
||||
Manager& manager_;
|
||||
|
||||
public:
|
||||
RocksDBEnv m_env;
|
||||
RocksDBEnv env;
|
||||
|
||||
RocksDBFactory(Manager& manager) : manager_(manager)
|
||||
{
|
||||
@@ -479,14 +455,14 @@ public:
|
||||
Scheduler& scheduler,
|
||||
beast::Journal journal) override
|
||||
{
|
||||
return std::make_unique<RocksDBBackend>(keyBytes, keyValues, scheduler, journal, &m_env);
|
||||
return std::make_unique<RocksDBBackend>(keyBytes, keyValues, scheduler, journal, &env);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
registerRocksDBFactory(Manager& manager)
|
||||
{
|
||||
static RocksDBFactory const instance{manager};
|
||||
static RocksDBFactory const kInstance{manager};
|
||||
}
|
||||
|
||||
} // namespace xrpl::NodeStore
|
||||
|
||||
@@ -29,7 +29,7 @@ Currency
|
||||
ammLPTCurrency(Asset const& asset1, Asset const& asset2)
|
||||
{
|
||||
// AMM LPToken is 0x03 plus 19 bytes of the hash
|
||||
std::int32_t constexpr AMMCurrencyCode = 0x03;
|
||||
static constexpr std::int32_t kAmmCurrencyCode = 0x03;
|
||||
auto const& [minA, maxA] = std::minmax(asset1, asset2);
|
||||
uint256 const hash = std::visit(
|
||||
[](auto&& issue1, auto&& issue2) {
|
||||
@@ -44,7 +44,7 @@ ammLPTCurrency(Asset const& asset1, Asset const& asset2)
|
||||
minA.value(),
|
||||
maxA.value());
|
||||
Currency currency;
|
||||
*currency.begin() = AMMCurrencyCode;
|
||||
*currency.begin() = kAmmCurrencyCode;
|
||||
std::copy(hash.begin(), hash.begin() + currency.size() - 1, currency.begin() + 1);
|
||||
return currency;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ invalidAMMAsset(Asset const& asset, std::optional<std::pair<Asset, Asset>> const
|
||||
{
|
||||
auto const err = asset.visit(
|
||||
[](MPTIssue const& issue) -> std::optional<NotTEC> {
|
||||
if (issue.getIssuer() == beast::zero)
|
||||
if (issue.getIssuer() == beast::kZero)
|
||||
return temBAD_MPT;
|
||||
return std::nullopt;
|
||||
},
|
||||
@@ -101,7 +101,7 @@ invalidAMMAmount(
|
||||
{
|
||||
if (auto const res = invalidAMMAsset(amount.asset(), pair))
|
||||
return res;
|
||||
if (amount < beast::zero || (!validZero && amount == beast::zero))
|
||||
if (amount < beast::kZero || (!validZero && amount == beast::kZero))
|
||||
return temBAD_AMOUNT;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -112,14 +112,13 @@ ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot)
|
||||
// It should be impossible for expiration to be < TOTAL_TIME_SLOT_SECS,
|
||||
// but check just to be safe
|
||||
auto const expiration = auctionSlot[sfExpiration];
|
||||
XRPL_ASSERT(
|
||||
expiration >= TOTAL_TIME_SLOT_SECS, "xrpl::ammAuctionTimeSlot : minimum expiration");
|
||||
if (expiration >= TOTAL_TIME_SLOT_SECS)
|
||||
XRPL_ASSERT(expiration >= kTotalTimeSlotSecs, "xrpl::ammAuctionTimeSlot : minimum expiration");
|
||||
if (expiration >= kTotalTimeSlotSecs)
|
||||
{
|
||||
if (auto const start = expiration - TOTAL_TIME_SLOT_SECS; current >= start)
|
||||
if (auto const start = expiration - kTotalTimeSlotSecs; current >= start)
|
||||
{
|
||||
if (auto const diff = current - start; diff < TOTAL_TIME_SLOT_SECS)
|
||||
return diff / AUCTION_SLOT_INTERVAL_DURATION;
|
||||
if (auto const diff = current - start; diff < kTotalTimeSlotSecs)
|
||||
return diff / kAuctionSlotIntervalDuration;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
|
||||
@@ -35,7 +35,7 @@ private:
|
||||
std::vector<CachedAccountID> cache_;
|
||||
|
||||
// We use a hash function designed to resist algorithmic complexity attacks
|
||||
hardened_hash<> hasher_;
|
||||
HardenedHash<> hasher_;
|
||||
|
||||
// 64 spinlocks, packed into a single 64-bit value
|
||||
std::atomic<std::uint64_t> locks_ = 0;
|
||||
@@ -53,10 +53,10 @@ public:
|
||||
{
|
||||
auto const index = hasher_(id) % cache_.size();
|
||||
|
||||
packed_spinlock sl(locks_, index % 64);
|
||||
PackedSpinlock sl(locks_, index % 64);
|
||||
|
||||
{
|
||||
std::lock_guard const lock(sl);
|
||||
std::scoped_lock const lock(sl);
|
||||
|
||||
// The check against the first character of the encoding ensures
|
||||
// that we don't mishandle the case of the all-zero account:
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
XRPL_ASSERT(ret.size() <= 38, "xrpl::detail::AccountIdCache : maximum result size");
|
||||
|
||||
{
|
||||
std::lock_guard const lock(sl);
|
||||
std::scoped_lock const lock(sl);
|
||||
cache_[index].id = id;
|
||||
std::strcpy(cache_[index].encoding, ret.c_str());
|
||||
}
|
||||
@@ -80,20 +80,20 @@ public:
|
||||
|
||||
} // namespace detail
|
||||
|
||||
static std::unique_ptr<detail::AccountIdCache> accountIdCache;
|
||||
static std::unique_ptr<detail::AccountIdCache> gAccountIdCache;
|
||||
|
||||
void
|
||||
initAccountIdCache(std::size_t count)
|
||||
{
|
||||
if (!accountIdCache && count != 0)
|
||||
accountIdCache = std::make_unique<detail::AccountIdCache>(count);
|
||||
if (!gAccountIdCache && count != 0)
|
||||
gAccountIdCache = std::make_unique<detail::AccountIdCache>(count);
|
||||
}
|
||||
|
||||
std::string
|
||||
toBase58(AccountID const& v)
|
||||
{
|
||||
if (accountIdCache)
|
||||
return accountIdCache->toBase58(v);
|
||||
if (gAccountIdCache)
|
||||
return gAccountIdCache->toBase58(v);
|
||||
|
||||
return encodeBase58Token(TokenType::AccountID, v.data(), v.size());
|
||||
}
|
||||
@@ -103,9 +103,9 @@ std::optional<AccountID>
|
||||
parseBase58(std::string const& s)
|
||||
{
|
||||
auto const result = decodeBase58Token(s, TokenType::AccountID);
|
||||
if (result.size() != AccountID::bytes)
|
||||
if (result.size() != AccountID::kBytes)
|
||||
return std::nullopt;
|
||||
return AccountID{result};
|
||||
return AccountID::fromRaw(result);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -146,29 +146,29 @@ parseBase58(std::string const& s)
|
||||
AccountID
|
||||
calcAccountID(PublicKey const& pk)
|
||||
{
|
||||
static_assert(AccountID::bytes == sizeof(ripesha_hasher::result_type));
|
||||
static_assert(AccountID::kBytes == sizeof(RipeshaHasher::result_type));
|
||||
|
||||
ripesha_hasher rsh;
|
||||
RipeshaHasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
return AccountID{static_cast<ripesha_hasher::result_type>(rsh)};
|
||||
return AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
xrpAccount()
|
||||
{
|
||||
static AccountID const account(beast::zero);
|
||||
return account;
|
||||
static AccountID const kAccount(beast::kZero);
|
||||
return kAccount;
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
noAccount()
|
||||
{
|
||||
static AccountID const account(1);
|
||||
return account;
|
||||
static AccountID const kAccount(1);
|
||||
return kAccount;
|
||||
}
|
||||
|
||||
bool
|
||||
to_issuer(AccountID& issuer, std::string const& s)
|
||||
toIssuer(AccountID& issuer, std::string const& s)
|
||||
{
|
||||
if (issuer.parseHex(s))
|
||||
return true;
|
||||
|
||||
@@ -30,7 +30,7 @@ Asset::getText() const
|
||||
}
|
||||
|
||||
void
|
||||
Asset::setJson(Json::Value& jv) const
|
||||
Asset::setJson(json::Value& jv) const
|
||||
{
|
||||
std::visit([&](auto&& issue) { issue.setJson(jv); }, issue_);
|
||||
}
|
||||
@@ -48,7 +48,7 @@ to_string(Asset const& asset)
|
||||
}
|
||||
|
||||
bool
|
||||
validJSONAsset(Json::Value const& jv)
|
||||
validJSONAsset(json::Value const& jv)
|
||||
{
|
||||
if (jv.isMember(jss::mpt_issuance_id))
|
||||
return !(jv.isMember(jss::currency) || jv.isMember(jss::issuer));
|
||||
@@ -56,7 +56,7 @@ validJSONAsset(Json::Value const& jv)
|
||||
}
|
||||
|
||||
Asset
|
||||
assetFromJson(Json::Value const& v)
|
||||
assetFromJson(json::Value const& v)
|
||||
{
|
||||
if (!v.isMember(jss::currency) && !v.isMember(jss::mpt_issuance_id))
|
||||
Throw<std::runtime_error>("assetFromJson must contain currency or mpt_issuance_id");
|
||||
|
||||
@@ -22,7 +22,8 @@ namespace {
|
||||
// and follow the format described at http://semver.org/
|
||||
//------------------------------------------------------------------------------
|
||||
// clang-format off
|
||||
char const* const versionString = "3.2.0-b0"
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
char const* const versionString = "3.2.0-rc3"
|
||||
// clang-format on
|
||||
;
|
||||
|
||||
@@ -66,31 +67,31 @@ buildVersionString()
|
||||
std::string const&
|
||||
getVersionString()
|
||||
{
|
||||
static std::string const value = [] {
|
||||
static std::string const kValue = [] {
|
||||
std::string const s = buildVersionString();
|
||||
|
||||
beast::SemanticVersion v;
|
||||
if (!v.parse(s) || v.print() != s)
|
||||
LogicError(s + ": Bad server version string");
|
||||
logicError(s + ": Bad server version string");
|
||||
return s;
|
||||
}();
|
||||
return value;
|
||||
return kValue;
|
||||
}
|
||||
|
||||
std::string const&
|
||||
getFullVersionString()
|
||||
{
|
||||
static std::string const value = systemName() + "-" + getVersionString();
|
||||
return value;
|
||||
static std::string const kValue = systemName() + "-" + getVersionString();
|
||||
return kValue;
|
||||
}
|
||||
|
||||
static constexpr std::uint64_t implementationVersionIdentifier = 0x183B'0000'0000'0000LLU;
|
||||
static constexpr std::uint64_t implementationVersionIdentifierMask = 0xFFFF'0000'0000'0000LLU;
|
||||
static constexpr std::uint64_t kImplementationVersionIdentifier = 0x183B'0000'0000'0000LLU;
|
||||
static constexpr std::uint64_t kImplementationVersionIdentifierMask = 0xFFFF'0000'0000'0000LLU;
|
||||
|
||||
std::uint64_t
|
||||
encodeSoftwareVersion(std::string_view versionStr)
|
||||
{
|
||||
std::uint64_t c = implementationVersionIdentifier;
|
||||
std::uint64_t c = kImplementationVersionIdentifier;
|
||||
|
||||
beast::SemanticVersion v;
|
||||
|
||||
@@ -154,14 +155,14 @@ encodeSoftwareVersion(std::string_view versionStr)
|
||||
std::uint64_t
|
||||
getEncodedVersion()
|
||||
{
|
||||
static std::uint64_t const cookie = {encodeSoftwareVersion(getVersionString())};
|
||||
return cookie;
|
||||
static std::uint64_t const kCookie = {encodeSoftwareVersion(getVersionString())};
|
||||
return kCookie;
|
||||
}
|
||||
|
||||
bool
|
||||
isXrpldVersion(std::uint64_t version)
|
||||
{
|
||||
return (version & implementationVersionIdentifierMask) == implementationVersionIdentifier;
|
||||
return (version & kImplementationVersionIdentifierMask) == kImplementationVersionIdentifier;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -30,78 +30,78 @@ namespace detail {
|
||||
// status code.
|
||||
|
||||
// clang-format off
|
||||
constexpr static ErrorInfo unorderedErrorInfos[]{
|
||||
{rpcACT_MALFORMED, "actMalformed", "Account malformed."},
|
||||
{rpcACT_NOT_FOUND, "actNotFound", "Account not found."},
|
||||
{rpcALREADY_MULTISIG, "alreadyMultisig", "Already multisigned."},
|
||||
{rpcALREADY_SINGLE_SIG, "alreadySingleSig", "Already single-signed."},
|
||||
{rpcAMENDMENT_BLOCKED, "amendmentBlocked", "Amendment blocked, need upgrade.", 503},
|
||||
{rpcEXPIRED_VALIDATOR_LIST, "unlBlocked", "Validator list expired.", 503},
|
||||
{rpcATX_DEPRECATED, "deprecated", "Use the new API or specify a ledger range.", 400},
|
||||
{rpcBAD_KEY_TYPE, "badKeyType", "Bad key type.", 400},
|
||||
{rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid.", 500},
|
||||
{rpcBAD_ISSUER, "badIssuer", "Issuer account malformed.", 400},
|
||||
{rpcBAD_MARKET, "badMarket", "No such market.", 404},
|
||||
{rpcBAD_SECRET, "badSecret", "Secret does not match account.", 403},
|
||||
{rpcBAD_SEED, "badSeed", "Disallowed seed.", 403},
|
||||
{rpcBAD_SYNTAX, "badSyntax", "Syntax error.", 400},
|
||||
{rpcCHANNEL_MALFORMED, "channelMalformed", "Payment channel is malformed.", 400},
|
||||
{rpcCHANNEL_AMT_MALFORMED, "channelAmtMalformed", "Payment channel amount is malformed.", 400},
|
||||
{rpcCOMMAND_MISSING, "commandMissing", "Missing command entry.", 400},
|
||||
{rpcDB_DESERIALIZATION, "dbDeserialization", "Database deserialization error.", 502},
|
||||
{rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed.", 400},
|
||||
{rpcDST_ACT_MISSING, "dstActMissing", "Destination account not provided.", 400},
|
||||
{rpcDST_ACT_NOT_FOUND, "dstActNotFound", "Destination account not found.", 404},
|
||||
{rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed.", 400},
|
||||
{rpcDST_AMT_MISSING, "dstAmtMissing", "Destination amount/currency/issuer is missing.", 400},
|
||||
{rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed.", 400},
|
||||
{rpcEXCESSIVE_LGR_RANGE, "excessiveLgrRange", "Ledger range exceeds 1000.", 400},
|
||||
{rpcFORBIDDEN, "forbidden", "Bad credentials.", 403},
|
||||
{rpcHIGH_FEE, "highFee", "Current transaction fee exceeds your limit.", 402},
|
||||
{rpcINTERNAL, "internal", "Internal error.", 500},
|
||||
{rpcINVALID_LGR_RANGE, "invalidLgrRange", "Ledger range is invalid.", 400},
|
||||
{rpcINVALID_PARAMS, "invalidParams", "Invalid parameters.", 400},
|
||||
{rpcINVALID_HOTWALLET, "invalidHotWallet", "Invalid hotwallet.", 400},
|
||||
{rpcISSUE_MALFORMED, "issueMalformed", "Issue is malformed.", 400},
|
||||
{rpcJSON_RPC, "json_rpc", "JSON-RPC transport error.", 500},
|
||||
{rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid.", 400},
|
||||
{rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed.", 400},
|
||||
{rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found.", 404},
|
||||
{rpcLGR_NOT_VALIDATED, "lgrNotValidated", "Ledger not validated.", 202},
|
||||
{rpcMASTER_DISABLED, "masterDisabled", "Master key is disabled.", 403},
|
||||
{rpcNOT_ENABLED, "notEnabled", "Not enabled in configuration.", 501},
|
||||
{rpcNOT_IMPL, "notImpl", "Not implemented.", 501},
|
||||
{rpcNOT_READY, "notReady", "Not ready to handle this request.", 503},
|
||||
{rpcNOT_SUPPORTED, "notSupported", "Operation not supported.", 501},
|
||||
{rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable.", 503},
|
||||
{rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable.", 503},
|
||||
{rpcNOT_SYNCED, "notSynced", "Not synced to the network.", 503},
|
||||
{rpcNO_EVENTS, "noEvents", "Current transport does not support events.", 405},
|
||||
{rpcNO_NETWORK, "noNetwork", "Not synced to the network.", 503},
|
||||
{rpcWRONG_NETWORK, "wrongNetwork", "Wrong network.", 503},
|
||||
{rpcNO_PERMISSION, "noPermission", "You don't have permission for this command.", 401},
|
||||
{rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress.", 404},
|
||||
{rpcOBJECT_NOT_FOUND, "objectNotFound", "The requested object was not found.", 404},
|
||||
{rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed.", 400},
|
||||
{rpcSENDMAX_MALFORMED, "sendMaxMalformed", "SendMax amount malformed.", 400},
|
||||
{rpcSIGNING_MALFORMED, "signingMalformed", "Signing of transaction is malformed.", 400},
|
||||
{rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server.", 429},
|
||||
{rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed.", 400},
|
||||
{rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided.", 400},
|
||||
{rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found.", 404},
|
||||
{rpcDELEGATE_ACT_NOT_FOUND, "delegateActNotFound", "Delegate account not found.", 404},
|
||||
{rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed.", 400},
|
||||
{rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed.", 400},
|
||||
{rpcSTREAM_MALFORMED, "malformedStream", "Stream malformed.", 400},
|
||||
{rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now.", 503},
|
||||
{rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found.", 404},
|
||||
{rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method.", 405},
|
||||
{rpcORACLE_MALFORMED, "oracleMalformed", "Oracle request is malformed.", 400},
|
||||
{rpcBAD_CREDENTIALS, "badCredentials", "Credentials do not exist, are not accepted, or have expired.", 400},
|
||||
{rpcTX_SIGNED, "transactionSigned", "Transaction should not be signed.", 400},
|
||||
{rpcDOMAIN_MALFORMED, "domainMalformed", "Domain is malformed.", 400},
|
||||
{rpcENTRY_NOT_FOUND, "entryNotFound", "Entry not found.", 400},
|
||||
{rpcUNEXPECTED_LEDGER_TYPE, "unexpectedLedgerType", "Unexpected ledger type.", 400},
|
||||
static constexpr ErrorInfo kUnorderedErrorInfos[]{
|
||||
{RpcActMalformed, "actMalformed", "Account malformed."},
|
||||
{RpcActNotFound, "actNotFound", "Account not found."},
|
||||
{RpcAlreadyMultisig, "alreadyMultisig", "Already multisigned."},
|
||||
{RpcAlreadySingleSig, "alreadySingleSig", "Already single-signed."},
|
||||
{RpcAmendmentBlocked, "amendmentBlocked", "Amendment blocked, need upgrade.", 503},
|
||||
{RpcExpiredValidatorList, "unlBlocked", "Validator list expired.", 503},
|
||||
{RpcAtxDeprecated, "deprecated", "Use the new API or specify a ledger range.", 400},
|
||||
{RpcBadKeyType, "badKeyType", "Bad key type.", 400},
|
||||
{RpcBadFeature, "badFeature", "Feature unknown or invalid.", 500},
|
||||
{RpcBadIssuer, "badIssuer", "Issuer account malformed.", 400},
|
||||
{RpcBadMarket, "badMarket", "No such market.", 404},
|
||||
{RpcBadSecret, "badSecret", "Secret does not match account.", 403},
|
||||
{RpcBadSeed, "badSeed", "Disallowed seed.", 403},
|
||||
{RpcBadSyntax, "badSyntax", "Syntax error.", 400},
|
||||
{RpcChannelMalformed, "channelMalformed", "Payment channel is malformed.", 400},
|
||||
{RpcChannelAmtMalformed, "channelAmtMalformed", "Payment channel amount is malformed.", 400},
|
||||
{RpcCommandMissing, "commandMissing", "Missing command entry.", 400},
|
||||
{RpcDbDeserialization, "dbDeserialization", "Database deserialization error.", 502},
|
||||
{RpcDstActMalformed, "dstActMalformed", "Destination account is malformed.", 400},
|
||||
{RpcDstActMissing, "dstActMissing", "Destination account not provided.", 400},
|
||||
{RpcDstActNotFound, "dstActNotFound", "Destination account not found.", 404},
|
||||
{RpcDstAmtMalformed, "dstAmtMalformed", "Destination amount/currency/issuer is malformed.", 400},
|
||||
{RpcDstAmtMissing, "dstAmtMissing", "Destination amount/currency/issuer is missing.", 400},
|
||||
{RpcDstIsrMalformed, "dstIsrMalformed", "Destination issuer is malformed.", 400},
|
||||
{RpcExcessiveLgrRange, "excessiveLgrRange", "Ledger range exceeds 1000.", 400},
|
||||
{RpcForbidden, "forbidden", "Bad credentials.", 403},
|
||||
{RpcHighFee, "highFee", "Current transaction fee exceeds your limit.", 402},
|
||||
{RpcInternal, "internal", "Internal error.", 500},
|
||||
{RpcInvalidLgrRange, "invalidLgrRange", "Ledger range is invalid.", 400},
|
||||
{RpcInvalidParams, "invalidParams", "Invalid parameters.", 400},
|
||||
{RpcInvalidHotwallet, "invalidHotWallet", "Invalid hotwallet.", 400},
|
||||
{RpcIssueMalformed, "issueMalformed", "Issue is malformed.", 400},
|
||||
{RpcJsonRpc, "json_rpc", "JSON-RPC transport error.", 500},
|
||||
{RpcLgrIdxsInvalid, "lgrIdxsInvalid", "Ledger indexes invalid.", 400},
|
||||
{RpcLgrIdxMalformed, "lgrIdxMalformed", "Ledger index malformed.", 400},
|
||||
{RpcLgrNotFound, "lgrNotFound", "Ledger not found.", 404},
|
||||
{RpcLgrNotValidated, "lgrNotValidated", "Ledger not validated.", 202},
|
||||
{RpcMasterDisabled, "masterDisabled", "Master key is disabled.", 403},
|
||||
{RpcNotEnabled, "notEnabled", "Not enabled in configuration.", 501},
|
||||
{RpcNotImpl, "notImpl", "Not implemented.", 501},
|
||||
{RpcNotReady, "notReady", "Not ready to handle this request.", 503},
|
||||
{RpcNotSupported, "notSupported", "Operation not supported.", 501},
|
||||
{RpcNoClosed, "noClosed", "Closed ledger is unavailable.", 503},
|
||||
{RpcNoCurrent, "noCurrent", "Current ledger is unavailable.", 503},
|
||||
{RpcNotSynced, "notSynced", "Not synced to the network.", 503},
|
||||
{RpcNoEvents, "noEvents", "Current transport does not support events.", 405},
|
||||
{RpcNoNetwork, "noNetwork", "Not synced to the network.", 503},
|
||||
{RpcWrongNetwork, "wrongNetwork", "Wrong network.", 503},
|
||||
{RpcNoPermission, "noPermission", "You don't have permission for this command.", 401},
|
||||
{RpcNoPfRequest, "noPathRequest", "No pathfinding request in progress.", 404},
|
||||
{RpcObjectNotFound, "objectNotFound", "The requested object was not found.", 404},
|
||||
{RpcPublicMalformed, "publicMalformed", "Public key is malformed.", 400},
|
||||
{RpcSendmaxMalformed, "sendMaxMalformed", "SendMax amount malformed.", 400},
|
||||
{RpcSigningMalformed, "signingMalformed", "Signing of transaction is malformed.", 400},
|
||||
{RpcSlowDown, "slowDown", "You are placing too much load on the server.", 429},
|
||||
{RpcSrcActMalformed, "srcActMalformed", "Source account is malformed.", 400},
|
||||
{RpcSrcActMissing, "srcActMissing", "Source account not provided.", 400},
|
||||
{RpcSrcActNotFound, "srcActNotFound", "Source account not found.", 404},
|
||||
{RpcDelegateActNotFound, "delegateActNotFound", "Delegate account not found.", 404},
|
||||
{RpcSrcCurMalformed, "srcCurMalformed", "Source currency is malformed.", 400},
|
||||
{RpcSrcIsrMalformed, "srcIsrMalformed", "Source issuer is malformed.", 400},
|
||||
{RpcStreamMalformed, "malformedStream", "Stream malformed.", 400},
|
||||
{RpcTooBusy, "tooBusy", "The server is too busy to help you now.", 503},
|
||||
{RpcTxnNotFound, "txnNotFound", "Transaction not found.", 404},
|
||||
{RpcUnknownCommand, "unknownCmd", "Unknown method.", 405},
|
||||
{RpcOracleMalformed, "oracleMalformed", "Oracle request is malformed.", 400},
|
||||
{RpcBadCredentials, "badCredentials", "Credentials do not exist, are not accepted, or have expired.", 400},
|
||||
{RpcTxSigned, "transactionSigned", "Transaction should not be signed.", 400},
|
||||
{RpcDomainMalformed, "domainMalformed", "Domain is malformed.", 400},
|
||||
{RpcEntryNotFound, "entryNotFound", "Entry not found.", 400},
|
||||
{RpcUnexpectedLedgerType, "unexpectedLedgerType", "Unexpected ledger type.", 400},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -115,14 +115,14 @@ sortErrorInfos(ErrorInfo const (&unordered)[N]) -> std::array<ErrorInfo, M>
|
||||
|
||||
for (ErrorInfo const& info : unordered)
|
||||
{
|
||||
if (info.code <= rpcSUCCESS || info.code > rpcLAST)
|
||||
if (info.code <= RpcSuccess || info.code > RpcLast)
|
||||
throw(std::out_of_range("Invalid error_code_i"));
|
||||
|
||||
// The first valid code follows rpcSUCCESS immediately.
|
||||
static_assert(rpcSUCCESS == 0, "Unexpected error_code_i layout.");
|
||||
static_assert(RpcSuccess == 0, "Unexpected error_code_i layout.");
|
||||
int const index{info.code - 1};
|
||||
|
||||
if (ret[index].code != rpcUNKNOWN)
|
||||
if (ret[index].code != RpcUnknown)
|
||||
throw(std::invalid_argument("Duplicate error_code_i in list"));
|
||||
|
||||
ret[index] = info;
|
||||
@@ -134,18 +134,18 @@ sortErrorInfos(ErrorInfo const (&unordered)[N]) -> std::array<ErrorInfo, M>
|
||||
// It's okay for there to be missing entries; they will contain the code
|
||||
// rpcUNKNOWN. But other than that all entries should match their index.
|
||||
int codeCount{0};
|
||||
int expect{rpcBAD_SYNTAX - 1};
|
||||
int expect{RpcBadSyntax - 1};
|
||||
for (ErrorInfo const& info : ret)
|
||||
{
|
||||
++expect;
|
||||
if (info.code == rpcUNKNOWN)
|
||||
if (info.code == RpcUnknown)
|
||||
continue;
|
||||
|
||||
if (info.code != expect)
|
||||
throw(std::invalid_argument("Empty error_code_i in list"));
|
||||
++codeCount;
|
||||
}
|
||||
if (expect != rpcLAST)
|
||||
if (expect != RpcLast)
|
||||
throw(std::invalid_argument("Insufficient list entries"));
|
||||
if (codeCount != N)
|
||||
throw(std::invalid_argument("Bad handling of unorderedErrorInfos"));
|
||||
@@ -153,74 +153,74 @@ sortErrorInfos(ErrorInfo const (&unordered)[N]) -> std::array<ErrorInfo, M>
|
||||
return ret;
|
||||
}
|
||||
|
||||
constexpr auto sortedErrorInfos{sortErrorInfos<rpcLAST>(unorderedErrorInfos)};
|
||||
constexpr auto kSortedErrorInfos{sortErrorInfos<RpcLast>(kUnorderedErrorInfos)};
|
||||
|
||||
constexpr ErrorInfo unknownError;
|
||||
constexpr ErrorInfo kUnknownError;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
inject_error(error_code_i code, Json::Value& json)
|
||||
injectError(ErrorCodeI code, json::Value& json)
|
||||
{
|
||||
ErrorInfo const& info(get_error_info(code));
|
||||
ErrorInfo const& info(getErrorInfo(code));
|
||||
json[jss::error] = info.token;
|
||||
json[jss::error_code] = info.code;
|
||||
json[jss::error_message] = info.message;
|
||||
}
|
||||
|
||||
void
|
||||
inject_error(error_code_i code, std::string const& message, Json::Value& json)
|
||||
injectError(ErrorCodeI code, std::string const& message, json::Value& json)
|
||||
{
|
||||
ErrorInfo const& info(get_error_info(code));
|
||||
ErrorInfo const& info(getErrorInfo(code));
|
||||
json[jss::error] = info.token;
|
||||
json[jss::error_code] = info.code;
|
||||
json[jss::error_message] = message;
|
||||
}
|
||||
|
||||
ErrorInfo const&
|
||||
get_error_info(error_code_i code)
|
||||
getErrorInfo(ErrorCodeI code)
|
||||
{
|
||||
if (code <= rpcSUCCESS || code > rpcLAST)
|
||||
return detail::unknownError;
|
||||
return detail::sortedErrorInfos[code - 1];
|
||||
if (code <= RpcSuccess || code > RpcLast)
|
||||
return detail::kUnknownError;
|
||||
return detail::kSortedErrorInfos[code - 1];
|
||||
}
|
||||
|
||||
Json::Value
|
||||
make_error(error_code_i code)
|
||||
json::Value
|
||||
makeError(ErrorCodeI code)
|
||||
{
|
||||
Json::Value json;
|
||||
inject_error(code, json);
|
||||
json::Value json;
|
||||
injectError(code, json);
|
||||
return json;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
make_error(error_code_i code, std::string const& message)
|
||||
json::Value
|
||||
makeError(ErrorCodeI code, std::string const& message)
|
||||
{
|
||||
Json::Value json;
|
||||
inject_error(code, message, json);
|
||||
json::Value json;
|
||||
injectError(code, message, json);
|
||||
return json;
|
||||
}
|
||||
|
||||
bool
|
||||
contains_error(Json::Value const& json)
|
||||
containsError(json::Value const& json)
|
||||
{
|
||||
return json.isObject() && json.isMember(jss::error);
|
||||
}
|
||||
|
||||
int
|
||||
error_code_http_status(error_code_i code)
|
||||
errorCodeHttpStatus(ErrorCodeI code)
|
||||
{
|
||||
return get_error_info(code).http_status;
|
||||
return getErrorInfo(code).httpStatus;
|
||||
}
|
||||
|
||||
} // namespace RPC
|
||||
|
||||
std::string
|
||||
rpcErrorString(Json::Value const& jv)
|
||||
rpcErrorString(json::Value const& jv)
|
||||
{
|
||||
XRPL_ASSERT(RPC::contains_error(jv), "xrpl::RPC::rpcErrorString : input contains an error");
|
||||
XRPL_ASSERT(RPC::containsError(jv), "xrpl::RPC::rpcErrorString : input contains an error");
|
||||
return jv[jss::error].asString() + jv[jss::error_message].asString();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
inline std::size_t
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
hash_value(xrpl::uint256 const& feature)
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
@@ -34,7 +35,7 @@ hash_value(xrpl::uint256 const& feature)
|
||||
|
||||
namespace {
|
||||
|
||||
enum class Supported : bool { no = false, yes };
|
||||
enum class Supported : bool { No = false, Yes };
|
||||
|
||||
// *NOTE*
|
||||
//
|
||||
@@ -71,45 +72,45 @@ class FeatureCollections
|
||||
uint256 feature;
|
||||
|
||||
Feature() = delete;
|
||||
explicit Feature(std::string name_, uint256 const& feature_)
|
||||
: name(std::move(name_)), feature(feature_)
|
||||
explicit Feature(std::string name, uint256 const& feature)
|
||||
: name(std::move(name)), feature(feature)
|
||||
{
|
||||
}
|
||||
|
||||
// These structs are used by the `features` multi_index_container to
|
||||
// provide access to the features collection by size_t index, string
|
||||
// name, and uint256 feature identifier
|
||||
struct byIndex
|
||||
struct ByIndex
|
||||
{
|
||||
};
|
||||
struct byName
|
||||
struct ByName
|
||||
{
|
||||
};
|
||||
struct byFeature
|
||||
struct ByFeature
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
// Intermediate types to help with readability
|
||||
template <class tag, typename Type, Type Feature::* PtrToMember>
|
||||
template <class Tag, typename Type, Type Feature::* PtrToMember>
|
||||
using feature_hashed_unique = boost::multi_index::hashed_unique<
|
||||
boost::multi_index::tag<tag>,
|
||||
boost::multi_index::tag<Tag>,
|
||||
boost::multi_index::member<Feature, Type, PtrToMember>>;
|
||||
|
||||
// Intermediate types to help with readability
|
||||
using feature_indexing = boost::multi_index::indexed_by<
|
||||
boost::multi_index::random_access<boost::multi_index::tag<Feature::byIndex>>,
|
||||
feature_hashed_unique<Feature::byFeature, uint256, &Feature::feature>,
|
||||
feature_hashed_unique<Feature::byName, std::string, &Feature::name>>;
|
||||
boost::multi_index::random_access<boost::multi_index::tag<Feature::ByIndex>>,
|
||||
feature_hashed_unique<Feature::ByFeature, uint256, &Feature::feature>,
|
||||
feature_hashed_unique<Feature::ByName, std::string, &Feature::name>>;
|
||||
|
||||
// This multi_index_container provides access to the features collection by
|
||||
// name, index, and uint256 feature identifier
|
||||
boost::multi_index::multi_index_container<Feature, feature_indexing> features;
|
||||
std::map<std::string, AmendmentSupport> all;
|
||||
std::map<std::string, VoteBehavior> supported;
|
||||
std::size_t upVotes = 0;
|
||||
std::size_t downVotes = 0;
|
||||
mutable std::atomic<bool> readOnly = false;
|
||||
boost::multi_index::multi_index_container<Feature, feature_indexing> features_;
|
||||
std::map<std::string, AmendmentSupport> all_;
|
||||
std::map<std::string, VoteBehavior> supported_;
|
||||
std::size_t upVotes_ = 0;
|
||||
std::size_t downVotes_ = 0;
|
||||
mutable std::atomic<bool> readOnly_ = false;
|
||||
|
||||
// These helper functions provide access to the features collection by name,
|
||||
// index, and uint256 feature identifier, so the details of
|
||||
@@ -117,31 +118,31 @@ class FeatureCollections
|
||||
Feature const&
|
||||
getByIndex(size_t i) const
|
||||
{
|
||||
if (i >= features.size())
|
||||
LogicError("Invalid FeatureBitset index");
|
||||
auto const& sequence = features.get<Feature::byIndex>();
|
||||
if (i >= features_.size())
|
||||
logicError("Invalid FeatureBitset index");
|
||||
auto const& sequence = features_.get<Feature::ByIndex>();
|
||||
return sequence[i];
|
||||
}
|
||||
size_t
|
||||
getIndex(Feature const& feature) const
|
||||
{
|
||||
auto const& sequence = features.get<Feature::byIndex>();
|
||||
auto const it_to = sequence.iterator_to(feature);
|
||||
return it_to - sequence.begin();
|
||||
auto const& sequence = features_.get<Feature::ByIndex>();
|
||||
auto const itTo = sequence.iterator_to(feature);
|
||||
return itTo - sequence.begin();
|
||||
}
|
||||
Feature const*
|
||||
getByFeature(uint256 const& feature) const
|
||||
{
|
||||
auto const& feature_index = features.get<Feature::byFeature>();
|
||||
auto const feature_it = feature_index.find(feature);
|
||||
return feature_it == feature_index.end() ? nullptr : &*feature_it;
|
||||
auto const& featureIndex = features_.get<Feature::ByFeature>();
|
||||
auto const featureIt = featureIndex.find(feature);
|
||||
return featureIt == featureIndex.end() ? nullptr : &*featureIt;
|
||||
}
|
||||
Feature const*
|
||||
getByName(std::string const& name) const
|
||||
{
|
||||
auto const& name_index = features.get<Feature::byName>();
|
||||
auto const name_it = name_index.find(name);
|
||||
return name_it == name_index.end() ? nullptr : &*name_it;
|
||||
auto const& nameIndex = features_.get<Feature::ByName>();
|
||||
auto const nameIt = nameIndex.find(name);
|
||||
return nameIt == nameIndex.end() ? nullptr : &*nameIt;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -170,7 +171,7 @@ public:
|
||||
std::map<std::string, AmendmentSupport> const&
|
||||
allAmendments() const
|
||||
{
|
||||
return all;
|
||||
return all_;
|
||||
}
|
||||
|
||||
/** Amendments that this server supports.
|
||||
@@ -179,21 +180,21 @@ public:
|
||||
std::map<std::string, VoteBehavior> const&
|
||||
supportedAmendments() const
|
||||
{
|
||||
return supported;
|
||||
return supported_;
|
||||
}
|
||||
|
||||
/** Amendments that this server WON'T vote for by default. */
|
||||
std::size_t
|
||||
numDownVotedAmendments() const
|
||||
{
|
||||
return downVotes;
|
||||
return downVotes_;
|
||||
}
|
||||
|
||||
/** Amendments that this server WILL vote for by default. */
|
||||
std::size_t
|
||||
numUpVotedAmendments() const
|
||||
{
|
||||
return upVotes;
|
||||
return upVotes_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -201,14 +202,14 @@ public:
|
||||
|
||||
FeatureCollections::FeatureCollections()
|
||||
{
|
||||
features.reserve(xrpl::detail::numFeatures);
|
||||
features_.reserve(xrpl::detail::kNumFeatures);
|
||||
}
|
||||
|
||||
std::optional<uint256>
|
||||
FeatureCollections::getRegisteredFeature(std::string const& name) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
readOnly.load(), "xrpl::FeatureCollections::getRegisteredFeature : startup completed");
|
||||
readOnly_.load(), "xrpl::FeatureCollections::getRegisteredFeature : startup completed");
|
||||
Feature const* feature = getByName(name);
|
||||
if (feature != nullptr)
|
||||
return feature->feature;
|
||||
@@ -219,61 +220,62 @@ void
|
||||
check(bool condition, char const* logicErrorMessage)
|
||||
{
|
||||
if (!condition)
|
||||
LogicError(logicErrorMessage);
|
||||
logicError(logicErrorMessage);
|
||||
}
|
||||
|
||||
uint256
|
||||
FeatureCollections::registerFeature(std::string const& name, Supported support, VoteBehavior vote)
|
||||
{
|
||||
check(!readOnly, "Attempting to register a feature after startup.");
|
||||
check(!readOnly_, "Attempting to register a feature after startup.");
|
||||
check(
|
||||
support == Supported::yes || vote == VoteBehavior::DefaultNo,
|
||||
support == Supported::Yes || vote == VoteBehavior::DefaultNo,
|
||||
"Invalid feature parameters. Must be supported to be up-voted.");
|
||||
Feature const* i = getByName(name);
|
||||
if (i == nullptr)
|
||||
{
|
||||
check(features.size() < detail::numFeatures, "More features defined than allocated.");
|
||||
check(features_.size() < detail::kNumFeatures, "More features defined than allocated.");
|
||||
|
||||
auto const f = sha512Half(Slice(name.data(), name.size()));
|
||||
|
||||
features.emplace_back(name, f);
|
||||
features_.emplace_back(name, f);
|
||||
|
||||
auto const getAmendmentSupport = [=]() {
|
||||
if (vote == VoteBehavior::Obsolete)
|
||||
return AmendmentSupport::Retired;
|
||||
return support == Supported::yes ? AmendmentSupport::Supported
|
||||
return support == Supported::Yes ? AmendmentSupport::Supported
|
||||
: AmendmentSupport::Unsupported;
|
||||
};
|
||||
all.emplace(name, getAmendmentSupport());
|
||||
all_.emplace(name, getAmendmentSupport());
|
||||
|
||||
if (support == Supported::yes)
|
||||
if (support == Supported::Yes)
|
||||
{
|
||||
supported.emplace(name, vote);
|
||||
supported_.emplace(name, vote);
|
||||
|
||||
if (vote == VoteBehavior::DefaultYes)
|
||||
{
|
||||
++upVotes;
|
||||
++upVotes_;
|
||||
}
|
||||
else
|
||||
{
|
||||
++downVotes;
|
||||
++downVotes_;
|
||||
}
|
||||
}
|
||||
check(upVotes + downVotes == supported.size(), "Feature counting logic broke");
|
||||
check(supported.size() <= features.size(), "More supported features than defined features");
|
||||
check(features.size() == all.size(), "The 'all' features list is populated incorrectly");
|
||||
check(upVotes_ + downVotes_ == supported_.size(), "Feature counting logic broke");
|
||||
check(
|
||||
supported_.size() <= features_.size(), "More supported features than defined features");
|
||||
check(features_.size() == all_.size(), "The 'all' features list is populated incorrectly");
|
||||
return f;
|
||||
}
|
||||
|
||||
// Each feature should only be registered once
|
||||
LogicError("Duplicate feature registration");
|
||||
logicError("Duplicate feature registration");
|
||||
}
|
||||
|
||||
/** Tell FeatureCollections when registration is complete. */
|
||||
bool
|
||||
FeatureCollections::registrationIsDone()
|
||||
{
|
||||
readOnly = true;
|
||||
readOnly_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -281,11 +283,11 @@ size_t
|
||||
FeatureCollections::featureToBitsetIndex(uint256 const& f) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
readOnly.load(), "xrpl::FeatureCollections::featureToBitsetIndex : startup completed");
|
||||
readOnly_.load(), "xrpl::FeatureCollections::featureToBitsetIndex : startup completed");
|
||||
|
||||
Feature const* feature = getByFeature(f);
|
||||
if (feature == nullptr)
|
||||
LogicError("Invalid Feature ID");
|
||||
logicError("Invalid Feature ID");
|
||||
|
||||
return getIndex(*feature);
|
||||
}
|
||||
@@ -294,7 +296,7 @@ uint256 const&
|
||||
FeatureCollections::bitsetIndexToFeature(size_t i) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
readOnly.load(), "xrpl::FeatureCollections::bitsetIndexToFeature : startup completed");
|
||||
readOnly_.load(), "xrpl::FeatureCollections::bitsetIndexToFeature : startup completed");
|
||||
Feature const& feature = getByIndex(i);
|
||||
return feature.feature;
|
||||
}
|
||||
@@ -302,12 +304,12 @@ FeatureCollections::bitsetIndexToFeature(size_t i) const
|
||||
std::string
|
||||
FeatureCollections::featureToName(uint256 const& f) const
|
||||
{
|
||||
XRPL_ASSERT(readOnly.load(), "xrpl::FeatureCollections::featureToName : startup completed");
|
||||
XRPL_ASSERT(readOnly_.load(), "xrpl::FeatureCollections::featureToName : startup completed");
|
||||
Feature const* feature = getByFeature(f);
|
||||
return (feature != nullptr) ? feature->name : to_string(f);
|
||||
}
|
||||
|
||||
FeatureCollections featureCollections;
|
||||
FeatureCollections gFeatureCollections;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -315,7 +317,7 @@ FeatureCollections featureCollections;
|
||||
std::map<std::string, AmendmentSupport> const&
|
||||
allAmendments()
|
||||
{
|
||||
return featureCollections.allAmendments();
|
||||
return gFeatureCollections.allAmendments();
|
||||
}
|
||||
|
||||
/** Amendments that this server supports.
|
||||
@@ -324,21 +326,21 @@ allAmendments()
|
||||
std::map<std::string, VoteBehavior> const&
|
||||
detail::supportedAmendments()
|
||||
{
|
||||
return featureCollections.supportedAmendments();
|
||||
return gFeatureCollections.supportedAmendments();
|
||||
}
|
||||
|
||||
/** Amendments that this server won't vote for by default. */
|
||||
std::size_t
|
||||
detail::numDownVotedAmendments()
|
||||
{
|
||||
return featureCollections.numDownVotedAmendments();
|
||||
return gFeatureCollections.numDownVotedAmendments();
|
||||
}
|
||||
|
||||
/** Amendments that this server will vote for by default. */
|
||||
std::size_t
|
||||
detail::numUpVotedAmendments()
|
||||
{
|
||||
return featureCollections.numUpVotedAmendments();
|
||||
return gFeatureCollections.numUpVotedAmendments();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -346,13 +348,13 @@ detail::numUpVotedAmendments()
|
||||
std::optional<uint256>
|
||||
getRegisteredFeature(std::string const& name)
|
||||
{
|
||||
return featureCollections.getRegisteredFeature(name);
|
||||
return gFeatureCollections.getRegisteredFeature(name);
|
||||
}
|
||||
|
||||
uint256
|
||||
registerFeature(std::string const& name, Supported support, VoteBehavior vote)
|
||||
{
|
||||
return featureCollections.registerFeature(name, support, vote);
|
||||
return gFeatureCollections.registerFeature(name, support, vote);
|
||||
}
|
||||
|
||||
// Retired features are in the ledger and have no code controlled by the
|
||||
@@ -360,32 +362,32 @@ registerFeature(std::string const& name, Supported support, VoteBehavior vote)
|
||||
uint256
|
||||
retireFeature(std::string const& name)
|
||||
{
|
||||
return registerFeature(name, Supported::yes, VoteBehavior::Obsolete);
|
||||
return registerFeature(name, Supported::Yes, VoteBehavior::Obsolete);
|
||||
}
|
||||
|
||||
/** Tell FeatureCollections when registration is complete. */
|
||||
bool
|
||||
registrationIsDone()
|
||||
{
|
||||
return featureCollections.registrationIsDone();
|
||||
return gFeatureCollections.registrationIsDone();
|
||||
}
|
||||
|
||||
size_t
|
||||
featureToBitsetIndex(uint256 const& f)
|
||||
{
|
||||
return featureCollections.featureToBitsetIndex(f);
|
||||
return gFeatureCollections.featureToBitsetIndex(f);
|
||||
}
|
||||
|
||||
uint256
|
||||
bitsetIndexToFeature(size_t i)
|
||||
{
|
||||
return featureCollections.bitsetIndexToFeature(i);
|
||||
return gFeatureCollections.bitsetIndexToFeature(i);
|
||||
}
|
||||
|
||||
std::string
|
||||
featureToName(uint256 const& f)
|
||||
{
|
||||
return featureCollections.featureToName(f);
|
||||
return gFeatureCollections.featureToName(f);
|
||||
}
|
||||
|
||||
// All known amendments must be registered either here or below with the
|
||||
@@ -443,8 +445,7 @@ enforceValidFeatureName(auto fn) -> char const*
|
||||
// All of the features should now be registered, since variables in a cpp file
|
||||
// are initialized from top to bottom.
|
||||
//
|
||||
// Use initialization of one final static variable to set
|
||||
// featureCollections::readOnly.
|
||||
[[maybe_unused]] static bool const readOnlySet = featureCollections.registrationIsDone();
|
||||
// Use initialization of one final static variable to set featureCollections::readOnly_.
|
||||
[[maybe_unused]] static bool const kReadOnlySet = gFeatureCollections.registrationIsDone();
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace {
|
||||
LocalValue<bool>&
|
||||
getStaticSTNumberSwitchover()
|
||||
{
|
||||
static LocalValue<bool> r{true};
|
||||
return r;
|
||||
static LocalValue<bool> kR{true};
|
||||
return kR;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -43,11 +43,11 @@ setSTNumberSwitchover(bool v)
|
||||
/* The range for the mantissa when normalized */
|
||||
// log(2^63,10) ~ 18.96
|
||||
//
|
||||
static std::int64_t constexpr minMantissa = STAmount::cMinValue;
|
||||
static std::int64_t constexpr maxMantissa = STAmount::cMaxValue;
|
||||
static constexpr std::int64_t kMinMantissa = STAmount::kMinValue;
|
||||
static constexpr std::int64_t kMaxMantissa = STAmount::kMaxValue;
|
||||
/* The range for the exponent when normalized */
|
||||
static int constexpr minExponent = STAmount::cMinOffset;
|
||||
static int constexpr maxExponent = STAmount::cMaxOffset;
|
||||
static constexpr int kMinExponent = STAmount::kMinOffset;
|
||||
static constexpr int kMaxExponent = STAmount::kMaxOffset;
|
||||
|
||||
IOUAmount
|
||||
IOUAmount::fromNumber(Number const& number)
|
||||
@@ -56,14 +56,14 @@ IOUAmount::fromNumber(Number const& number)
|
||||
// to normalize, which calls fromNumber
|
||||
IOUAmount result{};
|
||||
std::tie(result.mantissa_, result.exponent_) =
|
||||
number.normalizeToRange(minMantissa, maxMantissa);
|
||||
number.normalizeToRange<kMinMantissa, kMaxMantissa>();
|
||||
return result;
|
||||
}
|
||||
|
||||
IOUAmount
|
||||
IOUAmount::minPositiveAmount()
|
||||
{
|
||||
return IOUAmount(minMantissa, minExponent);
|
||||
return IOUAmount(kMinMantissa, kMinExponent);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -71,7 +71,7 @@ IOUAmount::normalize()
|
||||
{
|
||||
if (mantissa_ == 0)
|
||||
{
|
||||
*this = beast::zero;
|
||||
*this = beast::kZero;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,10 +79,10 @@ IOUAmount::normalize()
|
||||
{
|
||||
Number const v{mantissa_, exponent_};
|
||||
*this = fromNumber(v);
|
||||
if (exponent_ > maxExponent)
|
||||
if (exponent_ > kMaxExponent)
|
||||
Throw<std::overflow_error>("value overflow");
|
||||
if (exponent_ < minExponent)
|
||||
*this = beast::zero;
|
||||
if (exponent_ < kMinExponent)
|
||||
*this = beast::kZero;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,28 +91,28 @@ IOUAmount::normalize()
|
||||
if (negative)
|
||||
mantissa_ = -mantissa_;
|
||||
|
||||
while ((mantissa_ < minMantissa) && (exponent_ > minExponent))
|
||||
while ((mantissa_ < kMinMantissa) && (exponent_ > kMinExponent))
|
||||
{
|
||||
mantissa_ *= 10;
|
||||
--exponent_;
|
||||
}
|
||||
|
||||
while (mantissa_ > maxMantissa)
|
||||
while (mantissa_ > kMaxMantissa)
|
||||
{
|
||||
if (exponent_ >= maxExponent)
|
||||
if (exponent_ >= kMaxExponent)
|
||||
Throw<std::overflow_error>("IOUAmount::normalize");
|
||||
|
||||
mantissa_ /= 10;
|
||||
++exponent_;
|
||||
}
|
||||
|
||||
if ((exponent_ < minExponent) || (mantissa_ < minMantissa))
|
||||
if ((exponent_ < kMinExponent) || (mantissa_ < kMinMantissa))
|
||||
{
|
||||
*this = beast::zero;
|
||||
*this = beast::kZero;
|
||||
return;
|
||||
}
|
||||
|
||||
if (exponent_ > maxExponent)
|
||||
if (exponent_ > kMaxExponent)
|
||||
Throw<std::overflow_error>("value overflow");
|
||||
|
||||
if (negative)
|
||||
@@ -121,19 +121,19 @@ IOUAmount::normalize()
|
||||
|
||||
IOUAmount::IOUAmount(Number const& other) : IOUAmount(fromNumber(other))
|
||||
{
|
||||
if (exponent_ > maxExponent)
|
||||
if (exponent_ > kMaxExponent)
|
||||
Throw<std::overflow_error>("value overflow");
|
||||
if (exponent_ < minExponent)
|
||||
*this = beast::zero;
|
||||
if (exponent_ < kMinExponent)
|
||||
*this = beast::kZero;
|
||||
}
|
||||
|
||||
IOUAmount&
|
||||
IOUAmount::operator+=(IOUAmount const& other)
|
||||
{
|
||||
if (other == beast::zero)
|
||||
if (other == beast::kZero)
|
||||
return *this;
|
||||
|
||||
if (*this == beast::zero)
|
||||
if (*this == beast::kZero)
|
||||
{
|
||||
*this = other;
|
||||
return *this;
|
||||
@@ -165,7 +165,7 @@ IOUAmount::operator+=(IOUAmount const& other)
|
||||
|
||||
if (mantissa_ >= -10 && mantissa_ <= 10)
|
||||
{
|
||||
*this = beast::zero;
|
||||
*this = beast::kZero;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundU
|
||||
// A vector with the value 10^index for indexes from 0 to 29
|
||||
// The largest intermediate value we expect is 2^96, which
|
||||
// is less than 10^29
|
||||
static auto const powerTable = [] {
|
||||
static auto const kPowerTable = [] {
|
||||
std::vector<uint128_t> result;
|
||||
result.reserve(30); // 2^96 is largest intermediate result size
|
||||
uint128_t cur(1);
|
||||
@@ -204,11 +204,11 @@ mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundU
|
||||
|
||||
// Return floor(log10(v))
|
||||
// Note: Returns -1 for v == 0
|
||||
static auto log10Floor = [](uint128_t const& v) {
|
||||
static auto kLoG10Floor = [](uint128_t const& v) {
|
||||
// Find the index of the first element >= the requested element, the
|
||||
// index is the log of the element in the log table.
|
||||
auto const l = std::ranges::lower_bound(powerTable, v);
|
||||
int index = std::distance(powerTable.begin(), l);
|
||||
auto const l = std::ranges::lower_bound(kPowerTable, v);
|
||||
int index = std::distance(kPowerTable.begin(), l);
|
||||
// If we're not equal, subtract to get the floor
|
||||
if (*l != v)
|
||||
--index;
|
||||
@@ -216,14 +216,14 @@ mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundU
|
||||
};
|
||||
|
||||
// Return ceil(log10(v))
|
||||
static auto log10Ceil = [](uint128_t const& v) {
|
||||
static auto kLoG10Ceil = [](uint128_t const& v) {
|
||||
// Find the index of the first element >= the requested element, the
|
||||
// index is the log of the element in the log table.
|
||||
auto const l = std::ranges::lower_bound(powerTable, v);
|
||||
return int(std::distance(powerTable.begin(), l));
|
||||
auto const l = std::ranges::lower_bound(kPowerTable, v);
|
||||
return int(std::distance(kPowerTable.begin(), l));
|
||||
};
|
||||
|
||||
static auto const fl64 = log10Floor(std::numeric_limits<std::int64_t>::max());
|
||||
static auto const kFl64 = kLoG10Floor(std::numeric_limits<std::int64_t>::max());
|
||||
|
||||
bool const neg = amt.mantissa() < 0;
|
||||
uint128_t const den128(den);
|
||||
@@ -244,12 +244,12 @@ mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundU
|
||||
// and (rem/den128) is as large as possible. Scale by multiplying low
|
||||
// and rem by 10 and subtracting one from the exponent. We could do this
|
||||
// with a loop, but it's more efficient to use logarithms.
|
||||
auto const roomToGrow = fl64 - log10Ceil(low);
|
||||
auto const roomToGrow = kFl64 - kLoG10Ceil(low);
|
||||
if (roomToGrow > 0)
|
||||
{
|
||||
exponent -= roomToGrow;
|
||||
low *= powerTable[roomToGrow];
|
||||
rem *= powerTable[roomToGrow];
|
||||
low *= kPowerTable[roomToGrow];
|
||||
rem *= kPowerTable[roomToGrow];
|
||||
}
|
||||
auto const addRem = rem / den128;
|
||||
low += addRem;
|
||||
@@ -261,14 +261,14 @@ mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundU
|
||||
// and adding one to the exponent until the low will fit in the 64-bit
|
||||
// mantissa. Use logarithms to avoid looping.
|
||||
bool hasRem = bool(rem);
|
||||
auto const mustShrink = log10Ceil(low) - fl64;
|
||||
auto const mustShrink = kLoG10Ceil(low) - kFl64;
|
||||
if (mustShrink > 0)
|
||||
{
|
||||
uint128_t const sav(low);
|
||||
exponent += mustShrink;
|
||||
low /= powerTable[mustShrink];
|
||||
low /= kPowerTable[mustShrink];
|
||||
if (!hasRem)
|
||||
hasRem = bool(sav - low * powerTable[mustShrink]);
|
||||
hasRem = bool(sav - low * kPowerTable[mustShrink]);
|
||||
}
|
||||
|
||||
std::int64_t mantissa = low.convert_to<std::int64_t>();
|
||||
@@ -297,7 +297,7 @@ mulRatio(IOUAmount const& amt, std::uint32_t num, std::uint32_t den, bool roundU
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
return IOUAmount(-minMantissa, minExponent);
|
||||
return IOUAmount(-kMinMantissa, kMinExponent);
|
||||
}
|
||||
// This subtraction cannot underflow because `result` is not zero
|
||||
return IOUAmount(result.mantissa() - 1, result.exponent());
|
||||
|
||||
@@ -50,53 +50,52 @@ namespace xrpl {
|
||||
and marked as [[deprecated]] to prevent accidental reuse.
|
||||
*/
|
||||
enum class LedgerNameSpace : std::uint16_t {
|
||||
ACCOUNT = 'a',
|
||||
DIR_NODE = 'd',
|
||||
TRUST_LINE = 'r',
|
||||
OFFER = 'o',
|
||||
OWNER_DIR = 'O',
|
||||
BOOK_DIR = 'B',
|
||||
SKIP_LIST = 's',
|
||||
ESCROW = 'u',
|
||||
AMENDMENTS = 'f',
|
||||
FEE_SETTINGS = 'e',
|
||||
TICKET = 'T',
|
||||
SIGNER_LIST = 'S',
|
||||
XRP_PAYMENT_CHANNEL = 'x',
|
||||
CHECK = 'C',
|
||||
DEPOSIT_PREAUTH = 'p',
|
||||
DEPOSIT_PREAUTH_CREDENTIALS = 'P',
|
||||
NEGATIVE_UNL = 'N',
|
||||
NFTOKEN_OFFER = 'q',
|
||||
NFTOKEN_BUY_OFFERS = 'h',
|
||||
NFTOKEN_SELL_OFFERS = 'i',
|
||||
AMM = 'A',
|
||||
BRIDGE = 'H',
|
||||
XCHAIN_CLAIM_ID = 'Q',
|
||||
XCHAIN_CREATE_ACCOUNT_CLAIM_ID = 'K',
|
||||
DID = 'I',
|
||||
ORACLE = 'R',
|
||||
MPTOKEN_ISSUANCE = '~',
|
||||
MPTOKEN = 't',
|
||||
CREDENTIAL = 'D',
|
||||
PERMISSIONED_DOMAIN = 'm',
|
||||
DELEGATE = 'E',
|
||||
VAULT = 'V',
|
||||
LOAN_BROKER = 'l', // lower-case L
|
||||
LOAN = 'L',
|
||||
Account = 'a',
|
||||
DirNode = 'd',
|
||||
TrustLine = 'r',
|
||||
Offer = 'o',
|
||||
OwnerDir = 'O',
|
||||
BookDir = 'B',
|
||||
SkipList = 's',
|
||||
Escrow = 'u',
|
||||
Amendments = 'f',
|
||||
FeeSettings = 'e',
|
||||
Ticket = 'T',
|
||||
SignerList = 'S',
|
||||
XRPPaymentChannel = 'x',
|
||||
Check = 'C',
|
||||
DepositPreauth = 'p',
|
||||
DepositPreauthCredentials = 'P',
|
||||
NegativeUnl = 'N',
|
||||
NftokenOffer = 'q',
|
||||
NftokenBuyOffers = 'h',
|
||||
NftokenSellOffers = 'i',
|
||||
Amm = 'A',
|
||||
Bridge = 'H',
|
||||
XchainClaimId = 'Q',
|
||||
XchainCreateAccountClaimId = 'K',
|
||||
Did = 'I',
|
||||
Oracle = 'R',
|
||||
MPTokenIssuance = '~',
|
||||
MPToken = 't',
|
||||
Credential = 'D',
|
||||
PermissionedDomain = 'm',
|
||||
Delegate = 'E',
|
||||
Vault = 'V',
|
||||
LoanBroker = 'l', // lower-case L
|
||||
Loan = 'L',
|
||||
|
||||
// No longer used or supported. Left here to reserve the space
|
||||
// to avoid accidental reuse.
|
||||
CONTRACT [[deprecated]] = 'c',
|
||||
GENERATOR [[deprecated]] = 'g',
|
||||
NICKNAME [[deprecated]] = 'n',
|
||||
// No longer used or supported. Left here to reserve the space to avoid accidental reuse.
|
||||
Contract [[deprecated]] = 'c',
|
||||
Generator [[deprecated]] = 'g',
|
||||
Nickname [[deprecated]] = 'n',
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
static uint256
|
||||
indexHash(LedgerNameSpace space, Args const&... args)
|
||||
{
|
||||
return sha512Half(safe_cast<std::uint16_t>(space), args...);
|
||||
return sha512Half(safeCast<std::uint16_t>(space), args...);
|
||||
}
|
||||
|
||||
uint256
|
||||
@@ -115,21 +114,21 @@ getBookBase(Book const& book)
|
||||
if constexpr (std::is_same_v<TIn, Issue> && std::is_same_v<TOut, Issue>)
|
||||
{
|
||||
return getIndexHash(
|
||||
LedgerNameSpace::BOOK_DIR, in.currency, out.currency, in.account, out.account);
|
||||
LedgerNameSpace::BookDir, in.currency, out.currency, in.account, out.account);
|
||||
}
|
||||
else if constexpr (std::is_same_v<TIn, Issue> && std::is_same_v<TOut, MPTIssue>)
|
||||
{
|
||||
return getIndexHash(
|
||||
LedgerNameSpace::BOOK_DIR, in.currency, out.getMptID(), in.account);
|
||||
LedgerNameSpace::BookDir, in.currency, out.getMptID(), in.account);
|
||||
}
|
||||
else if constexpr (std::is_same_v<TIn, MPTIssue> && std::is_same_v<TOut, Issue>)
|
||||
{
|
||||
return getIndexHash(
|
||||
LedgerNameSpace::BOOK_DIR, in.getMptID(), out.currency, out.account);
|
||||
LedgerNameSpace::BookDir, in.getMptID(), out.currency, out.account);
|
||||
}
|
||||
else
|
||||
{
|
||||
return getIndexHash(LedgerNameSpace::BOOK_DIR, in.getMptID(), out.getMptID());
|
||||
return getIndexHash(LedgerNameSpace::BookDir, in.getMptID(), out.getMptID());
|
||||
}
|
||||
},
|
||||
book.in.value(),
|
||||
@@ -144,9 +143,9 @@ getBookBase(Book const& book)
|
||||
uint256
|
||||
getQualityNext(uint256 const& uBase)
|
||||
{
|
||||
static constexpr uint256 nextQuality(
|
||||
static constexpr uint256 kNextQuality(
|
||||
"0000000000000000000000000000000000000000000000010000000000000000");
|
||||
return uBase + nextQuality;
|
||||
return uBase + kNextQuality;
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
@@ -159,7 +158,7 @@ getQuality(uint256 const& uBase)
|
||||
uint256
|
||||
getTicketIndex(AccountID const& account, std::uint32_t ticketSeq)
|
||||
{
|
||||
return indexHash(LedgerNameSpace::TICKET, account, ticketSeq);
|
||||
return indexHash(LedgerNameSpace::Ticket, account, ticketSeq);
|
||||
}
|
||||
|
||||
uint256
|
||||
@@ -186,7 +185,7 @@ namespace keylet {
|
||||
Keylet
|
||||
account(AccountID const& id) noexcept
|
||||
{
|
||||
return Keylet{ltACCOUNT_ROOT, indexHash(LedgerNameSpace::ACCOUNT, id)};
|
||||
return Keylet{ltACCOUNT_ROOT, indexHash(LedgerNameSpace::Account, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -198,8 +197,8 @@ child(uint256 const& key) noexcept
|
||||
Keylet const&
|
||||
skip() noexcept
|
||||
{
|
||||
static Keylet const ret{ltLEDGER_HASHES, indexHash(LedgerNameSpace::SKIP_LIST)};
|
||||
return ret;
|
||||
static Keylet const kRet{ltLEDGER_HASHES, indexHash(LedgerNameSpace::SkipList)};
|
||||
return kRet;
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -208,32 +207,32 @@ skip(LedgerIndex ledger) noexcept
|
||||
return {
|
||||
ltLEDGER_HASHES,
|
||||
indexHash(
|
||||
LedgerNameSpace::SKIP_LIST, std::uint32_t(static_cast<std::uint32_t>(ledger) >> 16))};
|
||||
LedgerNameSpace::SkipList, std::uint32_t(static_cast<std::uint32_t>(ledger) >> 16))};
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
amendments() noexcept
|
||||
{
|
||||
static Keylet const ret{ltAMENDMENTS, indexHash(LedgerNameSpace::AMENDMENTS)};
|
||||
return ret;
|
||||
static Keylet const kRet{ltAMENDMENTS, indexHash(LedgerNameSpace::Amendments)};
|
||||
return kRet;
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
fees() noexcept
|
||||
{
|
||||
static Keylet const ret{ltFEE_SETTINGS, indexHash(LedgerNameSpace::FEE_SETTINGS)};
|
||||
return ret;
|
||||
static Keylet const kRet{ltFEE_SETTINGS, indexHash(LedgerNameSpace::FeeSettings)};
|
||||
return kRet;
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
negativeUNL() noexcept
|
||||
{
|
||||
static Keylet const ret{ltNEGATIVE_UNL, indexHash(LedgerNameSpace::NEGATIVE_UNL)};
|
||||
return ret;
|
||||
static Keylet const kRet{ltNEGATIVE_UNL, indexHash(LedgerNameSpace::NegativeUnl)};
|
||||
return kRet;
|
||||
}
|
||||
|
||||
Keylet
|
||||
book_t::operator()(Book const& b) const
|
||||
BookT::operator()(Book const& b) const
|
||||
{
|
||||
return {ltDIR_NODE, getBookBase(b)};
|
||||
}
|
||||
@@ -258,13 +257,13 @@ line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexc
|
||||
|
||||
return {
|
||||
ltRIPPLE_STATE,
|
||||
indexHash(LedgerNameSpace::TRUST_LINE, accounts.first, accounts.second, currency)};
|
||||
indexHash(LedgerNameSpace::TrustLine, accounts.first, accounts.second, currency)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
offer(AccountID const& id, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltOFFER, indexHash(LedgerNameSpace::OFFER, id, seq)};
|
||||
return {ltOFFER, indexHash(LedgerNameSpace::Offer, id, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -286,20 +285,20 @@ quality(Keylet const& k, std::uint64_t q) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
next_t::operator()(Keylet const& k) const
|
||||
NextT::operator()(Keylet const& k) const
|
||||
{
|
||||
XRPL_ASSERT(k.type == ltDIR_NODE, "xrpl::keylet::next_t::operator() : valid input type");
|
||||
XRPL_ASSERT(k.type == ltDIR_NODE, "xrpl::keylet::NextT::operator() : valid input type");
|
||||
return {ltDIR_NODE, getQualityNext(k.key)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
ticket_t::operator()(AccountID const& id, std::uint32_t ticketSeq) const
|
||||
TicketT::operator()(AccountID const& id, std::uint32_t ticketSeq) const
|
||||
{
|
||||
return {ltTICKET, getTicketIndex(id, ticketSeq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
ticket_t::operator()(AccountID const& id, SeqProxy ticketSeq) const
|
||||
TicketT::operator()(AccountID const& id, SeqProxy ticketSeq) const
|
||||
{
|
||||
return {ltTICKET, getTicketIndex(id, ticketSeq)};
|
||||
}
|
||||
@@ -310,7 +309,7 @@ ticket_t::operator()(AccountID const& id, SeqProxy ticketSeq) const
|
||||
static Keylet
|
||||
signers(AccountID const& account, std::uint32_t page) noexcept
|
||||
{
|
||||
return {ltSIGNER_LIST, indexHash(LedgerNameSpace::SIGNER_LIST, account, page)};
|
||||
return {ltSIGNER_LIST, indexHash(LedgerNameSpace::SignerList, account, page)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -322,13 +321,13 @@ signers(AccountID const& account) noexcept
|
||||
Keylet
|
||||
check(AccountID const& id, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltCHECK, indexHash(LedgerNameSpace::CHECK, id, seq)};
|
||||
return {ltCHECK, indexHash(LedgerNameSpace::Check, id, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept
|
||||
{
|
||||
return {ltDEPOSIT_PREAUTH, indexHash(LedgerNameSpace::DEPOSIT_PREAUTH, owner, preauthorized)};
|
||||
return {ltDEPOSIT_PREAUTH, indexHash(LedgerNameSpace::DepositPreauth, owner, preauthorized)};
|
||||
}
|
||||
|
||||
// Credentials should be sorted here, use credentials::makeSorted
|
||||
@@ -343,7 +342,7 @@ depositPreauth(
|
||||
hashes.emplace_back(sha512Half(o.first, o.second));
|
||||
|
||||
return {
|
||||
ltDEPOSIT_PREAUTH, indexHash(LedgerNameSpace::DEPOSIT_PREAUTH_CREDENTIALS, owner, hashes)};
|
||||
ltDEPOSIT_PREAUTH, indexHash(LedgerNameSpace::DepositPreauthCredentials, owner, hashes)};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -357,7 +356,7 @@ unchecked(uint256 const& key) noexcept
|
||||
Keylet
|
||||
ownerDir(AccountID const& id) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::OWNER_DIR, id)};
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::OwnerDir, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -366,33 +365,33 @@ page(uint256 const& key, std::uint64_t index) noexcept
|
||||
if (index == 0)
|
||||
return {ltDIR_NODE, key};
|
||||
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::DIR_NODE, key, index)};
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::DirNode, key, index)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
escrow(AccountID const& src, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltESCROW, indexHash(LedgerNameSpace::ESCROW, src, seq)};
|
||||
return {ltESCROW, indexHash(LedgerNameSpace::Escrow, src, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltPAYCHAN, indexHash(LedgerNameSpace::XRP_PAYMENT_CHANNEL, src, dst, seq)};
|
||||
return {ltPAYCHAN, indexHash(LedgerNameSpace::XRPPaymentChannel, src, dst, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftpage_min(AccountID const& owner)
|
||||
nftpageMin(AccountID const& owner)
|
||||
{
|
||||
std::array<std::uint8_t, 32> buf{};
|
||||
std::memcpy(buf.data(), owner.data(), owner.size());
|
||||
return {ltNFTOKEN_PAGE, uint256{buf}};
|
||||
return {ltNFTOKEN_PAGE, uint256::fromRaw(buf)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftpage_max(AccountID const& owner)
|
||||
nftpageMax(AccountID const& owner)
|
||||
{
|
||||
uint256 id = nft::pageMask;
|
||||
uint256 id = nft::kPageMask;
|
||||
std::memcpy(id.data(), owner.data(), owner.size());
|
||||
return {ltNFTOKEN_PAGE, id};
|
||||
}
|
||||
@@ -401,25 +400,25 @@ Keylet
|
||||
nftpage(Keylet const& k, uint256 const& token)
|
||||
{
|
||||
XRPL_ASSERT(k.type == ltNFTOKEN_PAGE, "xrpl::keylet::nftpage : valid input type");
|
||||
return {ltNFTOKEN_PAGE, (k.key & ~nft::pageMask) + (token & nft::pageMask)};
|
||||
return {ltNFTOKEN_PAGE, (k.key & ~nft::kPageMask) + (token & nft::kPageMask)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftoffer(AccountID const& owner, std::uint32_t seq)
|
||||
{
|
||||
return {ltNFTOKEN_OFFER, indexHash(LedgerNameSpace::NFTOKEN_OFFER, owner, seq)};
|
||||
return {ltNFTOKEN_OFFER, indexHash(LedgerNameSpace::NftokenOffer, owner, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nft_buys(uint256 const& id) noexcept
|
||||
nftBuys(uint256 const& id) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::NFTOKEN_BUY_OFFERS, id)};
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::NftokenBuyOffers, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nft_sells(uint256 const& id) noexcept
|
||||
nftSells(uint256 const& id) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::NFTOKEN_SELL_OFFERS, id)};
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::NftokenSellOffers, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -431,7 +430,7 @@ amm(Asset const& asset1, Asset const& asset2) noexcept
|
||||
if constexpr (std::is_same_v<TIss1, Issue> && std::is_same_v<TIss2, Issue>)
|
||||
{
|
||||
return amm(indexHash(
|
||||
LedgerNameSpace::AMM,
|
||||
LedgerNameSpace::Amm,
|
||||
issue1.account,
|
||||
issue1.currency,
|
||||
issue2.account,
|
||||
@@ -440,16 +439,16 @@ amm(Asset const& asset1, Asset const& asset2) noexcept
|
||||
else if constexpr (std::is_same_v<TIss1, Issue> && std::is_same_v<TIss2, MPTIssue>)
|
||||
{
|
||||
return amm(indexHash(
|
||||
LedgerNameSpace::AMM, issue1.account, issue1.currency, issue2.getMptID()));
|
||||
LedgerNameSpace::Amm, issue1.account, issue1.currency, issue2.getMptID()));
|
||||
}
|
||||
else if constexpr (std::is_same_v<TIss1, MPTIssue> && std::is_same_v<TIss2, Issue>)
|
||||
{
|
||||
return amm(indexHash(
|
||||
LedgerNameSpace::AMM, issue1.getMptID(), issue2.account, issue2.currency));
|
||||
LedgerNameSpace::Amm, issue1.getMptID(), issue2.account, issue2.currency));
|
||||
}
|
||||
else if constexpr (std::is_same_v<TIss1, MPTIssue> && std::is_same_v<TIss2, MPTIssue>)
|
||||
{
|
||||
return amm(indexHash(LedgerNameSpace::AMM, issue1.getMptID(), issue2.getMptID()));
|
||||
return amm(indexHash(LedgerNameSpace::Amm, issue1.getMptID(), issue2.getMptID()));
|
||||
}
|
||||
},
|
||||
minA.value(),
|
||||
@@ -465,7 +464,7 @@ amm(uint256 const& id) noexcept
|
||||
Keylet
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept
|
||||
{
|
||||
return {ltDELEGATE, indexHash(LedgerNameSpace::DELEGATE, account, authorizedAccount)};
|
||||
return {ltDELEGATE, indexHash(LedgerNameSpace::Delegate, account, authorizedAccount)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -475,7 +474,7 @@ bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType)
|
||||
// there can only be one bridge per lockingChainCurrency. On the issuing
|
||||
// chain there can only be one bridge per issuingChainCurrency.
|
||||
auto const& issue = bridge.issue(chainType);
|
||||
return {ltBRIDGE, indexHash(LedgerNameSpace::BRIDGE, bridge.door(chainType), issue.currency)};
|
||||
return {ltBRIDGE, indexHash(LedgerNameSpace::Bridge, bridge.door(chainType), issue.currency)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -484,7 +483,7 @@ xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
return {
|
||||
ltXCHAIN_OWNED_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XCHAIN_CLAIM_ID,
|
||||
LedgerNameSpace::XchainClaimId,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
@@ -498,7 +497,7 @@ xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
return {
|
||||
ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XCHAIN_CREATE_ACCOUNT_CLAIM_ID,
|
||||
LedgerNameSpace::XchainCreateAccountClaimId,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
@@ -509,13 +508,13 @@ xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
Keylet
|
||||
did(AccountID const& account) noexcept
|
||||
{
|
||||
return {ltDID, indexHash(LedgerNameSpace::DID, account)};
|
||||
return {ltDID, indexHash(LedgerNameSpace::Did, account)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
oracle(AccountID const& account, std::uint32_t const& documentID) noexcept
|
||||
{
|
||||
return {ltORACLE, indexHash(LedgerNameSpace::ORACLE, account, documentID)};
|
||||
return {ltORACLE, indexHash(LedgerNameSpace::Oracle, account, documentID)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -527,7 +526,7 @@ mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept
|
||||
Keylet
|
||||
mptIssuance(MPTID const& issuanceID) noexcept
|
||||
{
|
||||
return {ltMPTOKEN_ISSUANCE, indexHash(LedgerNameSpace::MPTOKEN_ISSUANCE, issuanceID)};
|
||||
return {ltMPTOKEN_ISSUANCE, indexHash(LedgerNameSpace::MPTokenIssuance, issuanceID)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -539,37 +538,37 @@ mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept
|
||||
Keylet
|
||||
mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept
|
||||
{
|
||||
return {ltMPTOKEN, indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)};
|
||||
return {ltMPTOKEN, indexHash(LedgerNameSpace::MPToken, issuanceKey, holder)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
credential(AccountID const& subject, AccountID const& issuer, Slice const& credType) noexcept
|
||||
{
|
||||
return {ltCREDENTIAL, indexHash(LedgerNameSpace::CREDENTIAL, subject, issuer, credType)};
|
||||
return {ltCREDENTIAL, indexHash(LedgerNameSpace::Credential, subject, issuer, credType)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
vault(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return vault(indexHash(LedgerNameSpace::VAULT, owner, seq));
|
||||
return vault(indexHash(LedgerNameSpace::Vault, owner, seq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return loanbroker(indexHash(LedgerNameSpace::LOAN_BROKER, owner, seq));
|
||||
return loanbroker(indexHash(LedgerNameSpace::LoanBroker, owner, seq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept
|
||||
{
|
||||
return loan(indexHash(LedgerNameSpace::LOAN, loanBrokerID, loanSeq));
|
||||
return loan(indexHash(LedgerNameSpace::Loan, loanBrokerID, loanSeq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltPERMISSIONED_DOMAIN, indexHash(LedgerNameSpace::PERMISSIONED_DOMAIN, account, seq)};
|
||||
return {ltPERMISSIONED_DOMAIN, indexHash(LedgerNameSpace::PermissionedDomain, account, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
|
||||
@@ -13,160 +13,160 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
add(sfSignerEntry.jsonName,
|
||||
sfSignerEntry.getCode(),
|
||||
{
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfSignerWeight, soeREQUIRED},
|
||||
{sfWalletLocator, soeOPTIONAL},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSignerWeight, SoeRequired},
|
||||
{sfWalletLocator, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfSigner.jsonName,
|
||||
sfSigner.getCode(),
|
||||
{
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfSigningPubKey, soeREQUIRED},
|
||||
{sfTxnSignature, soeREQUIRED},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSigningPubKey, SoeRequired},
|
||||
{sfTxnSignature, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfMajority.jsonName,
|
||||
sfMajority.getCode(),
|
||||
{
|
||||
{sfAmendment, soeREQUIRED},
|
||||
{sfCloseTime, soeREQUIRED},
|
||||
{sfAmendment, SoeRequired},
|
||||
{sfCloseTime, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfDisabledValidator.jsonName,
|
||||
sfDisabledValidator.getCode(),
|
||||
{
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfFirstLedgerSequence, soeREQUIRED},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfFirstLedgerSequence, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfNFToken.jsonName,
|
||||
sfNFToken.getCode(),
|
||||
{
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfNFTokenID, SoeRequired},
|
||||
{sfURI, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfVoteEntry.jsonName,
|
||||
sfVoteEntry.getCode(),
|
||||
{
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfTradingFee, soeDEFAULT},
|
||||
{sfVoteWeight, soeREQUIRED},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfTradingFee, SoeDefault},
|
||||
{sfVoteWeight, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfAuctionSlot.jsonName,
|
||||
sfAuctionSlot.getCode(),
|
||||
{{sfAccount, soeREQUIRED},
|
||||
{sfExpiration, soeREQUIRED},
|
||||
{sfDiscountedFee, soeDEFAULT},
|
||||
{sfPrice, soeREQUIRED},
|
||||
{sfAuthAccounts, soeOPTIONAL}});
|
||||
{{sfAccount, SoeRequired},
|
||||
{sfExpiration, SoeRequired},
|
||||
{sfDiscountedFee, SoeDefault},
|
||||
{sfPrice, SoeRequired},
|
||||
{sfAuthAccounts, SoeOptional}});
|
||||
|
||||
add(sfXChainClaimAttestationCollectionElement.jsonName,
|
||||
sfXChainClaimAttestationCollectionElement.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, soeREQUIRED},
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfSignature, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfAttestationRewardAccount, soeREQUIRED},
|
||||
{sfWasLockingChainSend, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
{sfDestination, soeOPTIONAL},
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainCreateAccountAttestationCollectionElement.jsonName,
|
||||
sfXChainCreateAccountAttestationCollectionElement.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, soeREQUIRED},
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfSignature, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfAttestationRewardAccount, soeREQUIRED},
|
||||
{sfWasLockingChainSend, soeREQUIRED},
|
||||
{sfXChainAccountCreateCount, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfXChainClaimProofSig.jsonName,
|
||||
sfXChainClaimProofSig.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, soeREQUIRED},
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfAttestationRewardAccount, soeREQUIRED},
|
||||
{sfWasLockingChainSend, soeREQUIRED},
|
||||
{sfDestination, soeOPTIONAL},
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainCreateAccountProofSig.jsonName,
|
||||
sfXChainCreateAccountProofSig.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, soeREQUIRED},
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
{sfAttestationRewardAccount, soeREQUIRED},
|
||||
{sfWasLockingChainSend, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfAuthAccount.jsonName,
|
||||
sfAuthAccount.getCode(),
|
||||
{
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfAccount, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfPriceData.jsonName,
|
||||
sfPriceData.getCode(),
|
||||
{
|
||||
{sfBaseAsset, soeREQUIRED},
|
||||
{sfQuoteAsset, soeREQUIRED},
|
||||
{sfAssetPrice, soeOPTIONAL},
|
||||
{sfScale, soeDEFAULT},
|
||||
{sfBaseAsset, SoeRequired},
|
||||
{sfQuoteAsset, SoeRequired},
|
||||
{sfAssetPrice, SoeOptional},
|
||||
{sfScale, SoeDefault},
|
||||
});
|
||||
|
||||
add(sfCredential.jsonName,
|
||||
sfCredential.getCode(),
|
||||
{
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
{sfIssuer, SoeRequired},
|
||||
{sfCredentialType, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfPermission.jsonName.c_str(), sfPermission.getCode(), {{sfPermissionValue, soeREQUIRED}});
|
||||
add(sfPermission.jsonName.cStr(), sfPermission.getCode(), {{sfPermissionValue, SoeRequired}});
|
||||
|
||||
add(sfBatchSigner.jsonName.c_str(),
|
||||
add(sfBatchSigner.jsonName.cStr(),
|
||||
sfBatchSigner.getCode(),
|
||||
{{sfAccount, soeREQUIRED},
|
||||
{sfSigningPubKey, soeOPTIONAL},
|
||||
{sfTxnSignature, soeOPTIONAL},
|
||||
{sfSigners, soeOPTIONAL}});
|
||||
{{sfAccount, SoeRequired},
|
||||
{sfSigningPubKey, SoeOptional},
|
||||
{sfTxnSignature, SoeOptional},
|
||||
{sfSigners, SoeOptional}});
|
||||
|
||||
add(sfBook.jsonName,
|
||||
sfBook.getCode(),
|
||||
{
|
||||
{sfBookDirectory, soeREQUIRED},
|
||||
{sfBookNode, soeREQUIRED},
|
||||
{sfBookDirectory, SoeRequired},
|
||||
{sfBookNode, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfCounterpartySignature.jsonName,
|
||||
sfCounterpartySignature.getCode(),
|
||||
{
|
||||
{sfSigningPubKey, soeOPTIONAL},
|
||||
{sfTxnSignature, soeOPTIONAL},
|
||||
{sfSigners, soeOPTIONAL},
|
||||
{sfSigningPubKey, SoeOptional},
|
||||
{sfTxnSignature, SoeOptional},
|
||||
{sfSigners, SoeOptional},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
InnerObjectFormats::getInstance()
|
||||
{
|
||||
static InnerObjectFormats const instance;
|
||||
return instance;
|
||||
static InnerObjectFormats const kInstance;
|
||||
return kInstance;
|
||||
}
|
||||
|
||||
SOTemplate const*
|
||||
|
||||
@@ -43,7 +43,7 @@ Issue::getText() const
|
||||
}
|
||||
|
||||
void
|
||||
Issue::setJson(Json::Value& jv) const
|
||||
Issue::setJson(json::Value& jv) const
|
||||
{
|
||||
jv[jss::currency] = to_string(currency);
|
||||
if (!isXRP(currency))
|
||||
@@ -77,16 +77,16 @@ to_string(Issue const& ac)
|
||||
return to_string(ac.account) + "/" + to_string(ac.currency);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
to_json(Issue const& is)
|
||||
json::Value
|
||||
toJson(Issue const& is)
|
||||
{
|
||||
Json::Value jv;
|
||||
json::Value jv;
|
||||
is.setJson(jv);
|
||||
return jv;
|
||||
}
|
||||
|
||||
Issue
|
||||
issueFromJson(Json::Value const& v)
|
||||
issueFromJson(json::Value const& v)
|
||||
{
|
||||
if (!v.isObject())
|
||||
{
|
||||
@@ -99,38 +99,38 @@ issueFromJson(Json::Value const& v)
|
||||
Throw<std::runtime_error>("issueFromJson, Issue should not have mpt_issuance_id");
|
||||
}
|
||||
|
||||
Json::Value const curStr = v[jss::currency];
|
||||
Json::Value const issStr = v[jss::issuer];
|
||||
json::Value const curStr = v[jss::currency];
|
||||
json::Value const issStr = v[jss::issuer];
|
||||
|
||||
if (!curStr.isString())
|
||||
{
|
||||
Throw<Json::error>("issueFromJson currency must be a string Json value");
|
||||
Throw<json::Error>("issueFromJson currency must be a string Json value");
|
||||
}
|
||||
|
||||
auto const currency = to_currency(curStr.asString());
|
||||
auto const currency = toCurrency(curStr.asString());
|
||||
if (currency == badCurrency() || currency == noCurrency())
|
||||
{
|
||||
Throw<Json::error>("issueFromJson currency must be a valid currency");
|
||||
Throw<json::Error>("issueFromJson currency must be a valid currency");
|
||||
}
|
||||
|
||||
if (isXRP(currency))
|
||||
{
|
||||
if (!issStr.isNull())
|
||||
{
|
||||
Throw<Json::error>("Issue, XRP should not have issuer");
|
||||
Throw<json::Error>("Issue, XRP should not have issuer");
|
||||
}
|
||||
return xrpIssue();
|
||||
}
|
||||
|
||||
if (!issStr.isString())
|
||||
{
|
||||
Throw<Json::error>("issueFromJson issuer must be a string Json value");
|
||||
Throw<json::Error>("issueFromJson issuer must be a string Json value");
|
||||
}
|
||||
auto const issuer = parseBase58<AccountID>(issStr.asString());
|
||||
|
||||
if (!issuer)
|
||||
if (!issuer || *issuer == noAccount() || *issuer == xrpAccount())
|
||||
{
|
||||
Throw<Json::error>("issueFromJson issuer must be a valid account");
|
||||
Throw<json::Error>("issueFromJson issuer must be a valid account");
|
||||
}
|
||||
|
||||
return Issue{currency, *issuer};
|
||||
|
||||
@@ -11,12 +11,12 @@ namespace xrpl {
|
||||
std::vector<SOElement> const&
|
||||
LedgerFormats::getCommonFields()
|
||||
{
|
||||
static auto const commonFields = std::vector<SOElement>{
|
||||
{sfLedgerIndex, soeOPTIONAL},
|
||||
{sfLedgerEntryType, soeREQUIRED},
|
||||
{sfFlags, soeREQUIRED},
|
||||
static auto const kCommonFields = std::vector<SOElement>{
|
||||
{sfLedgerIndex, SoeOptional},
|
||||
{sfLedgerEntryType, SoeRequired},
|
||||
{sfFlags, SoeRequired},
|
||||
};
|
||||
return commonFields;
|
||||
return kCommonFields;
|
||||
}
|
||||
|
||||
LedgerFormats::LedgerFormats()
|
||||
@@ -41,8 +41,8 @@ LedgerFormats::LedgerFormats()
|
||||
LedgerFormats const&
|
||||
LedgerFormats::getInstance()
|
||||
{
|
||||
static LedgerFormats const instance;
|
||||
return instance;
|
||||
static LedgerFormats const kInstance;
|
||||
return kInstance;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -61,7 +61,7 @@ calculateLedgerHash(LedgerHeader const& info)
|
||||
{
|
||||
// VFALCO This has to match addRaw in View.h.
|
||||
return sha512Half(
|
||||
HashPrefix::ledgerMaster,
|
||||
HashPrefix::LedgerMaster,
|
||||
std::uint32_t(info.seq),
|
||||
std::uint64_t(info.drops.drops()),
|
||||
info.parentHash,
|
||||
|
||||
@@ -44,15 +44,15 @@ MPTIssue::getText() const
|
||||
}
|
||||
|
||||
void
|
||||
MPTIssue::setJson(Json::Value& jv) const
|
||||
MPTIssue::setJson(json::Value& jv) const
|
||||
{
|
||||
jv[jss::mpt_issuance_id] = to_string(mptID_);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
to_json(MPTIssue const& mptIssue)
|
||||
json::Value
|
||||
toJson(MPTIssue const& mptIssue)
|
||||
{
|
||||
Json::Value jv;
|
||||
json::Value jv;
|
||||
mptIssue.setJson(jv);
|
||||
return jv;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ to_string(MPTIssue const& mptIssue)
|
||||
}
|
||||
|
||||
MPTIssue
|
||||
mptIssueFromJson(Json::Value const& v)
|
||||
mptIssueFromJson(json::Value const& v)
|
||||
{
|
||||
if (!v.isObject())
|
||||
{
|
||||
@@ -78,17 +78,17 @@ mptIssueFromJson(Json::Value const& v)
|
||||
Throw<std::runtime_error>("mptIssueFromJson, MPTIssue should not have currency or issuer");
|
||||
}
|
||||
|
||||
Json::Value const& idStr = v[jss::mpt_issuance_id];
|
||||
json::Value const& idStr = v[jss::mpt_issuance_id];
|
||||
|
||||
if (!idStr.isString())
|
||||
{
|
||||
Throw<Json::error>("mptIssueFromJson MPTID must be a string Json value");
|
||||
Throw<json::Error>("mptIssueFromJson MPTID must be a string Json value");
|
||||
}
|
||||
|
||||
MPTID id;
|
||||
if (!id.parseHex(idStr.asString()))
|
||||
{
|
||||
Throw<Json::error>("mptIssueFromJson MPTID is invalid");
|
||||
Throw<json::Error>("mptIssueFromJson MPTID is invalid");
|
||||
}
|
||||
|
||||
return MPTIssue{id};
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace xrpl::RPC {
|
||||
|
||||
void
|
||||
insertNFTSyntheticInJson(
|
||||
Json::Value& response,
|
||||
json::Value& response,
|
||||
std::shared_ptr<STTx const> const& transaction,
|
||||
TxMeta const& transactionMeta)
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@ getNFTokenIDFromDeletedOffer(TxMeta const& transactionMeta)
|
||||
|
||||
void
|
||||
insertNFTokenID(
|
||||
Json::Value& response,
|
||||
json::Value& response,
|
||||
std::shared_ptr<STTx const> const& transaction,
|
||||
TxMeta const& transactionMeta)
|
||||
{
|
||||
@@ -159,7 +159,7 @@ insertNFTokenID(
|
||||
{
|
||||
std::vector<uint256> const result = getNFTokenIDFromDeletedOffer(transactionMeta);
|
||||
|
||||
response[jss::nftoken_ids] = Json::Value(Json::arrayValue);
|
||||
response[jss::nftoken_ids] = json::Value(json::ValueType::Array);
|
||||
for (auto const& nftID : result)
|
||||
response[jss::nftoken_ids].append(to_string(nftID));
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ getOfferIDFromCreatedOffer(TxMeta const& transactionMeta)
|
||||
|
||||
void
|
||||
insertNFTokenOfferID(
|
||||
Json::Value& response,
|
||||
json::Value& response,
|
||||
std::shared_ptr<STTx const> const& transaction,
|
||||
TxMeta const& transactionMeta)
|
||||
{
|
||||
|
||||
@@ -92,8 +92,8 @@ Permission::Permission()
|
||||
Permission const&
|
||||
Permission::getInstance()
|
||||
{
|
||||
static Permission const instance;
|
||||
return instance;
|
||||
static Permission const kInstance;
|
||||
return kInstance;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
@@ -182,7 +182,7 @@ Permission::isDelegable(std::uint32_t const& permissionValue, Rules const& rules
|
||||
if (txFeaturesIt->second != uint256{} && !rules.enabled(txFeaturesIt->second))
|
||||
return false;
|
||||
|
||||
if (it->second == Delegation::notDelegable)
|
||||
if (it->second == Delegation::NotDelegable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user