Branch data Line data Source code
1 : : // Copyright (c) 2023 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_IPC_CAPNP_COMMON_TYPES_H
6 : : #define BITCOIN_IPC_CAPNP_COMMON_TYPES_H
7 : :
8 : : #include <clientversion.h>
9 : : #include <interfaces/types.h>
10 : : #include <primitives/transaction.h>
11 : : #include <serialize.h>
12 : : #include <streams.h>
13 : : #include <univalue.h>
14 : :
15 : : #include <cstddef>
16 : : #include <mp/proxy-types.h>
17 : : #include <mp/type-chrono.h>
18 : : #include <mp/type-context.h>
19 : : #include <mp/type-data.h>
20 : : #include <mp/type-decay.h>
21 : : #include <mp/type-interface.h>
22 : : #include <mp/type-message.h>
23 : : #include <mp/type-number.h>
24 : : #include <mp/type-optional.h>
25 : : #include <mp/type-pointer.h>
26 : : #include <mp/type-string.h>
27 : : #include <mp/type-struct.h>
28 : : #include <mp/type-threadmap.h>
29 : : #include <mp/type-vector.h>
30 : : #include <type_traits>
31 : : #include <utility>
32 : :
33 : : namespace ipc {
34 : : namespace capnp {
35 : : //! Construct a ParamStream wrapping a data stream with serialization parameters
36 : : //! needed to pass transaction objects between bitcoin processes.
37 : : //! In the future, more params may be added here to serialize other objects that
38 : : //! require serialization parameters. Params should just be chosen to serialize
39 : : //! objects completely and ensure that serializing and deserializing objects
40 : : //! with the specified parameters produces equivalent objects. It's also
41 : : //! harmless to specify serialization parameters here that are not used.
42 : : template <typename S>
43 : 8 : auto Wrap(S& s)
44 : : {
45 : 8 : return ParamsStream{s, TX_WITH_WITNESS};
46 : : }
47 : :
48 : : //! Detect if type has a deserialize_type constructor, which is
49 : : //! used to deserialize types like CTransaction that can't be unserialized into
50 : : //! existing objects because they are immutable.
51 : : template <typename T>
52 : : concept Deserializable = std::is_constructible_v<T, ::deserialize_type, ::DataStream&>;
53 : : } // namespace capnp
54 : : } // namespace ipc
55 : :
56 : : //! Functions to serialize / deserialize common bitcoin types.
57 : : namespace mp {
58 : : //! Overload multiprocess library's CustomBuildField hook to allow any
59 : : //! serializable object to be stored in a capnproto Data field or passed to a
60 : : //! capnproto interface. Use Priority<1> so this hook has medium priority, and
61 : : //! higher priority hooks could take precedence over this one.
62 : : template <typename LocalType, typename Value, typename Output>
63 : 4 : void CustomBuildField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Value&& value, Output&& output)
64 : : // Enable if serializeable and if LocalType is not cv or reference qualified. If
65 : : // LocalType is cv or reference qualified, it is important to fall back to
66 : : // lower-priority Priority<0> implementation of this function that strips cv
67 : : // references, to prevent this CustomBuildField overload from taking precedence
68 : : // over more narrow overloads for specific LocalTypes.
69 : : requires Serializable<LocalType, DataStream> && std::is_same_v<LocalType, std::remove_cv_t<std::remove_reference_t<LocalType>>>
70 : : {
71 : 4 : DataStream stream;
72 [ + - ]: 4 : auto wrapper{ipc::capnp::Wrap(stream)};
73 [ - + ]: 4 : value.Serialize(wrapper);
[ # # # # ]
74 [ + - - + ]: 4 : auto result = output.init(stream.size());
75 : 4 : memcpy(result.begin(), stream.data(), stream.size());
76 : 4 : }
77 : :
78 : : //! Overload multiprocess library's CustomReadField hook to allow any object
79 : : //! with an Unserialize method to be read from a capnproto Data field or
80 : : //! returned from capnproto interface. Use Priority<1> so this hook has medium
81 : : //! priority, and higher priority hooks could take precedence over this one.
82 : : template <typename LocalType, typename Input, typename ReadDest>
83 : 2 : decltype(auto) CustomReadField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest)
84 : : requires Unserializable<LocalType, DataStream> && (!ipc::capnp::Deserializable<LocalType>)
85 : : {
86 : 2 : return read_dest.update([&](auto& value) {
87 [ + - ][ # # : 2 : if (!input.has()) return;
# # # # ]
[ # # # # ]
88 : 2 : auto data = input.get();
89 : 2 : SpanReader stream({data.begin(), data.end()});
90 : 2 : auto wrapper{ipc::capnp::Wrap(stream)};
91 : 2 : value.Unserialize(wrapper);
92 : 2 : });
93 : : }
94 : :
95 : : //! Overload multiprocess library's CustomReadField hook to allow any object
96 : : //! with a deserialize constructor to be read from a capnproto Data field or
97 : : //! returned from capnproto interface. Use Priority<1> so this hook has medium
98 : : //! priority, and higher priority hooks could take precedence over this one.
99 : : template <typename LocalType, typename Input, typename ReadDest>
100 : 2 : decltype(auto) CustomReadField(TypeList<LocalType>, Priority<1>, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest)
101 : : requires ipc::capnp::Deserializable<LocalType>
102 : : {
103 [ - + ]: 2 : assert(input.has());
104 : 2 : auto data = input.get();
105 : 2 : SpanReader stream({data.begin(), data.end()});
106 : 2 : auto wrapper{ipc::capnp::Wrap(stream)};
107 : 2 : return read_dest.construct(::deserialize, wrapper);
108 : : }
109 : :
110 : : //! Overload CustomBuildField and CustomReadField to serialize UniValue
111 : : //! parameters and return values as JSON strings.
112 : : template <typename Value, typename Output>
113 : 2 : void CustomBuildField(TypeList<UniValue>, Priority<1>, InvokeContext& invoke_context, Value&& value, Output&& output)
114 : : {
115 [ - + ]: 2 : std::string str = value.write();
116 [ + - - + ]: 4 : auto result = output.init(str.size());
117 : 2 : memcpy(result.begin(), str.data(), str.size());
118 : 2 : }
119 : :
120 : : template <typename Input, typename ReadDest>
121 : 2 : decltype(auto) CustomReadField(TypeList<UniValue>, Priority<1>, InvokeContext& invoke_context, Input&& input,
122 : : ReadDest&& read_dest)
123 : : {
124 : 2 : return read_dest.update([&](auto& value) {
125 : 2 : auto data = input.get();
126 : 2 : value.read(std::string_view{data.begin(), data.size()});
127 : 2 : });
128 : : }
129 : :
130 : : } // namespace mp
131 : :
132 : : #endif // BITCOIN_IPC_CAPNP_COMMON_TYPES_H
|