mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-22 15:04:44 +01:00
Disallow bech32m addresses for legacy wallet things
We don't want the legacy wallet to ever have bech32m addresses so don't allow importing them. This includes addmultisigaddress as that is a legacy wallet only RPC Additionally, bech32m multisigs are not available yet, so disallow them in createmultisig.
This commit is contained in:
parent
6dbe4d1072
commit
87a0e7a3b7
12 changed files with 113 additions and 41 deletions
|
@ -108,3 +108,19 @@ CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore,
|
||||||
} // no default case, so the compiler can warn about missing cases
|
} // no default case, so the compiler can warn about missing cases
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) {
|
||||||
|
if (std::holds_alternative<PKHash>(dest) ||
|
||||||
|
std::holds_alternative<ScriptHash>(dest)) {
|
||||||
|
return OutputType::LEGACY;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<WitnessV0KeyHash>(dest) ||
|
||||||
|
std::holds_alternative<WitnessV0ScriptHash>(dest)) {
|
||||||
|
return OutputType::BECH32;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<WitnessV1Taproot>(dest) ||
|
||||||
|
std::holds_alternative<WitnessUnknown>(dest)) {
|
||||||
|
return OutputType::BECH32M;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
|
@ -47,4 +47,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
|
||||||
*/
|
*/
|
||||||
CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType);
|
CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType);
|
||||||
|
|
||||||
|
/** Get the OutputType for a CTxDestination */
|
||||||
|
std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest);
|
||||||
|
|
||||||
#endif // BITCOIN_OUTPUTTYPE_H
|
#endif // BITCOIN_OUTPUTTYPE_H
|
||||||
|
|
|
@ -131,6 +131,9 @@ static RPCHelpMan createmultisig()
|
||||||
if (!ParseOutputType(request.params[2].get_str(), output_type)) {
|
if (!ParseOutputType(request.params[2].get_str(), output_type)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[2].get_str()));
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[2].get_str()));
|
||||||
}
|
}
|
||||||
|
if (output_type == OutputType::BECH32M) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "createmultisig cannot create bech32m multisig addresses");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct using pay-to-script-hash:
|
// Construct using pay-to-script-hash:
|
||||||
|
|
|
@ -640,22 +640,6 @@ public:
|
||||||
std::optional<OutputType> GetOutputType() const override { return std::nullopt; }
|
std::optional<OutputType> GetOutputType() const override { return std::nullopt; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) {
|
|
||||||
if (std::holds_alternative<PKHash>(dest) ||
|
|
||||||
std::holds_alternative<ScriptHash>(dest)) {
|
|
||||||
return OutputType::LEGACY;
|
|
||||||
}
|
|
||||||
if (std::holds_alternative<WitnessV0KeyHash>(dest) ||
|
|
||||||
std::holds_alternative<WitnessV0ScriptHash>(dest)) {
|
|
||||||
return OutputType::BECH32;
|
|
||||||
}
|
|
||||||
if (std::holds_alternative<WitnessV1Taproot>(dest) ||
|
|
||||||
std::holds_alternative<WitnessUnknown>(dest)) {
|
|
||||||
return OutputType::BECH32M;
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A parsed addr(A) descriptor. */
|
/** A parsed addr(A) descriptor. */
|
||||||
class AddressDescriptor final : public DescriptorImpl
|
class AddressDescriptor final : public DescriptorImpl
|
||||||
{
|
{
|
||||||
|
|
|
@ -286,6 +286,9 @@ RPCHelpMan importaddress()
|
||||||
if (fP2SH) {
|
if (fP2SH) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
|
||||||
}
|
}
|
||||||
|
if (OutputTypeFromDestination(dest) == OutputType::BECH32M) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m addresses cannot be imported into legacy wallets");
|
||||||
|
}
|
||||||
|
|
||||||
pwallet->MarkDirty();
|
pwallet->MarkDirty();
|
||||||
|
|
||||||
|
@ -962,6 +965,9 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP
|
||||||
if (!IsValidDestination(dest)) {
|
if (!IsValidDestination(dest)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
|
||||||
}
|
}
|
||||||
|
if (OutputTypeFromDestination(dest) == OutputType::BECH32M) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m addresses cannot be imported into legacy wallets");
|
||||||
|
}
|
||||||
script = GetScriptForDestination(dest);
|
script = GetScriptForDestination(dest);
|
||||||
} else {
|
} else {
|
||||||
if (!IsHex(output)) {
|
if (!IsHex(output)) {
|
||||||
|
@ -1086,6 +1092,9 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
||||||
if (!parsed_desc) {
|
if (!parsed_desc) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error);
|
||||||
}
|
}
|
||||||
|
if (parsed_desc->GetOutputType() == OutputType::BECH32M) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m descriptors cannot be imported into legacy wallets");
|
||||||
|
}
|
||||||
|
|
||||||
have_solving_data = parsed_desc->IsSolvable();
|
have_solving_data = parsed_desc->IsSolvable();
|
||||||
const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
|
const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
|
||||||
|
|
|
@ -269,6 +269,9 @@ static RPCHelpMan getnewaddress()
|
||||||
if (!ParseOutputType(request.params[1].get_str(), output_type)) {
|
if (!ParseOutputType(request.params[1].get_str(), output_type)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
|
||||||
}
|
}
|
||||||
|
if (output_type == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination dest;
|
CTxDestination dest;
|
||||||
|
@ -313,6 +316,9 @@ static RPCHelpMan getrawchangeaddress()
|
||||||
if (!ParseOutputType(request.params[0].get_str(), output_type)) {
|
if (!ParseOutputType(request.params[0].get_str(), output_type)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
|
||||||
}
|
}
|
||||||
|
if (output_type == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CTxDestination dest;
|
CTxDestination dest;
|
||||||
|
@ -1004,6 +1010,9 @@ static RPCHelpMan addmultisigaddress()
|
||||||
if (!ParseOutputType(request.params[3].get_str(), output_type)) {
|
if (!ParseOutputType(request.params[3].get_str(), output_type)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
|
||||||
}
|
}
|
||||||
|
if (output_type == OutputType::BECH32M) {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m multisig addresses cannot be created with legacy wallets");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct using pay-to-script-hash:
|
// Construct using pay-to-script-hash:
|
||||||
|
|
|
@ -26,6 +26,7 @@ bool LegacyScriptPubKeyMan::GetNewDestination(const OutputType type, CTxDestinat
|
||||||
error = _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types").translated;
|
error = _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types").translated;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
assert(type != OutputType::BECH32M);
|
||||||
|
|
||||||
LOCK(cs_KeyStore);
|
LOCK(cs_KeyStore);
|
||||||
error.clear();
|
error.clear();
|
||||||
|
@ -299,6 +300,7 @@ bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool i
|
||||||
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
|
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
assert(type != OutputType::BECH32M);
|
||||||
|
|
||||||
LOCK(cs_KeyStore);
|
LOCK(cs_KeyStore);
|
||||||
if (!CanGetAddresses(internal)) {
|
if (!CanGetAddresses(internal)) {
|
||||||
|
@ -1303,6 +1305,7 @@ void LegacyScriptPubKeyMan::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const
|
||||||
|
|
||||||
void LegacyScriptPubKeyMan::KeepDestination(int64_t nIndex, const OutputType& type)
|
void LegacyScriptPubKeyMan::KeepDestination(int64_t nIndex, const OutputType& type)
|
||||||
{
|
{
|
||||||
|
assert(type != OutputType::BECH32M);
|
||||||
// Remove from key pool
|
// Remove from key pool
|
||||||
WalletBatch batch(m_storage.GetDatabase());
|
WalletBatch batch(m_storage.GetDatabase());
|
||||||
batch.ErasePool(nIndex);
|
batch.ErasePool(nIndex);
|
||||||
|
@ -1336,6 +1339,7 @@ void LegacyScriptPubKeyMan::ReturnDestination(int64_t nIndex, bool fInternal, co
|
||||||
|
|
||||||
bool LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const OutputType type, bool internal)
|
bool LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey& result, const OutputType type, bool internal)
|
||||||
{
|
{
|
||||||
|
assert(type != OutputType::BECH32M);
|
||||||
if (!CanGetAddresses(internal)) {
|
if (!CanGetAddresses(internal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1404,6 +1408,7 @@ bool LegacyScriptPubKeyMan::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& key
|
||||||
|
|
||||||
void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType type)
|
void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType type)
|
||||||
{
|
{
|
||||||
|
assert(type != OutputType::BECH32M);
|
||||||
if (key.IsCompressed() && (type == OutputType::P2SH_SEGWIT || type == OutputType::BECH32)) {
|
if (key.IsCompressed() && (type == OutputType::P2SH_SEGWIT || type == OutputType::BECH32)) {
|
||||||
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
|
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
|
||||||
CScript witprog = GetScriptForDestination(witdest);
|
CScript witprog = GetScriptForDestination(witdest);
|
||||||
|
|
|
@ -97,6 +97,9 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
sorted_key_desc = descsum_create('sh(multi(2,{}))'.format(sorted_key_str))
|
sorted_key_desc = descsum_create('sh(multi(2,{}))'.format(sorted_key_str))
|
||||||
assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address'])
|
assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address'])
|
||||||
|
|
||||||
|
# Check that bech32m is currently not allowed
|
||||||
|
assert_raises_rpc_error(-5, "createmultisig cannot create bech32m multisig addresses", self.nodes[0].createmultisig, 2, self.pub, "bech32m")
|
||||||
|
|
||||||
def check_addmultisigaddress_errors(self):
|
def check_addmultisigaddress_errors(self):
|
||||||
if self.options.descriptors:
|
if self.options.descriptors:
|
||||||
return
|
return
|
||||||
|
@ -108,6 +111,10 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
|
||||||
self.nodes[0].importaddress(a)
|
self.nodes[0].importaddress(a)
|
||||||
assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
|
assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
|
||||||
|
|
||||||
|
# Bech32m address type is disallowed for legacy wallets
|
||||||
|
pubs = [self.nodes[1].getaddressinfo(addr)["pubkey"] for addr in addresses]
|
||||||
|
assert_raises_rpc_error(-5, "Bech32m multisig addresses cannot be created with legacy wallets", self.nodes[0].addmultisigaddress, 2, pubs, "", "bech32m")
|
||||||
|
|
||||||
def checkbalances(self):
|
def checkbalances(self):
|
||||||
node0, node1, node2 = self.nodes
|
node0, node1, node2 = self.nodes
|
||||||
node0.generate(COINBASE_MATURITY)
|
node0.generate(COINBASE_MATURITY)
|
||||||
|
|
|
@ -373,5 +373,15 @@ class AddressTypeTest(BitcoinTestFramework):
|
||||||
self.test_address(4, self.nodes[4].getrawchangeaddress(), multisig=False, typ='p2sh-segwit')
|
self.test_address(4, self.nodes[4].getrawchangeaddress(), multisig=False, typ='p2sh-segwit')
|
||||||
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:
|
||||||
|
self.log.info("Descriptor wallets do not have bech32m addreses 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: Keypool ran out, please call keypoolrefill first", self.nodes[0].getrawchangeaddress, "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")
|
||||||
|
assert_raises_rpc_error(-8, "Legacy wallets cannot provide bech32m addresses", self.nodes[0].getrawchangeaddress, "bech32m")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
AddressTypeTest().main()
|
AddressTypeTest().main()
|
||||||
|
|
|
@ -420,6 +420,9 @@ class WalletTest(BitcoinTestFramework):
|
||||||
# This will raise an exception for importing an invalid pubkey
|
# This will raise an exception for importing an invalid pubkey
|
||||||
assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f")
|
assert_raises_rpc_error(-5, "Pubkey is not a valid public key", self.nodes[0].importpubkey, "5361746f736869204e616b616d6f746f")
|
||||||
|
|
||||||
|
# Bech32m addresses cannot be imported into a legacy wallet
|
||||||
|
assert_raises_rpc_error(-5, "Bech32m addresses cannot be imported into legacy wallets", self.nodes[0].importaddress, "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6")
|
||||||
|
|
||||||
# Import address and private key to check correct behavior of spendable unspents
|
# Import address and private key to check correct behavior of spendable unspents
|
||||||
# 1. Send some coins to generate new UTXO
|
# 1. Send some coins to generate new UTXO
|
||||||
address_to_import = self.nodes[2].getnewaddress()
|
address_to_import = self.nodes[2].getnewaddress()
|
||||||
|
|
|
@ -746,6 +746,27 @@ class ImportMultiTest(BitcoinTestFramework):
|
||||||
assert 'hdmasterfingerprint' not in pub_import_info
|
assert 'hdmasterfingerprint' not in pub_import_info
|
||||||
assert 'hdkeypath' not in pub_import_info
|
assert 'hdkeypath' not in pub_import_info
|
||||||
|
|
||||||
|
# Bech32m addresses and descriptors cannot be imported
|
||||||
|
self.log.info("Bech32m addresses and descriptors cannot be imported")
|
||||||
|
self.test_importmulti(
|
||||||
|
{
|
||||||
|
"scriptPubKey": {"address": "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6"},
|
||||||
|
"timestamp": "now",
|
||||||
|
},
|
||||||
|
success=False,
|
||||||
|
error_code=-5,
|
||||||
|
error_message="Bech32m addresses cannot be imported into legacy wallets",
|
||||||
|
)
|
||||||
|
self.test_importmulti(
|
||||||
|
{
|
||||||
|
"desc": descsum_create("tr({})".format(pub)),
|
||||||
|
"timestamp": "now",
|
||||||
|
},
|
||||||
|
success=False,
|
||||||
|
error_code=-5,
|
||||||
|
error_message="Bech32m descriptors cannot be imported into legacy wallets",
|
||||||
|
)
|
||||||
|
|
||||||
# Import some public keys to the keypool of a no privkey wallet
|
# Import some public keys to the keypool of a no privkey wallet
|
||||||
self.log.info("Adding pubkey to keypool of disableprivkey wallet")
|
self.log.info("Adding pubkey to keypool of disableprivkey wallet")
|
||||||
self.nodes[1].createwallet(wallet_name="noprivkeys", disable_private_keys=True)
|
self.nodes[1].createwallet(wallet_name="noprivkeys", disable_private_keys=True)
|
||||||
|
|
|
@ -135,31 +135,33 @@ class WalletLabelsTest(BitcoinTestFramework):
|
||||||
# in the label. This is a no-op.
|
# in the label. This is a no-op.
|
||||||
change_label(node, labels[2].addresses[0], labels[2], labels[2])
|
change_label(node, labels[2].addresses[0], labels[2], labels[2])
|
||||||
|
|
||||||
self.log.info('Check watchonly labels')
|
if self.options.descriptors:
|
||||||
node.createwallet(wallet_name='watch_only', disable_private_keys=True)
|
# This is a descriptor wallet test because of segwit v1+ addresses
|
||||||
wallet_watch_only = node.get_wallet_rpc('watch_only')
|
self.log.info('Check watchonly labels')
|
||||||
BECH32_VALID = {
|
node.createwallet(wallet_name='watch_only', disable_private_keys=True)
|
||||||
'✔️_VER15_PROG40': 'bcrt10qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxkg7fn',
|
wallet_watch_only = node.get_wallet_rpc('watch_only')
|
||||||
'✔️_VER16_PROG03': 'bcrt1sqqqqq8uhdgr',
|
BECH32_VALID = {
|
||||||
'✔️_VER16_PROB02': 'bcrt1sqqqq4wstyw',
|
'✔️_VER15_PROG40': 'bcrt10qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxkg7fn',
|
||||||
}
|
'✔️_VER16_PROG03': 'bcrt1sqqqqq8uhdgr',
|
||||||
BECH32_INVALID = {
|
'✔️_VER16_PROB02': 'bcrt1sqqqq4wstyw',
|
||||||
'❌_VER15_PROG41': 'bcrt1sqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqajlxj8',
|
}
|
||||||
'❌_VER16_PROB01': 'bcrt1sqq5r4036',
|
BECH32_INVALID = {
|
||||||
}
|
'❌_VER15_PROG41': 'bcrt1sqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqajlxj8',
|
||||||
for l in BECH32_VALID:
|
'❌_VER16_PROB01': 'bcrt1sqq5r4036',
|
||||||
ad = BECH32_VALID[l]
|
}
|
||||||
wallet_watch_only.importaddress(label=l, rescan=False, address=ad)
|
for l in BECH32_VALID:
|
||||||
node.generatetoaddress(1, ad)
|
ad = BECH32_VALID[l]
|
||||||
assert_equal(wallet_watch_only.getaddressesbylabel(label=l), {ad: {'purpose': 'receive'}})
|
wallet_watch_only.importaddress(label=l, rescan=False, address=ad)
|
||||||
assert_equal(wallet_watch_only.getreceivedbylabel(label=l), 0)
|
node.generatetoaddress(1, ad)
|
||||||
for l in BECH32_INVALID:
|
assert_equal(wallet_watch_only.getaddressesbylabel(label=l), {ad: {'purpose': 'receive'}})
|
||||||
ad = BECH32_INVALID[l]
|
assert_equal(wallet_watch_only.getreceivedbylabel(label=l), 0)
|
||||||
assert_raises_rpc_error(
|
for l in BECH32_INVALID:
|
||||||
-5,
|
ad = BECH32_INVALID[l]
|
||||||
"Address is not valid" if self.options.descriptors else "Invalid Bitcoin address or script",
|
assert_raises_rpc_error(
|
||||||
lambda: wallet_watch_only.importaddress(label=l, rescan=False, address=ad),
|
-5,
|
||||||
)
|
"Address is not valid" if self.options.descriptors else "Invalid Bitcoin address or script",
|
||||||
|
lambda: wallet_watch_only.importaddress(label=l, rescan=False, address=ad),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Label:
|
class Label:
|
||||||
|
|
Loading…
Add table
Reference in a new issue