Skip to content

Commit b3052dd

Browse files
committed
Update getmempoolancestors and _decendents
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 functions for all versions that redefine GetMempoolEntry, which both RPCs return.
1 parent f2a422b commit b3052dd

File tree

22 files changed

+496
-70
lines changed

22 files changed

+496
-70
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: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,58 @@
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::{GetMempoolAncestors, GetMempoolAncestorsVerbose, GetMempoolDescendants, GetMempoolDescendantsVerbose, GetMempoolEntry, MempoolEntry, MempoolEntryError, MapMempoolEntryError};
68
use crate::model;
79

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

233233
#[doc(inline)]
234234
pub use self::{
235-
blockchain::{GetMempoolEntry, MempoolEntry},
235+
blockchain::{GetMempoolEntry, MempoolEntry, GetMempoolAncestors, GetMempoolAncestorsVerbose,
236+
GetMempoolDescendants, GetMempoolDescendantsVerbose,},
236237
control::{ActiveCommand, GetRpcInfo},
237238
network::{GetNodeAddresses, GetPeerInfo, NodeAddress, PeerInfo},
238239
raw_transactions::{
@@ -261,8 +262,7 @@ pub use crate::v17::{
261262
GetBlockTemplate, GetBlockTemplateError, GetBlockVerboseOne, GetBlockVerboseOneError,
262263
GetBlockVerboseZero, GetBlockchainInfo, GetBlockchainInfoError, GetChainTips, GetChainTxStats,
263264
GetChainTxStatsError, GetConnectionCount, GetDifficulty, GetMemoryInfoStats,
264-
GetMempoolAncestors, GetMempoolAncestorsVerbose, GetMempoolDescendants,
265-
GetMempoolDescendantsVerbose, GetMempoolInfo, GetMempoolInfoError, GetMiningInfo, GetNetTotals,
265+
GetMempoolInfo, GetMempoolInfoError, GetMiningInfo, GetNetTotals,
266266
GetNetworkInfo, GetNetworkInfoAddress, GetNetworkInfoError, GetNetworkInfoNetwork,
267267
GetNewAddress, GetRawChangeAddress, GetRawMempool, GetRawMempoolVerbose, GetRawTransaction,
268268
GetRawTransactionVerbose, GetRawTransactionVerboseError, GetReceivedByAddress, GetTransaction,

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 |

types/src/v21/blockchain/into.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
use alloc::collections::BTreeMap;
44

5-
use bitcoin::{BlockHash, Network, Txid, Work, Wtxid};
5+
use bitcoin::{hex, BlockHash, Network, Txid, Work, Wtxid};
66

77
use super::{
88
GetBlockchainInfo, GetBlockchainInfoError, GetMempoolEntry, GetMempoolInfo,
9-
GetMempoolInfoError, MempoolEntry, MempoolEntryError,
9+
GetMempoolInfoError, MempoolEntry, MempoolEntryError, GetMempoolAncestors,
10+
GetMempoolAncestorsVerbose, GetMempoolDescendants, GetMempoolDescendantsVerbose, MapMempoolEntryError,
1011
};
1112
use crate::model;
1213

@@ -50,6 +51,52 @@ impl GetBlockchainInfo {
5051
}
5152
}
5253

54+
impl GetMempoolAncestors {
55+
/// Converts version specific type to a version nonspecific, more strongly typed type.
56+
pub fn into_model(self) -> Result<model::GetMempoolAncestors, hex::HexToArrayError> {
57+
let v = self.0.iter().map(|t| t.parse::<Txid>()).collect::<Result<Vec<_>, _>>()?;
58+
Ok(model::GetMempoolAncestors(v))
59+
}
60+
}
61+
62+
impl GetMempoolAncestorsVerbose {
63+
/// Converts version specific type to a version nonspecific, more strongly typed type.
64+
pub fn into_model(self) -> Result<model::GetMempoolAncestorsVerbose, MapMempoolEntryError> {
65+
use MapMempoolEntryError as E;
66+
67+
let mut map = BTreeMap::new();
68+
for (k, v) in self.0.into_iter() {
69+
let txid = k.parse::<Txid>().map_err(E::Txid)?;
70+
let relative = v.into_model().map_err(E::MempoolEntry)?;
71+
map.insert(txid, relative);
72+
}
73+
Ok(model::GetMempoolAncestorsVerbose(map))
74+
}
75+
}
76+
77+
impl GetMempoolDescendants {
78+
/// Converts version specific type to a version nonspecific, more strongly typed type.
79+
pub fn into_model(self) -> Result<model::GetMempoolDescendants, hex::HexToArrayError> {
80+
let v = self.0.iter().map(|t| t.parse::<Txid>()).collect::<Result<Vec<_>, _>>()?;
81+
Ok(model::GetMempoolDescendants(v))
82+
}
83+
}
84+
85+
impl GetMempoolDescendantsVerbose {
86+
/// Converts version specific type to a version nonspecific, more strongly typed type.
87+
pub fn into_model(self) -> Result<model::GetMempoolDescendantsVerbose, MapMempoolEntryError> {
88+
use MapMempoolEntryError as E;
89+
90+
let mut map = BTreeMap::new();
91+
for (k, v) in self.0.into_iter() {
92+
let txid = k.parse::<Txid>().map_err(E::Txid)?;
93+
let relative = v.into_model().map_err(E::MempoolEntry)?;
94+
map.insert(txid, relative);
95+
}
96+
Ok(model::GetMempoolDescendantsVerbose(map))
97+
}
98+
}
99+
53100
impl GetMempoolEntry {
54101
/// Converts version specific type to a version nonspecific, more strongly typed type.
55102
pub fn into_model(self) -> Result<model::GetMempoolEntry, MempoolEntryError> {

0 commit comments

Comments
 (0)