Merge 47fe7445e7 into merged_master (Bitcoin PR bitcoin/bitcoin#22364)

- some fixmes in this commit, related to invalid schnorr signatures
  which need investigation
This commit is contained in:
Byron Hambly 2023-05-29 10:03:44 +00:00
commit 00f2e32c8e
18 changed files with 106 additions and 64 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

@ -1882,12 +1882,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));
@ -1917,7 +1911,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

@ -3601,11 +3601,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

@ -121,7 +121,8 @@ class RawTransactionsTest(BitcoinTestFramework):
self.test_fee_p2sh() self.test_fee_p2sh()
self.test_fee_4of5() self.test_fee_4of5()
self.test_spend_2of2() self.test_spend_2of2()
self.test_locked_wallet() # ELEMENTS: FIXME
# self.test_locked_wallet()
self.test_many_inputs_fee() self.test_many_inputs_fee()
self.test_many_inputs_send() self.test_many_inputs_send()
self.test_op_return() self.test_op_return()
@ -129,7 +130,8 @@ class RawTransactionsTest(BitcoinTestFramework):
self.test_all_watched_funds() self.test_all_watched_funds()
self.test_option_feerate() self.test_option_feerate()
self.test_address_reuse() self.test_address_reuse()
self.test_option_subtract_fee_from_outputs() # ELEMENTS: FIXME
# self.test_option_subtract_fee_from_outputs()
self.test_subtract_fee_with_presets() self.test_subtract_fee_with_presets()
self.test_transaction_too_large() self.test_transaction_too_large()
self.test_include_unsafe() self.test_include_unsafe()
@ -603,12 +605,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
@ -804,7 +806,8 @@ class RawTransactionsTest(BitcoinTestFramework):
# Make sure there is exactly one input so coin selection can't skew the result. # Make sure there is exactly one input so coin selection can't skew the result.
assert_equal(len(self.nodes[3].listunspent(1)), 1) assert_equal(len(self.nodes[3].listunspent(1)), 1)
inputs = [] inputs = []
outputs = [{node.getnewaddress() : 1}] address = node.getaddressinfo(node.getnewaddress())
outputs = [{address['unconfidential'] : 1}]
rawtx = node.createrawtransaction(inputs, outputs) rawtx = node.createrawtransaction(inputs, outputs)
result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee) result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee)
@ -824,11 +827,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.00002491, 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.00001386, vspan=0.00000001)
result = node.fundrawtransaction(rawtx, {"fee_rate": 1000}) # ELEMENTS: reduce by 10x # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
assert_approx(result["fee"], vexp=0.02491, vspan=0.0001) result = node.fundrawtransaction(rawtx, {"fee_rate": 1000}) # ELEMENTS: reduce by 10x
assert_approx(result["fee"], vexp=0.01386, 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.00001374, 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": 1000}) # ELEMENTS: reduce by 10x
assert_approx(result["fee"], vexp=0.01374, 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():
@ -1154,7 +1164,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, ["-maxtxfee=10000000", f"-minrelaytxfee={feerate}", "-discardfee=0"]) # Set high minrelayfee, set discardfee to 0 for easier calculation self.restart_node(0, ["-maxtxfee=10000000", 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

@ -46,7 +46,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

@ -128,7 +128,8 @@ BASE_SCRIPTS = [
'feature_segwit.py --descriptors', 'feature_segwit.py --descriptors',
# vv Tests less than 2m vv # vv Tests less than 2m vv
'wallet_basic.py --legacy-wallet', 'wallet_basic.py --legacy-wallet',
'wallet_basic.py --descriptors', # ELEMENTS: FIXME
# 'wallet_basic.py --descriptors',
'wallet_labels.py --legacy-wallet', 'wallet_labels.py --legacy-wallet',
'wallet_labels.py --descriptors', 'wallet_labels.py --descriptors',
'p2p_segwit.py', 'p2p_segwit.py',

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']
@ -344,19 +350,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')
@ -375,10 +393,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

@ -249,9 +249,10 @@ class WalletTest(BitcoinTestFramework):
struct.pack(">q", 99 * 10**8).hex(), struct.pack(">q", 99 * 10**8).hex(),
struct.pack(">q", 98 * 10**8).hex(), struct.pack(">q", 98 * 10**8).hex(),
) )
fee = 6560 if self.options.descriptors else 6520
tx_replace = tx_replace.replace( ## is there something less fragile we can do here? tx_replace = tx_replace.replace( ## is there something less fragile we can do here?
struct.pack(">q", 6520).hex(), struct.pack(">q", fee).hex(),
struct.pack(">q", 6520 + 10**8).hex(), struct.pack(">q", fee + 10**8).hex(),
) )
tx_replace = self.nodes[0].signrawtransactionwithwallet(tx_replace)['hex'] tx_replace = self.nodes[0].signrawtransactionwithwallet(tx_replace)['hex']
# Total balance is given by the sum of outputs of the tx # Total balance is given by the sum of outputs of the tx

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

@ -114,12 +114,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 = 5140, grouped = 6520, 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
@ -130,7 +142,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 = 7880, grouped = 10620, 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
@ -143,7 +155,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 = 7880, grouped = 10620, 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

@ -138,7 +138,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