Skip to content
Closed
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
83 changes: 83 additions & 0 deletions src/rpc/mempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,88 @@ RPCHelpMan getmempoolentry()
};
}

static RPCHelpMan gettxspendingprevout()
{
return RPCHelpMan{"gettxspendingprevout",
"Scans the mempool to find transactions spending any of the given outputs",
{
{"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
},
},
},
},
},
RPCResult{
RPCResult::Type::ARR, "", "",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"},
{RPCResult::Type::NUM, "vout", "the vout value of the checked output"},
{RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"},
}},
}
},
RPCExamples{
HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
+ HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const UniValue& output_params = request.params[0].get_array();
if (output_params.empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
}

std::vector<COutPoint> prevouts;
prevouts.reserve(output_params.size());

for (unsigned int idx = 0; idx < output_params.size(); idx++) {
const UniValue& o = output_params[idx].get_obj();

RPCTypeCheckObj(o,
{
{"txid", UniValueType(UniValue::VSTR)},
{"vout", UniValueType(UniValue::VNUM)},
}, /*fAllowNull=*/false, /*fStrict=*/true);

const uint256 txid(ParseHashO(o, "txid"));
const int nOutput{o.find_value("vout").getInt<int>()};
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
}

prevouts.emplace_back(txid, nOutput);
}

const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
LOCK(mempool.cs);

UniValue result{UniValue::VARR};

for (const COutPoint& prevout : prevouts) {
UniValue o(UniValue::VOBJ);
o.pushKV("txid", prevout.hash.ToString());
o.pushKV("vout", (uint64_t)prevout.n);

const CTransaction* spendingTx = mempool.GetConflictTx(prevout);
if (spendingTx != nullptr) {
o.pushKV("spendingtxid", spendingTx->GetHash().ToString());
}

result.push_back(o);
}

return result;
},
};
}

UniValue MempoolInfoToJSON(const CTxMemPool& pool, const llmq::CInstantSendManager& isman)
{
// Make sure this call is atomic in the pool.
Expand Down Expand Up @@ -478,6 +560,7 @@ void RegisterMempoolRPCCommands(CRPCTable& t)
{"blockchain", &getmempoolentry},
{"blockchain", &getmempoolinfo},
{"blockchain", &getrawmempool},
{"blockchain", &gettxspendingprevout},
{"blockchain", &savemempool},
};
for (const auto& c : commands) {
Expand Down
Loading