diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -523,6 +523,9 @@ "unconfirmed transactions spending outputs from this transaction", {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}}, + RPCResult{RPCResult::Type::BOOL, "unbroadcast", + "Whether this transaction is currently unbroadcast (initial " + "broadcast not yet confirmed)"}, }; } @@ -572,6 +575,7 @@ } info.pushKV("spentby", spent); + info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetId())); } UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose) { @@ -1725,7 +1729,7 @@ ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee) .GetFeePerK())); ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); - + ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()}); return ret; } @@ -1754,6 +1758,9 @@ "minrelaytxfee and minimum mempool fee"}, {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"}, + {RPCResult::Type::NUM, "unbroadcastcount", + "Current number of transactions that haven't passed initial " + "broadcast yet"}, }}, RPCExamples{HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", "")}, diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -798,6 +798,12 @@ return m_unbroadcast_txids; } + // Returns if a txid is in the unbroadcast set + bool IsUnbroadcastTx(const TxId &txid) const { + LOCK(cs); + return (m_unbroadcast_txids.count(txid) != 0); + } + private: /** * UpdateForDescendants is used by UpdateTransactionsFromBlock to update the diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -226,6 +226,11 @@ for tx in chain[:MAX_ANCESTORS_CUSTOM]: assert tx in mempool1 # TODO: more detailed check of node1's mempool (fees etc.) + # check transaction unbroadcast info (should be false if in both + # mempools) + mempool = self.nodes[0].getrawmempool(True) + for tx in mempool: + assert_equal(mempool[tx]['unbroadcast'], False) # TODO: test ancestor size limits diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py --- a/test/functional/mempool_unbroadcast.py +++ b/test/functional/mempool_unbroadcast.py @@ -54,6 +54,13 @@ txFS = node.signrawtransactionwithwallet(txF["hex"]) rpc_tx_hsh = node.sendrawtransaction(txFS["hex"]) + # check transactions are in unbroadcast using rpc + mempoolinfo = self.nodes[0].getmempoolinfo() + assert_equal(mempoolinfo['unbroadcastcount'], 2) + mempool = self.nodes[0].getrawmempool(True) + for tx in mempool: + assert_equal(mempool[tx]['unbroadcast'], True) + # check that second node doesn't have these two txns mempool = self.nodes[1].getrawmempool() assert rpc_tx_hsh not in mempool @@ -73,6 +80,11 @@ assert rpc_tx_hsh in mempool assert wallet_tx_hsh in mempool + # check that transactions are no longer in first node's unbroadcast set + mempool = self.nodes[0].getrawmempool(True) + for tx in mempool: + assert_equal(mempool[tx]['unbroadcast'], False) + self.log.info( "Add another connection & ensure transactions aren't broadcast again")