mirror of https://github.com/oxen-io/oxen-core.git
Eliminate most << output operators
Replace (nearly) everything with fmt formatting. Some crap in wallet2 remains that I'm not going to bother with.
This commit is contained in:
parent
c4f4bfc87e
commit
463590ad5c
|
@ -215,18 +215,6 @@ POP_WARNINGS
|
|||
trim(str);
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string pad_string(std::string s, size_t n, char c = ' ', bool prepend = false)
|
||||
{
|
||||
if (s.size() < n)
|
||||
{
|
||||
if (prepend)
|
||||
s = std::string(n - s.size(), c) + s;
|
||||
else
|
||||
s.append(n - s.size(), c);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //_STRING_TOOLS_H_
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "epee/string_tools.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "common/pruning.h"
|
||||
#include "common/hex.h"
|
||||
#include "common/median.h"
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <sodium.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include "common/command_line.h"
|
||||
#include "common/varint.h"
|
||||
#include "common/signal_handler.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "serialization/boost_std_variant.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "common/string_util.h"
|
||||
#include "common/varint.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "common/signal_handler.h"
|
||||
#include "common/hex.h"
|
||||
#include "serialization/crypto.h"
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "common/command_line.h"
|
||||
#include "common/varint.h"
|
||||
#include "common/median.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "bootstrap_file.h"
|
||||
#include "blocksdat_file.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
#include "version.h"
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "common/hex.h"
|
||||
#include "common/fs-format.h"
|
||||
#include <fmt/color.h>
|
||||
|
||||
namespace
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "common/command_line.h"
|
||||
#include "common/varint.h"
|
||||
#include "common/signal_handler.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "common/command_line.h"
|
||||
#include "common/varint.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "blocksdat_file.h"
|
||||
#include "common/fs-format.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include "bootstrap_file.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
#include "common/fs-format.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include "common/oxen.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "common/hex.h"
|
||||
|
||||
namespace cryptonote
|
||||
|
|
|
@ -64,6 +64,7 @@ target_link_libraries(common
|
|||
cncrypto
|
||||
oxenmq::oxenmq
|
||||
filesystem
|
||||
oxen::logging
|
||||
fmt::fmt
|
||||
date::date
|
||||
PRIVATE
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
//
|
||||
#include "file.h"
|
||||
#include "fs-format.h"
|
||||
#include "logging/oxen_logger.h"
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
@ -31,6 +33,11 @@ namespace formattable {
|
|||
template <typename T, typename SFINAE = void>
|
||||
constexpr bool via_to_string = false;
|
||||
|
||||
// Same as above, but looks for a to_hex_string() instead of to_string(), for types that get
|
||||
// dumped as hex.
|
||||
template <typename T, typename SFINAE = void>
|
||||
constexpr bool via_to_hex_string = false;
|
||||
|
||||
// Scoped enums can alternatively be formatted as their underlying integer value by specializing
|
||||
// this function to true:
|
||||
template <typename T, typename SFINAE = void>
|
||||
|
@ -40,12 +47,19 @@ namespace formattable {
|
|||
|
||||
template <typename T, typename SFINAE = void>
|
||||
constexpr bool has_to_string_method = false;
|
||||
template <typename T, typename SFINAE = void>
|
||||
constexpr bool has_to_hex_string_method = false;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool has_to_string_method<T,
|
||||
std::void_t<decltype(std::declval<const T&>().to_string())>
|
||||
> = true;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool has_to_hex_string_method<T,
|
||||
std::void_t<decltype(std::declval<const T&>().to_hex_string())>
|
||||
> = true;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace formattable
|
||||
|
@ -70,6 +84,22 @@ namespace fmt {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<T, Char, std::enable_if_t<::formattable::via_to_hex_string<T>>>
|
||||
: formatter<std::string_view>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
auto format(const T& val, FormatContext& ctx) const {
|
||||
if constexpr (::formattable::detail::has_to_hex_string_method<T>)
|
||||
return formatter<std::string_view>::format(val.to_hex_string(), ctx);
|
||||
else {
|
||||
using namespace formattable;
|
||||
return formatter<std::string_view>::format(to_hex_string(val), ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<T, Char, std::enable_if_t<::formattable::via_underlying<T>>>
|
||||
|
|
|
@ -20,16 +20,7 @@ namespace fs {
|
|||
#else
|
||||
|
||||
#include <ghc/filesystem.hpp>
|
||||
#include "formattable.h"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace formattable {
|
||||
template <> inline constexpr bool via_to_string<ghc::filesystem::path> = true;
|
||||
|
||||
inline std::string to_string(const ghc::filesystem::path& path) {
|
||||
return path.string();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,18 +5,26 @@ namespace tools {
|
|||
|
||||
static auto logcat = log::Cat("msgwriter");
|
||||
|
||||
scoped_message_writer& scoped_message_writer::flush()
|
||||
{
|
||||
if (!m_content.empty())
|
||||
{
|
||||
logcat->log(m_log_level, "{}{}", m_prefix, m_content);
|
||||
|
||||
if (m_color) {
|
||||
rdln::suspend_readline pause_readline;
|
||||
fmt::print(fg(*m_color), "{}{}\n", m_prefix, m_content);
|
||||
}
|
||||
else
|
||||
fmt::print("{}{}\n", m_prefix, m_content);
|
||||
|
||||
m_content.clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
scoped_message_writer::~scoped_message_writer()
|
||||
{
|
||||
if (m_flush)
|
||||
{
|
||||
m_flush = false;
|
||||
if (fmt::terminal_color::white == m_color)
|
||||
logcat->log(m_log_level, m_oss.str());
|
||||
else
|
||||
logcat->log(m_log_level, "{}",
|
||||
log::detail::text_style_wrapper{fg(m_color), "{}", m_oss.str()});
|
||||
std::cout << std::endl;
|
||||
}
|
||||
flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,59 +43,116 @@ namespace tools
|
|||
class scoped_message_writer
|
||||
{
|
||||
private:
|
||||
bool m_flush;
|
||||
std::ostringstream m_oss;
|
||||
fmt::terminal_color m_color;
|
||||
std::string m_prefix;
|
||||
std::string m_content;
|
||||
std::optional<fmt::terminal_color> m_color;
|
||||
oxen::log::Level m_log_level;
|
||||
public:
|
||||
scoped_message_writer(
|
||||
fmt::terminal_color color = fmt::terminal_color::white
|
||||
, std::string prefix = {}
|
||||
, spdlog::level::level_enum log_level = spdlog::level::info
|
||||
)
|
||||
: m_flush(true)
|
||||
, m_color(color)
|
||||
, m_log_level(log_level)
|
||||
explicit scoped_message_writer(
|
||||
std::optional<fmt::terminal_color> color = std::nullopt,
|
||||
std::string prefix = "",
|
||||
log::Level log_level = log::Level::info
|
||||
)
|
||||
: m_color{color}, m_log_level{log_level}, m_prefix{std::move(prefix)}
|
||||
{}
|
||||
|
||||
scoped_message_writer(scoped_message_writer&& o)
|
||||
: m_prefix{std::move(o.m_prefix)},
|
||||
m_content{std::move(o.m_content)},
|
||||
m_color{o.m_color},
|
||||
m_log_level{o.m_log_level}
|
||||
{
|
||||
m_oss << prefix;
|
||||
o.m_content.clear();
|
||||
}
|
||||
|
||||
scoped_message_writer(scoped_message_writer&& rhs)
|
||||
: m_flush(std::move(rhs.m_flush))
|
||||
, m_oss(std::move(rhs.m_oss))
|
||||
, m_color(std::move(rhs.m_color))
|
||||
, m_log_level(std::move(rhs.m_log_level))
|
||||
{
|
||||
rhs.m_flush = false;
|
||||
}
|
||||
|
||||
scoped_message_writer(scoped_message_writer& rhs) = delete;
|
||||
scoped_message_writer& operator=(scoped_message_writer& rhs) = delete;
|
||||
scoped_message_writer(const scoped_message_writer& rhs) = delete;
|
||||
scoped_message_writer& operator=(const scoped_message_writer& rhs) = delete;
|
||||
scoped_message_writer& operator=(scoped_message_writer&& rhs) = delete;
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(const T& val)
|
||||
/// Appends a message and returns *this (so that it can be chained). If called with more than 1
|
||||
/// argument then the first argument is fmt::format'ed with the remaining arguments.
|
||||
template <typename... T>
|
||||
scoped_message_writer& append(std::string_view msg, T&&... args)
|
||||
{
|
||||
m_oss << val;
|
||||
return m_oss;
|
||||
if constexpr (sizeof...(T))
|
||||
fmt::format_to(std::back_inserter(m_content), msg, std::forward<T>(args)...);
|
||||
else
|
||||
m_content.append(msg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Same as .append(msg). (Doesn't format, just like the single-argument .append(msg)).
|
||||
scoped_message_writer& operator+=(std::string_view msg) { return append(msg); }
|
||||
|
||||
/// Essentially the same as +=, but can only be used on an rvalue instance of the object, so that
|
||||
/// you can do things like: `scoped_message_writer{} + "abc"`, which feels more natural than
|
||||
/// `scoped_message_writer{} += "abc"`.
|
||||
scoped_message_writer&& operator+(std::string_view msg) && { append(msg); return std::move(*this); }
|
||||
|
||||
/// Flushes the current message to output and resets it. This is normally not called explicitly
|
||||
/// but rather implicitly when the object is destroyed.
|
||||
scoped_message_writer& flush();
|
||||
|
||||
/// Prints the complete message on destruction.
|
||||
~scoped_message_writer();
|
||||
};
|
||||
|
||||
inline scoped_message_writer success_msg_writer(bool color = true)
|
||||
template <typename... T>
|
||||
scoped_message_writer msg_writer(std::optional<fmt::terminal_color> color = std::nullopt, T&&... args)
|
||||
{
|
||||
return scoped_message_writer(color ? fmt::terminal_color::green : fmt::terminal_color::white, std::string(), spdlog::level::info);
|
||||
scoped_message_writer writer{color};
|
||||
if constexpr (sizeof...(T))
|
||||
writer.append(std::forward<T>(args)...);
|
||||
return writer;
|
||||
}
|
||||
|
||||
inline scoped_message_writer msg_writer(fmt::terminal_color color = fmt::terminal_color::white)
|
||||
template <typename... T>
|
||||
scoped_message_writer msg_writer(std::string_view msg, T&&... args)
|
||||
{
|
||||
return scoped_message_writer(color, std::string(), spdlog::level::info);
|
||||
return msg_writer(std::nullopt, msg, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
inline scoped_message_writer fail_msg_writer()
|
||||
|
||||
constexpr std::optional<fmt::terminal_color> success_color{fmt::terminal_color::green};
|
||||
constexpr std::optional<fmt::terminal_color> fail_color{fmt::terminal_color::red};
|
||||
|
||||
/// Constructs and returns a scoped_message_writer for a typical success message, with or without
|
||||
/// color, as specified by the first argument. If additional arguments are provided they will be
|
||||
/// passed to append(...) to set a message (or formatted message, if multiple arguments are given).
|
||||
///
|
||||
/// (We deduce the Bool argument here to avoid implicit conversion to bool from non-bool values).
|
||||
template <typename Bool, typename... T, std::enable_if_t<std::is_same_v<Bool, bool>, int> = 0>
|
||||
scoped_message_writer success_msg_writer(Bool color, T&&... args)
|
||||
{
|
||||
return scoped_message_writer(fmt::terminal_color::red, "Error: ", spdlog::level::err);
|
||||
auto writer = msg_writer(color ? success_color : std::nullopt);
|
||||
if constexpr (sizeof...(T))
|
||||
writer.append(std::forward<T>(args)...);
|
||||
return writer;
|
||||
}
|
||||
|
||||
inline scoped_message_writer success_msg_writer()
|
||||
{
|
||||
return success_msg_writer(true);
|
||||
}
|
||||
|
||||
/// Same as above, but for calling without just a message (with a bool). Color will be true.
|
||||
template <typename... T>
|
||||
scoped_message_writer success_msg_writer(std::string_view msg, T&&... args)
|
||||
{
|
||||
return success_msg_writer(true, msg, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
/// Constructs and returns a scoped_message_writer for a typical error message. Color will be
|
||||
/// enabled and the message will be prefixed with "Error: ". Given arguments, if any, are passed to
|
||||
/// .append() and so can specify either a single unformatted string, or a format string + format
|
||||
/// arguments.
|
||||
template <typename... T>
|
||||
scoped_message_writer fail_msg_writer(T&&... args)
|
||||
{
|
||||
scoped_message_writer writer{fail_color, "Error: ", spdlog::level::err};
|
||||
if constexpr (sizeof...(T))
|
||||
writer.append(std::forward<T>(args)...);
|
||||
return writer;
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "string_util.h"
|
||||
#include <fmt/core.h>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace tools {
|
||||
|
||||
|
@ -80,66 +79,39 @@ std::string lowercase_ascii_string(std::string_view src)
|
|||
}
|
||||
|
||||
std::string friendly_duration(std::chrono::nanoseconds dur) {
|
||||
std::ostringstream os;
|
||||
std::string friendly;
|
||||
auto append = std::back_inserter(friendly);
|
||||
bool some = false;
|
||||
if (dur >= 24h) {
|
||||
os << dur / 24h << 'd';
|
||||
fmt::format_to(append, "{}d", dur / 24h);
|
||||
dur %= 24h;
|
||||
some = true;
|
||||
}
|
||||
if (dur >= 1h || some) {
|
||||
os << dur / 1h << 'h';
|
||||
fmt::format_to(append, "{}h", dur / 1h);
|
||||
dur %= 1h;
|
||||
some = true;
|
||||
}
|
||||
if (dur >= 1min || some) {
|
||||
os << dur / 1min << 'm';
|
||||
fmt::format_to(append, "{}m", dur / 1min);
|
||||
dur %= 1min;
|
||||
some = true;
|
||||
}
|
||||
if (some || dur == 0s) {
|
||||
// If we have >= minutes or its exactly 0 seconds then don't bother with fractional seconds
|
||||
os << dur / 1s << 's';
|
||||
fmt::format_to(append, "{}s", dur / 1s);
|
||||
} else {
|
||||
double seconds = std::chrono::duration<double>(dur).count();
|
||||
os.precision(3);
|
||||
if (dur >= 1s)
|
||||
os << seconds << "s";
|
||||
fmt::format_to(append, "{:.3f}s", seconds);
|
||||
else if (dur >= 1ms)
|
||||
os << seconds * 1000 << "ms";
|
||||
fmt::format_to(append, "{:.3f}ms", seconds * 1000);
|
||||
else if (dur >= 1us)
|
||||
os << seconds * 1'000'000 << u8"µs";
|
||||
fmt::format_to(append, "{:.3f}µs", seconds * 1'000'000);
|
||||
else
|
||||
os << seconds * 1'000'000'000 << "ns";
|
||||
fmt::format_to(append, "{:.0f}ns", seconds * 1'000'000'000);
|
||||
}
|
||||
return os.str();
|
||||
return friendly;
|
||||
}
|
||||
|
||||
std::string short_duration(std::chrono::duration<double> dur) {
|
||||
std::ostringstream os;
|
||||
os << std::fixed << std::setprecision(1);
|
||||
if (dur >= 36h)
|
||||
os << dur / 24h;
|
||||
else if (dur >= 90min)
|
||||
os << dur / 1h;
|
||||
else if (dur >= 90s)
|
||||
os << dur / 1min;
|
||||
else if (dur >= 1s)
|
||||
os << dur / 1s;
|
||||
else if (dur >= 100ms)
|
||||
os << std::setprecision(0) << dur / 1ms;
|
||||
else if (dur >= 1ms)
|
||||
os << dur / 1ms;
|
||||
else if (dur >= 100us)
|
||||
os << std::setprecision(0) << dur / 1us;
|
||||
else if (dur >= 1us)
|
||||
os << dur / 1us;
|
||||
else if (dur >= 1ns)
|
||||
os << std::setprecision(0) << dur / 1ns;
|
||||
else
|
||||
os << "0s";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <charconv>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <fmt/format.h>
|
||||
#include "epee/span.h" // epee
|
||||
|
||||
namespace tools {
|
||||
|
@ -60,30 +60,28 @@ std::vector<std::string_view> split(std::string_view str, std::string_view delim
|
|||
std::vector<std::string_view> split_any(std::string_view str, std::string_view delims, bool trim = false);
|
||||
|
||||
/// Joins [begin, end) with a delimiter and returns the resulting string. Elements can be anything
|
||||
/// that can be sent to an ostream via `<<`.
|
||||
/// that can be formatted. Semi-deprecated: this just uses fmt to join.
|
||||
template <typename It>
|
||||
std::string join(std::string_view delimiter, It begin, It end) {
|
||||
std::ostringstream o;
|
||||
if (begin != end)
|
||||
o << *begin++;
|
||||
while (begin != end)
|
||||
o << delimiter << *begin++;
|
||||
return o.str();
|
||||
return fmt::format("{}", fmt::join(begin, end, delimiter));
|
||||
}
|
||||
|
||||
/// Wrapper around the above that takes a container and passes c.begin(), c.end() to the above.
|
||||
/// Same as the above, but works on a container. Just use fmt::join.
|
||||
template <typename Container>
|
||||
std::string join(std::string_view delimiter, const Container& c) { return join(delimiter, c.begin(), c.end()); }
|
||||
std::string join(std::string_view delimiter, const Container& c) {
|
||||
return fmt::format("{}", fmt::join(c, delimiter));
|
||||
}
|
||||
|
||||
/// Similar to join(), but first applies a transformation to each element.
|
||||
template <typename It, typename UnaryOperation>
|
||||
std::string join_transform(std::string_view delimiter, It begin, It end, UnaryOperation transform) {
|
||||
std::ostringstream o;
|
||||
std::string result;
|
||||
auto append = std::back_inserter(result);
|
||||
if (begin != end)
|
||||
o << transform(*begin++);
|
||||
result = fmt::format("{}", transform(*begin++));
|
||||
while (begin != end)
|
||||
o << delimiter << transform(*begin++);
|
||||
return o.str();
|
||||
fmt::format_to(append, "{}{}", delimiter, transform(*begin++));
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Wrapper around the above that takes a container and passes c.begin(), c.end().
|
||||
|
@ -92,22 +90,23 @@ std::string join_transform(std::string_view delimiter, const Container& c, Unary
|
|||
return join_transform(delimiter, c.begin(), c.end(), std::forward<UnaryOperation>(transform));
|
||||
}
|
||||
|
||||
/// Concatenates a bunch of random values together with delim as a separator via << operator.
|
||||
/// Concatenates a bunch of random values together with delim as a separator via fmt::format.
|
||||
/// Returns the result as a string.
|
||||
template <typename T, typename... Ts>
|
||||
std::string join_stuff(std::string_view delim, T&& first, Ts&&... stuff) {
|
||||
std::ostringstream o;
|
||||
o << std::forward<T>(first);
|
||||
((o << delim << std::forward<Ts>(stuff)), ...);
|
||||
return o.str();
|
||||
std::string result = fmt::format(std::forward<T>(first));
|
||||
auto append = std::back_inserter(result);
|
||||
(fmt::format_to(append, "{}{}", delim, std::forward<Ts>(stuff)), ...);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Concatenates arguments via << operator, returns as a string.
|
||||
/// Concatenates arguments via fmt::format operator, returns as a string.
|
||||
template <typename... T>
|
||||
std::string concat(T&&... stuff) {
|
||||
std::ostringstream o;
|
||||
(o << ... << std::forward<T>(stuff));
|
||||
return o.str();
|
||||
std::string result;
|
||||
auto append = std::back_inserter(result);
|
||||
(fmt::format_to(append, "{}", std::forward<T>(stuff)), ...);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Simple version of whitespace trimming: mutates the given string view to remove leading
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#include "epee/mlocker.h"
|
||||
#include "generic-ops.h"
|
||||
#include "common/hex.h"
|
||||
#include "common/format.h"
|
||||
#include "common/formattable.h"
|
||||
#include "hash.h"
|
||||
|
||||
namespace crypto {
|
||||
|
@ -284,27 +286,11 @@ namespace crypto {
|
|||
const public_key& pub,
|
||||
const signature& sig);
|
||||
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::ed25519_public_key &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::x25519_public_key &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::string to_string(const ec_point& P) { return "<{}>"_format(tools::type_to_hex(P)); }
|
||||
inline std::string to_string(const signature& s) { return "<{}>"_format(tools::type_to_hex(s)); }
|
||||
inline std::string to_string(const ed25519_public_key& P) { return "<{}>"_format(tools::type_to_hex(P)); }
|
||||
inline std::string to_string(const x25519_public_key& P) { return "<{}>"_format(tools::type_to_hex(P)); }
|
||||
|
||||
constexpr inline crypto::public_key null_pkey{};
|
||||
const inline crypto::secret_key null_skey{};
|
||||
}
|
||||
|
@ -315,3 +301,8 @@ CRYPTO_MAKE_HASHABLE(key_image)
|
|||
CRYPTO_MAKE_HASHABLE(signature)
|
||||
CRYPTO_MAKE_HASHABLE(ed25519_public_key)
|
||||
CRYPTO_MAKE_HASHABLE(x25519_public_key)
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_string<crypto::ec_point> = true;
|
||||
template <> inline constexpr bool formattable::via_to_string<crypto::signature> = true;
|
||||
template <> inline constexpr bool formattable::via_to_string<crypto::ed25519_public_key> = true;
|
||||
template <> inline constexpr bool formattable::via_to_string<crypto::x25519_public_key> = true;
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "common/format.h"
|
||||
#include "crypto.h"
|
||||
#include "hash.h"
|
||||
|
||||
namespace crypto {
|
||||
template <typename T, typename SFINAE = void>
|
||||
constexpr bool is_hex_printable = false;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_hex_printable<T, std::enable_if_t<std::is_base_of_v<ec_point, T> && sizeof(T) == sizeof(ec_point)>> = true;
|
||||
|
||||
template <> inline constexpr bool is_hex_printable<signature> = true;
|
||||
template <> inline constexpr bool is_hex_printable<ed25519_public_key> = true;
|
||||
template <> inline constexpr bool is_hex_printable<x25519_public_key> = true;
|
||||
template <> inline constexpr bool is_hex_printable<hash> = true;
|
||||
template <> inline constexpr bool is_hex_printable<hash8> = true;
|
||||
|
||||
template <typename T> inline constexpr bool is_hex_printable<T&> = is_hex_printable<T>;
|
||||
template <typename T> inline constexpr bool is_hex_printable<T&&> = is_hex_printable<T>;
|
||||
template <typename T> inline constexpr bool is_hex_printable<const T> = is_hex_printable<T>;
|
||||
|
||||
// Helper for when you are really sure you want to print a secret key (which is not printable by
|
||||
// default so that you have to be explicit and can't accidentally expose one in a log
|
||||
// statement).
|
||||
inline std::string expose_secret(const ec_scalar& secret) {
|
||||
return "<{}>"_format(tools::type_to_hex(secret));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct fmt::formatter<T, Char, std::enable_if_t<crypto::is_hex_printable<T>>> : fmt::formatter<std::string> {
|
||||
auto format(const T& v, format_context& ctx) {
|
||||
return formatter<std::string>::format("<{}>"_format(tools::type_to_hex(v)), ctx);
|
||||
}
|
||||
};
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
#include "generic-ops.h"
|
||||
#include "common/hex.h"
|
||||
#include "common/formattable.h"
|
||||
#include "common/format.h"
|
||||
#include "crypto/cn_heavy_hash.hpp"
|
||||
|
||||
namespace crypto {
|
||||
|
@ -156,12 +158,9 @@ namespace crypto {
|
|||
return c;
|
||||
}
|
||||
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
|
||||
inline std::string to_hex_string(const crypto::hash& h) { return "<{}>"_format(tools::type_to_hex(h)); }
|
||||
inline std::string to_hex_string(const crypto::hash8& h) { return "<{}>"_format(tools::type_to_hex(h)); }
|
||||
|
||||
constexpr inline crypto::hash null_hash = {};
|
||||
constexpr inline crypto::hash8 null_hash8 = {};
|
||||
|
@ -169,3 +168,6 @@ namespace crypto {
|
|||
|
||||
CRYPTO_MAKE_HASHABLE(hash)
|
||||
CRYPTO_MAKE_COMPARABLE(hash8)
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_hex_string<crypto::hash> = true;
|
||||
template <> inline constexpr bool formattable::via_to_hex_string<crypto::hash8> = true;
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <atomic>
|
||||
#include "serialization/variant.h"
|
||||
#include "serialization/vector.h"
|
||||
|
@ -176,9 +175,6 @@ namespace cryptonote
|
|||
{
|
||||
|
||||
public:
|
||||
static char const* version_to_string(txversion v);
|
||||
static char const* type_to_string(txtype type);
|
||||
|
||||
static constexpr txversion get_min_version_for_hf(hf hf_version);
|
||||
static txversion get_max_version_for_hf(hf hf_version);
|
||||
static constexpr txtype get_max_type_for_hf (hf hf_version);
|
||||
|
@ -560,42 +556,6 @@ namespace cryptonote
|
|||
return result;
|
||||
}
|
||||
|
||||
inline const char* transaction_prefix::version_to_string(txversion v)
|
||||
{
|
||||
switch(v)
|
||||
{
|
||||
case txversion::v1: return "1";
|
||||
case txversion::v2_ringct: return "2_ringct";
|
||||
case txversion::v3_per_output_unlock_times: return "3_per_output_unlock_times";
|
||||
case txversion::v4_tx_types: return "4_tx_types";
|
||||
default: assert(false); return "xx_unhandled_version";
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* transaction_prefix::type_to_string(txtype type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case txtype::standard: return "standard";
|
||||
case txtype::state_change: return "state_change";
|
||||
case txtype::key_image_unlock: return "key_image_unlock";
|
||||
case txtype::stake: return "stake";
|
||||
case txtype::oxen_name_system: return "oxen_name_system";
|
||||
default: assert(false); return "xx_unhandled_type";
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, txtype t) {
|
||||
return os << transaction::type_to_string(t);
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& os, txversion v) {
|
||||
return os << transaction::version_to_string(v);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, hf v) = delete;/*{
|
||||
return os << "HF" << static_cast<int>(v);
|
||||
}*/
|
||||
|
||||
// Serialization for the `hf` type; this is simply writing/reading the underlying uint8_t value
|
||||
template <class Archive>
|
||||
void serialize_value(Archive& ar, hf& x) {
|
||||
|
@ -606,21 +566,6 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<cryptonote::txtype> : fmt::formatter<std::string_view> {
|
||||
auto format(cryptonote::txtype t, format_context& ctx) {
|
||||
return formatter<std::string_view>::format(
|
||||
cryptonote::transaction::type_to_string(t), ctx);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct fmt::formatter<cryptonote::txversion> : fmt::formatter<std::string_view> {
|
||||
auto format(cryptonote::txversion v, format_context& ctx) {
|
||||
return formatter<std::string_view>::format(
|
||||
cryptonote::transaction::version_to_string(v), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<cryptonote::account_public_address>
|
||||
|
@ -648,3 +593,5 @@ VARIANT_TAG(cryptonote::txout_to_scripthash, "scripthash", 0x1);
|
|||
VARIANT_TAG(cryptonote::txout_to_key, "key", 0x2);
|
||||
VARIANT_TAG(cryptonote::transaction, "tx", 0xcc);
|
||||
VARIANT_TAG(cryptonote::block, "block", 0xbb);
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_string<cryptonote::transaction> = true;
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "cryptonote_config.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "crypto/fmt.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "cryptonote_basic/verification_context.h"
|
||||
#include "cryptonote_core/service_node_voting.h"
|
||||
|
@ -269,7 +268,7 @@ namespace cryptonote
|
|||
bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
|
||||
if (!r)
|
||||
{
|
||||
log::warning(logcat, "key image helper: failed to generate_key_derivation({}, <{}>)", tx_public_key, expose_secret(ack.m_view_secret_key));
|
||||
log::warning(logcat, "key image helper: failed to generate_key_derivation({}, <{}>)", tx_public_key, tools::type_to_hex(ack.m_view_secret_key));
|
||||
memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation));
|
||||
}
|
||||
|
||||
|
@ -280,7 +279,7 @@ namespace cryptonote
|
|||
r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation);
|
||||
if (!r)
|
||||
{
|
||||
log::warning(logcat, "key image helper: failed to generate_key_derivation({}, {})", additional_tx_public_keys[i], expose_secret(ack.m_view_secret_key));
|
||||
log::warning(logcat, "key image helper: failed to generate_key_derivation({}, {})", additional_tx_public_keys[i], tools::type_to_hex(ack.m_view_secret_key));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -902,13 +901,13 @@ namespace cryptonote
|
|||
{
|
||||
if (!tx.is_transfer() && tx.vout.size() != 0)
|
||||
{
|
||||
log::warning(logcat, "tx type: {} must have 0 outputs, received: {}, id={}", transaction::type_to_string(tx.type), tx.vout.size(), get_transaction_hash(tx));
|
||||
log::warning(logcat, "tx type: {} must have 0 outputs, received: {}, id={}", tx.type, tx.vout.size(), get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tx.version >= txversion::v3_per_output_unlock_times && tx.vout.size() != tx.output_unlock_times.size())
|
||||
{
|
||||
log::warning(logcat, "tx version: {} must have equal number of output unlock times and outputs", transaction::version_to_string(tx.version));
|
||||
log::warning(logcat, "tx version: {} must have equal number of output unlock times and outputs", tx.version);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -1104,7 +1103,7 @@ namespace cryptonote
|
|||
if (tvc.m_key_image_blacklisted) os << "Key image is blacklisted on the service node network, ";
|
||||
|
||||
if (tx)
|
||||
os << "TX Version: " << tx->version << ", Type: " << tx->type;
|
||||
os << "TX Version: {}, Type: {}"_format(tx->version, tx->type);
|
||||
|
||||
std::string buf = os.str();
|
||||
if (buf.size() >= 2 && buf[buf.size() - 2] == ',')
|
||||
|
|
|
@ -248,12 +248,10 @@ namespace cryptonote
|
|||
|
||||
bool is_valid_address(const std::string address, cryptonote::network_type nettype, bool allow_subaddress = true, bool allow_integrated = true);
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, transaction const &tx)
|
||||
inline std::string to_string(const transaction& tx)
|
||||
{
|
||||
stream << "tx={version=" << tx.version << ", type=" << tx.type << ", hash=" << get_transaction_hash(tx) << "}";
|
||||
return stream;
|
||||
return "tx={{version={}, type={}, hash={}}}"_format(tx.version, tx.type, get_transaction_hash(tx));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
template <typename T>
|
||||
bool t_serializable_object_from_blob(T& to, const std::string& blob)
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <ostream>
|
||||
|
||||
#include "common/oxen.h"
|
||||
#include "common/formattable.h"
|
||||
#include "common/format.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
@ -48,7 +50,7 @@ namespace cryptonote
|
|||
|
||||
std::string to_string() const
|
||||
{
|
||||
return std::to_string(major) + '/' + std::to_string(minor);
|
||||
return "{}/{}"_format(major, minor);
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
|
@ -62,14 +64,10 @@ namespace cryptonote
|
|||
field(ar, "major", x.major);
|
||||
field(ar, "minor", x.minor);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const cryptonote::subaddress_index& subaddr_index)
|
||||
{
|
||||
return out << subaddr_index.major << '/' << subaddr_index.minor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_string<cryptonote::subaddress_index> = true;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
|
|
|
@ -113,6 +113,7 @@ struct alignas(size_t) generic_owner
|
|||
std::string to_string(cryptonote::network_type nettype) const;
|
||||
explicit operator bool() const { return (type == generic_owner_sig_type::monero) ? wallet.address != cryptonote::null_address : ed25519; }
|
||||
bool operator==(generic_owner const &other) const;
|
||||
bool operator!=(generic_owner const &other) const { return !(*this == other); }
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
ENUM_FIELD(type, type < generic_owner_sig_type::_count)
|
||||
|
@ -149,9 +150,6 @@ struct generic_signature
|
|||
};
|
||||
|
||||
static_assert(sizeof(crypto::ed25519_signature) == sizeof(crypto::signature), "ONS allows storing either ed25519 or monero style signatures, we store all signatures into crypto::signature in ONS");
|
||||
inline std::ostream &operator<<(std::ostream &o, const generic_signature &v) {
|
||||
return o << '<' << tools::type_to_hex(v.data) << '>';
|
||||
}
|
||||
|
||||
} // namespace ons
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <cassert>
|
||||
#include "common/formattable.h"
|
||||
|
||||
namespace cryptonote {
|
||||
|
||||
enum class txversion : uint16_t {
|
||||
using namespace std::literals;
|
||||
|
||||
enum class txversion : uint16_t {
|
||||
v0 = 0,
|
||||
v1,
|
||||
v2_ringct,
|
||||
|
@ -21,4 +26,31 @@ enum class txversion : uint16_t {
|
|||
_count
|
||||
};
|
||||
|
||||
inline constexpr std::string_view to_string(txversion v) {
|
||||
switch(v)
|
||||
{
|
||||
case txversion::v1: return "1"sv;
|
||||
case txversion::v2_ringct: return "2_ringct"sv;
|
||||
case txversion::v3_per_output_unlock_times: return "3_per_output_unlock_times"sv;
|
||||
case txversion::v4_tx_types: return "4_tx_types"sv;
|
||||
default: assert(false); return "xx_unhandled_version"sv;
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr std::string_view to_string(txtype type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case txtype::standard: return "standard"sv;
|
||||
case txtype::state_change: return "state_change"sv;
|
||||
case txtype::key_image_unlock: return "key_image_unlock"sv;
|
||||
case txtype::stake: return "stake"sv;
|
||||
case txtype::oxen_name_system: return "oxen_name_system"sv;
|
||||
default: assert(false); return "xx_unhandled_type"sv;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_string<cryptonote::txversion> = true;
|
||||
template <> inline constexpr bool formattable::via_to_string<cryptonote::txtype> = true;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "common/hex.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/median.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "epee/string_tools.h"
|
||||
|
||||
#include <unordered_set>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <oxenc/base32z.h>
|
||||
|
||||
|
@ -50,6 +49,7 @@ extern "C" {
|
|||
#include "cryptonote_core.h"
|
||||
#include "uptime_proof.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "common/sha256sum.h"
|
||||
#include "common/threadpool.h"
|
||||
#include "common/command_line.h"
|
||||
|
@ -1488,11 +1488,11 @@ namespace cryptonote
|
|||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Blink validation failed:";
|
||||
std::string blink_error = "Blink validation failed:";
|
||||
auto append = std::back_inserter(blink_error);
|
||||
for (auto &f : failures)
|
||||
os << " [" << int(bdata.quorum[f.first]) << ":" << int(bdata.position[f.first]) << "]: " << f.second;
|
||||
log::info(logcat, "Invalid blink tx {}: {}", bdata.tx_hash, os.str());
|
||||
fmt::format_to(append, " [{}:{}]: {}", int(bdata.quorum[f.first]), int(bdata.position[f.first]), f.second);
|
||||
log::info(logcat, "Invalid blink tx {}: {}", bdata.tx_hash, blink_error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "crypto/fmt.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "multisig/multisig.h"
|
||||
#include "epee/int-util.h"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "common/oxen.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
|
@ -132,20 +133,18 @@ namespace {
|
|||
|
||||
std::string ons_extra_string(cryptonote::network_type nettype, cryptonote::tx_extra_oxen_name_system const &data)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << "ONS Extra={";
|
||||
std::string extra = "ONS Extra={";
|
||||
auto append = std::back_inserter(extra);
|
||||
if (data.is_buying())
|
||||
{
|
||||
stream << "owner=" << data.owner.to_string(nettype);
|
||||
stream << ", backup_owner=" << (data.backup_owner ? data.backup_owner.to_string(nettype) : "(none)");
|
||||
}
|
||||
fmt::format_to(append, "owner={}, backup_owner={}",
|
||||
data.owner.to_string(nettype), (data.backup_owner ? data.backup_owner.to_string(nettype) : "(none)"));
|
||||
else if (data.is_renewing())
|
||||
stream << "renewal";
|
||||
extra += "renewal";
|
||||
else
|
||||
stream << "signature=" << tools::type_to_hex(data.signature.data);
|
||||
fmt::format_to(append, "signature={}", tools::type_to_hex(data.signature.data));
|
||||
|
||||
stream << ", type=" << data.type << ", name_hash=" << data.name_hash << "}";
|
||||
return stream.str();
|
||||
fmt::format_to(append, ", type={}, name_hash={}}}", data.type, data.name_hash);
|
||||
return extra;
|
||||
}
|
||||
|
||||
/// Clears any existing bindings
|
||||
|
@ -742,13 +741,9 @@ static constexpr bool char_is_alphanum_or(char c)
|
|||
static constexpr bool char_is_alphanum(char c) { return char_is_alphanum_or<>(c); }
|
||||
|
||||
template <typename... T>
|
||||
static bool check_condition(bool condition, std::string* reason, T&&... args) {
|
||||
static bool check_condition(bool condition, std::string* reason, std::string_view format, T&&... args) {
|
||||
if (condition && reason)
|
||||
{
|
||||
std::ostringstream os;
|
||||
(os << ... << std::forward<T>(args));
|
||||
*reason = os.str();
|
||||
}
|
||||
*reason = fmt::format(format, std::forward<T>(args)...);
|
||||
return condition;
|
||||
}
|
||||
|
||||
|
@ -766,17 +761,15 @@ bool validate_ons_name(mapping_type type, std::string name, std::string *reason)
|
|||
else
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
std::stringstream err_stream;
|
||||
err_stream << "ONS type=" << mapping_type_str(type) << ", specifies unhandled mapping type in name validation";
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
*reason = "ONS type={} specifies unhandled mapping type in name validation"_format(type);
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Validate name length
|
||||
name = tools::lowercase_ascii_string(name);
|
||||
if (check_condition((name.empty() || name.size() > max_name_len), reason, "ONS type=", type, ", specifies mapping from name->value where the name's length=", name.size(), " is 0 or exceeds the maximum length=", max_name_len, ", given name=", name))
|
||||
if (check_condition((name.empty() || name.size() > max_name_len), reason,
|
||||
"ONS type={} specifies mapping from name->value where the name's length={} is 0 or exceeds the maximum length={}, given name={}",
|
||||
type, name.size(), max_name_len, name))
|
||||
return false;
|
||||
|
||||
std::string_view name_view{name}; // Will chop this down as we validate each part
|
||||
|
@ -796,41 +789,46 @@ bool validate_ons_name(mapping_type type, std::string name, std::string *reason)
|
|||
// domains (in which case the user looking up "foo.loki" would try end up trying to resolve
|
||||
// "foo.loki.loki").
|
||||
for (auto& reserved : {"localhost.loki"sv, "loki.loki"sv, "snode.loki"sv})
|
||||
if (check_condition(name == reserved, reason, "ONS type=", type, ", specifies mapping from name->value using protocol reserved name=", name))
|
||||
if (check_condition(name == reserved, reason,
|
||||
"ONS type={} specifies mapping from name->value using protocol reserved name={}", type, name))
|
||||
return false;
|
||||
|
||||
auto constexpr SHORTEST_DOMAIN = "a.loki"sv;
|
||||
if (check_condition(name.size() < SHORTEST_DOMAIN.size(), reason, "ONS type=", type, ", specifies mapping from name->value where the name is shorter than the shortest possible name=", SHORTEST_DOMAIN, ", given name=", name))
|
||||
if (check_condition(name.size() < SHORTEST_DOMAIN.size(), reason,
|
||||
"ONS type={} specifies mapping from name->value where the name is shorter than the shortest possible name={}, given name={}", type, SHORTEST_DOMAIN, name))
|
||||
return false;
|
||||
|
||||
// Must end with .loki
|
||||
auto constexpr SUFFIX = ".loki"sv;
|
||||
if (check_condition(!tools::ends_with(name_view, SUFFIX), reason, "ONS type=", type, ", specifies mapping from name->value where the name does not end with the domain .loki, name=", name))
|
||||
if (check_condition(!tools::ends_with(name_view, SUFFIX), reason,
|
||||
"ONS type={} specifies mapping from name->value where the name does not end with the domain .loki, name={}", type, name))
|
||||
return false;
|
||||
|
||||
name_view.remove_suffix(SUFFIX.size());
|
||||
|
||||
// All domains containing '--' as 3rd/4th letter are reserved except for xn-- punycode domains
|
||||
if (check_condition(name_view.size() >= 4 && name_view.substr(2, 2) == "--"sv && !tools::starts_with(name_view, "xn--"sv),
|
||||
reason, "ONS type=", type, ", specifies reserved name `?\?--*.loki': ", name))
|
||||
reason, "ONS type={} specifies reserved name `?\?--*.loki': {}", type, name))
|
||||
return false;
|
||||
|
||||
// Must start with alphanumeric
|
||||
if (check_condition(!char_is_alphanum(name_view.front()), reason, "ONS type=", type, ", specifies mapping from name->value where the name does not start with an alphanumeric character, name=", name))
|
||||
if (check_condition(!char_is_alphanum(name_view.front()), reason,
|
||||
"ONS type={} specifies mapping from name->value where the name does not start with an alphanumeric character, name={}", type, name))
|
||||
return false;
|
||||
|
||||
name_view.remove_prefix(1);
|
||||
|
||||
if (!name_view.empty()) {
|
||||
// Character preceding .loki must be alphanumeric
|
||||
if (check_condition(!char_is_alphanum(name_view.back()), reason, "ONS type=", type ,", specifies mapping from name->value where the character preceding the .loki is not alphanumeric, char=", name_view.back(), ", name=", name))
|
||||
if (check_condition(!char_is_alphanum(name_view.back()), reason,
|
||||
"ONS type={} specifies mapping from name->value where the character preceding the .loki is not alphanumeric, char={}, name={}", type, name_view.back(), name))
|
||||
return false;
|
||||
name_view.remove_suffix(1);
|
||||
}
|
||||
|
||||
// Inbetween start and preceding suffix, (alphanumeric or hyphen) characters permitted
|
||||
if (check_condition(!std::all_of(name_view.begin(), name_view.end(), char_is_alphanum_or<'-'>),
|
||||
reason, "ONS type=", type, ", specifies mapping from name->value where the domain name contains more than the permitted alphanumeric or hyphen characters, name=", name))
|
||||
reason, "ONS type={} specifies mapping from name->value where the domain name contains more than the permitted alphanumeric or hyphen characters, name={}", type, name))
|
||||
return false;
|
||||
}
|
||||
else if (type == mapping_type::session || type == mapping_type::wallet)
|
||||
|
@ -840,20 +838,22 @@ bool validate_ons_name(mapping_type type, std::string name, std::string *reason)
|
|||
// ^[a-z0-9_]([a-z0-9-_]*[a-z0-9_])?$
|
||||
|
||||
// Must start with (alphanumeric or underscore)
|
||||
if (check_condition(!char_is_alphanum_or<'_'>(name_view.front()), reason, "ONS type=", type, ", specifies mapping from name->value where the name does not start with an alphanumeric or underscore character, name=", name))
|
||||
if (check_condition(!char_is_alphanum_or<'_'>(name_view.front()), reason,
|
||||
"ONS type={} specifies mapping from name->value where the name does not start with an alphanumeric or underscore character, name={}", type, name))
|
||||
return false;
|
||||
name_view.remove_prefix(1);
|
||||
|
||||
if (!name_view.empty()) {
|
||||
// Must NOT end with a hyphen '-'
|
||||
if (check_condition(!char_is_alphanum_or<'_'>(name_view.back()), reason, "ONS type=", type, ", specifies mapping from name->value where the last character is a hyphen '-' which is disallowed, name=", name))
|
||||
if (check_condition(!char_is_alphanum_or<'_'>(name_view.back()), reason,
|
||||
"ONS type={} specifies mapping from name->value where the last character is a hyphen '-' which is disallowed, name={}", type, name))
|
||||
return false;
|
||||
name_view.remove_suffix(1);
|
||||
}
|
||||
|
||||
// Inbetween start and preceding suffix, (alphanumeric, hyphen or underscore) characters permitted
|
||||
if (check_condition(!std::all_of(name_view.begin(), name_view.end(), char_is_alphanum_or<'-', '_'>),
|
||||
reason, "ONS type=", type, ", specifies mapping from name->value where the name contains more than the permitted alphanumeric, underscore or hyphen characters, name=", name))
|
||||
reason, "ONS type={} specifies mapping from name->value where the name contains more than the permitted alphanumeric, underscore or hyphen characters, name={}", type, name))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
@ -886,11 +886,8 @@ static bool check_lengths(mapping_type type, std::string_view value, size_t max,
|
|||
{
|
||||
if (reason)
|
||||
{
|
||||
std::stringstream err_stream;
|
||||
err_stream << "ONS type=" << type << ", specifies mapping from name_hash->encrypted_value where the value's length=" << value.size() << ", does not equal the required length=" << max << ", given value=";
|
||||
if (binary_val) err_stream << oxenc::to_hex(value);
|
||||
else err_stream << value;
|
||||
*reason = err_stream.str();
|
||||
*reason = "ONS type={} specifies mapping from name_hash->encrypted_value where the value's length={} does not equal the required length={}, given value={}"_format(
|
||||
type, value.size(), max, binary_val ? oxenc::to_hex(value) : value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -903,7 +900,6 @@ bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type
|
|||
if (blob) *blob = {};
|
||||
|
||||
// Check length of the value
|
||||
std::stringstream err_stream;
|
||||
cryptonote::address_parse_info addr_info = {};
|
||||
if (type == mapping_type::wallet)
|
||||
{
|
||||
|
@ -912,15 +908,9 @@ bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type
|
|||
if (reason)
|
||||
{
|
||||
if (value.empty())
|
||||
{
|
||||
err_stream << "The value=" << value;
|
||||
err_stream << ", mapping into the wallet address, specifies a wallet address of 0 length";
|
||||
}
|
||||
*reason = "The value={}, mapping into the wallet address, specifies a wallet address of 0 length"_format(value);
|
||||
else
|
||||
{
|
||||
err_stream << "Could not convert the wallet address string, check it is correct, value=" << value;
|
||||
}
|
||||
*reason = err_stream.str();
|
||||
*reason = "Could not convert the wallet address string, check it is correct, value={}"_format(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -955,7 +945,7 @@ bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type
|
|||
// 51 base32z chars (=255 bits) followed by a 1-bit value ('y'=0, or 'o'=0b10000); anything else
|
||||
// in the last spot isn't a valid lokinet address.
|
||||
if (check_condition(value.size() != 57 || !tools::ends_with(value, ".loki") || !oxenc::is_base32z(value.substr(0, 52)) || !(value[51] == 'y' || value[51] == 'o'),
|
||||
reason, "'", value, "' is not a valid lokinet address"))
|
||||
reason, "'{}' is not a valid lokinet address", value))
|
||||
return false;
|
||||
|
||||
if (blob)
|
||||
|
@ -968,14 +958,17 @@ bool mapping_value::validate(cryptonote::network_type nettype, mapping_type type
|
|||
{
|
||||
assert(type == mapping_type::session);
|
||||
// NOTE: Check value is hex of the right size
|
||||
if (check_condition(value.size() != 2*SESSION_PUBLIC_KEY_BINARY_LENGTH, reason, "The value=", value, " is not the required ", 2*SESSION_PUBLIC_KEY_BINARY_LENGTH, "-character hex string session public key, length=", value.size()))
|
||||
if (check_condition(value.size() != 2*SESSION_PUBLIC_KEY_BINARY_LENGTH, reason,
|
||||
"The value={} is not the required {}-character hex string session public key, length={}", value, 2*SESSION_PUBLIC_KEY_BINARY_LENGTH, value.size()))
|
||||
return false;
|
||||
|
||||
if (check_condition(!oxenc::is_hex(value), reason, ", specifies name -> value mapping where the value is not a hex string given value="))
|
||||
if (check_condition(!oxenc::is_hex(value), reason,
|
||||
"value={} specifies name -> value mapping where the value is not a hex string", value))
|
||||
return false;
|
||||
|
||||
// NOTE: Session public keys are 33 bytes, with the first byte being 0x05 and the remaining 32 being the public key.
|
||||
if (check_condition(!tools::starts_with(value, "05"), reason, "ONS type=session, specifies mapping from name -> ed25519 key where the key is not prefixed with 05, given ed25519=", value))
|
||||
if (check_condition(!tools::starts_with(value, "05"), reason,
|
||||
"ONS type=session specifies mapping from name -> ed25519 key where the key is not prefixed with 05, given ed25519={}", value))
|
||||
return false;
|
||||
|
||||
if (blob) // NOTE: Given blob, write the binary output
|
||||
|
@ -995,7 +988,6 @@ static_assert(SODIUM_ENCRYPTION_EXTRA_BYTES >= crypto_secretbox_MACBYTES);
|
|||
bool mapping_value::validate_encrypted(mapping_type type, std::string_view value, mapping_value* blob, std::string *reason)
|
||||
{
|
||||
if (blob) *blob = {};
|
||||
std::stringstream err_stream;
|
||||
|
||||
int value_len = crypto_aead_xchacha20poly1305_ietf_ABYTES + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
|
||||
|
||||
|
@ -1017,10 +1009,7 @@ bool mapping_value::validate_encrypted(mapping_type type, std::string_view value
|
|||
else
|
||||
{
|
||||
if (reason)
|
||||
{
|
||||
err_stream << "Unhandled type passed into " << __func__;
|
||||
*reason = err_stream.str();
|
||||
}
|
||||
*reason = "Unhandled type passed into {}"_format(__func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1090,9 +1079,6 @@ static bool verify_ons_signature(crypto::hash const &hash, ons::generic_signatur
|
|||
|
||||
static bool validate_against_previous_mapping(ons::name_system_db &ons_db, uint64_t blockchain_height, cryptonote::transaction const &tx, cryptonote::tx_extra_oxen_name_system const &ons_extra, std::string *reason)
|
||||
{
|
||||
std::stringstream err_stream;
|
||||
OXEN_DEFER { if (reason && reason->empty()) *reason = err_stream.str(); };
|
||||
|
||||
crypto::hash expected_prev_txid = crypto::null_hash;
|
||||
std::string name_hash = hash_to_base64(ons_extra.name_hash);
|
||||
ons::mapping_record mapping = ons_db.get_mapping(ons_extra.type, name_hash);
|
||||
|
@ -1102,20 +1088,25 @@ static bool validate_against_previous_mapping(ons::name_system_db &ons_db, uint6
|
|||
// Updating: the mapping must exist and be active, the updated fields must actually change from
|
||||
// the current value, and a valid signature over the updated values must be present.
|
||||
|
||||
if (check_condition(!mapping, reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " update requested but mapping does not exist."))
|
||||
if (check_condition(!mapping, reason,
|
||||
"{}, {} update requested but mapping does not exist.", tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
if (check_condition(!mapping.active(blockchain_height), reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " TX requested to update mapping that has already expired"))
|
||||
if (check_condition(!mapping.active(blockchain_height), reason,
|
||||
"{}, {} TX requested to update mapping that has already expired", tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
expected_prev_txid = mapping.txid;
|
||||
|
||||
constexpr auto SPECIFYING_SAME_VALUE_ERR = " field to update is specifying the same mapping "sv;
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::encrypted_value) && ons_extra.encrypted_value == mapping.encrypted_value.to_view(), reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), SPECIFYING_SAME_VALUE_ERR, "value"))
|
||||
constexpr auto SPECIFYING_SAME_VALUE_ERR = "{}, {} field to update is specifying the same mapping {}"sv;
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::encrypted_value) && ons_extra.encrypted_value == mapping.encrypted_value.to_view(), reason,
|
||||
SPECIFYING_SAME_VALUE_ERR, tx, ons_extra_string(ons_db.network_type(), ons_extra), "value"))
|
||||
return false;
|
||||
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::owner) && ons_extra.owner == mapping.owner, reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), SPECIFYING_SAME_VALUE_ERR, "owner"))
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::owner) && ons_extra.owner == mapping.owner, reason,
|
||||
SPECIFYING_SAME_VALUE_ERR, tx, ons_extra_string(ons_db.network_type(), ons_extra), "owner"))
|
||||
return false;
|
||||
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::backup_owner) && ons_extra.backup_owner == mapping.backup_owner, reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), SPECIFYING_SAME_VALUE_ERR, "backup_owner"))
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::backup_owner) && ons_extra.backup_owner == mapping.backup_owner, reason,
|
||||
SPECIFYING_SAME_VALUE_ERR, tx, ons_extra_string(ons_db.network_type(), ons_extra), "backup_owner"))
|
||||
return false;
|
||||
|
||||
// Validate signature
|
||||
|
@ -1124,7 +1115,8 @@ static bool validate_against_previous_mapping(ons::name_system_db &ons_db, uint6
|
|||
ons_extra.field_is_set(ons::extra_field::owner) ? &ons_extra.owner : nullptr,
|
||||
ons_extra.field_is_set(ons::extra_field::backup_owner) ? &ons_extra.backup_owner : nullptr,
|
||||
expected_prev_txid);
|
||||
if (check_condition(data.empty(), reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " unexpectedly failed to generate signature, please inform the Loki developers"))
|
||||
if (check_condition(data.empty(), reason,
|
||||
"{}, {} unexpectedly failed to generate signature, please inform the Oxen developers", tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
|
||||
crypto::hash hash;
|
||||
|
@ -1132,52 +1124,65 @@ static bool validate_against_previous_mapping(ons::name_system_db &ons_db, uint6
|
|||
|
||||
if (check_condition(!verify_ons_signature(hash, ons_extra.signature, mapping.owner) &&
|
||||
!verify_ons_signature(hash, ons_extra.signature, mapping.backup_owner), reason,
|
||||
tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " failed to verify signature for ONS update, current owner=", mapping.owner.to_string(ons_db.network_type()), ", backup owner=", mapping.backup_owner.to_string(ons_db.network_type())))
|
||||
"{}, {} failed to verify signature for ONS update, current owner={}, backup owner={}",
|
||||
tx, ons_extra_string(ons_db.network_type(), ons_extra), mapping.owner.to_string(ons_db.network_type()), mapping.backup_owner.to_string(ons_db.network_type())))
|
||||
return false;
|
||||
}
|
||||
else if (ons_extra.is_buying())
|
||||
{
|
||||
// If buying a new name then the existing name must not be active
|
||||
if (check_condition(mapping.active(blockchain_height), reason,
|
||||
"Cannot buy an ONS name that is already registered: name_hash=", mapping.name_hash, ", type=", mapping.type,
|
||||
"; TX: ", tx, "; ", ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
"Cannot buy an ONS name that is already registered: name_hash={}, type={}; TX: {}; {}",
|
||||
mapping.name_hash, mapping.type, tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
|
||||
// If buying a new wallet name then the existing session name must not be active and vice versa
|
||||
// The owner of an existing name but different type is allowed to register but the owner and backup owners
|
||||
// of the new mapping must be from the same owners and backup owners of the previous mapping ie no
|
||||
// new addresses are allowed to be added as owner or backup owner.
|
||||
if (ons_extra.type == mapping_type::wallet)
|
||||
if (ons_extra.type == mapping_type::wallet || ons_extra.type == mapping_type::session)
|
||||
{
|
||||
ons::mapping_record session_mapping = ons_db.get_mapping(mapping_type::session, name_hash);
|
||||
if (check_condition(session_mapping.active(blockchain_height) && (!(session_mapping.owner == ons_extra.owner || session_mapping.backup_owner == ons_extra.owner) || !(!ons_extra.field_is_set(ons::extra_field::backup_owner) || session_mapping.backup_owner == ons_extra.backup_owner || session_mapping.owner == ons_extra.backup_owner)), reason,
|
||||
"Cannot buy an ONS wallet name that has an already registered session name: name_hash=", mapping.name_hash, ", type=", mapping.type,
|
||||
"; TX: ", tx, "; ", ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
} else if (ons_extra.type == mapping_type::session) {
|
||||
ons::mapping_record wallet_mapping = ons_db.get_mapping(mapping_type::wallet, name_hash);
|
||||
if (check_condition(wallet_mapping.active(blockchain_height) && (!(wallet_mapping.owner == ons_extra.owner || wallet_mapping.backup_owner == ons_extra.owner) || !(!ons_extra.field_is_set(ons::extra_field::backup_owner) || wallet_mapping.backup_owner == ons_extra.backup_owner || wallet_mapping.owner == ons_extra.backup_owner)), reason,
|
||||
"Cannot buy an ONS session name that has an already registered wallet name: name_hash=", mapping.name_hash, ", type=", mapping.type,
|
||||
"; TX: ", tx, "; ", ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
auto buy_type_name = ons_extra.type == mapping_type::wallet ? "wallet"sv : "session"sv;
|
||||
auto alt_type_name = ons_extra.type == mapping_type::wallet ? "session"sv : "wallet"sv;
|
||||
auto alt_type = ons_extra.type == mapping_type::wallet ? mapping_type::session : mapping_type::wallet;
|
||||
|
||||
ons::mapping_record alt_mapping = ons_db.get_mapping(alt_type, name_hash);
|
||||
|
||||
auto is_alt_record_owner = [&alt_mapping](const auto& new_owner) {
|
||||
return new_owner == alt_mapping.owner || new_owner == alt_mapping.backup_owner;
|
||||
};
|
||||
|
||||
if (check_condition(
|
||||
alt_mapping.active(blockchain_height) && // alternative mapping exists
|
||||
(
|
||||
!is_alt_record_owner(ons_extra.owner) ||
|
||||
(ons_extra.field_is_set(ons::extra_field::backup_owner) && !is_alt_record_owner(ons_extra.backup_owner))
|
||||
),
|
||||
reason,
|
||||
"Cannot buy an ONS {} name that has an already registered {} name: name_hash={}, type={}; TX: {}; {}",
|
||||
buy_type_name, alt_type_name, mapping.name_hash, mapping.type, tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ons_extra.is_renewing())
|
||||
{
|
||||
// We allow anyone to renew a name, but it has to exist and be currently active
|
||||
if (check_condition(!mapping, reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " renewal requested but mapping does not exist."))
|
||||
if (check_condition(!mapping, reason, "{}, {} renewal requested but mapping does not exist.", tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
if (check_condition(!mapping.active(blockchain_height), reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " TX requested to renew mapping that has already expired"))
|
||||
if (check_condition(!mapping.active(blockchain_height), reason,
|
||||
"{}, {} TX requested to renew mapping that has already expired", tx, ons_extra_string(ons_db.network_type(), ons_extra)))
|
||||
return false;
|
||||
expected_prev_txid = mapping.txid;
|
||||
}
|
||||
else
|
||||
{
|
||||
check_condition(true, reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " is not a valid buy, update, or renew ONS tx");
|
||||
check_condition(true, reason, "{}, {} is not a valid buy, update, or renew ONS tx", tx, ons_extra_string(ons_db.network_type(), ons_extra));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (check_condition(ons_extra.prev_txid != expected_prev_txid, reason, tx, ", ", ons_extra_string(ons_db.network_type(), ons_extra), " specified prior txid=", ons_extra.prev_txid, ", but ONS DB reports=", expected_prev_txid, ", possible competing TX was submitted and accepted before this TX was processed"))
|
||||
if (check_condition(ons_extra.prev_txid != expected_prev_txid, reason,
|
||||
"{}, {} specified prior txid {} but expected {}; perhaps a competing ONS TX was submitted and accepted before this ONS update TX was processed?",
|
||||
tx, ons_extra_string(ons_db.network_type(), ons_extra), ons_extra.prev_txid, expected_prev_txid))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -1192,10 +1197,12 @@ bool name_system_db::validate_ons_tx(hf hf_version, uint64_t blockchain_height,
|
|||
// Pull out ONS Extra from TX
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (check_condition(tx.type != cryptonote::txtype::oxen_name_system, reason, tx, ", uses wrong tx type, expected=", cryptonote::txtype::oxen_name_system))
|
||||
if (check_condition(tx.type != cryptonote::txtype::oxen_name_system, reason,
|
||||
"{} uses wrong tx type, expected={}", tx, cryptonote::txtype::oxen_name_system))
|
||||
return false;
|
||||
|
||||
if (check_condition(!cryptonote::get_field_from_tx_extra(tx.extra, ons_extra), reason, tx, ", didn't have oxen name service in the tx_extra"))
|
||||
if (check_condition(!cryptonote::get_field_from_tx_extra(tx.extra, ons_extra), reason,
|
||||
"{} didn't have oxen name service in the tx_extra", tx))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1204,17 +1211,21 @@ bool name_system_db::validate_ons_tx(hf hf_version, uint64_t blockchain_height,
|
|||
// Check TX ONS Serialized Fields are NULL if they are not specified
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
{
|
||||
constexpr auto VALUE_SPECIFIED_BUT_NOT_REQUESTED = ", given field but field is not requested to be serialised="sv;
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::encrypted_value) && ons_extra.encrypted_value.size(), reason, tx, ", ", ons_extra_string(nettype, ons_extra), VALUE_SPECIFIED_BUT_NOT_REQUESTED, "encrypted_value"))
|
||||
constexpr auto VALUE_SPECIFIED_BUT_NOT_REQUESTED = "{}, {} given field {} but field is not requested to be serialised"sv;
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::encrypted_value) && ons_extra.encrypted_value.size(), reason,
|
||||
VALUE_SPECIFIED_BUT_NOT_REQUESTED, tx, ons_extra_string(nettype, ons_extra), "encrypted_value"))
|
||||
return false;
|
||||
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::owner) && ons_extra.owner, reason, tx, ", ", ons_extra_string(nettype, ons_extra), VALUE_SPECIFIED_BUT_NOT_REQUESTED, "owner"))
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::owner) && ons_extra.owner, reason,
|
||||
VALUE_SPECIFIED_BUT_NOT_REQUESTED, tx, ons_extra_string(nettype, ons_extra), "owner"))
|
||||
return false;
|
||||
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::backup_owner) && ons_extra.backup_owner, reason, tx, ", ", ons_extra_string(nettype, ons_extra), VALUE_SPECIFIED_BUT_NOT_REQUESTED, "backup_owner"))
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::backup_owner) && ons_extra.backup_owner, reason,
|
||||
VALUE_SPECIFIED_BUT_NOT_REQUESTED, tx, ons_extra_string(nettype, ons_extra), "backup_owner"))
|
||||
return false;
|
||||
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::signature) && ons_extra.signature, reason, tx, ", ", ons_extra_string(nettype, ons_extra), VALUE_SPECIFIED_BUT_NOT_REQUESTED, "signature"))
|
||||
if (check_condition(!ons_extra.field_is_set(ons::extra_field::signature) && ons_extra.signature, reason,
|
||||
VALUE_SPECIFIED_BUT_NOT_REQUESTED, tx, ons_extra_string(nettype, ons_extra), "signature"))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1222,22 +1233,28 @@ bool name_system_db::validate_ons_tx(hf hf_version, uint64_t blockchain_height,
|
|||
// Simple ONS Extra Validation
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (check_condition(ons_extra.version != 0, reason, tx, ", ", ons_extra_string(nettype, ons_extra), " unexpected version=", std::to_string(ons_extra.version), ", expected=0"))
|
||||
if (check_condition(ons_extra.version != 0, reason,
|
||||
"{}, {} unexpected version={:d}, expected 0", tx, ons_extra_string(nettype, ons_extra), ons_extra.version))
|
||||
return false;
|
||||
|
||||
if (check_condition(!ons::mapping_type_allowed(hf_version, ons_extra.type), reason, tx, ", ", ons_extra_string(nettype, ons_extra), " specifying type=", ons_extra.type, " is disallowed in HF", +static_cast<uint8_t>(hf_version)))
|
||||
if (check_condition(!ons::mapping_type_allowed(hf_version, ons_extra.type), reason,
|
||||
"{}, {} specifying type={} is disallowed in HF{:d}", tx, ons_extra_string(nettype, ons_extra), ons_extra.type, static_cast<uint8_t>(hf_version)))
|
||||
return false;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Serialized Values Check
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
if (check_condition(!ons_extra.is_buying() && !ons_extra.is_updating() && !ons_extra.is_renewing(), reason, tx, ", ", ons_extra_string(nettype, ons_extra), " TX extra does not specify valid combination of bits for serialized fields=", std::bitset<sizeof(ons_extra.fields) * 8>(static_cast<size_t>(ons_extra.fields)).to_string()))
|
||||
if (check_condition(!ons_extra.is_buying() && !ons_extra.is_updating() && !ons_extra.is_renewing(), reason,
|
||||
"{}, {} TX extra does not specify valid combination of bits for serialized fields={}",
|
||||
tx, ons_extra_string(nettype, ons_extra), std::bitset<sizeof(ons_extra.fields) * 8>(static_cast<size_t>(ons_extra.fields)).to_string()))
|
||||
return false;
|
||||
|
||||
if (check_condition(ons_extra.field_is_set(ons::extra_field::owner) &&
|
||||
ons_extra.field_is_set(ons::extra_field::backup_owner) &&
|
||||
ons_extra.owner == ons_extra.backup_owner,
|
||||
reason, tx, ", ", ons_extra_string(nettype, ons_extra), " specifying owner the same as the backup owner=", ons_extra.backup_owner.to_string(nettype)))
|
||||
reason,
|
||||
"{}, {} specifying owner the same as the backup owner={}",
|
||||
tx, ons_extra_string(nettype, ons_extra), ons_extra.backup_owner.to_string(nettype)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1247,7 +1264,8 @@ bool name_system_db::validate_ons_tx(hf hf_version, uint64_t blockchain_height,
|
|||
// ONS Field(s) Validation
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
{
|
||||
if (check_condition((ons_extra.name_hash == null_name_hash || ons_extra.name_hash == crypto::null_hash), reason, tx, ", ", ons_extra_string(nettype, ons_extra), " specified the null name hash"))
|
||||
if (check_condition((ons_extra.name_hash == null_name_hash || ons_extra.name_hash == crypto::null_hash), reason,
|
||||
"{}, {} specified the null name hash", tx, ons_extra_string(nettype, ons_extra)))
|
||||
return false;
|
||||
|
||||
if (ons_extra.field_is_set(ons::extra_field::encrypted_value))
|
||||
|
@ -1275,12 +1293,10 @@ bool name_system_db::validate_ons_tx(hf hf_version, uint64_t blockchain_height,
|
|||
burn = burn_required;
|
||||
}
|
||||
|
||||
if (burn != burn_required)
|
||||
{
|
||||
char const *over_or_under = burn > burn_required ? "too much " : "insufficient ";
|
||||
if (check_condition(true, reason, tx, ", ", ons_extra_string(nettype, ons_extra), " burned ", over_or_under, "oxen=", burn, ", require=", burn_required))
|
||||
if (check_condition(burn != burn_required, reason,
|
||||
"{}, {} burned {} OXEN={}, required={}",
|
||||
tx, ons_extra_string(nettype, ons_extra), burn > burn_required ? "too much" : "insufficient", burn, burn_required))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -115,9 +115,8 @@ struct mapping_value
|
|||
mapping_value();
|
||||
mapping_value(std::string encrypted_value, std::string nonce);
|
||||
};
|
||||
inline std::ostream &operator<<(std::ostream &os, mapping_value const &v) { return os << oxenc::to_hex(v.to_view()); }
|
||||
|
||||
inline std::string_view mapping_type_str(mapping_type type)
|
||||
inline constexpr std::string_view mapping_type_str(mapping_type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
@ -130,7 +129,6 @@ inline std::string_view mapping_type_str(mapping_type type)
|
|||
default: assert(false); return "xx_unhandled_type"sv;
|
||||
}
|
||||
}
|
||||
inline std::ostream &operator<<(std::ostream &os, mapping_type type) { return os << mapping_type_str(type); }
|
||||
|
||||
constexpr bool mapping_type_allowed(cryptonote::hf hf_version, mapping_type type) {
|
||||
return (type == mapping_type::session && hf_version >= cryptonote::hf::hf15_ons)
|
||||
|
|
|
@ -68,11 +68,6 @@ namespace service_nodes
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, quorum const &q)
|
||||
{
|
||||
return os << q.to_string();
|
||||
}
|
||||
|
||||
|
||||
struct quorum_manager
|
||||
{
|
||||
|
@ -166,9 +161,4 @@ namespace service_nodes
|
|||
uint64_t quorum_checksum(const std::vector<crypto::public_key> &pubkeys, size_t offset = 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<service_nodes::quorum> : fmt::formatter<std::string> {
|
||||
auto format(service_nodes::quorum quorum, format_context& ctx) {
|
||||
return formatter<std::string>::format(quorum.to_string(), ctx);
|
||||
}
|
||||
};
|
||||
template <> inline constexpr bool formattable::via_to_string<service_nodes::quorum> = true;
|
||||
|
|
|
@ -75,10 +75,6 @@ namespace service_nodes
|
|||
}
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, quorum_type q) {
|
||||
return os << to_string(q);
|
||||
}
|
||||
|
||||
enum struct quorum_group : uint8_t { invalid, validator, worker, _count };
|
||||
struct quorum_vote_t
|
||||
{
|
||||
|
@ -176,11 +172,5 @@ namespace service_nodes
|
|||
mutable std::recursive_mutex m_lock;
|
||||
};
|
||||
}; // namespace service_nodes
|
||||
//
|
||||
template <>
|
||||
struct fmt::formatter<service_nodes::quorum_type> : fmt::formatter<std::string_view> {
|
||||
auto format(service_nodes::quorum_type quorum, format_context& ctx) {
|
||||
return formatter<std::string_view>::format(to_string(quorum), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_string<service_nodes::quorum_type> = true;
|
||||
|
|
|
@ -406,14 +406,14 @@ bool command_parser_executor::is_key_image_spent(const std::vector<std::string>&
|
|||
{
|
||||
if (args.empty())
|
||||
{
|
||||
tools::fail_msg_writer() << "Invalid arguments. Expected: is_key_image_spent <key_image> [<key_image> ...]\n";
|
||||
tools::fail_msg_writer("Invalid arguments. Expected: is_key_image_spent <key_image> [<key_image> ...]\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<crypto::key_image> kis;
|
||||
for (const auto& hex : args) {
|
||||
if (!tools::hex_to_type(hex, kis.emplace_back())) {
|
||||
tools::fail_msg_writer() << "Invalid key image: '" << hex << "'";
|
||||
tools::fail_msg_writer("Invalid key image: '{}'", hex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -466,7 +466,7 @@ bool command_parser_executor::start_mining(const std::vector<std::string>& args)
|
|||
}
|
||||
if (info.is_subaddress)
|
||||
{
|
||||
tools::fail_msg_writer() << "subaddress for mining reward is not yet supported!";
|
||||
tools::fail_msg_writer("subaddress for mining reward is not yet supported!");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,7 @@ bool command_parser_executor::start_mining(const std::vector<std::string>& args)
|
|||
unsigned int threads_count = 1, num_blocks = 0;
|
||||
if (threads_val.size() && !tools::parse_int(threads_val, threads_count))
|
||||
{
|
||||
tools::fail_msg_writer() << "Failed to parse threads value" << threads_val;
|
||||
tools::fail_msg_writer("Failed to parse threads value {}", threads_val);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -510,14 +510,14 @@ bool command_parser_executor::set_limit(const std::vector<std::string>& args)
|
|||
return m_executor.get_limit();
|
||||
|
||||
if (args.size() > 2) {
|
||||
tools::fail_msg_writer() << "Too many arguments: expected 0-2 values";
|
||||
tools::fail_msg_writer("Too many arguments ({}): expected 0-2 values", args.size());
|
||||
return false;
|
||||
}
|
||||
int64_t limit_down;
|
||||
if (args[0] == "default") // Accept "default" as a string because getting -1 through the cli arg parsing is a nuissance
|
||||
limit_down = -1;
|
||||
else if (!tools::parse_int(args[0], limit_down)) {
|
||||
tools::fail_msg_writer() << "Failed to parse '" << args[0] << "' as a limit";
|
||||
tools::fail_msg_writer("Failed to parse '{}' as a limit", args[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -527,7 +527,7 @@ bool command_parser_executor::set_limit(const std::vector<std::string>& args)
|
|||
else if (args[1] == "default")
|
||||
limit_up = -1;
|
||||
else if (!tools::parse_int(args[1], limit_up)) {
|
||||
tools::fail_msg_writer() << "Failed to parse '" << args[1] << "' as a limit";
|
||||
tools::fail_msg_writer("Failed to parse '{}' as a limit", args[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -83,11 +83,11 @@ public:
|
|||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
if (!error.empty())
|
||||
tools::fail_msg_writer() << error << ": " << e.what();
|
||||
tools::fail_msg_writer("{}: {}", error, e.what());
|
||||
return false;
|
||||
} catch (...) {}
|
||||
if (!error.empty())
|
||||
tools::fail_msg_writer() << error;
|
||||
tools::fail_msg_writer(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ public:
|
|||
if (!try_running([this] { return invoke<RPC>(); }, error_prefix))
|
||||
return false;
|
||||
|
||||
tools::success_msg_writer() << success_msg;
|
||||
tools::success_msg_writer(success_msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "common/string_util.h"
|
||||
#include "device/io_ledger_tcp.hpp"
|
||||
#include "io_hid.hpp"
|
||||
#include "version.h"
|
||||
|
@ -388,7 +389,7 @@ namespace hw::ledger {
|
|||
|
||||
void device_ledger::logRESP() {
|
||||
if (apdu_verbose)
|
||||
log::debug(logcat, "RESP (+{}): {} {}", tools::short_duration(std::chrono::steady_clock::now() - last_cmd), oxenc::to_hex(std::string_view{reinterpret_cast<const char*>(&sw), sizeof(sw)}), oxenc::to_hex(buffer_recv, buffer_recv + length_recv));
|
||||
log::debug(logcat, "RESP (+{}): {} {}", tools::friendly_duration(std::chrono::steady_clock::now() - last_cmd), oxenc::to_hex(std::string_view{reinterpret_cast<const char*>(&sw), sizeof(sw)}), oxenc::to_hex(buffer_recv, buffer_recv + length_recv));
|
||||
}
|
||||
|
||||
int device_ledger::set_command_header(unsigned char ins, unsigned char p1, unsigned char p2) {
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <oxenc/endian.h>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
|
@ -877,11 +876,7 @@ namespace trezor{
|
|||
}
|
||||
|
||||
static std::string get_usb_path(uint8_t bus_id, const std::vector<uint8_t> &path){
|
||||
std::ostringstream ss;
|
||||
ss << WebUsbTransport::PATH_PREFIX << std::setw(3) << std::setfill('0') << (int)bus_id;
|
||||
for (int port : path)
|
||||
ss << ':' << port;
|
||||
return ss.str();
|
||||
return fmt::format("{}{:03d}:{:d}", WebUsbTransport::PATH_PREFIX, bus_id, fmt::join(path, ":"));
|
||||
}
|
||||
|
||||
const char * WebUsbTransport::PATH_PREFIX = "webusb:";
|
||||
|
|
|
@ -35,11 +35,11 @@
|
|||
* \brief Generates a set of multisig wallets
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <fmt/core.h>
|
||||
#include "crypto/crypto.h" // for crypto::secret_key definition
|
||||
#include "common/fs-format.h"
|
||||
#include "common/i18n.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/util.h"
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
|
||||
static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path& basename, network_type nettype, bool create_address_file)
|
||||
{
|
||||
tools::msg_writer() << fmt::format(genms::tr("Generating {:d} {:d}/{:d} multisig wallets"), total, threshold, total);
|
||||
tools::msg_writer(genms::tr("Generating {:d} {:d}/{:d} multisig wallets"), total, threshold, total);
|
||||
|
||||
const auto pwd_container = tools::password_container::prompt(true, "Enter password for new multisig wallets");
|
||||
|
||||
|
@ -100,7 +100,7 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path
|
|||
wallets[n]->decrypt_keys(pwd_container->password());
|
||||
if (!tools::wallet2::verify_multisig_info(wallets[n]->get_multisig_info(), sk[n], pk[n]))
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Failed to verify multisig info");
|
||||
tools::fail_msg_writer(genms::tr("Failed to verify multisig info"));
|
||||
return false;
|
||||
}
|
||||
wallets[n]->encrypt_keys(pwd_container->password());
|
||||
|
@ -108,10 +108,10 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path
|
|||
|
||||
// make the wallets multisig
|
||||
std::vector<std::string> extra_info(total);
|
||||
std::stringstream ss;
|
||||
std::vector<fs::path> filenames;
|
||||
for (size_t n = 0; n < total; ++n)
|
||||
{
|
||||
fs::path name = basename;
|
||||
auto& name = filenames.emplace_back(basename);
|
||||
name += "-" + std::to_string(n + 1);
|
||||
std::vector<crypto::secret_key> skn;
|
||||
std::vector<crypto::public_key> pkn;
|
||||
|
@ -124,7 +124,6 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path
|
|||
}
|
||||
}
|
||||
extra_info[n] = wallets[n]->make_multisig(pwd_container->password(), skn, pkn, threshold);
|
||||
ss << " " << name << std::endl;
|
||||
}
|
||||
|
||||
//exchange keys unless exchange_multisig_keys returns no extra info
|
||||
|
@ -136,7 +135,7 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path
|
|||
{
|
||||
if (!tools::wallet2::verify_extra_multisig_info(extra_info[n], pkeys, signers[n]))
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error verifying multisig extra info");
|
||||
tools::fail_msg_writer(genms::tr("Error verifying multisig extra info"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -146,12 +145,13 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const fs::path
|
|||
}
|
||||
}
|
||||
|
||||
std::string address = wallets[0]->get_account().get_public_address_str(wallets[0]->nettype());
|
||||
tools::success_msg_writer() << genms::tr("Generated multisig wallets for address ") << address << std::endl << ss.str();
|
||||
tools::success_msg_writer("{}{}\n{}", genms::tr("Generated multisig wallets for address "),
|
||||
wallets[0]->get_account().get_public_address_str(wallets[0]->nettype()),
|
||||
fmt::join(filenames, " "));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error creating multisig wallets: ") << e.what();
|
||||
tools::fail_msg_writer("{}{}", genms::tr("Error creating multisig wallets: "), e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ int main(int argc, char* argv[])
|
|||
desc_params,
|
||||
po::options_description{},
|
||||
boost::program_options::positional_options_description(),
|
||||
[](const std::string &s){ tools::scoped_message_writer() << s; },
|
||||
[](const std::string &s){ tools::msg_writer(s); },
|
||||
"oxen-gen-multisig.log"
|
||||
);
|
||||
if (!vm)
|
||||
|
@ -193,14 +193,14 @@ int main(int argc, char* argv[])
|
|||
devnet = command_line::get_arg(*vm, arg_devnet);
|
||||
if (testnet && devnet)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: Can't specify more than one of --testnet and --devnet");
|
||||
tools::fail_msg_writer(genms::tr("Error: Can't specify more than one of --testnet and --devnet"));
|
||||
return 1;
|
||||
}
|
||||
if (command_line::has_arg(*vm, arg_scheme))
|
||||
{
|
||||
if (sscanf(command_line::get_arg(*vm, arg_scheme).c_str(), "%u/%u", &threshold, &total) != 2)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: expected N/M, but got: ") << command_line::get_arg(*vm, arg_scheme);
|
||||
tools::fail_msg_writer("{}{}", genms::tr("Error: expected N/M, but got: "), command_line::get_arg(*vm, arg_scheme));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
if (threshold)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: either --scheme or both of --threshold and --participants may be given");
|
||||
tools::fail_msg_writer(genms::tr("Error: either --scheme or both of --threshold and --participants may be given"));
|
||||
return 1;
|
||||
}
|
||||
threshold = command_line::get_arg(*vm, arg_threshold);
|
||||
|
@ -217,14 +217,14 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
if (total)
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: either --scheme or both of --threshold and --participants may be given");
|
||||
tools::fail_msg_writer(genms::tr("Error: either --scheme or both of --threshold and --participants may be given"));
|
||||
return 1;
|
||||
}
|
||||
total = command_line::get_arg(*vm, arg_participants);
|
||||
}
|
||||
if (threshold <= 1 || threshold > total)
|
||||
{
|
||||
tools::fail_msg_writer() << fmt::format(genms::tr("Error: expected N > 1 and N <= M, but got N=={:d} and M=={:d}"), threshold, total);
|
||||
tools::fail_msg_writer(genms::tr("Error: expected N > 1 and N <= M, but got N=={:d} and M=={:d}"), threshold, total);
|
||||
return 1;
|
||||
}
|
||||
fs::path basename;
|
||||
|
@ -234,7 +234,7 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
else
|
||||
{
|
||||
tools::fail_msg_writer() << genms::tr("Error: --filename-base is required");
|
||||
tools::fail_msg_writer(genms::tr("Error: --filename-base is required"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "epee/string_tools.h"
|
||||
#include "epee/time_helper.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "common/pruning.h"
|
||||
#include "net/error.h"
|
||||
#include "common/periodic_task.h"
|
||||
|
|
|
@ -560,8 +560,13 @@ namespace rct {
|
|||
inline const crypto::hash &rct2hash(const rct::key &k) { return (const crypto::hash&)k; }
|
||||
inline bool operator==(const rct::key &k0, const crypto::public_key &k1) { return !crypto_verify_32(k0.bytes, (const unsigned char*)&k1); }
|
||||
inline bool operator!=(const rct::key &k0, const crypto::public_key &k1) { return crypto_verify_32(k0.bytes, (const unsigned char*)&k1); }
|
||||
|
||||
inline std::string to_hex_string(const rct::key& v) {
|
||||
return "<{}>"_format(tools::type_to_hex(v));
|
||||
}
|
||||
}
|
||||
|
||||
template <> inline constexpr bool formattable::via_to_hex_string<rct::key> = true;
|
||||
|
||||
namespace cryptonote {
|
||||
inline bool operator==(const crypto::public_key &k0, const rct::key &k1) { return !crypto_verify_32((const unsigned char*)&k0, k1.bytes); }
|
||||
|
@ -570,12 +575,6 @@ namespace cryptonote {
|
|||
inline bool operator!=(const crypto::secret_key &k0, const rct::key &k1) { return crypto_verify_32((const unsigned char*)&k0, k1.bytes); }
|
||||
}
|
||||
|
||||
namespace rct {
|
||||
inline std::ostream &operator <<(std::ostream &o, const rct::key &v) {
|
||||
return o << '<' << tools::type_to_hex(v) << '>';
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<rct::key> { std::size_t operator()(const rct::key &k) const { return reinterpret_cast<const std::size_t&>(k); } };
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
* \brief Source file that defines simple_wallet class.
|
||||
*/
|
||||
|
||||
#include <fmt/color.h>
|
||||
#include "common/string_util.h"
|
||||
#include "oxen_economy.h"
|
||||
#include <algorithm>
|
||||
|
@ -63,6 +64,7 @@
|
|||
#include "common/signal_handler.h"
|
||||
#include "common/base58.h"
|
||||
#include "common/scoped_message_writer.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "cryptonote_core/service_node_voting.h"
|
||||
#include "cryptonote_core/service_node_list.h"
|
||||
|
@ -91,6 +93,12 @@ extern "C"
|
|||
#include <sodium.h>
|
||||
}
|
||||
|
||||
// grumble, grumble
|
||||
namespace formattable {
|
||||
std::string to_string(const boost::basic_format<char>& f) { return f.str(); }
|
||||
template <> constexpr bool via_to_string<boost::basic_format<char>> = true;
|
||||
}
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
|
@ -302,22 +310,6 @@ namespace
|
|||
return buf;
|
||||
}
|
||||
|
||||
std::optional<tools::password_container> password_prompter(const char *prompt, bool verify)
|
||||
{
|
||||
rdln::suspend_readline pause_readline;
|
||||
auto pwd_container = tools::password_container::prompt(verify, prompt);
|
||||
if (!pwd_container)
|
||||
{
|
||||
tools::fail_msg_writer() << sw::tr("failed to read wallet password");
|
||||
}
|
||||
return pwd_container;
|
||||
}
|
||||
|
||||
std::optional<tools::password_container> default_password_prompter(bool verify)
|
||||
{
|
||||
return password_prompter(verify ? sw::tr("Enter a new password for the wallet") : sw::tr("Wallet password"), verify);
|
||||
}
|
||||
|
||||
inline std::string interpret_rpc_response(bool ok, const std::string& status)
|
||||
{
|
||||
std::string err;
|
||||
|
@ -339,26 +331,59 @@ namespace
|
|||
return err;
|
||||
}
|
||||
|
||||
tools::scoped_message_writer success_msg_writer(bool color = false)
|
||||
// Replacing all the << in here with proper formatting is just too painful, so make a crappy
|
||||
// subclass that provides a << that just slams it through a basic format.
|
||||
class simplewallet_crappy_message_writer : public tools::scoped_message_writer {
|
||||
public:
|
||||
using tools::scoped_message_writer::scoped_message_writer;
|
||||
|
||||
template <typename T>
|
||||
auto& operator<<(T&& val) {
|
||||
append("{}", std::forward<T>(val));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
simplewallet_crappy_message_writer success_msg_writer(bool color = false)
|
||||
{
|
||||
return tools::scoped_message_writer(color ? fmt::terminal_color::green : fmt::terminal_color::white, std::string{}, spdlog::level::info);
|
||||
std::optional<fmt::terminal_color> c = std::nullopt;
|
||||
if (color)
|
||||
c = fmt::terminal_color::green;
|
||||
return simplewallet_crappy_message_writer(c, std::string{}, spdlog::level::info);
|
||||
}
|
||||
|
||||
tools::scoped_message_writer message_writer(fmt::terminal_color color = fmt::terminal_color::white)
|
||||
simplewallet_crappy_message_writer message_writer(std::optional<fmt::terminal_color> color = std::nullopt)
|
||||
{
|
||||
return tools::scoped_message_writer(color);
|
||||
return simplewallet_crappy_message_writer(color);
|
||||
}
|
||||
|
||||
tools::scoped_message_writer fail_msg_writer()
|
||||
simplewallet_crappy_message_writer fail_msg_writer()
|
||||
{
|
||||
return tools::scoped_message_writer(fmt::terminal_color::red, sw::tr("Error: "), spdlog::level::err);
|
||||
return simplewallet_crappy_message_writer(fmt::terminal_color::red, sw::tr("Error: "), spdlog::level::err);
|
||||
}
|
||||
|
||||
tools::scoped_message_writer warn_msg_writer()
|
||||
simplewallet_crappy_message_writer warn_msg_writer()
|
||||
{
|
||||
return tools::scoped_message_writer(fmt::terminal_color::red, sw::tr("Warning: "), spdlog::level::warn);
|
||||
return simplewallet_crappy_message_writer(fmt::terminal_color::red, sw::tr("Warning: "), spdlog::level::warn);
|
||||
}
|
||||
|
||||
std::optional<tools::password_container> password_prompter(const char *prompt, bool verify)
|
||||
{
|
||||
rdln::suspend_readline pause_readline;
|
||||
auto pwd_container = tools::password_container::prompt(verify, prompt);
|
||||
if (!pwd_container)
|
||||
{
|
||||
fail_msg_writer() << sw::tr("failed to read wallet password");
|
||||
}
|
||||
return pwd_container;
|
||||
}
|
||||
|
||||
std::optional<tools::password_container> default_password_prompter(bool verify)
|
||||
{
|
||||
return password_prompter(verify ? sw::tr("Enter a new password for the wallet") : sw::tr("Wallet password"), verify);
|
||||
}
|
||||
|
||||
|
||||
bool parse_bool(const std::string& s, bool& result)
|
||||
{
|
||||
if (command_line::is_yes(s, "1", "true", simple_wallet::tr("true")))
|
||||
|
@ -498,7 +523,7 @@ namespace
|
|||
}
|
||||
catch (const tools::error::tx_rejected& e)
|
||||
{
|
||||
fail_msg_writer() << (boost::format(sw::tr("transaction %s was rejected by daemon")) % get_transaction_hash(e.tx()));
|
||||
fail_msg_writer() << (boost::format(sw::tr("transaction %s was rejected by daemon")) % get_transaction_hash(e.tx())).str();
|
||||
std::string reason = e.reason();
|
||||
if (!reason.empty())
|
||||
fail_msg_writer() << sw::tr("Reason: ") << reason;
|
||||
|
@ -2468,7 +2493,7 @@ bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std:
|
|||
bool simple_wallet::set_inactivity_lock_timeout(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
tools::fail_msg_writer() << tr("Inactivity lock timeout disabled on Windows");
|
||||
fail_msg_writer() << tr("Inactivity lock timeout disabled on Windows");
|
||||
return true;
|
||||
#endif
|
||||
const auto pwd_container = get_and_verify_password();
|
||||
|
@ -2482,7 +2507,7 @@ bool simple_wallet::set_inactivity_lock_timeout(const std::vector<std::string> &
|
|||
}
|
||||
else
|
||||
{
|
||||
tools::fail_msg_writer() << tr("Invalid number of seconds");
|
||||
fail_msg_writer() << tr("Invalid number of seconds");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -5608,7 +5633,7 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
|||
m_in_command = true;
|
||||
if (!user)
|
||||
{
|
||||
tools::msg_writer() << R"(
|
||||
message_writer() << R"(
|
||||
...........
|
||||
...............
|
||||
....OOOOOOOOOOO.... Your Oxen Wallet was locked to
|
||||
|
@ -5624,7 +5649,7 @@ void simple_wallet::check_for_inactivity_lock(bool user)
|
|||
while (1)
|
||||
{
|
||||
const char *inactivity_msg = user ? "" : tr("Locked due to inactivity.");
|
||||
tools::msg_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << tr("The wallet password is required to unlock the console.");
|
||||
message_writer() << inactivity_msg << (inactivity_msg[0] ? " " : "") << tr("The wallet password is required to unlock the console.");
|
||||
try
|
||||
{
|
||||
if (get_and_verify_password())
|
||||
|
@ -6178,7 +6203,7 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
|
|||
}
|
||||
|
||||
if (!stake_result.msg.empty()) // i.e. warnings
|
||||
tools::msg_writer() << stake_result.msg;
|
||||
message_writer() << stake_result.msg;
|
||||
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector = {stake_result.ptx};
|
||||
cryptonote::address_parse_info info = {};
|
||||
|
@ -6233,7 +6258,7 @@ bool simple_wallet::request_stake_unlock(const std::vector<std::string> &args_)
|
|||
tools::wallet2::request_stake_unlock_result unlock_result = m_wallet->can_request_stake_unlock(snode_key);
|
||||
if (unlock_result.success)
|
||||
{
|
||||
tools::msg_writer() << unlock_result.msg;
|
||||
message_writer() << unlock_result.msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6542,7 +6567,7 @@ bool simple_wallet::query_locked_stakes(bool print_details, bool print_key_image
|
|||
if (msg.empty() && print_details)
|
||||
msg = "No locked stakes known for this wallet on the network";
|
||||
if (!msg.empty())
|
||||
tools::msg_writer() << msg;
|
||||
message_writer() << msg;
|
||||
|
||||
return has_locked_stakes;
|
||||
}
|
||||
|
@ -6574,7 +6599,7 @@ static std::optional<ons::mapping_type> guess_ons_type(tools::wallet2& wallet, s
|
|||
auto hf_version = wallet.get_hard_fork_version();
|
||||
if (!hf_version)
|
||||
{
|
||||
tools::fail_msg_writer() << tools::wallet2::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
|
||||
fail_msg_writer() << tools::wallet2::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -6633,7 +6658,7 @@ bool simple_wallet::ons_buy_mapping(std::vector<std::string> args)
|
|||
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
tools::fail_msg_writer() << reason;
|
||||
fail_msg_writer() << reason;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6731,7 +6756,7 @@ bool simple_wallet::ons_renew_mapping(std::vector<std::string> args)
|
|||
&response);
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
tools::fail_msg_writer() << reason;
|
||||
fail_msg_writer() << reason;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6816,7 +6841,7 @@ bool simple_wallet::ons_update_mapping(std::vector<std::string> args)
|
|||
&response);
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
tools::fail_msg_writer() << reason;
|
||||
fail_msg_writer() << reason;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6929,32 +6954,32 @@ bool simple_wallet::ons_encrypt(std::vector<std::string> args)
|
|||
auto hf_version = m_wallet->get_hard_fork_version();
|
||||
if (!hf_version)
|
||||
{
|
||||
tools::fail_msg_writer() << tools::wallet2::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
|
||||
fail_msg_writer() << tools::wallet2::ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string reason;
|
||||
if (!ons::validate_ons_name(type, name, &reason))
|
||||
{
|
||||
tools::fail_msg_writer() << "Invalid ONS name '" << name << "': " << reason;
|
||||
fail_msg_writer() << "Invalid ONS name '" << name << "': " << reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
ons::mapping_value mval;
|
||||
if (!ons::mapping_value::validate(m_wallet->nettype(), type, value, &mval, &reason))
|
||||
{
|
||||
tools::fail_msg_writer() << "Invalid ONS value '" << value << "': " << reason;
|
||||
fail_msg_writer() << "Invalid ONS value '" << value << "': " << reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool old_argon2 = type == ons::mapping_type::session && hf_version < hf::hf16_pulse;
|
||||
if (!mval.encrypt(name, nullptr, old_argon2))
|
||||
{
|
||||
tools::fail_msg_writer() << "Value encryption failed";
|
||||
fail_msg_writer() << "Value encryption failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
tools::success_msg_writer() << "encrypted value=" << oxenc::to_hex(mval.to_view());
|
||||
success_msg_writer() << "encrypted value=" << oxenc::to_hex(mval.to_view());
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -6984,7 +7009,7 @@ bool simple_wallet::ons_make_update_mapping_signature(std::vector<std::string> a
|
|||
signature_binary,
|
||||
m_current_subaddress_account,
|
||||
&reason))
|
||||
tools::success_msg_writer() << "signature=" << tools::type_to_hex(signature_binary.ed25519);
|
||||
success_msg_writer() << "signature=" << tools::type_to_hex(signature_binary.ed25519);
|
||||
else
|
||||
fail_msg_writer() << reason;
|
||||
|
||||
|
@ -7091,7 +7116,7 @@ bool simple_wallet::ons_lookup(std::vector<std::string> args)
|
|||
return false;
|
||||
}
|
||||
|
||||
auto writer = tools::msg_writer();
|
||||
auto writer = message_writer();
|
||||
writer
|
||||
<< "Name: " << name
|
||||
<< "\n Type: " << static_cast<ons::mapping_type>(mapping["type"])
|
||||
|
@ -7182,7 +7207,7 @@ bool simple_wallet::ons_by_owner(const std::vector<std::string>& args)
|
|||
value = mv.to_readable_value(nettype, ons_type);
|
||||
}
|
||||
|
||||
auto writer = tools::msg_writer();
|
||||
auto writer = message_writer();
|
||||
writer
|
||||
<< "Name (hashed): " << entry["name_hash"];
|
||||
if (!name.empty()) writer
|
||||
|
@ -10336,7 +10361,7 @@ int main(int argc, char* argv[])
|
|||
desc_params,
|
||||
hidden_params,
|
||||
positional_options,
|
||||
[](const std::string &s){ tools::scoped_message_writer(fmt::terminal_color::white) << s; },
|
||||
[](const std::string &s){ tools::scoped_message_writer() + s; },
|
||||
"oxen-wallet-cli.log"
|
||||
);
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace Wallet {
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace Wallet {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <lmdb.h>
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "epee/misc_log_ex.h"
|
||||
#include "wallet_errors.h"
|
||||
#include "ringdb.h"
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "common/i18n.h"
|
||||
#include "common/util.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "common/apply_permutation.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
|
@ -249,7 +250,7 @@ namespace {
|
|||
if (auto got = m_vote_ctx.find("m_votes_not_sorted"); got != m_vote_ctx.end()) os << "Votes are not stored in ascending order";
|
||||
|
||||
if (tx)
|
||||
os << "TX Version: " << tx->version << ", Type: " << tx->type;
|
||||
os << "TX Version: {}, Type: {}"_format(tx->version, tx->type);
|
||||
|
||||
std::string buf = os.str();
|
||||
if (buf.size() >= 2 && buf[buf.size() - 2] == ',')
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
#include "common/file.h"
|
||||
#include "crypto/chacha.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "crypto/fmt.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "checkpoints/checkpoints.h"
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "common/i18n.h"
|
||||
#include "common/util.h"
|
||||
#include "common/file.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "epee/misc_log_ex.h"
|
||||
#include "epee/string_tools.h"
|
||||
#include "version.h"
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "common/command_line.h"
|
||||
#include "common/i18n.h"
|
||||
#include "common/signal_handler.h"
|
||||
#include "common/fs-format.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
|
|
|
@ -33,6 +33,7 @@ target_link_libraries(difficulty-tests
|
|||
cncrypto
|
||||
epee
|
||||
cryptonote_basic
|
||||
common
|
||||
extra)
|
||||
set_property(TARGET difficulty-tests
|
||||
PROPERTY
|
||||
|
|
|
@ -48,7 +48,6 @@ namespace
|
|||
"6c7251d54154cfa92c173a0dd39c1f948b655970153799af2aeadc9ff1add0ea";
|
||||
|
||||
template<typename T> void *addressof(T &t) { return &t; }
|
||||
template<> void *addressof(crypto::secret_key &k) { return addressof(unwrap(unwrap(k))); }
|
||||
|
||||
template<typename T>
|
||||
bool is_formatted()
|
||||
|
@ -60,9 +59,7 @@ namespace
|
|||
static_assert(sizeof(T) * 2 <= sizeof(expected), "T is too large for destination");
|
||||
std::memcpy(addressof(value), source, sizeof(T));
|
||||
|
||||
std::stringstream out;
|
||||
out << "BEGIN" << value << "END";
|
||||
return out.str() == "BEGIN<" + std::string{expected, sizeof(T) * 2} + ">END";
|
||||
return "{}"_format(value) == "<{}>"_format(std::string{expected, sizeof(T) * 2});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +68,6 @@ TEST(Crypto, Ostream)
|
|||
EXPECT_TRUE(is_formatted<crypto::hash8>());
|
||||
EXPECT_TRUE(is_formatted<crypto::hash>());
|
||||
EXPECT_TRUE(is_formatted<crypto::public_key>());
|
||||
EXPECT_TRUE(is_formatted<crypto::secret_key>());
|
||||
EXPECT_TRUE(is_formatted<crypto::signature>());
|
||||
EXPECT_TRUE(is_formatted<crypto::key_derivation>());
|
||||
EXPECT_TRUE(is_formatted<crypto::key_image>());
|
||||
|
|
|
@ -78,7 +78,7 @@ TEST(oxen_name_system, name_tests)
|
|||
for (size_t i = 0; i < names_count; i++)
|
||||
{
|
||||
name_test const &entry = names[i];
|
||||
ASSERT_EQ(ons::validate_ons_name(type, entry.name), entry.allowed) << "Values were {type=" << type << ", name=\"" << entry.name << "\"}";
|
||||
ASSERT_EQ(ons::validate_ons_name(type, entry.name), entry.allowed) << "Values were {{type={}, name=\"{}\"}}"_format(type, entry.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -778,11 +778,10 @@ TEST(ringct, reject_gen_simple_ver_non_simple)
|
|||
|
||||
TEST(ringct, key_ostream)
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "BEGIN" << rct::H << "END";
|
||||
auto out = "BEGIN{}END"_format(rct::H);
|
||||
EXPECT_EQ(
|
||||
std::string{"BEGIN<8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94>END"},
|
||||
out.str()
|
||||
out
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue