aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Zumsande <mzumsande@gmail.com>2023-08-15 12:02:14 -0400
committerMartin Zumsande <mzumsande@gmail.com>2023-08-22 13:28:15 -0400
commita9a1d69391596f57851f545fae12f8851149d2c3 (patch)
tree0db551032f05a88bcd5d8969ca2f6d13895092b6 /src
parent6ce5e8f4758e6fccf59b3980af417ec6c75e383e (diff)
rpc: add test-only sendmsgtopeer rpc
This rpc can be used when we want a node to send a message, but cannot use a python P2P object, for example for testing of low-level net transport behavior.
Diffstat (limited to 'src')
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/net.cpp49
-rw-r--r--src/test/fuzz/rpc.cpp1
3 files changed, 51 insertions, 0 deletions
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 2908c37c1f..0ee3f27761 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -299,6 +299,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getnodeaddresses", 0, "count"},
{ "addpeeraddress", 1, "port"},
{ "addpeeraddress", 2, "tried"},
+ { "sendmsgtopeer", 0, "peer_id" },
{ "stop", 0, "wait" },
};
// clang-format on
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index a2a46ef32f..f7b6c68344 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -968,6 +968,54 @@ static RPCHelpMan addpeeraddress()
};
}
+static RPCHelpMan sendmsgtopeer()
+{
+ return RPCHelpMan{
+ "sendmsgtopeer",
+ "Send a p2p message to a peer specified by id.\n"
+ "The message type and body must be provided, the message header will be generated.\n"
+ "This RPC is for testing only.",
+ {
+ {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to send the message to."},
+ {"msg_type", RPCArg::Type::STR, RPCArg::Optional::NO, strprintf("The message type (maximum length %i)", CMessageHeader::COMMAND_SIZE)},
+ {"msg", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The serialized message body to send, in hex, without a message header"},
+ },
+ RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
+ RPCExamples{
+ HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", "0 \"addr\" \"ffffff\"")},
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
+ const NodeId peer_id{request.params[0].getInt<int64_t>()};
+ const std::string& msg_type{request.params[1].get_str()};
+ if (msg_type.size() > CMessageHeader::COMMAND_SIZE) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Error: msg_type too long, max length is %i", CMessageHeader::COMMAND_SIZE));
+ }
+ auto msg{TryParseHex<unsigned char>(request.params[2].get_str())};
+ if (!msg.has_value()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Error parsing input for msg");
+ }
+
+ NodeContext& node = EnsureAnyNodeContext(request.context);
+ CConnman& connman = EnsureConnman(node);
+
+ CSerializedNetMsg msg_ser;
+ msg_ser.data = msg.value();
+ msg_ser.m_type = msg_type;
+
+ bool success = connman.ForNode(peer_id, [&](CNode* node) {
+ connman.PushMessage(node, std::move(msg_ser));
+ return true;
+ });
+
+ if (!success) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not send message to peer");
+ }
+
+ UniValue ret{UniValue::VOBJ};
+ return ret;
+ },
+ };
+}
+
void RegisterNetRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
@@ -986,6 +1034,7 @@ void RegisterNetRPCCommands(CRPCTable& t)
{"network", &getnodeaddresses},
{"hidden", &addconnection},
{"hidden", &addpeeraddress},
+ {"hidden", &sendmsgtopeer},
};
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp
index 9e76c7be3e..24ec0e4a73 100644
--- a/src/test/fuzz/rpc.cpp
+++ b/src/test/fuzz/rpc.cpp
@@ -158,6 +158,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"reconsiderblock",
"scanblocks",
"scantxoutset",
+ "sendmsgtopeer", // when no peers are connected, no p2p message is sent
"sendrawtransaction",
"setmocktime",
"setnetworkactive",