Skip to content

Commit 58d9580

Browse files
committed
ipc: replace libmultiprocess runtime with native capnp
1 parent 6ca607f commit 58d9580

35 files changed

Lines changed: 2834 additions & 999 deletions

CMakeLists.txt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,7 @@ if(WITH_USDT)
121121
find_package(USDT MODULE REQUIRED)
122122
endif()
123123

124-
option(WITH_EXTERNAL_LIBMULTIPROCESS "Build with external libmultiprocess library instead of with local git subtree. This is not normally recommended, but can be useful for developing libmultiprocess itself." OFF)
125-
if(WITH_EXTERNAL_LIBMULTIPROCESS)
126-
find_package(Libmultiprocess REQUIRED COMPONENTS Lib)
127-
find_package(LibmultiprocessNative REQUIRED COMPONENTS Bin
128-
NAMES Libmultiprocess
129-
)
130-
endif()
124+
find_package(CapnProto REQUIRED)
131125

132126
option(BUILD_BENCH "Build bench_bitcoin executable." OFF)
133127
option(BUILD_FUZZ_BINARY "Build fuzz binary." OFF)

src/CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ include(../cmake/crc32c.cmake)
1919
include(../cmake/leveldb.cmake)
2020
include(../cmake/minisketch.cmake)
2121
add_subdirectory(univalue)
22-
if (NOT WITH_EXTERNAL_LIBMULTIPROCESS)
23-
include(../cmake/libmultiprocess.cmake)
24-
add_libmultiprocess(ipc/libmultiprocess)
25-
endif()
2622
include(../cmake/secp256k1.cmake)
2723
add_secp256k1(secp256k1)
2824

src/bitcoin.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,22 @@
88
#include <common/args.h>
99
#include <common/license_info.h>
1010
#include <common/system.h>
11-
#include <util/fs.h>
11+
#include <tinyformat.h>
1212
#include <util/exec.h>
13+
#include <util/fs.h>
1314
#include <util/strencodings.h>
1415
#include <util/translation.h>
1516

1617
#include <iostream>
1718
#include <string>
18-
#include <tinyformat.h>
1919
#include <vector>
2020

2121
const TranslateFn G_TRANSLATION_FUN{nullptr};
2222

2323
static constexpr auto HELP_USAGE = R"(Usage: %s [OPTIONS] COMMAND...
2424
2525
Options:
26-
-m, --multiprocess Run multiprocess binary bitcoin-node.
26+
-m, --ipc-server Run IPC server binary bitcoin-node.
2727
-M, --monolithic Run monolithic binary bitcoind. (Default behavior)
2828
-v, --version Show version information
2929
-h, --help Show full help message
@@ -47,7 +47,7 @@ Run '%s help' to see additional commands (e.g. for testing and debugging).
4747
)";
4848

4949
struct CommandLine {
50-
std::optional<bool> use_multiprocess;
50+
std::optional<bool> use_ipc_server;
5151
bool show_version{false};
5252
bool show_help{false};
5353
std::string_view command;
@@ -118,10 +118,10 @@ CommandLine ParseCommandLine(int argc, char* argv[])
118118
std::string_view arg = argv[i];
119119
if (!cmd.command.empty()) {
120120
cmd.args.emplace_back(argv[i]);
121-
} else if (arg == "-m" || arg == "--multiprocess") {
122-
cmd.use_multiprocess = true;
121+
} else if (arg == "-m" || arg == "--ipc-server") {
122+
cmd.use_ipc_server = true;
123123
} else if (arg == "-M" || arg == "--monolithic") {
124-
cmd.use_multiprocess = false;
124+
cmd.use_ipc_server = false;
125125
} else if (arg == "-v" || arg == "--version") {
126126
cmd.show_version = true;
127127
} else if (arg == "-h" || arg == "--help" || arg == "help") {
@@ -139,7 +139,7 @@ bool UseMultiprocess(const CommandLine& cmd)
139139
{
140140
// If -m or -M options were explicitly specified, there is no need to
141141
// further parse arguments to determine which to use.
142-
if (cmd.use_multiprocess) return *cmd.use_multiprocess;
142+
if (cmd.use_ipc_server) return *cmd.use_ipc_server;
143143

144144
ArgsManager args;
145145
args.SetDefaultFlags(ArgsManager::ALLOW_ANY);
@@ -154,8 +154,8 @@ bool UseMultiprocess(const CommandLine& cmd)
154154
}
155155
args.SelectConfigNetwork(args.GetChainTypeString());
156156

157-
// If any -ipc* options are set these need to be processed by a
158-
// multiprocess-capable binary.
157+
// If any -ipc* options are set these need to be processed by the
158+
// IPC-capable server binary.
159159
return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd");
160160
}
161161

@@ -187,7 +187,7 @@ static void ExecCommand(const std::vector<const char*>& args, std::string_view w
187187
auto try_exec = [&](fs::path exe_path, bool allow_notfound = true) {
188188
std::string exe_path_str{fs::PathToString(exe_path)};
189189
exec_args[0] = exe_path_str.c_str();
190-
if (util::ExecVp(exec_args[0], (char*const*)exec_args.data()) == -1) {
190+
if (util::ExecVp(exec_args[0], (char* const*)exec_args.data()) == -1) {
191191
if (allow_notfound && errno == ENOENT) return false;
192192
throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));
193193
}
@@ -217,11 +217,11 @@ static void ExecCommand(const std::vector<const char*>& args, std::string_view w
217217
// in libexec/
218218
(wrapper_dir.filename() == "bin" && try_exec(wrapper_dir.parent_path() / "libexec" / arg0.filename())) ||
219219
#ifdef WIN32
220-
// Otherwise check the "daemon" subdirectory in a windows install.
221-
(!wrapper_dir.empty() && try_exec(wrapper_dir / "daemon" / arg0.filename())) ||
220+
// Otherwise check the "daemon" subdirectory in a windows install.
221+
(!wrapper_dir.empty() && try_exec(wrapper_dir / "daemon" / arg0.filename())) ||
222222
#endif
223-
// Otherwise look for target executable next to current wrapper
224-
(!wrapper_dir.empty() && try_exec(wrapper_dir / arg0.filename(), fallback_os_search)) ||
225-
// Otherwise just look on the system path.
226-
(fallback_os_search && try_exec(arg0.filename(), false));
223+
// Otherwise look for target executable next to current wrapper
224+
(!wrapper_dir.empty() && try_exec(wrapper_dir / arg0.filename(), fallback_os_search)) ||
225+
// Otherwise just look on the system path.
226+
(fallback_os_search && try_exec(arg0.filename(), false));
227227
}

src/interfaces/ipc.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <functional>
99
#include <memory>
1010
#include <string>
11-
#include <typeindex>
1211

1312
namespace ipc {
1413
struct Context;
@@ -74,21 +73,8 @@ class Ipc
7473
//! Disconnect any incoming connections that are still connected.
7574
virtual void disconnectIncoming() = 0;
7675

77-
//! Add cleanup callback to remote interface that will run when the
78-
//! interface is deleted.
79-
template<typename Interface>
80-
void addCleanup(Interface& iface, std::function<void()> cleanup)
81-
{
82-
addCleanup(typeid(Interface), &iface, std::move(cleanup));
83-
}
84-
8576
//! IPC context struct accessor (see struct definition for more description).
8677
virtual ipc::Context& context() = 0;
87-
88-
protected:
89-
//! Internal implementation of public addCleanup method (above) as a
90-
//! type-erased virtual function, since template functions can't be virtual.
91-
virtual void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) = 0;
9278
};
9379

9480
//! Return implementation of Ipc interface.

src/interfaces/mining.h

Lines changed: 48 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
#define BITCOIN_INTERFACES_MINING_H
77

88
#include <consensus/amount.h>
9+
#include <interfaces/handler.h>
910
#include <interfaces/types.h>
1011
#include <node/mining_types.h>
1112
#include <primitives/block.h>
1213
#include <primitives/transaction.h>
1314
#include <uint256.h>
15+
#include <util/result.h>
1416
#include <util/time.h>
1517

1618
#include <cstdint>
19+
#include <functional>
1720
#include <memory>
1821
#include <optional>
1922
#include <string>
@@ -29,6 +32,9 @@ namespace interfaces {
2932
class BlockTemplate
3033
{
3134
public:
35+
using NextTemplateFn = std::function<void(std::unique_ptr<BlockTemplate>)>;
36+
using SubmitSolutionFn = std::function<void(bool)>;
37+
3238
virtual ~BlockTemplate() = default;
3339

3440
virtual CBlockHeader getBlockHeader() = 0;
@@ -75,32 +81,39 @@ class BlockTemplate
7581
* the solved block is constructed and broadcast by multiple nodes
7682
* (e.g. both the miner who constructed the template and the pool).
7783
*/
78-
virtual bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase) = 0;
84+
/**
85+
* Construct and broadcast the block asynchronously. The returned handler
86+
* cancels the submission before the callback runs.
87+
*/
88+
virtual std::unique_ptr<Handler> submitSolutionAsync(uint32_t version, uint32_t timestamp, uint32_t nonce, CTransactionRef coinbase, SubmitSolutionFn fn) = 0;
7989

8090
/**
81-
* Waits for fees in the next block to rise, a new tip or the timeout.
91+
* Watches for fees in the next block to rise, a new tip or the timeout.
8292
*
8393
* @param[in] options Control the timeout (default forever) and by how much total fees
8494
* for the next block should rise (default infinite).
95+
* @param[in] fn Called with a new block template, or nullptr on
96+
* timeout or cancellation.
8597
*
86-
* @returns a new BlockTemplate or nothing if the timeout occurs.
98+
* @returns a handler that cancels the watch before the callback runs.
8799
*
88100
* On testnet this will additionally return a template with difficulty 1 if
89101
* the tip is more than 20 minutes old.
90102
*/
91-
virtual std::unique_ptr<BlockTemplate> waitNext(node::BlockWaitOptions options = {}) = 0;
92-
93-
/**
94-
* Interrupts the current wait for the next block template.
95-
*/
96-
virtual void interruptWait() = 0;
103+
virtual std::unique_ptr<Handler> watchNext(node::BlockWaitOptions options, NextTemplateFn fn) = 0;
97104
};
98105

99106
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)
100107
//! ability to create block templates.
101108
class Mining
102109
{
103110
public:
111+
using TipChangedFn = std::function<void(std::optional<BlockRef>)>;
112+
using CreateBlockResult = util::Result<std::unique_ptr<BlockTemplate>>;
113+
using CreateBlockFn = std::function<void(CreateBlockResult)>;
114+
using CheckBlockFn = std::function<void(bool, std::string, std::string)>;
115+
using SubmitBlockFn = std::function<void(bool, std::string, std::string)>;
116+
104117
virtual ~Mining() = default;
105118

106119
//! If this chain is exclusively used for testing
@@ -112,85 +125,71 @@ class Mining
112125
//! Returns the hash and height for the tip of this chain
113126
virtual std::optional<BlockRef> getTip() = 0;
114127

115-
/**
116-
* Waits for the connected tip to change. During node initialization, this will
117-
* wait until the tip is connected (regardless of `timeout`).
118-
*
119-
* @param[in] current_tip block hash of the current chain tip. Function waits
120-
* for the chain tip to differ from this.
121-
* @param[in] timeout how long to wait for a new tip (default is forever)
122-
*
123-
* @retval BlockRef hash and height of the current chain tip after this call.
124-
* @retval std::nullopt if the node is shut down or interrupt() is called.
125-
*/
126-
virtual std::optional<BlockRef> waitTipChanged(uint256 current_tip, MillisecondsDouble timeout = MillisecondsDouble::max()) = 0;
128+
//! Watches for the connected tip to differ from current_tip. The returned
129+
//! handler cancels the watch before the callback runs.
130+
virtual std::unique_ptr<Handler> watchTip(uint256 current_tip, MillisecondsDouble timeout, TipChangedFn fn) = 0;
127131

128-
/**
129-
* Construct a new block template.
132+
/**
133+
* Construct a new block template asynchronously.
130134
*
131135
* @param[in] options options for creating the block
132136
* @param[in] cooldown wait for tip to be connected and IBD to complete.
133137
* If the best header is ahead of the tip, wait for the
134138
* tip to catch up. It's recommended to disable this on
135139
* regtest and signets with only one miner, as these
136140
* could stall.
137-
* @retval BlockTemplate a block template.
138-
* @retval std::nullptr if the node is shut down or interrupt() is called.
139-
*/
140-
virtual std::unique_ptr<BlockTemplate> createNewBlock(const node::BlockCreateOptions& options = {}, bool cooldown = true) = 0;
141-
142-
/**
143-
* Interrupts createNewBlock and waitTipChanged.
141+
* @param[in] fn called with a block template result. A successful result
142+
* may contain nullptr when the operation is cancelled or the
143+
* node is shutting down.
144+
*
145+
* @returns a handler that cancels the operation before the callback runs.
144146
*/
145-
virtual void interrupt() = 0;
147+
virtual std::unique_ptr<Handler> createNewBlockAsync(const node::BlockCreateOptions& options, bool cooldown, CreateBlockFn fn) = 0;
146148

147149
/**
148-
* Checks if a given block is valid.
150+
* Checks if a given block is valid asynchronously.
149151
*
150152
* @param[in] block the block to check
151153
* @param[in] options verification options: the proof-of-work check can be
152154
* skipped in order to verify a template generated by
153155
* external software.
154-
* @param[out] reason failure reason (BIP22)
155-
* @param[out] debug more detailed rejection reason
156-
* @returns whether the block is valid
156+
* @param[in] fn called with validity, failure reason (BIP22), and
157+
* more detailed rejection reason.
157158
*
158159
* For signets the challenge verification is skipped when check_pow is false.
159160
*/
160-
virtual bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) = 0;
161+
virtual std::unique_ptr<Handler> checkBlockAsync(CBlock block, node::BlockCheckOptions options, CheckBlockFn fn) = 0;
161162

162163
/**
163-
* Process a fully assembled block.
164+
* Process a fully assembled block asynchronously.
164165
*
165-
* Similar to the submitblock RPC. Accepts a complete block, validates
166-
* it, and if accepted as new, processes it into chainstate. Accepted
167-
* blocks may then be announced to peers through normal validation signals.
166+
* Similar to the submitblock RPC. Accepts a complete block, validates it,
167+
* and if accepted as new, processes it into chainstate. Accepted blocks may
168+
* then be announced to peers through normal validation signals.
168169
*
169-
* @param[in] block the complete block to submit
170-
* @param[out] reason failure reason (BIP22)
171-
* @param[out] debug more detailed rejection reason
172-
* @returns true if the block was accepted as a new block. Returns
173-
* false and sets reason if the block is a duplicate or
174-
* the validation result is inconclusive.
170+
* @param[in] block the complete block to submit
171+
* @param[in] fn called with accepted, failure reason (BIP22), and more
172+
* detailed rejection reason. Accepted is false for duplicate
173+
* or inconclusive validation results.
175174
*
176175
* @note Unlike the submitblock RPC, this method does not call
177176
* UpdateUncommittedBlockStructures to add a missing coinbase witness
178177
* reserved value. Callers must submit a fully formed block, including
179178
* the coinbase witness when a witness commitment is present.
180179
*/
181-
virtual bool submitBlock(const CBlock& block, std::string& reason, std::string& debug) = 0;
180+
virtual std::unique_ptr<Handler> submitBlockAsync(CBlock block, SubmitBlockFn fn) = 0;
182181

183182
//! Get internal node context. Useful for RPC and testing,
184183
//! but not accessible across processes.
185-
virtual const node::NodeContext* context() { return nullptr; }
184+
virtual node::NodeContext* context() { return nullptr; }
186185
};
187186

188187
//! Return implementation of Mining interface.
189188
//!
190189
//! @param[in] wait_loaded waits for chainstate data to be loaded before
191190
//! returning. Used to prevent external clients from
192191
//! being able to crash the node during startup.
193-
std::unique_ptr<Mining> MakeMining(const node::NodeContext& node, bool wait_loaded=true);
192+
std::unique_ptr<Mining> MakeMining(node::NodeContext& node, bool wait_loaded = true);
194193

195194
} // namespace interfaces
196195

0 commit comments

Comments
 (0)