0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

Merge bitcoin/bitcoin#22364: wallet: Make a tr() descriptor by default

4868c9f1b3 Extract Taproot internal keyid with GetKeyFromDestination (Andrew Chow)
d8abbe119c Mention bech32m in -addresstype and -changetype help (Andrew Chow)
8fb57845ee Create a tr() descriptor bech32m DescriptorScriptPubKeyMan by default (Andrew Chow)
54b3699862 Store pubkeys in TRDescriptor::MakeScripts (Andrew Chow)

Pull request description:

  Make a `tr()` descriptor by default in descriptor wallets so that users will be able to make and use segwit v1 bech32m addresses.

ACKs for top commit:
  MarcoFalke:
    Concept ACK 4868c9f1b3
  Sjors:
    re-utACK 4868c9f1b3
  gruve-p:
    ACK 4868c9f1b3
  meshcollider:
    Concept + code review ACK 4868c9f1b3

Tree-SHA512: e5896e665b8d559f1d759b6582d1bb24f70d4698a57307684339d9fdcdac28ae9bc17bc946a7efec9cb35c130a95ffc36e3961a335124ec4535d77b8d00e9631
This commit is contained in:
MarcoFalke 2021-11-22 10:00:34 +01:00
commit 47fe7445e7
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
16 changed files with 95 additions and 58 deletions

View file

@ -851,6 +851,7 @@ protected:
builder.Finalize(xpk); builder.Finalize(xpk);
WitnessV1Taproot output = builder.GetOutput(); WitnessV1Taproot output = builder.GetOutput();
out.tr_spenddata[output].Merge(builder.GetSpendData()); out.tr_spenddata[output].Merge(builder.GetSpendData());
out.pubkeys.emplace(keys[0].GetID(), keys[0]);
return Vector(GetScriptForDestination(output)); return Vector(GetScriptForDestination(output));
} }
bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override bool ToStringSubScriptHelper(const SigningProvider* arg, std::string& ret, const StringType type, const DescriptorCache* cache = nullptr) const override

View file

@ -190,8 +190,8 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS
CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest) CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{ {
// Only supports destinations which map to single public keys, i.e. P2PKH, // Only supports destinations which map to single public keys:
// P2WPKH, and P2SH-P2WPKH. // P2PKH, P2WPKH, P2SH-P2WPKH, P2TR
if (auto id = std::get_if<PKHash>(&dest)) { if (auto id = std::get_if<PKHash>(&dest)) {
return ToKeyID(*id); return ToKeyID(*id);
} }
@ -208,5 +208,15 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
} }
} }
} }
if (auto output_key = std::get_if<WitnessV1Taproot>(&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(); return CKeyID();
} }

View file

@ -43,9 +43,9 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions(ArgsManager& argsman) const 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("-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=<amt>", 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("-consolidatefeerate=<amt>", 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("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). " argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "

View file

@ -1876,12 +1876,6 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, OutputType addr_type, bool internal) 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); LOCK(cs_desc_man);
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
@ -1911,7 +1905,10 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
desc_prefix = "wpkh(" + xpub + "/84'"; desc_prefix = "wpkh(" + xpub + "/84'";
break; 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 } // no default case, so the compiler can warn about missing cases
assert(!desc_prefix.empty()); assert(!desc_prefix.empty());

View file

@ -68,9 +68,6 @@ struct FuzzedWallet {
CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider) CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
{ {
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)}; 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; CTxDestination dest;
bilingual_str error; bilingual_str error;
if (fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.ConsumeBool()) {

View file

@ -3168,11 +3168,6 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
for (bool internal : {false, true}) { for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) { 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<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this)); auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
if (IsCrypted()) { if (IsCrypted()) {
if (IsLocked()) { if (IsLocked()) {

View file

@ -571,12 +571,12 @@ class RawTransactionsTest(BitcoinTestFramework):
if self.options.descriptors: if self.options.descriptors:
self.nodes[1].walletpassphrase('test', 10) self.nodes[1].walletpassphrase('test', 10)
self.nodes[1].importdescriptors([{ self.nodes[1].importdescriptors([{
'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'), 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/0h/*h)'),
'timestamp': 'now', 'timestamp': 'now',
'active': True 'active': True
}, },
{ {
'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'), 'desc': descsum_create('tr(tprv8ZgxMBicQKsPdYeeZbPSKd2KYLmeVKtcFA7kqCxDvDR13MQ6us8HopUR2wLcS2ZKPhLyKsqpDL2FtL73LMHcgoCL7DXsciA8eX8nbjCR2eG/1h/*h)'),
'timestamp': 'now', 'timestamp': 'now',
'active': True, 'active': True,
'internal': 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"]): 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) assert_equal(self.nodes[3].fundrawtransaction(rawtx, {param: zero_value})["fee"], 0)
# With no arguments passed, expect fee of 141 satoshis. if self.options.descriptors:
assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001) # With no arguments passed, expect fee of 153 satoshis as descriptor wallets now have a taproot output.
# Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified. assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000153, vspan=0.00000001)
result = node.fundrawtransaction(rawtx, {"fee_rate": 10000}) # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
assert_approx(result["fee"], vexp=0.0141, vspan=0.0001) 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") self.log.info("Test fundrawtxn with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): 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 # Make sure the default wallet will not be loaded when restarted with a high minrelaytxfee
self.nodes[0].unloadwallet(self.default_wallet_name, False) self.nodes[0].unloadwallet(self.default_wallet_name, False)
feerate = Decimal("0.1") 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) self.nodes[0].loadwallet(self.default_wallet_name, True)
funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name) funds = self.nodes[0].get_wallet_rpc(self.default_wallet_name)

View file

@ -31,7 +31,7 @@ class PSBTTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.num_nodes = 3 self.num_nodes = 3
self.extra_args = [ 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"], ["-walletrbf=0", "-changetype=legacy"],
[] []
] ]

View file

@ -70,8 +70,8 @@ class ToolWalletTest(BitcoinTestFramework):
def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0): def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0):
wallet_name = self.default_wallet_name if name == "" else name wallet_name = self.default_wallet_name if name == "" else name
output_types = 3 # p2pkh, p2sh, segwit
if self.options.descriptors: if self.options.descriptors:
output_types = 4 # p2pkh, p2sh, segwit, bech32m
return textwrap.dedent('''\ return textwrap.dedent('''\
Wallet info Wallet info
=========== ===========
@ -85,6 +85,7 @@ class ToolWalletTest(BitcoinTestFramework):
Address Book: %d Address Book: %d
''' % (wallet_name, keypool * output_types, transactions, address)) ''' % (wallet_name, keypool * output_types, transactions, address))
else: else:
output_types = 3 # p2pkh, p2sh, segwit. Legacy wallets do not support bech32m.
return textwrap.dedent('''\ return textwrap.dedent('''\
Wallet info Wallet info
=========== ===========
@ -298,8 +299,8 @@ class ToolWalletTest(BitcoinTestFramework):
assert_equal(1000, out['keypoolsize_hd_internal']) assert_equal(1000, out['keypoolsize_hd_internal'])
assert_equal(True, 'hdseedid' in out) assert_equal(True, 'hdseedid' in out)
else: else:
assert_equal(3000, out['keypoolsize']) assert_equal(4000, out['keypoolsize'])
assert_equal(3000, out['keypoolsize_hd_internal']) assert_equal(4000, out['keypoolsize_hd_internal'])
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after) self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
assert_equal(timestamp_before, timestamp_after) assert_equal(timestamp_before, timestamp_after)

View file

@ -121,6 +121,12 @@ class AddressTypeTest(BitcoinTestFramework):
assert_equal(info['witness_version'], 0) assert_equal(info['witness_version'], 0)
assert_equal(len(info['witness_program']), 40) assert_equal(len(info['witness_program']), 40)
assert 'pubkey' in info 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': elif typ == 'legacy':
# P2SH-multisig # P2SH-multisig
assert info['isscript'] 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.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.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:") if self.options.descriptors:
self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit') 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_bech32_1], 'bech32') self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32') self.test_change_output_type(1, [to_address_bech32_1], 'bech32m')
self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32') 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.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_bech32_1], 'bech32')
self.test_change_output_type(2, [to_address_p2sh], '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):") if self.options.descriptors:
self.test_change_output_type(3, [to_address_bech32_1], 'bech32') 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_p2sh], 'bech32') 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.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') 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') self.test_address(4, self.nodes[4].getrawchangeaddress('bech32'), multisig=False, typ='bech32')
if self.options.descriptors: if self.options.descriptors:
self.log.info("Descriptor wallets do not have bech32m addresses by default yet") self.log.info("Descriptor wallets have bech32m addresses")
# TODO: Remove this when they do self.test_address(4, self.nodes[4].getnewaddress("", "bech32m"), multisig=False, typ="bech32m")
assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getnewaddress, "", "bech32m") self.test_address(4, self.nodes[4].getrawchangeaddress("bech32m"), multisig=False, typ="bech32m")
assert_raises_rpc_error(-12, "Error: No bech32m addresses available", self.nodes[0].getrawchangeaddress, "bech32m")
else: else:
self.log.info("Legacy wallets cannot make bech32m addresses") 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") assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getnewaddress, "", "bech32m")

View file

@ -146,7 +146,7 @@ class CreateWalletTest(BitcoinTestFramework):
w6.keypoolrefill(1) w6.keypoolrefill(1)
# There should only be 1 key for legacy, 3 for descriptors # There should only be 1 key for legacy, 3 for descriptors
walletinfo = w6.getwalletinfo() 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'], keys)
assert_equal(walletinfo['keypoolsize_hd_internal'], keys) assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
# Allow empty passphrase, but there should be a warning # Allow empty passphrase, but there should be a warning

View file

@ -37,12 +37,12 @@ class WalletDescriptorTest(BitcoinTestFramework):
self.log.info("Making a descriptor wallet") self.log.info("Making a descriptor wallet")
self.nodes[0].createwallet(wallet_name="desc1", descriptors=True) 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") self.log.info("Checking wallet info")
wallet_info = self.nodes[0].getwalletinfo() wallet_info = self.nodes[0].getwalletinfo()
assert_equal(wallet_info['format'], 'sqlite') assert_equal(wallet_info['format'], 'sqlite')
assert_equal(wallet_info['keypoolsize'], 300) assert_equal(wallet_info['keypoolsize'], 400)
assert_equal(wallet_info['keypoolsize_hd_internal'], 300) assert_equal(wallet_info['keypoolsize_hd_internal'], 400)
assert 'keypoololdest' not in wallet_info assert 'keypoololdest' not in wallet_info
# Check that getnewaddress works # Check that getnewaddress works

View file

@ -108,12 +108,24 @@ class WalletGroupTest(BitcoinTestFramework):
assert_equal(input_addrs[0], input_addrs[1]) assert_equal(input_addrs[0], input_addrs[1])
# Node 2 enforces avoidpartialspends so needs no checking here # 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") self.log.info("Test wallet option maxapsfee")
addr_aps = self.nodes[3].getnewaddress() addr_aps = self.nodes[3].getnewaddress()
self.nodes[0].sendtoaddress(addr_aps, 1.0) self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.nodes[0].sendtoaddress(addr_aps, 1.0) self.nodes[0].sendtoaddress(addr_aps, 1.0)
self.generate(self.nodes[0], 1) 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) txid4 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
tx4 = self.nodes[3].getrawtransaction(txid4, True) tx4 = self.nodes[3].getrawtransaction(txid4, True)
# tx4 should have 2 inputs and 2 outputs although one output would # 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() addr_aps2 = self.nodes[3].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)] [self.nodes[0].sendtoaddress(addr_aps2, 1.0) for _ in range(5)]
self.generate(self.nodes[0], 1) 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) txid5 = self.nodes[3].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
tx5 = self.nodes[3].getrawtransaction(txid5, True) tx5 = self.nodes[3].getrawtransaction(txid5, True)
# tx5 should have 3 inputs (1.0, 1.0, 1.0) and 2 outputs # 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() addr_aps3 = self.nodes[4].getnewaddress()
[self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)] [self.nodes[0].sendtoaddress(addr_aps3, 1.0) for _ in range(5)]
self.generate(self.nodes[0], 1) 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) txid6 = self.nodes[4].sendtoaddress(self.nodes[0].getnewaddress(), 2.95)
tx6 = self.nodes[4].getrawtransaction(txid6, True) tx6 = self.nodes[4].getrawtransaction(txid6, True)
# tx6 should have 5 inputs and 2 outputs # tx6 should have 5 inputs and 2 outputs

View file

@ -136,7 +136,7 @@ class WalletHDTest(BitcoinTestFramework):
keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['address'])['hdkeypath'] keypath = self.nodes[1].getaddressinfo(out['scriptPubKey']['address'])['hdkeypath']
if self.options.descriptors: 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: else:
assert_equal(keypath[0:7], "m/0'/1'") assert_equal(keypath[0:7], "m/0'/1'")

View file

@ -87,8 +87,8 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].walletlock() nodes[0].walletlock()
wi = nodes[0].getwalletinfo() wi = nodes[0].getwalletinfo()
if self.options.descriptors: if self.options.descriptors:
assert_equal(wi['keypoolsize_hd_internal'], 18) assert_equal(wi['keypoolsize_hd_internal'], 24)
assert_equal(wi['keypoolsize'], 18) assert_equal(wi['keypoolsize'], 24)
else: else:
assert_equal(wi['keypoolsize_hd_internal'], 6) assert_equal(wi['keypoolsize_hd_internal'], 6)
assert_equal(wi['keypoolsize'], 6) assert_equal(wi['keypoolsize'], 6)
@ -132,8 +132,8 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].keypoolrefill(100) nodes[0].keypoolrefill(100)
wi = nodes[0].getwalletinfo() wi = nodes[0].getwalletinfo()
if self.options.descriptors: if self.options.descriptors:
assert_equal(wi['keypoolsize_hd_internal'], 300) assert_equal(wi['keypoolsize_hd_internal'], 400)
assert_equal(wi['keypoolsize'], 300) assert_equal(wi['keypoolsize'], 400)
else: else:
assert_equal(wi['keypoolsize_hd_internal'], 100) assert_equal(wi['keypoolsize_hd_internal'], 100)
assert_equal(wi['keypoolsize'], 100) assert_equal(wi['keypoolsize'], 100)

View file

@ -43,9 +43,9 @@ class ListDescriptorsTest(BitcoinTestFramework):
node.createwallet(wallet_name='w3', descriptors=True) node.createwallet(wallet_name='w3', descriptors=True)
result = node.get_wallet_rpc('w3').listdescriptors() result = node.get_wallet_rpc('w3').listdescriptors()
assert_equal("w3", result['wallet_name']) assert_equal("w3", result['wallet_name'])
assert_equal(6, len(result['descriptors'])) assert_equal(8, len(result['descriptors']))
assert_equal(6, len([d for d in result['descriptors'] if d['active']])) assert_equal(8, 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(4, len([d for d in result['descriptors'] if d['internal']]))
for item in result['descriptors']: for item in result['descriptors']:
assert item['desc'] != '' assert item['desc'] != ''
assert item['next'] == 0 assert item['next'] == 0