mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-20 13:37:28 +02:00
Merge 488e745560 into merged_master (Bitcoin PR bitcoin/bitcoin#12677)
This commit is contained in:
commit
7e2135c61c
7 changed files with 48 additions and 8 deletions
8
doc/release-notes-12677.md
Normal file
8
doc/release-notes-12677.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Notable changes
|
||||
===============
|
||||
|
||||
Updated RPCs
|
||||
------------
|
||||
|
||||
- `listunspent` now includes `ancestorcount`, `ancestorsize`, and
|
||||
`ancestorfees` for each transaction output that is still in the mempool.
|
||||
|
|
@ -179,7 +179,7 @@ public:
|
|||
std::string& err_string) = 0;
|
||||
|
||||
//! Calculate mempool ancestor and descendant counts for the given transaction.
|
||||
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0;
|
||||
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) = 0;
|
||||
|
||||
//! Get the node's package limits.
|
||||
//! Currently only returns the ancestor and descendant count limits, but could be enhanced to
|
||||
|
|
|
|||
|
|
@ -575,11 +575,11 @@ public:
|
|||
// that Chain clients do not need to know about.
|
||||
return TransactionError::OK == err;
|
||||
}
|
||||
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
|
||||
void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize, CAmount* ancestorfees) override
|
||||
{
|
||||
ancestors = descendants = 0;
|
||||
if (!m_node.mempool) return;
|
||||
m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants);
|
||||
m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants, ancestorsize, ancestorfees);
|
||||
}
|
||||
void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1256,12 +1256,14 @@ uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
|
|||
return maximum;
|
||||
}
|
||||
|
||||
void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const {
|
||||
void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* const ancestorsize, CAmount* const ancestorfees) const {
|
||||
LOCK(cs);
|
||||
auto it = mapTx.find(txid);
|
||||
ancestors = descendants = 0;
|
||||
if (it != mapTx.end()) {
|
||||
ancestors = it->GetCountWithAncestors();
|
||||
if (ancestorsize) *ancestorsize = it->GetSizeWithAncestors();
|
||||
if (ancestorfees) *ancestorfees = it->GetModFeesWithAncestors();
|
||||
descendants = CalculateDescendantMaximum(it);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -755,8 +755,10 @@ public:
|
|||
/**
|
||||
* Calculate the ancestor and descendant count for the given transaction.
|
||||
* The counts include the transaction itself.
|
||||
* When ancestors is non-zero (ie, the transaction itself is in the mempool),
|
||||
* ancestorsize and ancestorfees will also be set to the appropriate values.
|
||||
*/
|
||||
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const;
|
||||
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) const;
|
||||
|
||||
/** @returns true if the mempool is fully loaded */
|
||||
bool IsLoaded() const;
|
||||
|
|
|
|||
|
|
@ -3154,6 +3154,9 @@ static RPCHelpMan listunspent()
|
|||
{RPCResult::Type::STR_HEX, "amountblinder", "the transaction output amount blinding factor in hex"},
|
||||
{RPCResult::Type::STR_HEX, "assetblinder", "the transaction output asset blinding factor in hex"},
|
||||
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
|
||||
{RPCResult::Type::NUM, "ancestorcount", /* optional */ true, "The number of in-mempool ancestor transactions, including this one (if transaction is in the mempool)"},
|
||||
{RPCResult::Type::NUM, "ancestorsize", /* optional */ true, "The virtual transaction size of in-mempool ancestors, including this one (if transaction is in the mempool)"},
|
||||
{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)"},
|
||||
{RPCResult::Type::STR_HEX, "redeemScript", "The redeemScript if scriptPubKey is P2SH"},
|
||||
{RPCResult::Type::STR, "witnessScript", "witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH"},
|
||||
{RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
|
||||
|
|
@ -3355,6 +3358,16 @@ static RPCHelpMan listunspent()
|
|||
entry.pushKV("assetblinder", out.tx->GetOutputAssetBlindingFactor(*pwallet, out.i).ToString());
|
||||
}
|
||||
entry.pushKV("confirmations", out.nDepth);
|
||||
if (!out.nDepth) {
|
||||
size_t ancestor_count, descendant_count, ancestor_size;
|
||||
CAmount ancestor_fees;
|
||||
pwallet->chain().getTransactionAncestry(out.tx->GetHash(), ancestor_count, descendant_count, &ancestor_size, &ancestor_fees);
|
||||
if (ancestor_count) {
|
||||
entry.pushKV("ancestorcount", uint64_t(ancestor_count));
|
||||
entry.pushKV("ancestorsize", uint64_t(ancestor_size));
|
||||
entry.pushKV("ancestorfees", uint64_t(ancestor_fees));
|
||||
}
|
||||
}
|
||||
entry.pushKV("spendable", out.fSpendable);
|
||||
entry.pushKV("solvable", out.fSolvable);
|
||||
if (out.fSolvable) {
|
||||
|
|
|
|||
|
|
@ -78,12 +78,17 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
|||
txid = utxos[0]['txid']
|
||||
vout = utxos[0]['vout']
|
||||
value = utxos[0]['amount']
|
||||
assert 'ancestorcount' not in utxos[0]
|
||||
assert 'ancestorsize' not in utxos[0]
|
||||
assert 'ancestorfees' not in utxos[0]
|
||||
|
||||
fee = Decimal("0.0001")
|
||||
# MAX_ANCESTORS transactions off a confirmed tx should be fine
|
||||
chain = []
|
||||
witness_chain = []
|
||||
for _ in range(MAX_ANCESTORS):
|
||||
ancestor_vsize = 0
|
||||
ancestor_fees = Decimal(0)
|
||||
for i in range(MAX_ANCESTORS):
|
||||
(txid, sent_value) = chain_transaction(self.nodes[0], [txid], [0], value, fee, 1)
|
||||
value = sent_value
|
||||
chain.append(txid)
|
||||
|
|
@ -92,6 +97,16 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
|||
witnesstx = self.nodes[0].decoderawtransaction(fulltx, True)
|
||||
witness_chain.append(witnesstx['hash'])
|
||||
|
||||
# Check that listunspent ancestor{count, size, fees} yield the correct results
|
||||
wallet_unspent = self.nodes[0].listunspent(minconf=0)
|
||||
this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info['txid'] == txid)
|
||||
assert_equal(this_unspent['ancestorcount'], i + 1)
|
||||
ancestor_vsize += self.nodes[0].getrawtransaction(txid=txid, verbose=True)['vsize']
|
||||
assert_equal(this_unspent['ancestorsize'], ancestor_vsize)
|
||||
print(self.nodes[0].gettransaction(txid=txid))
|
||||
ancestor_fees -= self.nodes[0].gettransaction(txid=txid)['fee']['bitcoin']
|
||||
assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN)
|
||||
|
||||
# Wait until mempool transactions have passed initial broadcast (sent inv and received getdata)
|
||||
# Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between
|
||||
peer_inv_store.wait_for_broadcast(witness_chain)
|
||||
|
|
@ -104,9 +119,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
|||
descendant_fees = 0
|
||||
descendant_vsize = 0
|
||||
|
||||
ancestor_vsize = sum([mempool[tx]['vsize'] for tx in mempool])
|
||||
assert_equal(ancestor_vsize, sum([mempool[tx]['vsize'] for tx in mempool]))
|
||||
ancestor_count = MAX_ANCESTORS
|
||||
ancestor_fees = sum([mempool[tx]['fee'] for tx in mempool])
|
||||
assert_equal(ancestor_fees, sum([mempool[tx]['fee'] for tx in mempool]))
|
||||
|
||||
descendants = []
|
||||
ancestors = list(chain)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue