Skip to content

Commit 8fb5784

Browse files
committed
Create a tr() descriptor bech32m DescriptorScriptPubKeyMan by default
1 parent 54b3699 commit 8fb5784

13 files changed

+80
-54
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,12 +1876,6 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
18761876

18771877
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal)
18781878
{
1879-
if (addr_type == OutputType::BECH32M) {
1880-
// Don't allow setting up taproot descriptors yet
1881-
// TODO: Allow setting up taproot descriptors
1882-
return false;
1883-
}
1884-
18851879
LOCK(cs_desc_man);
18861880
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
18871881

@@ -1911,7 +1905,10 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
19111905
desc_prefix = "wpkh(" + xpub + "/84'";
19121906
break;
19131907
}
1914-
case OutputType::BECH32M: assert(false); // TODO: Setup taproot descriptor
1908+
case OutputType::BECH32M: {
1909+
desc_prefix = "tr(" + xpub + "/86'";
1910+
break;
1911+
}
19151912
} // no default case, so the compiler can warn about missing cases
19161913
assert(!desc_prefix.empty());
19171914

src/wallet/test/fuzz/notifications.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ struct FuzzedWallet {
6868
CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
6969
{
7070
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
71-
if (type == OutputType::BECH32M) {
72-
type = OutputType::BECH32; // TODO: Setup taproot descriptor and remove this line
73-
}
7471
CTxDestination dest;
7572
bilingual_str error;
7673
if (fuzzed_data_provider.ConsumeBool()) {

src/wallet/wallet.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3164,11 +3164,6 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
31643164

31653165
for (bool internal : {false, true}) {
31663166
for (OutputType t : OUTPUT_TYPES) {
3167-
if (t == OutputType::BECH32M) {
3168-
// Skip taproot (bech32m) for now
3169-
// TODO: Setup taproot (bech32m) descriptors by default
3170-
continue;
3171-
}
31723167
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
31733168
if (IsCrypted()) {
31743169
if (IsLocked()) {

test/functional/rpc_fundrawtransaction.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -571,12 +571,12 @@ def test_locked_wallet(self):
571571
if self.options.descriptors:
572572
self.nodes[1].walletpassphrase('test', 10)
573573
self.nodes[1].importdescriptors([{
574-
'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
574+
'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
575575
'timestamp': 'now',
576576
'active': True
577577
},
578578
{
579-
'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
579+
'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
580580
'timestamp': 'now',
581581
'active': True,
582582
'internal': True
@@ -778,11 +778,18 @@ def test_option_feerate(self):
778778
for param, zero_value in product(["fee_rate", "feeRate"], [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]):
779779
assert_equal(self.nodes[3].fundrawtransaction(rawtx, {param: zero_value})["fee"], 0)
780780

781-
# With no arguments passed, expect fee of 141 satoshis.
782-
assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
783-
# Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
784-
result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
785-
assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
781+
if self.options.descriptors:
782+
# With no arguments passed, expect fee of 153 satoshis as descriptor wallets now have a taproot output.
783+
assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000153, vspan=0.00000001)
784+
# Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
785+
result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
786+
assert_approx(result["fee"], vexp=0.0153, vspan=0.0001)
787+
else:
788+
# With no arguments passed, expect fee of 141 satoshis as legacy wallets only support up to segwit v0.
789+
assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
790+
# Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
791+
result = node.fundrawtransaction(rawtx, {"fee_rate": 10000})
792+
assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
786793

787794
self.log.info("Test fundrawtxn with invalid estimate_mode settings")
788795
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
@@ -1073,7 +1080,7 @@ def test_22670(self):
10731080
# Make sure the default wallet will not be loaded when restarted with a high minrelaytxfee
10741081
self.nodes[0].unloadwallet(self.default_wallet_name, False)
10751082
feerate = Decimal("0.1")
1076-
self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0"]) # Set high minrelayfee, set discardfee to 0 for easier calculation
1083+
self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0", "-changetype=bech32", "-addresstype=bech32"]) # Set high minrelayfee, set discardfee to 0 for easier calculation
10771084

10781085
self.nodes[0].loadwallet(self.default_wallet_name, True)
10791086
funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name)

test/functional/rpc_psbt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class PSBTTest(BitcoinTestFramework):
3131
def set_test_params(self):
3232
self.num_nodes = 3
3333
self.extra_args = [
34-
["-walletrbf=1"],
34+
["-walletrbf=1", "-addresstype=bech32", "-changetype=bech32"], #TODO: Remove address type restrictions once taproot has psbt extensions
3535
["-walletrbf=0", "-changetype=legacy"],
3636
[]
3737
]

test/functional/tool_wallet.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ def log_wallet_timestamp_comparison(self, old, new):
7070

7171
def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0):
7272
wallet_name = self.default_wallet_name if name == "" else name
73-
output_types = 3 # p2pkh, p2sh, segwit
7473
if self.options.descriptors:
74+
output_types = 4 # p2pkh, p2sh, segwit, bech32m
7575
return textwrap.dedent('''\
7676
Wallet info
7777
===========
@@ -85,6 +85,7 @@ def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0
8585
Address Book: %d
8686
''' % (wallet_name, keypool * output_types, transactions, address))
8787
else:
88+
output_types = 3 # p2pkh, p2sh, segwit. Legacy wallets do not support bech32m.
8889
return textwrap.dedent('''\
8990
Wallet info
9091
===========
@@ -298,8 +299,8 @@ def test_getwalletinfo_on_different_wallet(self):
298299
assert_equal(1000, out['keypoolsize_hd_internal'])
299300
assert_equal(True, 'hdseedid' in out)
300301
else:
301-
assert_equal(3000, out['keypoolsize'])
302-
assert_equal(3000, out['keypoolsize_hd_internal'])
302+
assert_equal(4000, out['keypoolsize'])
303+
assert_equal(4000, out['keypoolsize_hd_internal'])
303304

304305
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
305306
assert_equal(timestamp_before, timestamp_after)

test/functional/wallet_address_types.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ def test_address(self, node, address, multisig, typ):
121121
assert_equal(info['witness_version'], 0)
122122
assert_equal(len(info['witness_program']), 40)
123123
assert 'pubkey' in info
124+
elif not multisig and typ == "bech32m":
125+
# P2TR single sig
126+
assert info["isscript"]
127+
assert info["iswitness"]
128+
assert_equal(info["witness_version"], 1)
129+
assert_equal(len(info["witness_program"]), 64)
124130
elif typ == 'legacy':
125131
# P2SH-multisig
126132
assert info['isscript']
@@ -339,19 +345,31 @@ def run_test(self):
339345
self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output (unless changetype is set otherwise):")
340346
self.test_change_output_type(0, [to_address_bech32_1], 'legacy')
341347

342-
self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:")
343-
self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
344-
self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
345-
self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
346-
self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
348+
if self.options.descriptors:
349+
self.log.info("Nodes with addresstype=p2sh-segwit only use a bech32m change output if any destination address is bech32:")
350+
self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
351+
self.test_change_output_type(1, [to_address_bech32_1], 'bech32m')
352+
self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32m')
353+
self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32m')
354+
else:
355+
self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:")
356+
self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
357+
self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
358+
self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
359+
self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
347360

348361
self.log.info("Nodes with change_type=bech32 always use a P2WPKH change output:")
349362
self.test_change_output_type(2, [to_address_bech32_1], 'bech32')
350363
self.test_change_output_type(2, [to_address_p2sh], 'bech32')
351364

352-
self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):")
353-
self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
354-
self.test_change_output_type(3, [to_address_p2sh], 'bech32')
365+
if self.options.descriptors:
366+
self.log.info("Nodes with addresstype=bech32 always use either a bech32 or bech32m change output (unless changetype is set otherwise):")
367+
self.test_change_output_type(3, [to_address_bech32_1], 'bech32m')
368+
self.test_change_output_type(3, [to_address_p2sh], 'bech32')
369+
else:
370+
self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):")
371+
self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
372+
self.test_change_output_type(3, [to_address_p2sh], 'bech32')
355373

356374
self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')
357375
self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')
@@ -370,10 +388,9 @@ def run_test(self):
370388
self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32')
371389

372390
if self.options.descriptors:
373-
self.log.info("Descriptor wallets do not have bech32m addresses by default yet")
374-
# TODO: Remove this when they do
375-
assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getnewaddress, "", "bech32m")
376-
assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getrawchangeaddress, "bech32m")
391+
self.log.info("Descriptor wallets have bech32m addresses")
392+
self.test_address(4, self.nodes[4].getnewaddress("", "bech32m"), multisig=False, typ="bech32m")
393+
self.test_address(4, self.nodes[4].getrawchangeaddress("bech32m"), multisig=False, typ="bech32m")
377394
else:
378395
self.log.info("Legacy wallets cannot make bech32m addresses")
379396
assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getnewaddress, "", "bech32m")

test/functional/wallet_createwallet.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def run_test(self):
146146
w6.keypoolrefill(1)
147147
# There should only be 1 key for legacy, 3 for descriptors
148148
walletinfo = w6.getwalletinfo()
149-
keys = 3 if self.options.descriptors else 1
149+
keys = 4 if self.options.descriptors else 1
150150
assert_equal(walletinfo['keypoolsize'], keys)
151151
assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
152152
# Allow empty passphrase, but there should be a warning

test/functional/wallet_descriptor.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ def run_test(self):
3737
self.log.info("Making a descriptor wallet")
3838
self.nodes[0].createwallet(wallet_name="desc1", descriptors=True)
3939

40-
# A descriptor wallet should have 100 addresses * 3 types = 300 keys
40+
# A descriptor wallet should have 100 addresses * 4 types = 400 keys
4141
self.log.info("Checking wallet info")
4242
wallet_info = self.nodes[0].getwalletinfo()
4343
assert_equal(wallet_info['format'], 'sqlite')
44-
assert_equal(wallet_info['keypoolsize'], 300)
45-
assert_equal(wallet_info['keypoolsize_hd_internal'], 300)
44+
assert_equal(wallet_info['keypoolsize'], 400)
45+
assert_equal(wallet_info['keypoolsize_hd_internal'], 400)
4646
assert 'keypoololdest' not in wallet_info
4747

4848
# Check that getnewaddress works

test/functional/wallet_groups.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,24 @@ def run_test(self):
108108
assert_equal(input_addrs[0], input_addrs[1])
109109
# Node 2 enforces avoidpartialspends so needs no checking here
110110

111+
if self.options.descriptors:
112+
# Descriptor wallets will use Taproot change by default which has different fees
113+
tx4_ungrouped_fee = 3060
114+
tx4_grouped_fee = 4400
115+
tx5_6_ungrouped_fee = 5760
116+
tx5_6_grouped_fee = 8480
117+
else:
118+
tx4_ungrouped_fee = 2820
119+
tx4_grouped_fee = 4160
120+
tx5_6_ungrouped_fee = 5520
121+
tx5_6_grouped_fee = 8240
122+
111123
self.log.info("Test wallet option maxapsfee")
112124
addr_aps = self.nodes[3].getnewaddress()
113125
self.nodes[0].sendtoaddress(addr_aps, 1.0)
114126
self.nodes[0].sendtoaddress(addr_aps, 1.0)
115127
self.generate(self.nodes[0], 1)
116-
with self.nodes[3].assert_debug_log(['Fee non-grouped = 2820, grouped = 4160, using grouped']):
128+
with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx4_ungrouped_fee}, grouped = {tx4_grouped_fee}, using grouped']):
117129
txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
118130
tx4 = self.nodes[3].getrawtransaction(txid4, True)
119131
# tx4 should have 2 inputs and 2 outputs although one output would
@@ -124,7 +136,7 @@ def run_test(self):
124136
addr_aps2 = self.nodes[3].getnewaddress()
125137
[self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
126138
self.generate(self.nodes[0], 1)
127-
with self.nodes[3].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using non-grouped']):
139+
with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using non-grouped']):
128140
txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
129141
tx5 = self.nodes[3].getrawtransaction(txid5, True)
130142
# tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs
@@ -137,7 +149,7 @@ def run_test(self):
137149
addr_aps3 = self.nodes[4].getnewaddress()
138150
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
139151
self.generate(self.nodes[0], 1)
140-
with self.nodes[4].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using grouped']):
152+
with self.nodes[4].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using grouped']):
141153
txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
142154
tx6 = self.nodes[4].getrawtransaction(txid6, True)
143155
# tx6 should have 5 inputs and 2 outputs

0 commit comments

Comments
 (0)