Skip to content

Commit b8af7ea

Browse files
committed
merge bitcoin#12677: Add ancestor{count,size,fees} to listunspent output
1 parent 03da836 commit b8af7ea

File tree

6 files changed

+40
-8
lines changed

6 files changed

+40
-8
lines changed

src/interfaces/chain.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ class Chain
201201
bilingual_str& err_string) = 0;
202202

203203
//! Calculate mempool ancestor and descendant counts for the given transaction.
204-
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0;
204+
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) = 0;
205205

206206
//! Get the node's package limits.
207207
//! Currently only returns the ancestor and descendant count limits, but could be enhanced to

src/node/interfaces.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -894,11 +894,11 @@ class ChainImpl : public Chain
894894
// that Chain clients do not need to know about.
895895
return TransactionError::OK == err;
896896
}
897-
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
897+
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override
898898
{
899899
ancestors = descendants = 0;
900900
if (!m_node.mempool) return;
901-
m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants);
901+
m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants, ancestorsize, ancestorfees);
902902
}
903903
void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
904904
{

src/txmempool.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1736,12 +1736,14 @@ uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
17361736
return maximum;
17371737
}
17381738

1739-
void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const {
1739+
void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const {
17401740
LOCK(cs);
17411741
auto it = mapTx.find(txid);
17421742
ancestors = descendants = 0;
17431743
if (it != mapTx.end()) {
17441744
ancestors = it->GetCountWithAncestors();
1745+
if (ancestorsize) *ancestorsize = it->GetSizeWithAncestors();
1746+
if (ancestorfees) *ancestorfees = it->GetModFeesWithAncestors();
17451747
descendants = CalculateDescendantMaximum(it);
17461748
}
17471749
}

src/txmempool.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,10 @@ class CTxMemPool
762762
/**
763763
* Calculate the ancestor and descendant count for the given transaction.
764764
* The counts include the transaction itself.
765+
* When ancestors is non-zero (ie, the transaction itself is in the mempool),
766+
* ancestorsize and ancestorfees will also be set to the appropriate values.
765767
*/
766-
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const;
768+
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) const;
767769

768770
/** @returns true if the mempool is fully loaded */
769771
bool IsLoaded() const;

src/wallet/rpcwallet.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3066,6 +3066,9 @@ static RPCHelpMan listunspent()
30663066
{RPCResult::Type::STR, "scriptPubKey", "the script key"},
30673067
{RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT},
30683068
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
3069+
{RPCResult::Type::NUM, "ancestorcount", /* optional */ true, "The number of in-mempool ancestor transactions, including this one (if transaction is in the mempool)"},
3070+
{RPCResult::Type::NUM, "ancestorsize", /* optional */ true, "The virtual transaction size of in-mempool ancestors, including this one (if transaction is in the mempool)"},
3071+
{RPCResult::Type::STR_AMOUNT, "ancestorfees", /* optional */ true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"},
30693072
{RPCResult::Type::STR_HEX, "redeemScript", "The redeemScript if scriptPubKey is P2SH"},
30703073
{RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
30713074
{RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
@@ -3227,6 +3230,16 @@ static RPCHelpMan listunspent()
32273230
entry.pushKV("scriptPubKey", HexStr(scriptPubKey));
32283231
entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
32293232
entry.pushKV("confirmations", out.nDepth);
3233+
if (!out.nDepth) {
3234+
size_t ancestor_count, descendant_count, ancestor_size;
3235+
CAmount ancestor_fees;
3236+
pwallet->chain().getTransactionAncestry(out.tx->GetHash(), ancestor_count, descendant_count, &ancestor_size, &ancestor_fees);
3237+
if (ancestor_count) {
3238+
entry.pushKV("ancestorcount", uint64_t(ancestor_count));
3239+
entry.pushKV("ancestorsize", uint64_t(ancestor_size));
3240+
entry.pushKV("ancestorfees", uint64_t(ancestor_fees));
3241+
}
3242+
}
32303243
entry.pushKV("spendable", out.fSpendable);
32313244
entry.pushKV("solvable", out.fSolvable);
32323245
if (out.fSolvable) {

test/functional/mempool_packages.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from decimal import Decimal
88

99
from test_framework.blocktools import COINBASE_MATURITY
10+
from test_framework.messages import COIN
1011
from test_framework.p2p import P2PTxInvStore
1112
from test_framework.test_framework import BitcoinTestFramework
1213
from test_framework.util import (
@@ -49,15 +50,29 @@ def run_test(self):
4950
txid = utxo[0]['txid']
5051
vout = utxo[0]['vout']
5152
value = utxo[0]['amount']
53+
assert 'ancestorcount' not in utxo[0]
54+
assert 'ancestorsize' not in utxo[0]
55+
assert 'ancestorfees' not in utxo[0]
5256

5357
fee = Decimal("0.0001")
5458
# MAX_ANCESTORS transactions off a confirmed tx should be fine
5559
chain = []
56-
for _ in range(MAX_ANCESTORS):
60+
ancestor_vsize = 0
61+
ancestor_fees = Decimal(0)
62+
for i in range(MAX_ANCESTORS):
5763
(txid, sent_value) = chain_transaction(self.nodes[0], [txid], [0], value, fee, 1)
5864
value = sent_value
5965
chain.append(txid)
6066

67+
# Check that listunspent ancestor{count, size, fees} yield the correct results
68+
wallet_unspent = self.nodes[0].listunspent(minconf=0)
69+
this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info['txid'] == txid)
70+
assert_equal(this_unspent['ancestorcount'], i + 1)
71+
ancestor_vsize += self.nodes[0].getrawtransaction(txid=txid, verbose=True)['size']
72+
assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
73+
ancestor_fees -= self.nodes[0].gettransaction(txid=txid)['fee']
74+
assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
75+
6176
# Wait until mempool transactions have passed initial broadcast (sent inv and received getdata)
6277
# Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between
6378
peer_inv_store.wait_for_broadcast(chain)
@@ -70,9 +85,9 @@ def run_test(self):
7085
descendant_fees = 0
7186
descendant_vsize = 0
7287

73-
ancestor_vsize = sum([mempool[tx]['vsize'] for tx in mempool])
88+
assert_equal(ancestor_vsize, sum([mempool[tx]['vsize'] for tx in mempool]))
7489
ancestor_count = MAX_ANCESTORS
75-
ancestor_fees = sum([mempool[tx]['fees']['base'] for tx in mempool])
90+
assert_equal(ancestor_fees, sum([mempool[tx]['fees']['base'] for tx in mempool]))
7691

7792
descendants = []
7893
ancestors = list(chain)

0 commit comments

Comments
 (0)