mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-16 04:32:39 +01:00
Add capnp serialization code for bitcoin types
- Add capnp ToBlob, ToArray, Wrap, Serialize, and Unserialize helper functions - Add support for std::chrono::seconds capnp serialization - Add support for util::Result capnp serialization
This commit is contained in:
parent
1d813e4bf5
commit
516f8637b8
2 changed files with 118 additions and 2 deletions
src/ipc/capnp
|
@ -8,9 +8,12 @@
|
||||||
#include <clientversion.h>
|
#include <clientversion.h>
|
||||||
#include <interfaces/types.h>
|
#include <interfaces/types.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
|
#include <protocol.h>
|
||||||
#include <serialize.h>
|
#include <serialize.h>
|
||||||
#include <streams.h>
|
#include <streams.h>
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
|
#include <util/result.h>
|
||||||
|
#include <util/translation.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <mp/proxy-types.h>
|
#include <mp/proxy-types.h>
|
||||||
|
@ -28,12 +31,27 @@
|
||||||
#include <mp/type-threadmap.h>
|
#include <mp/type-threadmap.h>
|
||||||
#include <mp/type-vector.h>
|
#include <mp/type-vector.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace capnp {
|
namespace capnp {
|
||||||
|
//! Convert kj::ArrayPtr to base_blob.
|
||||||
|
template <typename T>
|
||||||
|
inline T ToBlob(const kj::ArrayPtr<const kj::byte>& array)
|
||||||
|
{
|
||||||
|
return T({array.begin(), array.begin() + array.size()});
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Convert base_blob to kj::ArrayPtr.
|
||||||
|
template <typename T>
|
||||||
|
inline kj::ArrayPtr<const kj::byte> ToArray(const T& blob)
|
||||||
|
{
|
||||||
|
return {reinterpret_cast<const kj::byte*>(blob.data()), blob.size()};
|
||||||
|
}
|
||||||
|
|
||||||
//! Construct a ParamStream wrapping a data stream with serialization parameters
|
//! Construct a ParamStream wrapping a data stream with serialization parameters
|
||||||
//! needed to pass transaction objects between bitcoin processes.
|
//! needed to pass transaction and address objects between bitcoin processes.
|
||||||
//! In the future, more params may be added here to serialize other objects that
|
//! In the future, more params may be added here to serialize other objects that
|
||||||
//! require serialization parameters. Params should just be chosen to serialize
|
//! require serialization parameters. Params should just be chosen to serialize
|
||||||
//! objects completely and ensure that serializing and deserializing objects
|
//! objects completely and ensure that serializing and deserializing objects
|
||||||
|
@ -42,7 +60,28 @@ namespace capnp {
|
||||||
template <typename S>
|
template <typename S>
|
||||||
auto Wrap(S& s)
|
auto Wrap(S& s)
|
||||||
{
|
{
|
||||||
return ParamsStream{s, TX_WITH_WITNESS};
|
return ParamsStream{s, TX_WITH_WITNESS, CAddress::V2_NETWORK};
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Serialize bitcoin value.
|
||||||
|
template <typename T>
|
||||||
|
DataStream Serialize(const T& value)
|
||||||
|
{
|
||||||
|
DataStream stream;
|
||||||
|
auto wrapper{Wrap(stream)};
|
||||||
|
value.Serialize(wrapper);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Deserialize bitcoin value.
|
||||||
|
template <typename T>
|
||||||
|
T Unserialize(const kj::ArrayPtr<const kj::byte>& data)
|
||||||
|
{
|
||||||
|
SpanReader stream{{data.begin(), data.end()}};
|
||||||
|
T value;
|
||||||
|
auto wrapper{Wrap(stream)};
|
||||||
|
value.Unserialize(wrapper);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Detect if type has a deserialize_type constructor, which is
|
//! Detect if type has a deserialize_type constructor, which is
|
||||||
|
@ -127,6 +166,63 @@ decltype(auto) CustomReadField(TypeList<UniValue>, Priority<1>, InvokeContext& i
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Overload CustomBuildField and CustomReadField to serialize
|
||||||
|
//! UniValue::type_error exceptions as text strings.
|
||||||
|
template <typename Value, typename Output>
|
||||||
|
void CustomBuildField(TypeList<UniValue::type_error>, Priority<1>, InvokeContext& invoke_context,
|
||||||
|
Value&& value, Output&& output)
|
||||||
|
{
|
||||||
|
BuildField(TypeList<std::string>(), invoke_context, output, std::string(value.what()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Input, typename ReadDest>
|
||||||
|
decltype(auto) CustomReadField(TypeList<UniValue::type_error>, Priority<1>, InvokeContext& invoke_context,
|
||||||
|
Input&& input, ReadDest&& read_dest)
|
||||||
|
{
|
||||||
|
read_dest.construct(ReadField(TypeList<std::string>(), invoke_context, input, mp::ReadDestTemp<std::string>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Overload CustomBuildField and CustomReadField to serialize util::Result
|
||||||
|
//! return values as common.capnp Result and ResultVoid structs
|
||||||
|
template <typename LocalType, typename Value, typename Output>
|
||||||
|
void CustomBuildField(TypeList<util::Result<LocalType>>, Priority<1>, InvokeContext& invoke_context, Value&& value,
|
||||||
|
Output&& output)
|
||||||
|
{
|
||||||
|
auto result = output.init();
|
||||||
|
if (value) {
|
||||||
|
if constexpr (!std::is_same_v<LocalType, void>) {
|
||||||
|
using ValueAccessor = typename ProxyStruct<typename decltype(result)::Builds>::ValueAccessor;
|
||||||
|
BuildField(TypeList<LocalType>(), invoke_context, Make<StructField, ValueAccessor>(result), *value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BuildField(TypeList<bilingual_str>(), invoke_context, Make<ValueField>(result.initError()),
|
||||||
|
util::ErrorString(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename LocalType, typename Input, typename ReadDest>
|
||||||
|
decltype(auto) CustomReadField(TypeList<util::Result<LocalType>>, Priority<1>, InvokeContext& invoke_context,
|
||||||
|
Input&& input, ReadDest&& read_dest)
|
||||||
|
{
|
||||||
|
auto result = input.get();
|
||||||
|
if (result.hasError()) {
|
||||||
|
bilingual_str error;
|
||||||
|
ReadField(mp::TypeList<bilingual_str>(), invoke_context, mp::Make<mp::ValueField>(result.getError()),
|
||||||
|
mp::ReadDestUpdate(error));
|
||||||
|
read_dest.construct(util::Error{std::move(error)});
|
||||||
|
} else {
|
||||||
|
if constexpr (!std::is_same_v<LocalType, void>) {
|
||||||
|
assert (result.hasValue());
|
||||||
|
ReadField(mp::TypeList<LocalType>(), invoke_context, mp::Make<mp::ValueField>(result.getValue()),
|
||||||
|
mp::ReadDestEmplace(
|
||||||
|
mp::TypeList<LocalType>(), [&](auto&&... args) -> auto& {
|
||||||
|
return *read_dest.construct(LocalType{std::forward<decltype(args)>(args)...});
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
read_dest.construct();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace mp
|
} // namespace mp
|
||||||
|
|
||||||
#endif // BITCOIN_IPC_CAPNP_COMMON_TYPES_H
|
#endif // BITCOIN_IPC_CAPNP_COMMON_TYPES_H
|
||||||
|
|
|
@ -14,3 +14,23 @@ struct BlockRef $Proxy.wrap("interfaces::BlockRef") {
|
||||||
hash @0 :Data;
|
hash @0 :Data;
|
||||||
height @1 :Int32;
|
height @1 :Int32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BilingualStr $Proxy.wrap("bilingual_str") {
|
||||||
|
original @0 :Text;
|
||||||
|
translated @1 :Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Result(Value) {
|
||||||
|
value @0 :Value;
|
||||||
|
error @1: BilingualStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wrapper for util::Result<void>
|
||||||
|
struct ResultVoid(Value) {
|
||||||
|
error @0: BilingualStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Pair(Key, Value) {
|
||||||
|
key @0 :Key;
|
||||||
|
value @1 :Value;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue