Bitcoin Core 31.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
ipc_test.cpp
Go to the documentation of this file.
1// Copyright (c) 2023-present 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#include <interfaces/init.h>
7#include <ipc/process.h>
8#include <ipc/protocol.h>
9#include <logging.h>
10#include <mp/proxy-types.h>
11#include <ipc/capnp/mining.capnp.h>
12#include <ipc/test/ipc_test.capnp.h>
13#include <ipc/test/ipc_test.capnp.proxy.h>
14#include <ipc/test/ipc_test.h>
15#include <tinyformat.h>
16#include <validation.h>
17
18#include <future>
19#include <thread>
20#include <kj/common.h>
21#include <kj/memory.h>
22#include <kj/test.h>
23#include <stdexcept>
24
25#include <boost/test/unit_test.hpp>
26
27static_assert(ipc::capnp::messages::MAX_MONEY == MAX_MONEY);
28static_assert(ipc::capnp::messages::MAX_DOUBLE == std::numeric_limits<double>::max());
29static_assert(ipc::capnp::messages::DEFAULT_BLOCK_RESERVED_WEIGHT == DEFAULT_BLOCK_RESERVED_WEIGHT);
30static_assert(ipc::capnp::messages::DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS == DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS);
31
34{
35public:
36 std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
37};
38
40static std::string TempPath(std::string_view pattern)
41{
42 std::string temp{fs::PathToString(fs::path{fs::temp_directory_path()} / fs::PathFromString(std::string{pattern}))};
43 temp.push_back('\0');
44 int fd{mkstemp(temp.data())};
45 BOOST_CHECK_GE(fd, 0);
46 BOOST_CHECK_EQUAL(close(fd), 0);
47 temp.resize(temp.size() - 1);
48 fs::remove(fs::PathFromString(temp));
49 return temp;
50}
51
61{
62 // Setup: create FooImplementation object and listen for FooInterface requests
63 std::promise<std::unique_ptr<mp::ProxyClient<gen::FooInterface>>> foo_promise;
64 std::thread thread([&]() {
65 mp::EventLoop loop("IpcPipeTest", [](bool raise, const std::string& log) { LogInfo("LOG%i: %s", raise, log); });
66 auto pipe = loop.m_io_context.provider->newTwoWayPipe();
67
68 auto connection_client = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[0]));
69 auto foo_client = std::make_unique<mp::ProxyClient<gen::FooInterface>>(
70 connection_client->m_rpc_system->bootstrap(mp::ServerVatId().vat_id).castAs<gen::FooInterface>(),
71 connection_client.get(), /* destroy_connection= */ true);
72 (void)connection_client.release();
73 foo_promise.set_value(std::move(foo_client));
74
75 auto connection_server = std::make_unique<mp::Connection>(loop, kj::mv(pipe.ends[1]), [&](mp::Connection& connection) {
76 auto foo_server = kj::heap<mp::ProxyServer<gen::FooInterface>>(std::make_shared<FooImplementation>(), connection);
77 return capnp::Capability::Client(kj::mv(foo_server));
78 });
79 connection_server->onDisconnect([&] { connection_server.reset(); });
80 loop.loop();
81 });
82 std::unique_ptr<mp::ProxyClient<gen::FooInterface>> foo{foo_promise.get_future().get()};
83
84 // Test: make sure arguments were sent and return value is received
85 BOOST_CHECK_EQUAL(foo->add(1, 2), 3);
86
87 COutPoint txout1{Txid::FromUint256(uint256{100}), 200};
88 COutPoint txout2{foo->passOutPoint(txout1)};
89 BOOST_CHECK(txout1 == txout2);
90
92 uni1.pushKV("i", 1);
93 uni1.pushKV("s", "two");
94 UniValue uni2{foo->passUniValue(uni1)};
95 BOOST_CHECK_EQUAL(uni1.write(), uni2.write());
96
98 mtx.version = 2;
99 mtx.nLockTime = 3;
100 mtx.vin.emplace_back(txout1);
101 mtx.vout.emplace_back(COIN, CScript());
103 CTransactionRef tx2{foo->passTransaction(tx1)};
104 BOOST_CHECK(*Assert(tx1) == *Assert(tx2));
105
106 std::vector<char> vec1{'H', 'e', 'l', 'l', 'o'};
107 std::vector<char> vec2{foo->passVectorChar(vec1)};
108 BOOST_CHECK_EQUAL(std::string_view(vec1.begin(), vec1.end()), std::string_view(vec2.begin(), vec2.end()));
109
110 auto script1{CScript() << OP_11};
111 auto script2{foo->passScript(script1)};
112 BOOST_CHECK_EQUAL(HexStr(script1), HexStr(script2));
113
114 // Test cleanup: disconnect and join thread
115 foo.reset();
116 thread.join();
117}
118
121{
122 int fds[2];
123 BOOST_CHECK_EQUAL(socketpair(AF_UNIX, SOCK_STREAM, 0, fds), 0);
124 std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()};
125 std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol()};
126 std::promise<void> promise;
127 std::thread thread([&]() {
128 protocol->serve(fds[0], "test-serve", *init, [&] { promise.set_value(); });
129 });
130 promise.get_future().wait();
131 std::unique_ptr<interfaces::Init> remote_init{protocol->connect(fds[1], "test-connect")};
132 std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()};
133 BOOST_CHECK_EQUAL(remote_echo->echo("echo test"), "echo test");
134 remote_echo.reset();
135 remote_init.reset();
136 thread.join();
137}
138
140void IpcSocketTest(const fs::path& datadir)
141{
142 std::unique_ptr<interfaces::Init> init{std::make_unique<TestInit>()};
143 std::unique_ptr<ipc::Protocol> protocol{ipc::capnp::MakeCapnpProtocol()};
144 std::unique_ptr<ipc::Process> process{ipc::MakeProcess()};
145
146 std::string invalid_bind{"invalid:"};
147 BOOST_CHECK_THROW(process->bind(datadir, "test_bitcoin", invalid_bind), std::invalid_argument);
148 BOOST_CHECK_THROW(process->connect(datadir, "test_bitcoin", invalid_bind), std::invalid_argument);
149
150 auto bind_and_listen{[&](const std::string& bind_address) {
151 std::string address{bind_address};
152 int serve_fd = process->bind(datadir, "test_bitcoin", address);
153 BOOST_CHECK_GE(serve_fd, 0);
154 BOOST_CHECK_EQUAL(address, bind_address);
155 protocol->listen(serve_fd, "test-serve", *init);
156 }};
157
158 auto connect_and_test{[&](const std::string& connect_address) {
159 std::string address{connect_address};
160 int connect_fd{process->connect(datadir, "test_bitcoin", address)};
161 BOOST_CHECK_EQUAL(address, connect_address);
162 std::unique_ptr<interfaces::Init> remote_init{protocol->connect(connect_fd, "test-connect")};
163 std::unique_ptr<interfaces::Echo> remote_echo{remote_init->makeEcho()};
164 BOOST_CHECK_EQUAL(remote_echo->echo("echo test"), "echo test");
165 }};
166
167 // Need to specify explicit socket addresses outside the data directory, because the data
168 // directory path is so long that the default socket address and any other
169 // addresses in the data directory would fail with errors like:
170 // Address 'unix' path '"/tmp/test_common_Bitcoin Core/ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff/test_bitcoin.sock"' exceeded maximum socket path length
171 std::vector<std::string> addresses{
172 strprintf("unix:%s", TempPath("bitcoin_sock0_XXXXXX")),
173 strprintf("unix:%s", TempPath("bitcoin_sock1_XXXXXX")),
174 };
175
176 // Bind and listen on multiple addresses
177 for (const auto& address : addresses) {
178 bind_and_listen(address);
179 }
180
181 // Connect and test each address multiple times.
182 for (int i : {0, 1, 0, 0, 1}) {
183 connect_and_test(addresses[i]);
184 }
185}
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition amount.h:26
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition amount.h:15
#define Assert(val)
Identity function.
Definition check.h:113
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition transaction.h:29
Serialized script, used inside transaction inputs and outputs.
Definition script.h:405
TestInit(NodeContext &node)
std::unique_ptr< interfaces::Echo > makeEcho() override
Definition ipc_test.cpp:36
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
void pushKV(std::string key, UniValue val)
Definition univalue.cpp:125
kj::AsyncIoContext m_io_context
Capnp IO context.
Definition proxy-io.h:327
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition uint256.h:195
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition hex_base.cpp:30
static std::string TempPath(std::string_view pattern)
Generate a temporary path with temp_directory_path and mkstemp.
Definition ipc_test.cpp:40
void IpcSocketTest(const fs::path &datadir)
Test ipc::Process bind() and connect() methods connecting over a unix socket.
Definition ipc_test.cpp:140
void IpcPipeTest()
Definition ipc_test.cpp:60
void IpcSocketPairTest()
Test ipc::Protocol connect() and serve() methods connecting over a socketpair.
Definition ipc_test.cpp:120
#define LogInfo(...)
Definition log.h:95
std::unique_ptr< Echo > MakeEcho()
Return implementation of Echo interface.
std::unique_ptr< Protocol > MakeCapnpProtocol()
Definition protocol.cpp:154
std::unique_ptr< Process > MakeProcess()
Definition process.cpp:156
#define BOOST_CHECK_THROW(stmt, excMatch)
Definition object.cpp:18
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:17
#define BOOST_CHECK(expr)
Definition object.cpp:16
static constexpr unsigned int DEFAULT_COINBASE_OUTPUT_MAX_ADDITIONAL_SIGOPS
Default sigops cost to reserve for coinbase transaction outputs when creating block templates.
Definition policy.h:28
static constexpr unsigned int DEFAULT_BLOCK_RESERVED_WEIGHT
Default for -blockreservedweight.
Definition policy.h:26
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
@ OP_11
Definition script.h:94
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< CTxIn > vin
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...