zebra_rpc/methods/types/
get_raw_mempool.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Types used in `getrawmempool` RPC method.

use std::collections::HashMap;
#[cfg(feature = "getblocktemplate-rpcs")]
use std::collections::HashSet;

#[cfg(feature = "getblocktemplate-rpcs")]
use hex::ToHex as _;

use super::Zec;
#[cfg(feature = "getblocktemplate-rpcs")]
use zebra_chain::transaction::VerifiedUnminedTx;
use zebra_chain::{amount::NonNegative, block::Height};
#[cfg(feature = "getblocktemplate-rpcs")]
use zebra_node_services::mempool::TransactionDependencies;

/// Response to a `getrawmempool` RPC request.
///
/// See the notes for the [`Rpc::get_raw_mempool` method].
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
#[serde(untagged)]
pub enum GetRawMempool {
    /// The transaction IDs, as hex strings (verbose=0)
    TxIds(Vec<String>),
    /// A map of transaction IDs to mempool transaction details objects
    /// (verbose=1)
    Verbose(HashMap<String, MempoolObject>),
}

/// A mempool transaction details object as returned by `getrawmempool` in
/// verbose mode.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub struct MempoolObject {
    /// Transaction size in bytes.
    pub(crate) size: u64,
    /// Transaction fee in zatoshi.
    pub(crate) fee: Zec<NonNegative>,
    /// Transaction fee with fee deltas used for mining priority.
    #[serde(rename = "modifiedfee")]
    pub(crate) modified_fee: Zec<NonNegative>,
    /// Local time transaction entered pool in seconds since 1 Jan 1970 GMT
    pub(crate) time: i64,
    /// Block height when transaction entered pool.
    pub(crate) height: Height,
    /// Number of in-mempool descendant transactions (including this one).
    pub(crate) descendantcount: u64,
    /// Size of in-mempool descendants (including this one).
    pub(crate) descendantsize: u64,
    /// Modified fees (see "modifiedfee" above) of in-mempool descendants
    /// (including this one).
    pub(crate) descendantfees: u64,
    /// Transaction IDs of unconfirmed transactions used as inputs for this
    /// transaction.
    pub(crate) depends: Vec<String>,
}

impl MempoolObject {
    #[cfg(feature = "getblocktemplate-rpcs")]
    pub(crate) fn from_verified_unmined_tx(
        unmined_tx: &VerifiedUnminedTx,
        transactions: &[VerifiedUnminedTx],
        transaction_dependencies: &TransactionDependencies,
    ) -> Self {
        // Map transactions by their txids to make lookups easier
        let transactions_by_id = transactions
            .iter()
            .map(|unmined_tx| (unmined_tx.transaction.id.mined_id(), unmined_tx))
            .collect::<HashMap<_, _>>();

        // Get txids of this transaction's descendants (dependents)
        let empty_set = HashSet::new();
        let deps = transaction_dependencies
            .dependents()
            .get(&unmined_tx.transaction.id.mined_id())
            .unwrap_or(&empty_set);
        let deps_len = deps.len();

        // For each dependent: get the tx, then its size and fee; then sum them
        // up
        let (deps_size, deps_fees) = deps
            .iter()
            .filter_map(|id| transactions_by_id.get(id))
            .map(|unmined_tx| (unmined_tx.transaction.size, unmined_tx.miner_fee))
            .reduce(|(size1, fee1), (size2, fee2)| {
                (size1 + size2, (fee1 + fee2).unwrap_or_default())
            })
            .unwrap_or((0, Default::default()));

        // Create the MempoolObject from the information we have gathered
        let mempool_object = MempoolObject {
            size: unmined_tx.transaction.size as u64,
            fee: unmined_tx.miner_fee.into(),
            // Change this if we ever support fee deltas (prioritisetransaction call)
            modified_fee: unmined_tx.miner_fee.into(),
            time: unmined_tx
                .time
                .map(|time| time.timestamp())
                .unwrap_or_default(),
            height: unmined_tx.height.unwrap_or(Height(0)),
            // Note that the following three count this transaction itself
            descendantcount: deps_len as u64 + 1,
            descendantsize: (deps_size + unmined_tx.transaction.size) as u64,
            descendantfees: (deps_fees + unmined_tx.miner_fee)
                .unwrap_or_default()
                .into(),
            // Get dependencies as a txid vector
            depends: transaction_dependencies
                .dependencies()
                .get(&unmined_tx.transaction.id.mined_id())
                .cloned()
                .unwrap_or_else(HashSet::new)
                .iter()
                .map(|id| id.encode_hex())
                .collect(),
        };
        mempool_object
    }
}