Skip to content

Commit 4fd0ce7

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#22689: rpc: deprecate top-level fee fields in getmempool RPCs
2f9515f rpc: move fees object to match help (josibake) 07ade7d doc: add release note for fee field deprecation (josibake) 2ee406c test: add functional test for deprecatedrpc=fees (josibake) 35d928c rpc: deprecate fee fields from mempool entries (josibake) Pull request description: per #22682 , top level fee fields for mempool entries have been deprecated since 0.17 but are still returned. this PR properly deprecates them so that they are no longer returned unless `-deprecatedrpc=fees` is passed. the first commit takes care of deprecation and also updates `test/functional/mempool_packages.py` to only use the `fees` object. the second commit adds a new functional test for `-deprecatedrpc=fees` closes #22682 ## questions for the reviewer * `-deprecatedrpc=fees` made the most sense to me, but happy to change if there is a name that makes more sense * #22682 seems to indicate that after some period of time, the fields will be removed all together. if we have a rough idea of when this will be, i can add a `TODO: fully remove in vXX` comment to `entryToJSON` ## testing to get started on testing, compile, run the tests, and start your node with the deprecated rpcs flag: ```bash ./src/bitcoind -daemon -deprecatedrpc=fees ``` you should see entries with the deprecated fields like so: ```json { "<txid>": { "fees": { "base": 0.00000671, "modified": 0.00000671, "ancestor": 0.00000671, "descendant": 0.00000671 }, "fee": 0.00000671, "modifiedfee": 0.00000671, "descendantfees": 671, "ancestorfees": 671, "vsize": 144, "weight": 573, ... }, ``` you can also check `getmempoolentry` using any of the txid's from the output above. next start the node without the deprecated flag, repeat the commands from above and verify that the deprecated fields are no longer present at the top level, but present in the "fees" object ACKs for top commit: jnewbery: reACK 2f9515f glozow: utACK 2f9515f Tree-SHA512: b175f4d39d26d96dc5bae26717d3ccfa5842d98ab402065880bfdcf4921b14ca692a8919fe4e9969acbb5c4d6e6d07dd6462a7e0a0a7342556279b381e1a004e
2 parents 95fe477 + 2f9515f commit 4fd0ce7

File tree

6 files changed

+119
-40
lines changed

6 files changed

+119
-40
lines changed

doc/release-notes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ Updated RPCs
114114
causes the lock to be written persistently to the wallet database. This
115115
allows UTXOs to remain locked even after node restarts or crashes. (#23065)
116116

117+
- The top-level fee fields `fee`, `modifiedfee`, `ancestorfees` and `descendantfees`
118+
returned by RPCs `getmempoolentry`,`getrawmempool(verbose=true)`,
119+
`getmempoolancestors(verbose=true)` and `getmempooldescendants(verbose=true)`
120+
are deprecated and will be removed in the next major version (use
121+
`-deprecated=fees` if needed in this version). The same fee fields can be accessed
122+
through the `fees` object in the result. WARNING: deprecated
123+
fields `ancestorfees` and `descendantfees` are denominated in sats, whereas all
124+
fields in the `fees` object are denominated in BTC. (#22689)
125+
117126
New RPCs
118127
--------
119128

src/rpc/blockchain.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -464,23 +464,23 @@ static RPCHelpMan getdifficulty()
464464
static std::vector<RPCResult> MempoolEntryDescription() { return {
465465
RPCResult{RPCResult::Type::NUM, "vsize", "virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
466466
RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
467-
RPCResult{RPCResult::Type::STR_AMOUNT, "fee", "transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)"},
468-
RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", "transaction fee with fee deltas used for mining priority (DEPRECATED)"},
467+
RPCResult{RPCResult::Type::STR_AMOUNT, "fee", "transaction fee, denominated in " + CURRENCY_UNIT + " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
468+
RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT + " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
469469
RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
470470
RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
471471
RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
472472
RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
473-
RPCResult{RPCResult::Type::STR_AMOUNT, "descendantfees", "modified fees (see above) of in-mempool descendants (including this one) (DEPRECATED)"},
473+
RPCResult{RPCResult::Type::STR_AMOUNT, "descendantfees", "transaction fees of in-mempool descendants (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_ATOM + "s (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
474474
RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
475475
RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
476-
RPCResult{RPCResult::Type::STR_AMOUNT, "ancestorfees", "modified fees (see above) of in-mempool ancestors (including this one) (DEPRECATED)"},
476+
RPCResult{RPCResult::Type::STR_AMOUNT, "ancestorfees", "transaction fees of in-mempool ancestors (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_ATOM + "s (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
477477
RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
478478
RPCResult{RPCResult::Type::OBJ, "fees", "",
479479
{
480-
RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
481-
RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority in " + CURRENCY_UNIT},
482-
RPCResult{RPCResult::Type::STR_AMOUNT, "ancestor", "modified fees (see above) of in-mempool ancestors (including this one) in " + CURRENCY_UNIT},
483-
RPCResult{RPCResult::Type::STR_AMOUNT, "descendant", "modified fees (see above) of in-mempool descendants (including this one) in " + CURRENCY_UNIT},
480+
RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
481+
RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
482+
RPCResult{RPCResult::Type::STR_AMOUNT, "ancestor", "transaction fees of in-mempool ancestors (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
483+
RPCResult{RPCResult::Type::STR_AMOUNT, "descendant", "transaction fees of in-mempool descendants (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
484484
}},
485485
RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
486486
{RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
@@ -494,26 +494,35 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
494494
{
495495
AssertLockHeld(pool.cs);
496496

497-
UniValue fees(UniValue::VOBJ);
498-
fees.pushKV("base", ValueFromAmount(e.GetFee()));
499-
fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
500-
fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
501-
fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
502-
info.pushKV("fees", fees);
503-
504497
info.pushKV("vsize", (int)e.GetTxSize());
505498
info.pushKV("weight", (int)e.GetTxWeight());
506-
info.pushKV("fee", ValueFromAmount(e.GetFee()));
507-
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
499+
// TODO: top-level fee fields are deprecated. deprecated_fee_fields_enabled blocks should be removed in v24
500+
const bool deprecated_fee_fields_enabled{IsDeprecatedRPCEnabled("fees")};
501+
if (deprecated_fee_fields_enabled) {
502+
info.pushKV("fee", ValueFromAmount(e.GetFee()));
503+
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
504+
}
508505
info.pushKV("time", count_seconds(e.GetTime()));
509506
info.pushKV("height", (int)e.GetHeight());
510507
info.pushKV("descendantcount", e.GetCountWithDescendants());
511508
info.pushKV("descendantsize", e.GetSizeWithDescendants());
512-
info.pushKV("descendantfees", e.GetModFeesWithDescendants());
509+
if (deprecated_fee_fields_enabled) {
510+
info.pushKV("descendantfees", e.GetModFeesWithDescendants());
511+
}
513512
info.pushKV("ancestorcount", e.GetCountWithAncestors());
514513
info.pushKV("ancestorsize", e.GetSizeWithAncestors());
515-
info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
514+
if (deprecated_fee_fields_enabled) {
515+
info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
516+
}
516517
info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
518+
519+
UniValue fees(UniValue::VOBJ);
520+
fees.pushKV("base", ValueFromAmount(e.GetFee()));
521+
fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
522+
fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
523+
fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
524+
info.pushKV("fees", fees);
525+
517526
const CTransaction& tx = e.GetTx();
518527
std::set<std::string> setDepends;
519528
for (const CTxIn& txin : tx.vin)

test/functional/mempool_packages.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def run_test(self):
9191

9292
assert_equal(ancestor_vsize, sum([mempool[tx]['vsize'] for tx in mempool]))
9393
ancestor_count = MAX_ANCESTORS
94-
assert_equal(ancestor_fees, sum([mempool[tx]['fee'] for tx in mempool]))
94+
assert_equal(ancestor_fees, sum([mempool[tx]['fees']['base'] for tx in mempool]))
9595

9696
descendants = []
9797
ancestors = list(chain)
@@ -102,22 +102,19 @@ def run_test(self):
102102

103103
# Check that the descendant calculations are correct
104104
assert_equal(entry['descendantcount'], descendant_count)
105-
descendant_fees += entry['fee']
106-
assert_equal(entry['modifiedfee'], entry['fee'])
107-
assert_equal(entry['fees']['base'], entry['fee'])
108-
assert_equal(entry['fees']['modified'], entry['modifiedfee'])
109-
assert_equal(entry['descendantfees'], descendant_fees * COIN)
105+
descendant_fees += entry['fees']['base']
106+
assert_equal(entry['fees']['modified'], entry['fees']['base'])
110107
assert_equal(entry['fees']['descendant'], descendant_fees)
111108
descendant_vsize += entry['vsize']
112109
assert_equal(entry['descendantsize'], descendant_vsize)
113110
descendant_count += 1
114111

115112
# Check that ancestor calculations are correct
116113
assert_equal(entry['ancestorcount'], ancestor_count)
117-
assert_equal(entry['ancestorfees'], ancestor_fees * COIN)
114+
assert_equal(entry['fees']['ancestor'], ancestor_fees)
118115
assert_equal(entry['ancestorsize'], ancestor_vsize)
119116
ancestor_vsize -= entry['vsize']
120-
ancestor_fees -= entry['fee']
117+
ancestor_fees -= entry['fees']['base']
121118
ancestor_count -= 1
122119

123120
# Check that parent/child list is correct
@@ -168,9 +165,8 @@ def run_test(self):
168165
ancestor_fees = 0
169166
for x in chain:
170167
entry = self.nodes[0].getmempoolentry(x)
171-
ancestor_fees += entry['fee']
168+
ancestor_fees += entry['fees']['base']
172169
assert_equal(entry['fees']['ancestor'], ancestor_fees + Decimal('0.00001'))
173-
assert_equal(entry['ancestorfees'], ancestor_fees * COIN + 1000)
174170

175171
# Undo the prioritisetransaction for later tests
176172
self.nodes[0].prioritisetransaction(txid=chain[0], fee_delta=-1000)
@@ -182,9 +178,8 @@ def run_test(self):
182178
descendant_fees = 0
183179
for x in reversed(chain):
184180
entry = self.nodes[0].getmempoolentry(x)
185-
descendant_fees += entry['fee']
181+
descendant_fees += entry['fees']['base']
186182
assert_equal(entry['fees']['descendant'], descendant_fees + Decimal('0.00001'))
187-
assert_equal(entry['descendantfees'], descendant_fees * COIN + 1000)
188183

189184
# Adding one more transaction on to the chain should fail.
190185
assert_raises_rpc_error(-26, "too-long-mempool-chain", chain_transaction, self.nodes[0], [txid], [vout], value, fee, 1)
@@ -204,11 +199,9 @@ def run_test(self):
204199
descendant_fees = 0
205200
for x in reversed(chain):
206201
entry = self.nodes[0].getmempoolentry(x)
207-
descendant_fees += entry['fee']
202+
descendant_fees += entry['fees']['base']
208203
if (x == chain[-1]):
209-
assert_equal(entry['modifiedfee'], entry['fee'] + Decimal("0.00002"))
210-
assert_equal(entry['fees']['modified'], entry['fee'] + Decimal("0.00002"))
211-
assert_equal(entry['descendantfees'], descendant_fees * COIN + 2000)
204+
assert_equal(entry['fees']['modified'], entry['fees']['base'] + Decimal("0.00002"))
212205
assert_equal(entry['fees']['descendant'], descendant_fees + Decimal("0.00002"))
213206

214207
# Check that node1's mempool is as expected (-> custom ancestor limit)

test/functional/rpc_fundrawtransaction.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ def test_fee_p2pkh(self):
415415

416416
# Create same transaction over sendtoaddress.
417417
txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)
418-
signedFee = self.nodes[0].getmempoolentry(txId)['fee']
418+
signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
419419

420420
# Compare fee.
421421
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -441,7 +441,7 @@ def test_fee_p2pkh_multi_out(self):
441441

442442
# Create same transaction over sendtoaddress.
443443
txId = self.nodes[0].sendmany("", outputs)
444-
signedFee = self.nodes[0].getmempoolentry(txId)['fee']
444+
signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
445445

446446
# Compare fee.
447447
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -468,7 +468,7 @@ def test_fee_p2sh(self):
468468

469469
# Create same transaction over sendtoaddress.
470470
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
471-
signedFee = self.nodes[0].getmempoolentry(txId)['fee']
471+
signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
472472

473473
# Compare fee.
474474
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -512,7 +512,7 @@ def test_fee_4of5(self):
512512

513513
# Create same transaction over sendtoaddress.
514514
txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
515-
signedFee = self.nodes[0].getmempoolentry(txId)['fee']
515+
signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']
516516

517517
# Compare fee.
518518
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
@@ -644,7 +644,7 @@ def test_many_inputs_fee(self):
644644

645645
# Create same transaction over sendtoaddress.
646646
txId = self.nodes[1].sendmany("", outputs)
647-
signedFee = self.nodes[1].getmempoolentry(txId)['fee']
647+
signedFee = self.nodes[1].getmempoolentry(txId)['fees']['base']
648648

649649
# Compare fee.
650650
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2021 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test deprecation of fee fields from top level mempool entry object"""
6+
7+
from test_framework.blocktools import COIN
8+
from test_framework.test_framework import BitcoinTestFramework
9+
from test_framework.util import assert_equal
10+
from test_framework.wallet import MiniWallet
11+
12+
13+
def assertions_helper(new_object, deprecated_object, deprecated_fields):
14+
for field in deprecated_fields:
15+
assert field in deprecated_object
16+
assert field not in new_object
17+
18+
19+
class MempoolFeeFieldsDeprecationTest(BitcoinTestFramework):
20+
def set_test_params(self):
21+
self.num_nodes = 2
22+
self.extra_args = [[], ["-deprecatedrpc=fees"]]
23+
24+
def run_test(self):
25+
# we get spendable outputs from the premined chain starting
26+
# at block 76. see BitcoinTestFramework._initialize_chain() for details
27+
self.wallet = MiniWallet(self.nodes[0])
28+
self.wallet.rescan_utxos()
29+
30+
# we create the tx on the first node and wait until it syncs to node_deprecated
31+
# thus, any differences must be coming from getmempoolentry or getrawmempool
32+
tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
33+
self.nodes[1].sendrawtransaction(tx["hex"])
34+
35+
deprecated_fields = ["ancestorfees", "descendantfees", "modifiedfee", "fee"]
36+
self.test_getmempoolentry(tx["txid"], deprecated_fields)
37+
self.test_getrawmempool(tx["txid"], deprecated_fields)
38+
self.test_deprecated_fields_match(tx["txid"])
39+
40+
def test_getmempoolentry(self, txid, deprecated_fields):
41+
42+
self.log.info("Test getmempoolentry rpc")
43+
entry = self.nodes[0].getmempoolentry(txid)
44+
deprecated_entry = self.nodes[1].getmempoolentry(txid)
45+
assertions_helper(entry, deprecated_entry, deprecated_fields)
46+
47+
def test_getrawmempool(self, txid, deprecated_fields):
48+
49+
self.log.info("Test getrawmempool rpc")
50+
entry = self.nodes[0].getrawmempool(verbose=True)[txid]
51+
deprecated_entry = self.nodes[1].getrawmempool(verbose=True)[txid]
52+
assertions_helper(entry, deprecated_entry, deprecated_fields)
53+
54+
def test_deprecated_fields_match(self, txid):
55+
56+
self.log.info("Test deprecated fee fields match new fees object")
57+
entry = self.nodes[0].getmempoolentry(txid)
58+
deprecated_entry = self.nodes[1].getmempoolentry(txid)
59+
60+
assert_equal(deprecated_entry["fee"], entry["fees"]["base"])
61+
assert_equal(deprecated_entry["modifiedfee"], entry["fees"]["modified"])
62+
assert_equal(deprecated_entry["descendantfees"], entry["fees"]["descendant"] * COIN)
63+
assert_equal(deprecated_entry["ancestorfees"], entry["fees"]["ancestor"] * COIN)
64+
65+
66+
if __name__ == "__main__":
67+
MempoolFeeFieldsDeprecationTest().main()

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@
314314
'feature_presegwit_node_upgrade.py',
315315
'feature_settings.py',
316316
'rpc_getdescriptorinfo.py',
317+
'rpc_mempool_entry_fee_fields_deprecation.py',
317318
'rpc_help.py',
318319
'feature_help.py',
319320
'feature_shutdown.py',

0 commit comments

Comments
 (0)