aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRussell Yanofsky <russ@yanofsky.org>2020-11-24 13:59:33 -0500
committerRussell Yanofsky <russ@yanofsky.org>2021-04-23 03:02:50 -0500
commit84934bf70e11fe4cda1cfda60113a54895d4fdd5 (patch)
treea76e8bd27d3e32a9f433d6f24857d6b96e499efc /src
parent7d76cf667eff512043a28d4407cc89f58796c42b (diff)
downloadbitcoin-84934bf70e11fe4cda1cfda60113a54895d4fdd5.tar.xz
multiprocess: Add echoipc RPC method and test
Add simple interfaces::Echo IPC interface with one method that just takes and returns a string, to test multiprocess framework and provide an example of how it can be used to spawn and call between processes.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am3
-rw-r--r--src/init/bitcoin-node.cpp2
-rw-r--r--src/interfaces/echo.cpp18
-rw-r--r--src/interfaces/echo.h26
-rw-r--r--src/interfaces/init.cpp2
-rw-r--r--src/interfaces/init.h2
-rw-r--r--src/ipc/capnp/echo.capnp17
-rw-r--r--src/ipc/capnp/init-types.h3
-rw-r--r--src/ipc/capnp/init.capnp4
-rw-r--r--src/rpc/misc.cpp41
10 files changed, 118 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 71dd7b65a0..447015fc66 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -159,6 +159,7 @@ BITCOIN_CORE_H = \
init.h \
init/common.h \
interfaces/chain.h \
+ interfaces/echo.h \
interfaces/handler.h \
interfaces/init.h \
interfaces/ipc.h \
@@ -563,6 +564,7 @@ libbitcoin_util_a_SOURCES = \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
fs.cpp \
+ interfaces/echo.cpp \
interfaces/handler.cpp \
interfaces/init.cpp \
logging.cpp \
@@ -815,6 +817,7 @@ if HARDEN
endif
libbitcoin_ipc_mpgen_input = \
+ ipc/capnp/echo.capnp \
ipc/capnp/init.capnp
EXTRA_DIST += $(libbitcoin_ipc_mpgen_input)
%.capnp:
diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp
index b1c8a5b561..49684ede83 100644
--- a/src/init/bitcoin-node.cpp
+++ b/src/init/bitcoin-node.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <interfaces/echo.h>
#include <interfaces/init.h>
#include <interfaces/ipc.h>
#include <node/context.h>
@@ -21,6 +22,7 @@ public:
{
m_node.init = this;
}
+ std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
interfaces::Ipc* ipc() override { return m_ipc.get(); }
NodeContext& m_node;
std::unique_ptr<interfaces::Ipc> m_ipc;
diff --git a/src/interfaces/echo.cpp b/src/interfaces/echo.cpp
new file mode 100644
index 0000000000..9bbb42217b
--- /dev/null
+++ b/src/interfaces/echo.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <interfaces/echo.h>
+
+#include <memory>
+
+namespace interfaces {
+namespace {
+class EchoImpl : public Echo
+{
+public:
+ std::string echo(const std::string& echo) override { return echo; }
+};
+} // namespace
+std::unique_ptr<Echo> MakeEcho() { return std::make_unique<EchoImpl>(); }
+} // namespace interfaces
diff --git a/src/interfaces/echo.h b/src/interfaces/echo.h
new file mode 100644
index 0000000000..5578d9d9e6
--- /dev/null
+++ b/src/interfaces/echo.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_INTERFACES_ECHO_H
+#define BITCOIN_INTERFACES_ECHO_H
+
+#include <memory>
+#include <string>
+
+namespace interfaces {
+//! Simple string echoing interface for testing.
+class Echo
+{
+public:
+ virtual ~Echo() {}
+
+ //! Echo provided string.
+ virtual std::string echo(const std::string& echo) = 0;
+};
+
+//! Return implementation of Echo interface.
+std::unique_ptr<Echo> MakeEcho();
+} // namespace interfaces
+
+#endif // BITCOIN_INTERFACES_ECHO_H
diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp
index 1eeea9b5cb..a3c949e616 100644
--- a/src/interfaces/init.cpp
+++ b/src/interfaces/init.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <interfaces/chain.h>
+#include <interfaces/echo.h>
#include <interfaces/init.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
@@ -11,5 +12,6 @@ namespace interfaces {
std::unique_ptr<Node> Init::makeNode() { return {}; }
std::unique_ptr<Chain> Init::makeChain() { return {}; }
std::unique_ptr<WalletClient> Init::makeWalletClient(Chain& chain) { return {}; }
+std::unique_ptr<Echo> Init::makeEcho() { return {}; }
Ipc* Init::ipc() { return nullptr; }
} // namespace interfaces
diff --git a/src/interfaces/init.h b/src/interfaces/init.h
index 8aea027f01..2a38054a17 100644
--- a/src/interfaces/init.h
+++ b/src/interfaces/init.h
@@ -11,6 +11,7 @@ struct NodeContext;
namespace interfaces {
class Chain;
+class Echo;
class Ipc;
class Node;
class WalletClient;
@@ -29,6 +30,7 @@ public:
virtual std::unique_ptr<Node> makeNode();
virtual std::unique_ptr<Chain> makeChain();
virtual std::unique_ptr<WalletClient> makeWalletClient(Chain& chain);
+ virtual std::unique_ptr<Echo> makeEcho();
virtual Ipc* ipc();
};
diff --git a/src/ipc/capnp/echo.capnp b/src/ipc/capnp/echo.capnp
new file mode 100644
index 0000000000..df36ee0de3
--- /dev/null
+++ b/src/ipc/capnp/echo.capnp
@@ -0,0 +1,17 @@
+# Copyright (c) 2021 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+@0x888b4f7f51e691f7;
+
+using Cxx = import "/capnp/c++.capnp";
+$Cxx.namespace("ipc::capnp::messages");
+
+using Proxy = import "/mp/proxy.capnp";
+$Proxy.include("interfaces/echo.h");
+$Proxy.include("ipc/capnp/echo.capnp.h");
+
+interface Echo $Proxy.wrap("interfaces::Echo") {
+ destroy @0 (context :Proxy.Context) -> ();
+ echo @1 (context :Proxy.Context, echo: Text) -> (result :Text);
+}
diff --git a/src/ipc/capnp/init-types.h b/src/ipc/capnp/init-types.h
index c84b94802a..42031441b5 100644
--- a/src/ipc/capnp/init-types.h
+++ b/src/ipc/capnp/init-types.h
@@ -4,4 +4,7 @@
#ifndef BITCOIN_IPC_CAPNP_INIT_TYPES_H
#define BITCOIN_IPC_CAPNP_INIT_TYPES_H
+
+#include <ipc/capnp/echo.capnp.proxy-types.h>
+
#endif // BITCOIN_IPC_CAPNP_INIT_TYPES_H
diff --git a/src/ipc/capnp/init.capnp b/src/ipc/capnp/init.capnp
index be6eecb4b9..e6d358c665 100644
--- a/src/ipc/capnp/init.capnp
+++ b/src/ipc/capnp/init.capnp
@@ -8,9 +8,13 @@ using Cxx = import "/capnp/c++.capnp";
$Cxx.namespace("ipc::capnp::messages");
using Proxy = import "/mp/proxy.capnp";
+$Proxy.include("interfaces/echo.h");
$Proxy.include("interfaces/init.h");
$Proxy.includeTypes("ipc/capnp/init-types.h");
+using Echo = import "echo.capnp";
+
interface Init $Proxy.wrap("interfaces::Init") {
construct @0 (threadMap: Proxy.ThreadMap) -> (threadMap :Proxy.ThreadMap);
+ makeEcho @1 (context :Proxy.Context) -> (result :Echo.Echo);
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 00a06260ea..09b32345a2 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -7,6 +7,9 @@
#include <index/blockfilterindex.h>
#include <index/txindex.h>
#include <interfaces/chain.h>
+#include <interfaces/echo.h>
+#include <interfaces/init.h>
+#include <interfaces/ipc.h>
#include <key_io.h>
#include <node/context.h>
#include <outputtype.h>
@@ -644,6 +647,43 @@ static RPCHelpMan echo(const std::string& name)
static RPCHelpMan echo() { return echo("echo"); }
static RPCHelpMan echojson() { return echo("echojson"); }
+static RPCHelpMan echoipc()
+{
+ return RPCHelpMan{
+ "echoipc",
+ "\nEcho back the input argument, passing it through a spawned process in a multiprocess build.\n"
+ "This command is for testing.\n",
+ {{"arg", RPCArg::Type::STR, RPCArg::Optional::NO, "The string to echo",}},
+ RPCResult{RPCResult::Type::STR, "echo", "The echoed string."},
+ RPCExamples{HelpExampleCli("echo", "\"Hello world\"") +
+ HelpExampleRpc("echo", "\"Hello world\"")},
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
+ std::unique_ptr<interfaces::Echo> echo;
+ if (interfaces::Ipc* ipc = Assert(EnsureAnyNodeContext(request.context).init)->ipc()) {
+ // Spawn a new bitcoin-node process and call makeEcho to get a
+ // client pointer to a interfaces::Echo instance running in
+ // that process. This is just for testing. A slightly more
+ // realistic test spawning a different executable instead of
+ // the same executable would add a new bitcoin-echo executable,
+ // and spawn bitcoin-echo below instead of bitcoin-node. But
+ // using bitcoin-node avoids the need to build and install a
+ // new executable just for this one test.
+ auto init = ipc->spawnProcess("bitcoin-node");
+ echo = init->makeEcho();
+ ipc->addCleanup(*echo, [init = init.release()] { delete init; });
+ } else {
+ // IPC support is not available because this is a bitcoind
+ // process not a bitcoind-node process, so just create a local
+ // interfaces::Echo object and return it so the `echoipc` RPC
+ // method will work, and the python test calling `echoipc`
+ // can expect the same result.
+ echo = interfaces::MakeEcho();
+ }
+ return echo->echo(request.params[0].get_str());
+ },
+ };
+}
+
static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name)
{
UniValue ret_summary(UniValue::VOBJ);
@@ -719,6 +759,7 @@ static const CRPCCommand commands[] =
{ "hidden", &mockscheduler, },
{ "hidden", &echo, },
{ "hidden", &echojson, },
+ { "hidden", &echoipc, },
};
// clang-format on
for (const auto& c : commands) {