Skip to content

Commit 156f49d

Browse files
committed
interfaces: Change getUnspentOutput return type to avoid multiprocess segfault
Coin serialize method segfaults if IsSpent condition is true. This caused multiprocess code to segfault when serializing the Coin& output argument to of the Node::getUnspentOutput method if the coin was not found. Segfault could be triggered by double clicking and viewing transaction details in the GUI transaction list. Fix this by replacing Coin& output argument with optional<Coin> return value to avoid trying to serializing spent coins.
1 parent 4978754 commit 156f49d

File tree

3 files changed

+8
-8
lines changed

3 files changed

+8
-8
lines changed

src/interfaces/node.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ class Node
204204
//! Unset RPC timer interface.
205205
virtual void rpcUnsetTimerInterface(RPCTimerInterface* iface) = 0;
206206

207-
//! Get unspent outputs associated with a transaction.
208-
virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
207+
//! Get unspent output associated with a transaction.
208+
virtual std::optional<Coin> getUnspentOutput(const COutPoint& output) = 0;
209209

210210
//! Broadcast transaction.
211211
virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0;

src/node/interfaces.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,12 @@ class NodeImpl : public Node
328328
std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }
329329
void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); }
330330
void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); }
331-
bool getUnspentOutput(const COutPoint& output, Coin& coin) override
331+
std::optional<Coin> getUnspentOutput(const COutPoint& output) override
332332
{
333333
LOCK(::cs_main);
334-
return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
334+
Coin coin;
335+
if (chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin)) return coin;
336+
return {};
335337
}
336338
TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
337339
{

src/qt/transactiondesc.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -360,12 +360,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
360360
{
361361
COutPoint prevout = txin.prevout;
362362

363-
Coin prev;
364-
if(node.getUnspentOutput(prevout, prev))
365-
{
363+
if (auto prev{node.getUnspentOutput(prevout)}) {
366364
{
367365
strHTML += "<li>";
368-
const CTxOut &vout = prev.out;
366+
const CTxOut& vout = prev->out;
369367
CTxDestination address;
370368
if (ExtractDestination(vout.scriptPubKey, address))
371369
{

0 commit comments

Comments
 (0)