Skip to content

Commit a1e9faf

Browse files
committed
Merge #325: Add getmempoolancestors and getmempooldecendents tests and update for version changes
c35a122 Run the formatter (Jamil Lambert, PhD) b3052dd Update getmempoolancestors and _decendents (Jamil Lambert, PhD) f2a422b Fix MempoolEntry exports (Jamil Lambert, PhD) Pull request description: `getmempoolancestors` and `getmempooldecendants` are untested. The fields returned by the RPC are therefore a not checked and need to be updated. `MempoolEntry` is redefined in v18, v19, v21, v23 and v24. But it was reexported from v19 for later versions. - Fix the exports of `MempoolEntry`. - Add tests for both `getmempoolancestors` and `getmempooldecendants` including the verbose versions. - Add a helper function to create the child parent structure needed for the tests. - Add the struct definitions and `into_model` functions for all versions that redefine `MempoolEntry`, which both RPCs use as part of their return type. ACKs for top commit: tcharding: ACK c35a122 Tree-SHA512: bb5849a786b4f73b2edb51af8c268a5527fab083116d5becb52f74d372afb7d7ffd8cbee3173eac5efa3e2412b4a84ce407daa34e8b77d4d7e5909334cc15854
2 parents cb55a49 + c35a122 commit a1e9faf

File tree

22 files changed

+566
-137
lines changed

22 files changed

+566
-137
lines changed

integration_test/tests/blockchain.rs

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use integration_test::{Node, NodeExt as _, Wallet};
88
use node::client::client_sync;
99
use node::vtype::*; // All the version specific types.
1010
use node::mtype;
11+
use node::{Input, Output};
1112

1213
#[test]
1314
#[cfg(not(feature = "v25_and_below"))]
@@ -246,17 +247,67 @@ fn blockchain__get_difficulty__modelled() {
246247
}
247248

248249
#[test]
249-
#[cfg(feature = "TODO")]
250250
fn blockchain__get_mempool_ancestors__modelled() {
251-
// We can probably get away with not testing this because it returns the same type as
252-
// `getmempoolentry` which is tested below (for verbose=true). For verbose=false it
253-
// just returns a txid.
251+
let node = Node::with_wallet(Wallet::Default, &[]);
252+
node.fund_wallet();
253+
let (_address, parent_txid) = node.create_mempool_transaction();
254+
let child_txid = create_child_spending_parent(&node, parent_txid);
255+
256+
let json: GetMempoolAncestors =
257+
node.client.get_mempool_ancestors(child_txid).expect("getmempoolancestors");
258+
let model: Result<mtype::GetMempoolAncestors, _> = json.into_model();
259+
let ancestors = model.unwrap();
260+
261+
assert!(ancestors.0.contains(&parent_txid));
262+
}
263+
264+
#[test]
265+
fn blockchain__get_mempool_ancestors_verbose__modelled() {
266+
let node = Node::with_wallet(Wallet::Default, &[]);
267+
node.fund_wallet();
268+
let (_address, parent_txid) = node.create_mempool_transaction();
269+
let child_txid = create_child_spending_parent(&node, parent_txid);
270+
271+
let json: GetMempoolAncestorsVerbose = node
272+
.client
273+
.get_mempool_ancestors_verbose(child_txid)
274+
.expect("getmempoolancestors verbose");
275+
let model: Result<mtype::GetMempoolAncestorsVerbose, _> = json.into_model();
276+
let ancestors = model.unwrap();
277+
278+
assert!(ancestors.0.contains_key(&parent_txid));
254279
}
255280

256281
#[test]
257-
#[cfg(feature = "TODO")]
258282
fn blockchain__get_mempool_descendants__modelled() {
259-
// Same justification as for `blockchain__get_mempool_ancestors__modelled`
283+
let node = Node::with_wallet(Wallet::Default, &[]);
284+
node.fund_wallet();
285+
let (_address, parent_txid) = node.create_mempool_transaction();
286+
let child_txid = create_child_spending_parent(&node, parent_txid);
287+
288+
let json: GetMempoolDescendants =
289+
node.client.get_mempool_descendants(parent_txid).expect("getmempooldescendants");
290+
let model: Result<mtype::GetMempoolDescendants, _> = json.into_model();
291+
let descendants = model.unwrap();
292+
293+
assert!(descendants.0.contains(&child_txid));
294+
}
295+
296+
#[test]
297+
fn blockchain__get_mempool_descendants_verbose__modelled() {
298+
let node = Node::with_wallet(Wallet::Default, &[]);
299+
node.fund_wallet();
300+
let (_address, parent_txid) = node.create_mempool_transaction();
301+
let child_txid = create_child_spending_parent(&node, parent_txid);
302+
303+
let json: GetMempoolDescendantsVerbose = node
304+
.client
305+
.get_mempool_descendants_verbose(parent_txid)
306+
.expect("getmempooldescendants verbose");
307+
let model: Result<mtype::GetMempoolDescendantsVerbose, _> = json.into_model();
308+
let descendants = model.unwrap();
309+
310+
assert!(descendants.0.contains_key(&child_txid));
260311
}
261312

262313
#[test]
@@ -476,3 +527,29 @@ fn verify_tx_out_proof(node: &Node) -> Result<(), client_sync::Error> {
476527

477528
Ok(())
478529
}
530+
531+
/// Create and broadcast a child transaction spending vout 0 of the given parent mempool txid.
532+
/// Returns the child's txid.
533+
fn create_child_spending_parent(node: &Node, parent_txid: bitcoin::Txid) -> bitcoin::Txid {
534+
let inputs = vec![Input { txid: parent_txid, vout: 0, sequence: None }];
535+
let spend_address = node.client.new_address().expect("newaddress");
536+
let outputs = vec![Output::new(spend_address, bitcoin::Amount::from_sat(100_000))];
537+
538+
let raw: CreateRawTransaction =
539+
node.client.create_raw_transaction(&inputs, &outputs).expect("createrawtransaction");
540+
let unsigned = raw.transaction().expect("raw.transaction");
541+
542+
let funded: FundRawTransaction =
543+
node.client.fund_raw_transaction(&unsigned).expect("fundrawtransaction");
544+
let funded_tx = funded.transaction().expect("funded.transaction");
545+
546+
let signed: SignRawTransaction = node
547+
.client
548+
.sign_raw_transaction_with_wallet(&funded_tx)
549+
.expect("signrawtransactionwithwallet");
550+
let model = signed.into_model().expect("SignRawTransactionWithWallet into model");
551+
let child_txid = model.tx.compute_txid();
552+
let _ = node.client.send_raw_transaction(&model.tx).expect("sendrawtransaction");
553+
554+
child_txid
555+
}

types/src/v17/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
//! | getchaintips | version + model | |
3737
//! | getchaintxstats | version + model | |
3838
//! | getdifficulty | version + model | |
39-
//! | getmempoolancestors | version + model | UNTESTED (incl. verbose type) |
40-
//! | getmempooldescendants | version + model | UNTESTED (incl. verbose type) |
39+
//! | getmempoolancestors | version + model | |
40+
//! | getmempooldescendants | version + model | |
4141
//! | getmempoolentry | version + model | |
4242
//! | getmempoolinfo | version + model | |
4343
//! | getrawmempool | version + model | |

types/src/v18/blockchain/into.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,62 @@
11
// SPDX-License-Identifier: CC0-1.0
22

3-
use bitcoin::{Txid, Wtxid};
3+
use alloc::collections::BTreeMap;
44

5-
use super::{GetMempoolEntry, MempoolEntry, MempoolEntryError};
5+
use bitcoin::{hex, Txid, Wtxid};
6+
7+
use super::{
8+
GetMempoolAncestors, GetMempoolAncestorsVerbose, GetMempoolDescendants,
9+
GetMempoolDescendantsVerbose, GetMempoolEntry, MapMempoolEntryError, MempoolEntry,
10+
MempoolEntryError,
11+
};
612
use crate::model;
713

14+
impl GetMempoolAncestors {
15+
/// Converts version specific type to a version nonspecific, more strongly typed type.
16+
pub fn into_model(self) -> Result<model::GetMempoolAncestors, hex::HexToArrayError> {
17+
let v = self.0.iter().map(|t| t.parse::<Txid>()).collect::<Result<Vec<_>, _>>()?;
18+
Ok(model::GetMempoolAncestors(v))
19+
}
20+
}
21+
22+
impl GetMempoolAncestorsVerbose {
23+
/// Converts version specific type to a version nonspecific, more strongly typed type.
24+
pub fn into_model(self) -> Result<model::GetMempoolAncestorsVerbose, MapMempoolEntryError> {
25+
use MapMempoolEntryError as E;
26+
27+
let mut map = BTreeMap::new();
28+
for (k, v) in self.0.into_iter() {
29+
let txid = k.parse::<Txid>().map_err(E::Txid)?;
30+
let relative = v.into_model().map_err(E::MempoolEntry)?;
31+
map.insert(txid, relative);
32+
}
33+
Ok(model::GetMempoolAncestorsVerbose(map))
34+
}
35+
}
36+
37+
impl GetMempoolDescendants {
38+
/// Converts version specific type to a version nonspecific, more strongly typed type.
39+
pub fn into_model(self) -> Result<model::GetMempoolDescendants, hex::HexToArrayError> {
40+
let v = self.0.iter().map(|t| t.parse::<Txid>()).collect::<Result<Vec<_>, _>>()?;
41+
Ok(model::GetMempoolDescendants(v))
42+
}
43+
}
44+
45+
impl GetMempoolDescendantsVerbose {
46+
/// Converts version specific type to a version nonspecific, more strongly typed type.
47+
pub fn into_model(self) -> Result<model::GetMempoolDescendantsVerbose, MapMempoolEntryError> {
48+
use MapMempoolEntryError as E;
49+
50+
let mut map = BTreeMap::new();
51+
for (k, v) in self.0.into_iter() {
52+
let txid = k.parse::<Txid>().map_err(E::Txid)?;
53+
let relative = v.into_model().map_err(E::MempoolEntry)?;
54+
map.insert(txid, relative);
55+
}
56+
Ok(model::GetMempoolDescendantsVerbose(map))
57+
}
58+
}
59+
860
impl GetMempoolEntry {
961
/// Converts version specific type to a version nonspecific, more strongly typed type.
1062
pub fn into_model(self) -> Result<model::GetMempoolEntry, MempoolEntryError> {

types/src/v18/blockchain/mod.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,49 @@
66
77
mod into;
88

9+
use alloc::collections::BTreeMap;
10+
911
use serde::{Deserialize, Serialize};
1012

11-
use super::{MempoolEntryError, MempoolEntryFees};
13+
use super::{MapMempoolEntryError, MempoolEntryError, MempoolEntryFees};
14+
15+
/// Result of JSON-RPC method `getmempoolancestors` with verbose set to `false`.
16+
///
17+
/// > getmempoolancestors txid (verbose)
18+
/// >
19+
/// > If txid is in the mempool, returns all in-mempool ancestors.
20+
/// >
21+
/// > Arguments:
22+
/// > 1. "txid" (string, required) The transaction id (must be in mempool)
23+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
24+
#[serde(deny_unknown_fields)]
25+
pub struct GetMempoolAncestors(pub Vec<String>);
26+
27+
/// Result of JSON-RPC method `getmempoolancestors` with verbose set to true.
28+
///
29+
/// Map of txid to `MempoolEntry` i.e., an ancestor.
30+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
31+
#[serde(deny_unknown_fields)]
32+
pub struct GetMempoolAncestorsVerbose(pub BTreeMap<String, MempoolEntry>);
33+
34+
/// Result of JSON-RPC method `getmempooldescendants` with verbose set to `false`.
35+
///
36+
/// > getmempooldescendants txid (verbose)
37+
/// >
38+
/// > If txid is in the mempool, returns all in-mempool descendants.
39+
/// >
40+
/// > Arguments:
41+
/// > 1. "txid" (string, required) The transaction id (must be in mempool)
42+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
43+
#[serde(deny_unknown_fields)]
44+
pub struct GetMempoolDescendants(pub Vec<String>);
45+
46+
/// Result of JSON-RPC method `getmempooldescendants` with verbose set to true.
47+
///
48+
/// Map of txid to [`MempoolEntry`] i.e., a descendant.
49+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
50+
#[serde(deny_unknown_fields)]
51+
pub struct GetMempoolDescendantsVerbose(pub BTreeMap<String, MempoolEntry>);
1252

1353
/// Result of JSON-RPC method `getmempoolentry`.
1454
///

types/src/v18/mod.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@
3636
//! | getchaintips | version + model | |
3737
//! | getchaintxstats | version + model | |
3838
//! | getdifficulty | version + model | |
39-
//! | getmempoolancestors | version + model | UNTESTED (incl. verbose type) |
40-
//! | getmempooldescendants | version + model | UNTESTED (incl. verbose type) |
39+
//! | getmempoolancestors | version + model | |
40+
//! | getmempooldescendants | version + model | |
4141
//! | getmempoolentry | version + model | |
4242
//! | getmempoolinfo | version + model | |
4343
//! | getrawmempool | version + model | Includes additional 'verbose' type |
@@ -232,7 +232,10 @@ mod wallet;
232232

233233
#[doc(inline)]
234234
pub use self::{
235-
blockchain::{GetMempoolEntry, MempoolEntry},
235+
blockchain::{
236+
GetMempoolAncestors, GetMempoolAncestorsVerbose, GetMempoolDescendants,
237+
GetMempoolDescendantsVerbose, GetMempoolEntry, MempoolEntry,
238+
},
236239
control::{ActiveCommand, GetRpcInfo},
237240
network::{GetNodeAddresses, GetPeerInfo, NodeAddress, PeerInfo},
238241
raw_transactions::{
@@ -260,27 +263,25 @@ pub use crate::v17::{
260263
GetBlockHeaderVerbose, GetBlockHeaderVerboseError, GetBlockStats, GetBlockStatsError,
261264
GetBlockTemplate, GetBlockTemplateError, GetBlockVerboseOne, GetBlockVerboseOneError,
262265
GetBlockVerboseZero, GetBlockchainInfo, GetBlockchainInfoError, GetChainTips, GetChainTxStats,
263-
GetChainTxStatsError, GetConnectionCount, GetDifficulty, GetMemoryInfoStats,
264-
GetMempoolAncestors, GetMempoolAncestorsVerbose, GetMempoolDescendants,
265-
GetMempoolDescendantsVerbose, GetMempoolInfo, GetMempoolInfoError, GetMiningInfo, GetNetTotals,
266-
GetNetworkInfo, GetNetworkInfoAddress, GetNetworkInfoError, GetNetworkInfoNetwork,
267-
GetNewAddress, GetRawChangeAddress, GetRawMempool, GetRawMempoolVerbose, GetRawTransaction,
268-
GetRawTransactionVerbose, GetRawTransactionVerboseError, GetReceivedByAddress, GetTransaction,
269-
GetTransactionDetail, GetTransactionDetailError, GetTransactionError, GetTxOut, GetTxOutError,
270-
GetTxOutSetInfo, GetTxOutSetInfoError, GetUnconfirmedBalance, GetWalletInfo,
271-
GetWalletInfoError, GetZmqNotifications, ListAddressGroupings, ListAddressGroupingsError,
272-
ListAddressGroupingsItem, ListBanned, ListLabels, ListLockUnspent, ListLockUnspentItem,
273-
ListLockUnspentItemError, ListReceivedByAddress, ListReceivedByAddressError,
274-
ListReceivedByAddressItem, ListSinceBlock, ListSinceBlockError, ListSinceBlockTransaction,
275-
ListSinceBlockTransactionError, ListTransactions, ListTransactionsItem,
276-
ListTransactionsItemError, ListUnspentItemError, ListWallets, LoadWallet, LockUnspent, Locked,
277-
Logging, MapMempoolEntryError, MempoolAcceptance, MempoolEntryError, MempoolEntryFees,
278-
MempoolEntryFeesError, PruneBlockchain, PsbtInput, PsbtOutput, PsbtScript, RawTransaction,
279-
RawTransactionError, RawTransactionInput, RawTransactionOutput, RescanBlockchain, ScriptType,
280-
SendMany, SendRawTransaction, SendToAddress, SetNetworkActive, SetTxFee, SignFail,
281-
SignFailError, SignMessage, SignMessageWithPrivKey, SignRawTransaction,
282-
SignRawTransactionError, Softfork, SoftforkReject, TestMempoolAccept, TransactionCategory,
283-
UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, VerifyMessage,
284-
VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, WalletProcessPsbt,
285-
WitnessUtxo,
266+
GetChainTxStatsError, GetConnectionCount, GetDifficulty, GetMemoryInfoStats, GetMempoolInfo,
267+
GetMempoolInfoError, GetMiningInfo, GetNetTotals, GetNetworkInfo, GetNetworkInfoAddress,
268+
GetNetworkInfoError, GetNetworkInfoNetwork, GetNewAddress, GetRawChangeAddress, GetRawMempool,
269+
GetRawMempoolVerbose, GetRawTransaction, GetRawTransactionVerbose,
270+
GetRawTransactionVerboseError, GetReceivedByAddress, GetTransaction, GetTransactionDetail,
271+
GetTransactionDetailError, GetTransactionError, GetTxOut, GetTxOutError, GetTxOutSetInfo,
272+
GetTxOutSetInfoError, GetUnconfirmedBalance, GetWalletInfo, GetWalletInfoError,
273+
GetZmqNotifications, ListAddressGroupings, ListAddressGroupingsError, ListAddressGroupingsItem,
274+
ListBanned, ListLabels, ListLockUnspent, ListLockUnspentItem, ListLockUnspentItemError,
275+
ListReceivedByAddress, ListReceivedByAddressError, ListReceivedByAddressItem, ListSinceBlock,
276+
ListSinceBlockError, ListSinceBlockTransaction, ListSinceBlockTransactionError,
277+
ListTransactions, ListTransactionsItem, ListTransactionsItemError, ListUnspentItemError,
278+
ListWallets, LoadWallet, LockUnspent, Locked, Logging, MapMempoolEntryError, MempoolAcceptance,
279+
MempoolEntryError, MempoolEntryFees, MempoolEntryFeesError, PruneBlockchain, PsbtInput,
280+
PsbtOutput, PsbtScript, RawTransaction, RawTransactionError, RawTransactionInput,
281+
RawTransactionOutput, RescanBlockchain, ScriptType, SendMany, SendRawTransaction,
282+
SendToAddress, SetNetworkActive, SetTxFee, SignFail, SignFailError, SignMessage,
283+
SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, Softfork, SoftforkReject,
284+
TestMempoolAccept, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError,
285+
VerifyChain, VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt,
286+
WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo,
286287
};

types/src/v19/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
//! | getchaintips | version + model | |
3838
//! | getchaintxstats | version + model | |
3939
//! | getdifficulty | version + model | |
40-
//! | getmempoolancestors | version + model | UNTESTED (incl. verbose type) |
41-
//! | getmempooldescendants | version + model | UNTESTED (incl. verbose type) |
40+
//! | getmempoolancestors | version + model | |
41+
//! | getmempooldescendants | version + model | |
4242
//! | getmempoolentry | version + model | |
4343
//! | getmempoolinfo | version + model | |
4444
//! | getrawmempool | version + model | Includes additional 'verbose' type |

types/src/v20/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
//! | getchaintips | version + model | |
3838
//! | getchaintxstats | version + model | |
3939
//! | getdifficulty | version + model | |
40-
//! | getmempoolancestors | version + model | UNTESTED (incl. verbose type) |
41-
//! | getmempooldescendants | version + model | UNTESTED (incl. verbose type) |
40+
//! | getmempoolancestors | version + model | |
41+
//! | getmempooldescendants | version + model | |
4242
//! | getmempoolentry | version + model | |
4343
//! | getmempoolinfo | version + model | |
4444
//! | getrawmempool | version + model | Includes additional 'verbose' type |

0 commit comments

Comments
 (0)