Added webhook tx-confirmation support (#66)

This commit is contained in:
Lee *!* Clagett
2023-05-11 13:13:10 -04:00
committed by Lee *!* Clagett
parent 990e86f701
commit 3e0555e07d
32 changed files with 2051 additions and 122 deletions

View File

@@ -30,9 +30,19 @@
#include <type_traits>
#include "crypto/crypto.h" // monero/src
#include "span.h" // monero/contrib/include
#include "ringct/rctTypes.h" // monero/src
#include "wire/traits.h"
namespace crypto
{
template<typename R>
void read_bytes(R& source, crypto::secret_key& self)
{
source.binary(epee::as_mut_byte_span(unwrap(unwrap(self))));
}
}
namespace wire
{
template<>
@@ -40,6 +50,11 @@ namespace wire
: std::true_type
{};
template<>
struct is_blob<crypto::hash8>
: std::true_type
{};
template<>
struct is_blob<crypto::hash>
: std::true_type

View File

@@ -46,8 +46,12 @@
::wire::field( #name , self . name )
//! The optional field has the same key name and C/C++ name
#define WIRE_OPTIONAL_FIELD(name) \
::wire::optional_field( #name , std::ref( self . name ))
#define WIRE_OPTIONAL_FIELD_ID(id, name) \
::wire::optional_field< id >( #name , std::ref( self . name ))
//! The optional field has the same key name and C/C++ name
#define WIRE_OPTIONAL_FIELD(name) \
WIRE_OPTIONAL_FIELD_ID(0, name)
namespace wire
{
@@ -73,6 +77,10 @@ namespace wire
static constexpr std::size_t count() noexcept { return 1; }
static constexpr unsigned id() noexcept { return I; }
//! \return True if field is forced optional when `get_value().empty()`.
static constexpr bool optional_on_empty() noexcept
{ return is_optional_on_empty<value_type>::value; }
const char* name;
T value;
@@ -250,9 +258,9 @@ namespace wire
template<typename T, unsigned I>
inline constexpr bool available(const field_<T, true, I>&) noexcept
inline constexpr bool available(const field_<T, true, I>& elem) noexcept
{
return true;
return elem.is_required() || (elem.optional_on_empty() && !wire::empty(elem.get_value()));
}
template<typename T, unsigned I>
inline bool available(const field_<T, false, I>& elem)
@@ -269,18 +277,5 @@ namespace wire
{
return elem != nullptr;
}
// example usage : `wire::sum(std::size_t(wire::available(fields))...)`
inline constexpr int sum() noexcept
{
return 0;
}
template<typename T, typename... U>
inline constexpr T sum(const T head, const U... tail) noexcept
{
return head + sum(tail...);
}
}

View File

@@ -28,6 +28,7 @@
#pragma once
#include <cstdint>
#include <limits>
#include <string>
#include <limits>
#include <tuple>

View File

@@ -86,8 +86,12 @@ namespace wire
}
protected:
msgpack_writer(epee::byte_stream&& initial, bool integer_keys, bool needs_flush)
: writer(), bytes_(std::move(initial)), expected_(1), integer_keys_(integer_keys), needs_flush_(needs_flush)
{}
msgpack_writer(bool integer_keys, bool needs_flush)
: writer(), bytes_(), expected_(1), integer_keys_(integer_keys), needs_flush_(needs_flush)
: msgpack_writer(epee::byte_stream{}, integer_keys, needs_flush)
{}
//! \throw std::logic_error if tree was not completed
@@ -153,6 +157,10 @@ namespace wire
//! Buffers entire JSON message in memory
struct msgpack_slice_writer final : msgpack_writer
{
msgpack_slice_writer(epee::byte_stream&& initial, bool integer_keys = false)
: msgpack_writer(std::move(initial), integer_keys, false)
{}
explicit msgpack_slice_writer(bool integer_keys = false)
: msgpack_writer(integer_keys, false)
{}

View File

@@ -299,6 +299,24 @@ namespace wire_read
unpack_variant_field(index, source, dest.get_value(), static_cast< const wire::option<U>& >(dest)...);
}
template<typename T, bool Required, typename... U>
inline void reset_field(wire::variant_field_<T, Required, U...>& dest)
{}
template<typename T, unsigned I>
inline void reset_field(wire::field_<T, true, I>& dest)
{
// array fields are always optional, see `wire/field.h`
if (dest.optional_on_empty())
wire::clear(dest.get_value());
}
template<typename T, unsigned I>
inline void reset_field(wire::field_<T, false, I>& dest)
{
dest.get_value().reset();
}
template<typename R, typename T, unsigned I>
inline void unpack_field(std::size_t, R& source, wire::field_<T, true, I>& dest)
{
@@ -377,6 +395,14 @@ namespace wire_read
read_ = true;
return 1 + is_required();
}
//! Reset optional fields that were skipped
bool reset_omitted()
{
if (!is_required() && !read_)
reset_field(field_);
return true;
}
};
// `expand_tracker_map` writes all `tracker` types to a table
@@ -427,6 +453,7 @@ namespace wire_read
throw_exception(wire::error::schema::missing_key, "", missing);
}
wire::sum(fields.reset_omitted()...);
source.end_object();
}
} // wire_read

View File

@@ -42,5 +42,53 @@ namespace wire
template<typename T>
struct is_blob : std::false_type
{};
}
/*! Forces field to be optional when empty. Concept requirements for `T` when
`is_optional_on_empty<T>::value == true`:
* must have an `empty()` method that toggles whether the associated
`wire::field_<...>` is omitted by the `wire::writer`.
* must have a `clear()` method where `empty() == true` upon completion,
used by the `wire::reader` when the `wire::field_<...>` is omitted. */
template<typename T>
struct is_optional_on_empty
: is_array<T> // all array types in old output engine were optional when empty
{};
// example usage : `wire::sum(std::size_t(wire::available(fields))...)`
inline constexpr int sum() noexcept
{
return 0;
}
template<typename T, typename... U>
inline constexpr T sum(const T head, const U... tail) noexcept
{
return head + sum(tail...);
}
//! If `T` has no `empty()` function, this function is used
template<typename... T>
inline constexpr bool empty(const T&...) noexcept
{
static_assert(sum(is_optional_on_empty<T>::value...) == 0, "type needs empty method");
return false;
}
//! `T` has `empty()` function, use it
template<typename T>
inline auto empty(const T& container) -> decltype(container.empty())
{ return container.empty(); }
//! If `T` has no `clear()` function, this function is used
template<typename... T>
inline void clear(const T&...) noexcept
{
static_assert(sum(is_optional_on_empty<T>::value...) == 0, "type needs clear method");
}
//! `T` has `clear()` function, use it
template<typename T>
inline auto clear(T& container) -> decltype(container.clear())
{ return container.clear(); }
}

39
src/wire/uuid.h Normal file
View File

@@ -0,0 +1,39 @@
// Copyright (c) 2020, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <boost/uuid/uuid.hpp>
#include <type_traits>
namespace wire
{
template<>
struct is_blob<boost::uuids::uuid>
: std::true_type
{};
}

View File

@@ -170,15 +170,19 @@ namespace wire_write
template<typename W, typename T, unsigned I>
inline bool field(W& dest, const wire::field_<T, true, I> elem)
{
dest.key(I, elem.name);
write_bytes(dest, elem.get_value());
// Arrays always optional, see `wire/field.h`
if (wire::available(elem))
{
dest.key(I, elem.name);
write_bytes(dest, elem.get_value());
}
return true;
}
template<typename W, typename T, unsigned I>
inline bool field(W& dest, const wire::field_<T, false, I> elem)
{
if (bool(elem.get_value()))
if (wire::available(elem))
{
dest.key(I, elem.name);
write_bytes(dest, *elem.get_value());