From 54b3699862de687f782c7c52500d6a2372478355 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 28 Jun 2021 15:53:41 -0400 Subject: [PATCH 1/4] Store pubkeys in TRDescriptor::MakeScripts When expanding the scripts for a TRDescriptor, also store the pubkeys in the FlatSigningProvider. --- src/script/descriptor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 621a1b9fd6a..c3b4d1ddaa9 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -851,6 +851,7 @@ protected: builder.Finalize(xpk); WitnessV1Taproot output = builder.GetOutput(); out.tr_spenddata[output].Merge(builder.GetSpendData()); + out.pubkeys.emplace(keys[0].GetID(), keys[0]); return Vector(GetScriptForDestination(output)); } bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override From 8fb57845ee3844c9ba854471065109d2e409300f Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 23 Jun 2021 16:11:51 -0400 Subject: [PATCH 2/4] Create a tr() descriptor bech32m DescriptorScriptPubKeyMan by default --- src/wallet/scriptpubkeyman.cpp | 11 +++--- src/wallet/test/fuzz/notifications.cpp | 3 -- src/wallet/wallet.cpp | 5 --- test/functional/rpc_fundrawtransaction.py | 23 ++++++++----- test/functional/rpc_psbt.py | 2 +- test/functional/tool_wallet.py | 7 ++-- test/functional/wallet_address_types.py | 41 ++++++++++++++++------- test/functional/wallet_createwallet.py | 2 +- test/functional/wallet_descriptor.py | 6 ++-- test/functional/wallet_groups.py | 18 ++++++++-- test/functional/wallet_hd.py | 2 +- test/functional/wallet_keypool.py | 8 ++--- test/functional/wallet_listdescriptors.py | 6 ++-- 13 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 9173c790d4f..8d6f3b23957 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1876,12 +1876,6 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal) { - if (addr_type == OutputType::BECH32M) { - // Don't allow setting up taproot descriptors yet - // TODO: Allow setting up taproot descriptors - return false; - } - LOCK(cs_desc_man); assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); @@ -1911,7 +1905,10 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_ desc_prefix = "wpkh(" + xpub + "/84'"; break; } - case OutputType::BECH32M: assert(false); // TODO: Setup taproot descriptor + case OutputType::BECH32M: { + desc_prefix = "tr(" + xpub + "/86'"; + break; + } } // no default case, so the compiler can warn about missing cases assert(!desc_prefix.empty()); diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp index e8b49f12202..0601c492cd7 100644 --- a/src/wallet/test/fuzz/notifications.cpp +++ b/src/wallet/test/fuzz/notifications.cpp @@ -68,9 +68,6 @@ struct FuzzedWallet { CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider) { auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)}; - if (type == OutputType::BECH32M) { - type = OutputType::BECH32; // TODO: Setup taproot descriptor and remove this line - } CTxDestination dest; bilingual_str error; if (fuzzed_data_provider.ConsumeBool()) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7f60dd69060..b269fe253f7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3164,11 +3164,6 @@ void CWallet::SetupDescriptorScriptPubKeyMans() for (bool internal : {false, true}) { for (OutputType t : OUTPUT_TYPES) { - if (t == OutputType::BECH32M) { - // Skip taproot (bech32m) for now - // TODO: Setup taproot (bech32m) descriptors by default - continue; - } auto spk_manager = std::unique_ptr(new DescriptorScriptPubKeyMan(*this)); if (IsCrypted()) { if (IsLocked()) { diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index 0d8117bd023..93970ff40c7 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -571,12 +571,12 @@ class RawTransactionsTest(BitcoinTestFramework): if self.options.descriptors: self.nodes[1].walletpassphrase('test', 10) self.nodes[1].importdescriptors([{ - 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'), + 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'), 'timestamp': 'now', 'active': True }, { - 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'), + 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'), 'timestamp': 'now', 'active': True, 'internal': True @@ -778,11 +778,18 @@ class RawTransactionsTest(BitcoinTestFramework): for param, zero_value in product(["fee_rate", "feeRate"], [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]): assert_equal(self.nodes[3].fundrawtransaction(rawtx, {param: zero_value})["fee"], 0) - # With no arguments passed, expect fee of 141 satoshis. - assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001) - # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified. - result = node.fundrawtransaction(rawtx, {"fee_rate": 10000}) - assert_approx(result["fee"], vexp=0.0141, vspan=0.0001) + if self.options.descriptors: + # With no arguments passed, expect fee of 153 satoshis as descriptor wallets now have a taproot output. + assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000153, vspan=0.00000001) + # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified. + result = node.fundrawtransaction(rawtx, {"fee_rate": 10000}) + assert_approx(result["fee"], vexp=0.0153, vspan=0.0001) + else: + # With no arguments passed, expect fee of 141 satoshis as legacy wallets only support up to segwit v0. + assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001) + # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified. + result = node.fundrawtransaction(rawtx, {"fee_rate": 10000}) + assert_approx(result["fee"], vexp=0.0141, vspan=0.0001) self.log.info("Test fundrawtxn with invalid estimate_mode settings") for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): @@ -1073,7 +1080,7 @@ class RawTransactionsTest(BitcoinTestFramework): # Make sure the default wallet will not be loaded when restarted with a high minrelaytxfee self.nodes[0].unloadwallet(self.default_wallet_name, False) feerate = Decimal("0.1") - self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0"]) # Set high minrelayfee, set discardfee to 0 for easier calculation + self.restart_node(0, [f"-minrelaytxfee={feerate}", "-discardfee=0", "-changetype=bech32", "-addresstype=bech32"]) # Set high minrelayfee, set discardfee to 0 for easier calculation self.nodes[0].loadwallet(self.default_wallet_name, True) funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 9b00eab3466..4ac4f27d8ac 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -31,7 +31,7 @@ class PSBTTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 self.extra_args = [ - ["-walletrbf=1"], + ["-walletrbf=1", "-addresstype=bech32", "-changetype=bech32"], #TODO: Remove address type restrictions once taproot has psbt extensions ["-walletrbf=0", "-changetype=legacy"], [] ] diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py index 616ac29b15a..afe4dba7b4f 100755 --- a/test/functional/tool_wallet.py +++ b/test/functional/tool_wallet.py @@ -70,8 +70,8 @@ class ToolWalletTest(BitcoinTestFramework): def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0): wallet_name = self.default_wallet_name if name == "" else name - output_types = 3 # p2pkh, p2sh, segwit if self.options.descriptors: + output_types = 4 # p2pkh, p2sh, segwit, bech32m return textwrap.dedent('''\ Wallet info =========== @@ -85,6 +85,7 @@ class ToolWalletTest(BitcoinTestFramework): Address Book: %d ''' % (wallet_name, keypool * output_types, transactions, address)) else: + output_types = 3 # p2pkh, p2sh, segwit. Legacy wallets do not support bech32m. return textwrap.dedent('''\ Wallet info =========== @@ -298,8 +299,8 @@ class ToolWalletTest(BitcoinTestFramework): assert_equal(1000, out['keypoolsize_hd_internal']) assert_equal(True, 'hdseedid' in out) else: - assert_equal(3000, out['keypoolsize']) - assert_equal(3000, out['keypoolsize_hd_internal']) + assert_equal(4000, out['keypoolsize']) + assert_equal(4000, out['keypoolsize_hd_internal']) self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after) assert_equal(timestamp_before, timestamp_after) diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index e4fe150333a..eb6e497951c 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -121,6 +121,12 @@ class AddressTypeTest(BitcoinTestFramework): assert_equal(info['witness_version'], 0) assert_equal(len(info['witness_program']), 40) assert 'pubkey' in info + elif not multisig and typ == "bech32m": + # P2TR single sig + assert info["isscript"] + assert info["iswitness"] + assert_equal(info["witness_version"], 1) + assert_equal(len(info["witness_program"]), 64) elif typ == 'legacy': # P2SH-multisig assert info['isscript'] @@ -339,19 +345,31 @@ class AddressTypeTest(BitcoinTestFramework): self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output (unless changetype is set otherwise):") self.test_change_output_type(0, [to_address_bech32_1], 'legacy') - self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:") - self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit') - self.test_change_output_type(1, [to_address_bech32_1], 'bech32') - self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32') - self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32') + if self.options.descriptors: + self.log.info("Nodes with addresstype=p2sh-segwit only use a bech32m change output if any destination address is bech32:") + self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit') + self.test_change_output_type(1, [to_address_bech32_1], 'bech32m') + self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32m') + self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32m') + else: + self.log.info("Nodes with addresstype=p2sh-segwit only use a P2WPKH change output if any destination address is bech32:") + self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit') + self.test_change_output_type(1, [to_address_bech32_1], 'bech32') + self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32') + self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32') self.log.info("Nodes with change_type=bech32 always use a P2WPKH change output:") self.test_change_output_type(2, [to_address_bech32_1], 'bech32') self.test_change_output_type(2, [to_address_p2sh], 'bech32') - self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):") - self.test_change_output_type(3, [to_address_bech32_1], 'bech32') - self.test_change_output_type(3, [to_address_p2sh], 'bech32') + if self.options.descriptors: + self.log.info("Nodes with addresstype=bech32 always use either a bech32 or bech32m change output (unless changetype is set otherwise):") + self.test_change_output_type(3, [to_address_bech32_1], 'bech32m') + self.test_change_output_type(3, [to_address_p2sh], 'bech32') + else: + self.log.info("Nodes with addresstype=bech32 always use a P2WPKH change output (unless changetype is set otherwise):") + self.test_change_output_type(3, [to_address_bech32_1], 'bech32') + self.test_change_output_type(3, [to_address_p2sh], 'bech32') self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent') self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32') @@ -370,10 +388,9 @@ class AddressTypeTest(BitcoinTestFramework): self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32') if self.options.descriptors: - self.log.info("Descriptor wallets do not have bech32m addresses by default yet") - # TODO: Remove this when they do - assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getnewaddress, "", "bech32m") - assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getrawchangeaddress, "bech32m") + self.log.info("Descriptor wallets have bech32m addresses") + self.test_address(4, self.nodes[4].getnewaddress("", "bech32m"), multisig=False, typ="bech32m") + self.test_address(4, self.nodes[4].getrawchangeaddress("bech32m"), multisig=False, typ="bech32m") else: self.log.info("Legacy wallets cannot make bech32m addresses") assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getnewaddress, "", "bech32m") diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index a751138d890..4416a9655f8 100755 --- a/test/functional/wallet_createwallet.py +++ b/test/functional/wallet_createwallet.py @@ -146,7 +146,7 @@ class CreateWalletTest(BitcoinTestFramework): w6.keypoolrefill(1) # There should only be 1 key for legacy, 3 for descriptors walletinfo = w6.getwalletinfo() - keys = 3 if self.options.descriptors else 1 + keys = 4 if self.options.descriptors else 1 assert_equal(walletinfo['keypoolsize'], keys) assert_equal(walletinfo['keypoolsize_hd_internal'], keys) # Allow empty passphrase, but there should be a warning diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py index df2fdb29435..e47d021210e 100755 --- a/test/functional/wallet_descriptor.py +++ b/test/functional/wallet_descriptor.py @@ -37,12 +37,12 @@ class WalletDescriptorTest(BitcoinTestFramework): self.log.info("Making a descriptor wallet") self.nodes[0].createwallet(wallet_name="desc1", descriptors=True) - # A descriptor wallet should have 100 addresses * 3 types = 300 keys + # A descriptor wallet should have 100 addresses * 4 types = 400 keys self.log.info("Checking wallet info") wallet_info = self.nodes[0].getwalletinfo() assert_equal(wallet_info['format'], 'sqlite') - assert_equal(wallet_info['keypoolsize'], 300) - assert_equal(wallet_info['keypoolsize_hd_internal'], 300) + assert_equal(wallet_info['keypoolsize'], 400) + assert_equal(wallet_info['keypoolsize_hd_internal'], 400) assert 'keypoololdest' not in wallet_info # Check that getnewaddress works diff --git a/test/functional/wallet_groups.py b/test/functional/wallet_groups.py index c228bb122ab..9052bc7f7f4 100755 --- a/test/functional/wallet_groups.py +++ b/test/functional/wallet_groups.py @@ -108,12 +108,24 @@ class WalletGroupTest(BitcoinTestFramework): assert_equal(input_addrs[0], input_addrs[1]) # Node 2 enforces avoidpartialspends so needs no checking here + if self.options.descriptors: + # Descriptor wallets will use Taproot change by default which has different fees + tx4_ungrouped_fee = 3060 + tx4_grouped_fee = 4400 + tx5_6_ungrouped_fee = 5760 + tx5_6_grouped_fee = 8480 + else: + tx4_ungrouped_fee = 2820 + tx4_grouped_fee = 4160 + tx5_6_ungrouped_fee = 5520 + tx5_6_grouped_fee = 8240 + self.log.info("Test wallet option maxapsfee") addr_aps = self.nodes[3].getnewaddress() self.nodes[0].sendtoaddress(addr_aps, 1.0) self.nodes[0].sendtoaddress(addr_aps, 1.0) self.generate(self.nodes[0], 1) - with self.nodes[3].assert_debug_log(['Fee non-grouped = 2820, grouped = 4160, using grouped']): + with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx4_ungrouped_fee}, grouped = {tx4_grouped_fee}, using grouped']): txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 0.1) tx4 = self.nodes[3].getrawtransaction(txid4, True) # tx4 should have 2 inputs and 2 outputs although one output would @@ -124,7 +136,7 @@ class WalletGroupTest(BitcoinTestFramework): addr_aps2 = self.nodes[3].getnewaddress() [self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)] self.generate(self.nodes[0], 1) - with self.nodes[3].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using non-grouped']): + with self.nodes[3].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using non-grouped']): txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 2.95) tx5 = self.nodes[3].getrawtransaction(txid5, True) # tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs @@ -137,7 +149,7 @@ class WalletGroupTest(BitcoinTestFramework): addr_aps3 = self.nodes[4].getnewaddress() [self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)] self.generate(self.nodes[0], 1) - with self.nodes[4].assert_debug_log(['Fee non-grouped = 5520, grouped = 8240, using grouped']): + with self.nodes[4].assert_debug_log([f'Fee non-grouped = {tx5_6_ungrouped_fee}, grouped = {tx5_6_grouped_fee}, using grouped']): txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(), 2.95) tx6 = self.nodes[4].getrawtransaction(txid6, True) # tx6 should have 5 inputs and 2 outputs diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index ac878ea0aa8..d78afb42127 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -136,7 +136,7 @@ class WalletHDTest(BitcoinTestFramework): keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['address'])['hdkeypath'] if self.options.descriptors: - assert_equal(keypath[0:14], "m/84'/1'/0'/1/") + assert_equal(keypath[0:14], "m/86'/1'/0'/1/") else: assert_equal(keypath[0:7], "m/0'/1'") diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py index bf7a342be65..54c47511a9b 100755 --- a/test/functional/wallet_keypool.py +++ b/test/functional/wallet_keypool.py @@ -87,8 +87,8 @@ class KeyPoolTest(BitcoinTestFramework): nodes[0].walletlock() wi = nodes[0].getwalletinfo() if self.options.descriptors: - assert_equal(wi['keypoolsize_hd_internal'], 18) - assert_equal(wi['keypoolsize'], 18) + assert_equal(wi['keypoolsize_hd_internal'], 24) + assert_equal(wi['keypoolsize'], 24) else: assert_equal(wi['keypoolsize_hd_internal'], 6) assert_equal(wi['keypoolsize'], 6) @@ -132,8 +132,8 @@ class KeyPoolTest(BitcoinTestFramework): nodes[0].keypoolrefill(100) wi = nodes[0].getwalletinfo() if self.options.descriptors: - assert_equal(wi['keypoolsize_hd_internal'], 300) - assert_equal(wi['keypoolsize'], 300) + assert_equal(wi['keypoolsize_hd_internal'], 400) + assert_equal(wi['keypoolsize'], 400) else: assert_equal(wi['keypoolsize_hd_internal'], 100) assert_equal(wi['keypoolsize'], 100) diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py index 436bbdcfccb..202ef928879 100755 --- a/test/functional/wallet_listdescriptors.py +++ b/test/functional/wallet_listdescriptors.py @@ -43,9 +43,9 @@ class ListDescriptorsTest(BitcoinTestFramework): node.createwallet(wallet_name='w3', descriptors=True) result = node.get_wallet_rpc('w3').listdescriptors() assert_equal("w3", result['wallet_name']) - assert_equal(6, len(result['descriptors'])) - assert_equal(6, len([d for d in result['descriptors'] if d['active']])) - assert_equal(3, len([d for d in result['descriptors'] if d['internal']])) + assert_equal(8, len(result['descriptors'])) + assert_equal(8, len([d for d in result['descriptors'] if d['active']])) + assert_equal(4, len([d for d in result['descriptors'] if d['internal']])) for item in result['descriptors']: assert item['desc'] != '' assert item['next'] == 0 From d8abbe119c71f917e0fd2e80536c1e5d979b4dc6 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 23 Jun 2021 19:03:10 -0400 Subject: [PATCH 3/4] Mention bech32m in -addresstype and -changetype help --- src/wallet/init.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 7a5526a4cb7..4ff049170e8 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -43,9 +43,9 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit(); void WalletInit::AddWalletOptions(ArgsManager& argsman) const { - argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); + argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting many (possibly all) or none, instead of selecting on a per-output basis. Privacy is improved as addresses are mostly swept with fewer transactions and outputs are aggregated in clean change addresses. It may result in higher fees due to less optimal coin selection caused by this added limitation and possibly a larger-than-necessary number of inputs being used. Always enabled for wallets with \"avoid_reuse\" enabled, otherwise default: %u.", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); - argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); + argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-consolidatefeerate=", strprintf("The maximum feerate (in %s/kvB) at which transaction building may use more inputs than strictly necessary so that the wallet's UTXO pool can be reduced (default: %s).", CURRENCY_UNIT, FormatMoney(DEFAULT_CONSOLIDATE_FEERATE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-discardfee=", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). " From 4868c9f1b39f03adee0009cd41d96598b43e8b78 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 23 Jun 2021 21:17:48 -0400 Subject: [PATCH 4/4] Extract Taproot internal keyid with GetKeyFromDestination --- src/script/signingprovider.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index b80fbe22cee..17f97fa30c8 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -190,8 +190,8 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest) { - // Only supports destinations which map to single public keys, i.e. P2PKH, - // P2WPKH, and P2SH-P2WPKH. + // Only supports destinations which map to single public keys: + // P2PKH, P2WPKH, P2SH-P2WPKH, P2TR if (auto id = std::get_if(&dest)) { return ToKeyID(*id); } @@ -208,5 +208,15 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& } } } + if (auto output_key = std::get_if(&dest)) { + TaprootSpendData spenddata; + CPubKey pub; + if (store.GetTaprootSpendData(*output_key, spenddata) + && !spenddata.internal_key.IsNull() + && spenddata.merkle_root.IsNull() + && store.GetPubKeyByXOnly(spenddata.internal_key, pub)) { + return pub.GetID(); + } + } return CKeyID(); }