mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-12 05:32:22 +02:00
mining: add getTransactionsByTxID() IPC method
This commit is contained in:
@@ -180,6 +180,15 @@ public:
|
||||
*/
|
||||
virtual bool submitBlock(const CBlock& block, std::string& reason, std::string& debug) = 0;
|
||||
|
||||
/**
|
||||
* Fetch raw transactions from the mempool by txid.
|
||||
*
|
||||
* @param[in] txids transaction ids to look up
|
||||
* @returns one entry per requested txid containing the
|
||||
* transaction if found, otherwise nullptr
|
||||
*/
|
||||
virtual std::vector<CTransactionRef> getTransactionsByTxID(const std::vector<Txid>& txids) = 0;
|
||||
|
||||
//! Get internal node context. Useful for RPC and testing,
|
||||
//! but not accessible across processes.
|
||||
virtual const node::NodeContext* context() { return nullptr; }
|
||||
|
||||
@@ -26,6 +26,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") {
|
||||
checkBlock @5 (context :Proxy.Context, block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool);
|
||||
interrupt @6 () -> ();
|
||||
submitBlock @7 (context :Proxy.Context, block: Data) -> (reason: Text, debug: Text, result: Bool);
|
||||
getTransactionsByTxID @8 (context :Proxy.Context, txids: List(Data)) -> (result: List(Data));
|
||||
}
|
||||
|
||||
interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
|
||||
|
||||
@@ -1035,6 +1035,19 @@ public:
|
||||
return accepted && new_block && reason.empty();
|
||||
}
|
||||
|
||||
std::vector<CTransactionRef> getTransactionsByTxID(const std::vector<Txid>& txids) override
|
||||
{
|
||||
if (!m_node.mempool) return {};
|
||||
|
||||
std::vector<CTransactionRef> results;
|
||||
results.reserve(txids.size());
|
||||
LOCK(m_node.mempool->cs);
|
||||
for (const auto& txid : txids) {
|
||||
results.emplace_back(m_node.mempool->get(txid));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
const NodeContext* context() override { return &m_node; }
|
||||
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
|
||||
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
|
||||
|
||||
@@ -184,6 +184,16 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
|
||||
const auto high_fee_tx{entry.Fee(50000).Time(Now<NodeSeconds>()).SpendsCoinbase(false).FromTx(tx)};
|
||||
TryAddToMempool(tx_mempool, high_fee_tx);
|
||||
|
||||
// Test getTransactionsByTxID()
|
||||
const std::vector<Txid> tx_id_list{
|
||||
hashParentTx,
|
||||
Txid::FromUint256(uint256::ZERO) // non-existing tx
|
||||
};
|
||||
auto raw_txs = mining->getTransactionsByTxID(tx_id_list);
|
||||
BOOST_REQUIRE_EQUAL(raw_txs.size(), tx_id_list.size());
|
||||
BOOST_CHECK(raw_txs[0]);
|
||||
BOOST_CHECK(raw_txs[0]->GetHash() == hashParentTx);
|
||||
BOOST_CHECK(!raw_txs[1]);
|
||||
block_template = mining->createNewBlock(options, /*cooldown=*/false);
|
||||
BOOST_REQUIRE(block_template);
|
||||
block = block_template->getBlock();
|
||||
|
||||
@@ -672,6 +672,30 @@ class IPCMiningTest(BitcoinTestFramework):
|
||||
|
||||
asyncio.run(capnp.run(async_routine()))
|
||||
|
||||
def run_transaction_lookup_test(self):
|
||||
"""Test getTransactionsByTxID()."""
|
||||
self.log.info("Running transaction lookup test")
|
||||
|
||||
async def async_routine():
|
||||
ctx, mining = await make_mining_ctx(self)
|
||||
tx1 = self.miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
|
||||
tx2 = self.miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0], utxo_to_spend=tx1["new_utxo"])
|
||||
|
||||
self.log.debug("getTransactionsByTxID() returns mempool txs and nulls")
|
||||
raw_txs_txid = await mining.getTransactionsByTxID(ctx, [tx1["tx"].txid, tx2["tx"].txid, bytes(32)])
|
||||
assert_equal(len(raw_txs_txid.result), 3)
|
||||
assert_equal(raw_txs_txid.result[0].hex(), tx1["hex"])
|
||||
assert_equal(raw_txs_txid.result[1].hex(), tx2["hex"])
|
||||
assert_equal(raw_txs_txid.result[2], b'')
|
||||
|
||||
self.log.debug("Mined transactions are not returned")
|
||||
self.generate(self.nodes[0], 1)
|
||||
self.sync_all()
|
||||
raw_txs = await mining.getTransactionsByTxID(ctx, [tx1["tx"].txid])
|
||||
assert_equal(raw_txs.result[0], b'')
|
||||
|
||||
asyncio.run(capnp.run(async_routine()))
|
||||
|
||||
def run_low_height_test(self):
|
||||
"""Test that IPC createNewBlock() works at low block heights on a
|
||||
clean chain, in particular with regard to bad-cb-length.
|
||||
@@ -727,6 +751,7 @@ class IPCMiningTest(BitcoinTestFramework):
|
||||
self.run_waitnext_mining_policy_test()
|
||||
self.run_block_max_weight_test()
|
||||
self.run_ipc_option_override_test()
|
||||
self.run_transaction_lookup_test()
|
||||
|
||||
# Needs to run last because it resets the chain.
|
||||
self.run_low_height_test()
|
||||
|
||||
@@ -697,15 +697,20 @@ class CTransaction:
|
||||
"""Return wtxid (transaction hash with witness) as integer."""
|
||||
return uint256_from_str(hash256(self.serialize_with_witness()))
|
||||
|
||||
@property
|
||||
def txid(self):
|
||||
"""Return txid (transaction hash without witness) as little-endian bytes."""
|
||||
return hash256(self.serialize_without_witness())
|
||||
|
||||
@property
|
||||
def txid_hex(self):
|
||||
"""Return txid (transaction hash without witness) as hex string."""
|
||||
return hash256(self.serialize_without_witness())[::-1].hex()
|
||||
return self.txid[::-1].hex()
|
||||
|
||||
@property
|
||||
def txid_int(self):
|
||||
"""Return txid (transaction hash without witness) as integer."""
|
||||
return uint256_from_str(hash256(self.serialize_without_witness()))
|
||||
return uint256_from_str(self.txid)
|
||||
|
||||
def is_valid(self):
|
||||
for tout in self.vout:
|
||||
|
||||
Reference in New Issue
Block a user