Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/qt/rpcconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,18 @@ void RPCExecutor::request(const QString &command, const QString& wallet_name)
return;
}

// Avoid passing a very large string to the Qt text widget. Appending
// many megabytes of HTML to QTextEdit causes the UI thread to hang
// while the document is re-laid-out. Direct the user to bitcoin-cli
// for commands whose output exceeds the display limit.
if (result.size() > 1_MiB) {
Q_EMIT reply(RPCConsole::CMD_REPLY,
QString("Response too large to display (%1 bytes). "
"Use bitcoin-cli to retrieve the full result.")
.arg(result.size()));
return;
}

Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
}
catch (UniValue& objError)
Expand Down
26 changes: 26 additions & 0 deletions src/qt/test/rpcnestedtests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <qt/rpcconsole.h>
#include <rpc/server.h>
#include <test/util/setup_common.h>
#include <util/byte_units.h>
#include <univalue.h>

#include <QTest>
Expand All @@ -34,8 +35,27 @@ static RPCMethod rpcNestedTest_rpc()
};
}

// Returns a hex string larger than the RPCExecutor display limit (1 MiB) to
// exercise the large-output path. RPCExecuteCommandLine returns the full
// result; the truncation for display is enforced by RPCExecutor::request().
static RPCMethod rpcLargeOutput_rpc()
{
return RPCMethod{
"rpcLargeOutput",
"return a string larger than 1 MiB",
{},
RPCResult{RPCResult::Type::STR_HEX, "", ""},
RPCExamples{""},
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
// 1 MiB + 1 byte of hex characters
return UniValue{std::string(1_MiB + 1, 'a')};
},
};
}

static const CRPCCommand vRPCCommands[] = {
{"rpcNestedTest", &rpcNestedTest_rpc},
{"rpcLargeOutput", &rpcLargeOutput_rpc},
};

void RPCNestedTests::rpcNestedTests()
Expand Down Expand Up @@ -139,4 +159,10 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tolerate empty arguments when using ,
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tolerate empty arguments when using ,
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tolerate empty arguments when using ,

// Verify that RPCExecuteCommandLine returns the full result for large
// outputs. The size guard lives in RPCExecutor::request() and only affects
// what is rendered in the console widget, not the underlying RPC call.
RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcLargeOutput");
QVERIFY(result.size() > 1_MiB);
}