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:
parent
6ce5e8f475
commit
a9a1d69391
3 changed files with 51 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Reference in a new issue