mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 06:49:38 -04:00
wallet, rpc: Only allow keypool import from single key descriptors
Legacy wallets should only import keys to the keypool if they came in a single key descriptor. Instead of relying on assumptions about the descriptor based on how many pubkeys show up after expanding the descriptor, explicitly mark descriptors as being single key type and use that for the check.
This commit is contained in:
parent
99a4ddf5ab
commit
0ff072caa1
4 changed files with 26 additions and 2 deletions
|
@ -800,6 +800,7 @@ public:
|
|||
return OutputTypeFromDestination(m_destination);
|
||||
}
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return GetScriptForDestination(m_destination).size(); }
|
||||
|
@ -827,6 +828,7 @@ public:
|
|||
return OutputTypeFromDestination(dest);
|
||||
}
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
bool ToPrivateString(const SigningProvider& arg, std::string& out) const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return m_script.size(); }
|
||||
|
@ -855,6 +857,7 @@ protected:
|
|||
public:
|
||||
PKDescriptor(std::unique_ptr<PubkeyProvider> prov, bool xonly = false) : DescriptorImpl(Vector(std::move(prov)), "pk"), m_xonly(xonly) {}
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return true; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override {
|
||||
return 1 + (m_xonly ? 32 : m_pubkey_args[0]->GetSize()) + 1;
|
||||
|
@ -891,6 +894,7 @@ public:
|
|||
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "pkh") {}
|
||||
std::optional<OutputType> GetOutputType() const override { return OutputType::LEGACY; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return true; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 1 + 20 + 1 + 1; }
|
||||
|
||||
|
@ -925,6 +929,7 @@ public:
|
|||
WPKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "wpkh") {}
|
||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return true; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 20; }
|
||||
|
||||
|
@ -967,6 +972,7 @@ protected:
|
|||
public:
|
||||
ComboDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Vector(std::move(prov)), "combo") {}
|
||||
bool IsSingleType() const final { return false; }
|
||||
bool IsSingleKey() const final { return true; }
|
||||
std::unique_ptr<DescriptorImpl> Clone() const override
|
||||
{
|
||||
return std::make_unique<ComboDescriptor>(m_pubkey_args.at(0)->Clone());
|
||||
|
@ -991,6 +997,7 @@ protected:
|
|||
public:
|
||||
MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti" : "multi"), m_threshold(threshold), m_sorted(sorted) {}
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override {
|
||||
const auto n_keys = m_pubkey_args.size();
|
||||
|
@ -1042,6 +1049,7 @@ protected:
|
|||
public:
|
||||
MultiADescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers, bool sorted = false) : DescriptorImpl(std::move(providers), sorted ? "sortedmulti_a" : "multi_a"), m_threshold(threshold), m_sorted(sorted) {}
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override {
|
||||
const auto n_keys = m_pubkey_args.size();
|
||||
|
@ -1088,6 +1096,7 @@ public:
|
|||
return OutputType::LEGACY;
|
||||
}
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return m_subdescriptor_args[0]->IsSingleKey(); }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 20 + 1; }
|
||||
|
||||
|
@ -1129,6 +1138,7 @@ public:
|
|||
WSHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "wsh") {}
|
||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return m_subdescriptor_args[0]->IsSingleKey(); }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
||||
|
||||
|
@ -1207,6 +1217,7 @@ public:
|
|||
}
|
||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
||||
|
||||
|
@ -1334,6 +1345,7 @@ public:
|
|||
|
||||
bool IsSolvable() const override { return true; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return m_node->ScriptSize(); }
|
||||
|
||||
|
@ -1373,6 +1385,7 @@ public:
|
|||
RawTRDescriptor(std::unique_ptr<PubkeyProvider> output_key) : DescriptorImpl(Vector(std::move(output_key)), "rawtr") {}
|
||||
std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
|
||||
bool IsSingleType() const final { return true; }
|
||||
bool IsSingleKey() const final { return false; }
|
||||
|
||||
std::optional<int64_t> ScriptSize() const override { return 1 + 1 + 32; }
|
||||
|
||||
|
|
|
@ -111,6 +111,11 @@ struct Descriptor {
|
|||
/** Whether this descriptor will return one scriptPubKey or multiple (aka is or is not combo) */
|
||||
virtual bool IsSingleType() const = 0;
|
||||
|
||||
/** Whether this descriptor only produces single key scripts (i.e. pk(), pkh(), wpkh(), sh() and wsh() nested of those, and combo())
|
||||
* TODO: Remove this method once legacy wallets are removed as it is only necessary for importmulti.
|
||||
*/
|
||||
virtual bool IsSingleKey() const = 0;
|
||||
|
||||
/** Convert the descriptor to a private string. This fails if the provided provider does not have the relevant private keys. */
|
||||
virtual bool ToPrivateString(const SigningProvider& provider, std::string& out) const = 0;
|
||||
|
||||
|
|
|
@ -1091,6 +1091,9 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
|||
std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
|
||||
}
|
||||
|
||||
// Only single key descriptors are allowed to be imported to a legacy wallet's keypool
|
||||
bool can_keypool = parsed_descs.at(0)->IsSingleKey();
|
||||
|
||||
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
|
||||
|
||||
for (size_t j = 0; j < parsed_descs.size(); ++j) {
|
||||
|
@ -1107,8 +1110,10 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
|
|||
std::vector<CScript> scripts_temp;
|
||||
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
|
||||
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
|
||||
for (const auto& key_pair : out_keys.pubkeys) {
|
||||
ordered_pubkeys.emplace_back(key_pair.first, desc_internal);
|
||||
if (can_keypool) {
|
||||
for (const auto& key_pair : out_keys.pubkeys) {
|
||||
ordered_pubkeys.emplace_back(key_pair.first, desc_internal);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& x : out_keys.scripts) {
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
bool IsRange() const override { return false; }
|
||||
bool IsSolvable() const override { return false; }
|
||||
bool IsSingleType() const override { return true; }
|
||||
bool IsSingleKey() const override { return true; }
|
||||
bool ToPrivateString(const SigningProvider& provider, std::string& out) const override { return false; }
|
||||
bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const override { return false; }
|
||||
bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const override { return false; };
|
||||
|
|
Loading…
Add table
Reference in a new issue