Skip to content

Commit

Permalink
Merge #15749: Fix: importmulti only imports origin info for PKH outputs
Browse files Browse the repository at this point in the history
b5d3987 Take non-importing keys into account for spendability warning in descriptor import (Pieter Wuille)
6e59700 Import all origin info in importmulti; even for non-importing pubkeys (Pieter Wuille)
9a93c91 Keep full pubkeys in FlatSigningProvider::origins (Pieter Wuille)

Pull request description:

  This fixes #15743 and #15742.

  Since #15263, pubkeys are no longer imported for non-PKH (or WPKH, or any wrapped form of those) outputs, as that would incorrectly mark outputs to single-key versions of multisig policies as watched.

  As a side effect, this change also caused origin info not to be imported anymore for multisig policies.

  Fix this by plumbing through the full pubkey information for origins in FlatSigningProvider, and then importing all origin info we have in `importmulti` (knowing more never hurts, and additional origin information has no negative consequences like importing the pubkeys themselves).

ACKs for commit b5d398:
  MeshCollider:
    utACK b5d3987

Tree-SHA512: 37caa2be8d01b8baa12f70a58eaa7c583f5f0afbe012e02936dd8790dc5dc852f880b77258b34ddb68cae30c029585f2d1c4f5d00015380557a1e8b471e500f3
  • Loading branch information
meshcollider committed Apr 9, 2019
2 parents db29856 + b5d3987 commit 54798c3
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/script/descriptor.cpp
Expand Up @@ -436,7 +436,7 @@ class DescriptorImpl : public Descriptor
pubkeys.reserve(entries.size()); pubkeys.reserve(entries.size());
for (auto& entry : entries) { for (auto& entry : entries) {
pubkeys.push_back(entry.first); pubkeys.push_back(entry.first);
out.origins.emplace(entry.first.GetID(), std::move(entry.second)); out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
} }
if (m_script_arg) { if (m_script_arg) {
for (const auto& subscript : subscripts) { for (const auto& subscript : subscripts) {
Expand Down
8 changes: 7 additions & 1 deletion src/script/sign.cpp
Expand Up @@ -483,7 +483,13 @@ bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& inf


bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); } bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); } bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return LookupHelper(origins, keyid, info); } bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
std::pair<CPubKey, KeyOriginInfo> out;
bool ret = LookupHelper(origins, keyid, out);
if (ret) info = std::move(out.second);
return ret;
}
bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); } bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }


FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b) FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
Expand Down
2 changes: 1 addition & 1 deletion src/script/sign.h
Expand Up @@ -77,7 +77,7 @@ struct FlatSigningProvider final : public SigningProvider
{ {
std::map<CScriptID, CScript> scripts; std::map<CScriptID, CScript> scripts;
std::map<CKeyID, CPubKey> pubkeys; std::map<CKeyID, CPubKey> pubkeys;
std::map<CKeyID, KeyOriginInfo> origins; std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
std::map<CKeyID, CKey> keys; std::map<CKeyID, CKey> keys;


bool GetCScript(const CScriptID& scriptid, CScript& script) const override; bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
Expand Down
4 changes: 2 additions & 2 deletions src/test/descriptor_tests.cpp
Expand Up @@ -154,8 +154,8 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
// Test whether the observed key path is present in the 'paths' variable (which contains expected, unobserved paths), // Test whether the observed key path is present in the 'paths' variable (which contains expected, unobserved paths),
// and then remove it from that set. // and then remove it from that set.
for (const auto& origin : script_provider.origins) { for (const auto& origin : script_provider.origins) {
BOOST_CHECK_MESSAGE(paths.count(origin.second.path), "Unexpected key path: " + prv); BOOST_CHECK_MESSAGE(paths.count(origin.second.second.path), "Unexpected key path: " + prv);
left_paths.erase(origin.second.path); left_paths.erase(origin.second.second.path);
} }
} }
} }
Expand Down
14 changes: 8 additions & 6 deletions src/wallet/rpcdump.cpp
Expand Up @@ -900,7 +900,7 @@ struct ImportData
// Output data // Output data
std::set<CScript> import_scripts; std::set<CScript> import_scripts;
std::map<CKeyID, bool> used_keys; //!< Import these private keys if available (the value indicates whether if the key is required for solvability) std::map<CKeyID, bool> used_keys; //!< Import these private keys if available (the value indicates whether if the key is required for solvability)
std::map<CKeyID, KeyOriginInfo> key_origins; std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
}; };


enum class ScriptContext enum class ScriptContext
Expand Down Expand Up @@ -1197,6 +1197,9 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(), bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
[&](const std::pair<CKeyID, CPubKey>& used_key) { [&](const std::pair<CKeyID, CPubKey>& used_key) {
return privkey_map.count(used_key.first) > 0; return privkey_map.count(used_key.first) > 0;
}) && std::all_of(import_data.key_origins.begin(), import_data.key_origins.end(),
[&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
return privkey_map.count(entry.first) > 0;
}); });
if (!watch_only && !spendable) { if (!watch_only && !spendable) {
warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."); warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
Expand Down Expand Up @@ -1274,7 +1277,10 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
} }
pwallet->UpdateTimeFirstKey(timestamp); pwallet->UpdateTimeFirstKey(timestamp);
} }
for (const auto& entry : import_data.key_origins) {
pwallet->AddKeyOrigin(entry.second.first, entry.second.second);
}
for (const CKeyID& id : ordered_pubkeys) { for (const CKeyID& id : ordered_pubkeys) {
auto entry = pubkey_map.find(id); auto entry = pubkey_map.find(id);
if (entry == pubkey_map.end()) { if (entry == pubkey_map.end()) {
Expand All @@ -1285,10 +1291,6 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) { if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
} }
const auto& key_orig_it = import_data.key_origins.find(id);
if (key_orig_it != import_data.key_origins.end()) {
pwallet->AddKeyOrigin(pubkey, key_orig_it->second);
}
pwallet->mapKeyMetadata[id].nCreateTime = timestamp; pwallet->mapKeyMetadata[id].nCreateTime = timestamp;


// Add to keypool only works with pubkeys // Add to keypool only works with pubkeys
Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_importmulti.py
Expand Up @@ -629,7 +629,8 @@ def run_test(self):
self.log.info("Should import a 1-of-2 bare multisig from descriptor") self.log.info("Should import a 1-of-2 bare multisig from descriptor")
self.test_importmulti({"desc": descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey + ")"), self.test_importmulti({"desc": descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey + ")"),
"timestamp": "now"}, "timestamp": "now"},
success=True) success=True,
warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.log.info("Should not treat individual keys from the imported bare multisig as watchonly") self.log.info("Should not treat individual keys from the imported bare multisig as watchonly")
test_address(self.nodes[1], test_address(self.nodes[1],
key1.p2pkh_addr, key1.p2pkh_addr,
Expand Down

0 comments on commit 54798c3

Please sign in to comment.