0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

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.
This commit is contained in:
Martin Zumsande 2023-08-15 12:02:14 -04:00
parent 6ce5e8f475
commit a9a1d69391
3 changed files with 51 additions and 0 deletions

View file

@ -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

View file

@ -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);

View file

@ -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",