Merge bitcoin/bitcoin#32597: wallet: Always set descriptor cache upgraded flag for new wallets
47237cd193wallet, rpc: Output wallet flags in getwalletinfo (Ava Chow)bc2a26b296wallet: Add GetWalletFlags (Ava Chow)69f588a99awallet: Set upgraded descriptor cache flag for newly created wallets (Ava Chow) Pull request description: Newly created wallets will always have an upgraded descriptor cache, so set those. Also, to verify this behavior, add a new `flags` field to `getwalletinfo` and check that in the functional tests. Split from #32489 ACKs for top commit: Sjors: ACK47237cd193w0xlt: ACK https://github.com/bitcoin/bitcoin/pull/32597/commits/47237cd1938058b29fdec242c3a37611e255fda0 rkrux: ACK47237cd193Tree-SHA512: 97c7f85b858efe5ced9b8aafb6cd7c1a547de6f8013b82bfc75bc567cf73c9db5e168e3980355756541305520022fd776b8d4d240d3fb34ed86c27d2acaf4863
This commit is contained in:
5 files changed
+53
-12
No files matched your search
@@ -61,6 +61,10 @@ static RPCHelpMan getwalletinfo()
|
|||||||
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
|
{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},
|
||||||
{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
|
{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
|
||||||
{RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
|
{RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
|
||||||
|
{RPCResult::Type::ARR, "flags", "The flags currently set on the wallet",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::STR, "flag", "The name of the flag"},
|
||||||
|
}},
|
||||||
RESULT_LAST_PROCESSED_BLOCK,
|
RESULT_LAST_PROCESSED_BLOCK,
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
@@ -116,6 +120,21 @@ static RPCHelpMan getwalletinfo()
|
|||||||
obj.pushKV("birthtime", birthtime);
|
obj.pushKV("birthtime", birthtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push known flags
|
||||||
|
UniValue flags(UniValue::VARR);
|
||||||
|
uint64_t wallet_flags = pwallet->GetWalletFlags();
|
||||||
|
for (uint64_t i = 0; i < 64; ++i) {
|
||||||
|
uint64_t flag = uint64_t{1} << i;
|
||||||
|
if (flag & wallet_flags) {
|
||||||
|
if (flag & KNOWN_WALLET_FLAGS) {
|
||||||
|
flags.push_back(WALLET_FLAG_TO_STRING.at(WalletFlags{flag}));
|
||||||
|
} else {
|
||||||
|
flags.push_back(strprintf("unknown_flag_%u", i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.pushKV("flags", flags);
|
||||||
|
|
||||||
AppendLastProcessedBlock(obj, *pwallet);
|
AppendLastProcessedBlock(obj, *pwallet);
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
@@ -267,7 +286,7 @@ static RPCHelpMan loadwallet()
|
|||||||
static RPCHelpMan setwalletflag()
|
static RPCHelpMan setwalletflag()
|
||||||
{
|
{
|
||||||
std::string flags;
|
std::string flags;
|
||||||
for (auto& it : WALLET_FLAG_MAP)
|
for (auto& it : STRING_TO_WALLET_FLAG)
|
||||||
if (it.second & MUTABLE_WALLET_FLAGS)
|
if (it.second & MUTABLE_WALLET_FLAGS)
|
||||||
flags += (flags == "" ? "" : ", ") + it.first;
|
flags += (flags == "" ? "" : ", ") + it.first;
|
||||||
|
|
||||||
@@ -298,11 +317,11 @@ static RPCHelpMan setwalletflag()
|
|||||||
std::string flag_str = request.params[0].get_str();
|
std::string flag_str = request.params[0].get_str();
|
||||||
bool value = request.params[1].isNull() || request.params[1].get_bool();
|
bool value = request.params[1].isNull() || request.params[1].get_bool();
|
||||||
|
|
||||||
if (!WALLET_FLAG_MAP.count(flag_str)) {
|
if (!STRING_TO_WALLET_FLAG.count(flag_str)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto flag = WALLET_FLAG_MAP.at(flag_str);
|
auto flag = STRING_TO_WALLET_FLAG.at(flag_str);
|
||||||
|
|
||||||
if (!(flag & MUTABLE_WALLET_FLAGS)) {
|
if (!(flag & MUTABLE_WALLET_FLAGS)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
|
||||||
|
|||||||
@@ -1711,6 +1711,11 @@ void CWallet::InitWalletFlags(uint64_t flags)
|
|||||||
if (!LoadWalletFlags(flags)) assert(false);
|
if (!LoadWalletFlags(flags)) assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t CWallet::GetWalletFlags() const
|
||||||
|
{
|
||||||
|
return m_wallet_flags;
|
||||||
|
}
|
||||||
|
|
||||||
void CWallet::MaybeUpdateBirthTime(int64_t time)
|
void CWallet::MaybeUpdateBirthTime(int64_t time)
|
||||||
{
|
{
|
||||||
int64_t birthtime = m_birth_time.load();
|
int64_t birthtime = m_birth_time.load();
|
||||||
@@ -2862,7 +2867,9 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
|
|||||||
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
|
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
|
||||||
walletInstance->SetMinVersion(FEATURE_LATEST);
|
walletInstance->SetMinVersion(FEATURE_LATEST);
|
||||||
|
|
||||||
walletInstance->InitWalletFlags(wallet_creation_flags);
|
// Init with passed flags.
|
||||||
|
// Always set the cache upgrade flag as this feature is supported from the beginning.
|
||||||
|
walletInstance->InitWalletFlags(wallet_creation_flags | WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);
|
||||||
|
|
||||||
// Only descriptor wallets can be created
|
// Only descriptor wallets can be created
|
||||||
assert(walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
assert(walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
|
||||||
|
|||||||
+20
-8
@@ -160,14 +160,24 @@ static constexpr uint64_t KNOWN_WALLET_FLAGS =
|
|||||||
static constexpr uint64_t MUTABLE_WALLET_FLAGS =
|
static constexpr uint64_t MUTABLE_WALLET_FLAGS =
|
||||||
WALLET_FLAG_AVOID_REUSE;
|
WALLET_FLAG_AVOID_REUSE;
|
||||||
|
|
||||||
static const std::map<std::string,WalletFlags> WALLET_FLAG_MAP{
|
static const std::map<WalletFlags, std::string> WALLET_FLAG_TO_STRING{
|
||||||
{"avoid_reuse", WALLET_FLAG_AVOID_REUSE},
|
{WALLET_FLAG_AVOID_REUSE, "avoid_reuse"},
|
||||||
{"blank", WALLET_FLAG_BLANK_WALLET},
|
{WALLET_FLAG_BLANK_WALLET, "blank"},
|
||||||
{"key_origin_metadata", WALLET_FLAG_KEY_ORIGIN_METADATA},
|
{WALLET_FLAG_KEY_ORIGIN_METADATA, "key_origin_metadata"},
|
||||||
{"last_hardened_xpub_cached", WALLET_FLAG_LAST_HARDENED_XPUB_CACHED},
|
{WALLET_FLAG_LAST_HARDENED_XPUB_CACHED, "last_hardened_xpub_cached"},
|
||||||
{"disable_private_keys", WALLET_FLAG_DISABLE_PRIVATE_KEYS},
|
{WALLET_FLAG_DISABLE_PRIVATE_KEYS, "disable_private_keys"},
|
||||||
{"descriptor_wallet", WALLET_FLAG_DESCRIPTORS},
|
{WALLET_FLAG_DESCRIPTORS, "descriptor_wallet"},
|
||||||
{"external_signer", WALLET_FLAG_EXTERNAL_SIGNER}
|
{WALLET_FLAG_EXTERNAL_SIGNER, "external_signer"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<std::string, WalletFlags> STRING_TO_WALLET_FLAG{
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_AVOID_REUSE), WALLET_FLAG_AVOID_REUSE},
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_BLANK_WALLET), WALLET_FLAG_BLANK_WALLET},
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_KEY_ORIGIN_METADATA), WALLET_FLAG_KEY_ORIGIN_METADATA},
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED), WALLET_FLAG_LAST_HARDENED_XPUB_CACHED},
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_DISABLE_PRIVATE_KEYS), WALLET_FLAG_DISABLE_PRIVATE_KEYS},
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_DESCRIPTORS), WALLET_FLAG_DESCRIPTORS},
|
||||||
|
{WALLET_FLAG_TO_STRING.at(WALLET_FLAG_EXTERNAL_SIGNER), WALLET_FLAG_EXTERNAL_SIGNER}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A wrapper to reserve an address from a wallet
|
/** A wrapper to reserve an address from a wallet
|
||||||
@@ -904,6 +914,8 @@ public:
|
|||||||
void InitWalletFlags(uint64_t flags);
|
void InitWalletFlags(uint64_t flags);
|
||||||
/** Loads the flags into the wallet. (used by LoadWallet) */
|
/** Loads the flags into the wallet. (used by LoadWallet) */
|
||||||
bool LoadWalletFlags(uint64_t flags);
|
bool LoadWalletFlags(uint64_t flags);
|
||||||
|
//! Retrieve all of the wallet's flags
|
||||||
|
uint64_t GetWalletFlags() const;
|
||||||
|
|
||||||
/** Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet has no name */
|
/** Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet has no name */
|
||||||
std::string GetDisplayName() const override
|
std::string GetDisplayName() const override
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ class AvoidReuseTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Flags should be node1.avoid_reuse=false, node2.avoid_reuse=true
|
# Flags should be node1.avoid_reuse=false, node2.avoid_reuse=true
|
||||||
assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False)
|
assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False)
|
||||||
|
assert_equal(sorted(self.nodes[0].getwalletinfo()["flags"]), sorted(["descriptor_wallet", "last_hardened_xpub_cached"]))
|
||||||
assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True)
|
assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True)
|
||||||
|
assert_equal(sorted(self.nodes[1].getwalletinfo()["flags"]), sorted(["descriptor_wallet", "last_hardened_xpub_cached", "avoid_reuse"]))
|
||||||
|
|
||||||
self.restart_node(1)
|
self.restart_node(1)
|
||||||
self.connect_nodes(0, 1)
|
self.connect_nodes(0, 1)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class CreateWalletTest(BitcoinTestFramework):
|
|||||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getrawchangeaddress)
|
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getrawchangeaddress)
|
||||||
import_res = w1.importdescriptors([{"desc": w0.getaddressinfo(address1)['desc'], "timestamp": "now"}])
|
import_res = w1.importdescriptors([{"desc": w0.getaddressinfo(address1)['desc'], "timestamp": "now"}])
|
||||||
assert_equal(import_res[0]["success"], True)
|
assert_equal(import_res[0]["success"], True)
|
||||||
|
assert_equal(sorted(w1.getwalletinfo()["flags"]), sorted(["last_hardened_xpub_cached", "descriptor_wallet", "disable_private_keys"]))
|
||||||
|
|
||||||
self.log.info('Test that private keys cannot be imported')
|
self.log.info('Test that private keys cannot be imported')
|
||||||
privkey, pubkey = generate_keypair(wif=True)
|
privkey, pubkey = generate_keypair(wif=True)
|
||||||
|
|||||||
Reference in new issue
Block a user