Skip to content

Commit 7d59b8d

Browse files
committed
move: add mp/type-data.h
BuildField definition was moved from https://github.com/bitcoin/bitcoin/blob/0a931a9787b196d7a620863cc143d9319ffd356d/src/ipc/capnp/common-types.h#L137-L162 and tweaked to be more restrictive so it only matches `LocalType`'s that are convertible to spans and constructible from spans, not just types that are convertible to spans. This allows adding a matching CustomReadField function below, which is new. Having the CustomReadField function fixes a serialization bug in the bitcoin core mining IPC interface that was reported in Sjors/bitcoin#71 and #122 The bug was caused by not having CustomBuildField and CustomReadField paired together, so a lower priority CustomReadField was chosen that was not compatible.
1 parent 798f4b5 commit 7d59b8d

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ set(MP_PUBLIC_HEADERS
4848
include/mp/type-char.h
4949
include/mp/type-chrono.h
5050
include/mp/type-context.h
51+
include/mp/type-data.h
5152
include/mp/type-decay.h
5253
include/mp/type-exception.h
5354
include/mp/type-function.h

include/mp/type-data.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) 2025 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 MP_PROXY_TYPE_DATA_H
6+
#define MP_PROXY_TYPE_DATA_H
7+
8+
#include <mp/util.h>
9+
10+
namespace mp {
11+
template <typename T, typename U>
12+
concept IsSpanOf =
13+
std::convertible_to<T, std::span<const U>> &&
14+
std::constructible_from<T, const U*, const U*>;
15+
16+
template <typename T>
17+
concept IsByteSpan =
18+
IsSpanOf<T, std::byte> ||
19+
IsSpanOf<T, char> ||
20+
IsSpanOf<T, unsigned char> ||
21+
IsSpanOf<T, signed char>;
22+
23+
//! Generic ::capnp::Data field builder for any C++ type that can be converted
24+
//! to a span of bytes, like std::vector<char> or std::array<uint8_t>, or custom
25+
//! blob types like uint256 or PKHash with data() and size() methods pointing to
26+
//! bytes.
27+
template <typename LocalType, typename Value, typename Output>
28+
void CustomBuildField(TypeList<LocalType>, Priority<2>, InvokeContext& invoke_context, Value&& value, Output&& output)
29+
requires (std::is_same_v<decltype(output.get()), ::capnp::Data::Builder> && IsByteSpan<LocalType>)
30+
{
31+
auto data = std::span{value};
32+
auto result = output.init(data.size());
33+
memcpy(result.begin(), data.data(), data.size());
34+
}
35+
36+
template <typename LocalType, typename Input, typename ReadDest>
37+
decltype(auto) CustomReadField(TypeList<LocalType>, Priority<2>, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest)
38+
requires (std::is_same_v<decltype(input.get()), ::capnp::Data::Reader> && IsByteSpan<LocalType>)
39+
{
40+
using ByteType = decltype(std::span{std::declval<LocalType>().begin(), std::declval<LocalType>().end()})::element_type;
41+
const kj::byte *begin{input.get().begin()}, *end{input.get().end()};
42+
return read_dest.construct(reinterpret_cast<const ByteType*>(begin), reinterpret_cast<const ByteType*>(end));
43+
}
44+
} // namespace mp
45+
46+
#endif // MP_PROXY_TYPE_DATA_H

0 commit comments

Comments
 (0)