Merge #16301: Use CWallet::Import* functions in all import* RPCs
40ad2f6a58
Have importwallet use ImportPrivKeys and ImportScripts (Andrew Chow)78941da5ba
Optionally allow ImportScripts to set script creation timestamp (Andrew Chow)94bf156f39
Have importaddress use ImportScripts and ImportScriptPubKeys (Andrew Chow)a00d1e5ec5
Have importpubkey use CWallet's ImportScriptPubKeys and ImportPubKeys functions (Andrew Chow)c6a8274247
Have importprivkey use CWallet's ImportPrivKeys, ImportScripts, and ImportScriptPubKeys (Andrew Chow)fae7a5befd
Log when an import is being skipped because we already have it (Andrew Chow)ab28e31c95
Change ImportScriptPubKeys' internal to apply_label (Andrew Chow) Pull request description: #15741 introduced `ImportPrivKeys`, `ImportPubKeys`, `ImportScripts`, and `ImportScriptPubKeys` in `CWallet` which are used by `importmulti`. This PR changes the remaining `import*` RPCs (`importaddress`, `importprivkey`, `importpubkey`, and `importwallet`) to use these functions as well instead of directly adding the imported items to the wallet. ACKs for top commit: MarcoFalke: ACK40ad2f6a58
(checked that behavior changes are mentioned in the commit body) ryanofsky: utACK40ad2f6a58
. Only change since last review is a tweaked commit message (mentioning label update in importpubkey commit) Sjors: ACK40ad2f6a5
. Those extra tests also pass. Tree-SHA512: 910e3bbe20b6f8809a47b7293775db234125615d886c7fd99c194f4cdf00c765eb1e24b1799260f1213b98c88f9bbe696796f36087c182925e567d44e9194c98
This commit is contained in:
commit
dbf4f3f86a
3 changed files with 71 additions and 76 deletions
|
@ -185,19 +185,15 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
|||
}
|
||||
}
|
||||
|
||||
// Don't throw error in case a key is already there
|
||||
if (pwallet->HaveKey(vchAddress)) {
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
// whenever a key is imported, we need to scan the whole chain
|
||||
pwallet->UpdateTimeFirstKey(1);
|
||||
pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;
|
||||
|
||||
if (!pwallet->AddKeyPubKey(key, pubkey)) {
|
||||
// Use timestamp of 1 to scan the whole chain
|
||||
if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
|
||||
}
|
||||
pwallet->LearnAllRelatedScripts(pubkey);
|
||||
|
||||
// Add the wpkh script for this key if possible
|
||||
if (pubkey.IsCompressed()) {
|
||||
pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, 0 /* timestamp */);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fRescan) {
|
||||
|
@ -235,42 +231,6 @@ UniValue abortrescan(const JSONRPCRequest& request)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
|
||||
static void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
{
|
||||
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
|
||||
}
|
||||
|
||||
pwallet->MarkDirty();
|
||||
|
||||
if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, 0 /* nCreateTime */)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
|
||||
if (isRedeemScript) {
|
||||
const CScriptID id(script);
|
||||
if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
|
||||
}
|
||||
ImportAddress(pwallet, ScriptHash(id), strLabel);
|
||||
} else {
|
||||
CTxDestination destination;
|
||||
if (ExtractDestination(script, destination)) {
|
||||
pwallet->SetAddressBook(destination, strLabel, "receive");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
|
||||
{
|
||||
CScript script = GetScriptForDestination(dest);
|
||||
ImportScript(pwallet, script, strLabel, false);
|
||||
// add to address book or update label
|
||||
if (IsValidDestination(dest))
|
||||
pwallet->SetAddressBook(dest, strLabel, "receive");
|
||||
}
|
||||
|
||||
UniValue importaddress(const JSONRPCRequest& request)
|
||||
{
|
||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
||||
|
@ -341,10 +301,22 @@ UniValue importaddress(const JSONRPCRequest& request)
|
|||
if (fP2SH) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
|
||||
}
|
||||
ImportAddress(pwallet, dest, strLabel);
|
||||
|
||||
pwallet->MarkDirty();
|
||||
|
||||
pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
|
||||
} else if (IsHex(request.params[0].get_str())) {
|
||||
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
|
||||
ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);
|
||||
CScript redeem_script(data.begin(), data.end());
|
||||
|
||||
std::set<CScript> scripts = {redeem_script};
|
||||
pwallet->ImportScripts(scripts, 0 /* timestamp */);
|
||||
|
||||
if (fP2SH) {
|
||||
scripts.insert(GetScriptForDestination(ScriptHash(CScriptID(redeem_script))));
|
||||
}
|
||||
|
||||
pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
|
||||
}
|
||||
|
@ -529,11 +501,16 @@ UniValue importpubkey(const JSONRPCRequest& request)
|
|||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
||||
std::set<CScript> script_pub_keys;
|
||||
for (const auto& dest : GetAllDestinationsForKey(pubKey)) {
|
||||
ImportAddress(pwallet, dest, strLabel);
|
||||
script_pub_keys.insert(GetScriptForDestination(dest));
|
||||
}
|
||||
ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
|
||||
pwallet->LearnAllRelatedScripts(pubKey);
|
||||
|
||||
pwallet->MarkDirty();
|
||||
|
||||
pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
|
||||
|
||||
pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */);
|
||||
}
|
||||
if (fRescan)
|
||||
{
|
||||
|
@ -664,18 +641,18 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||
CPubKey pubkey = key.GetPubKey();
|
||||
assert(key.VerifyPubKey(pubkey));
|
||||
CKeyID keyid = pubkey.GetID();
|
||||
if (pwallet->HaveKey(keyid)) {
|
||||
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(PKHash(keyid)));
|
||||
continue;
|
||||
}
|
||||
|
||||
pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid)));
|
||||
if (!pwallet->AddKeyPubKey(key, pubkey)) {
|
||||
|
||||
if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
|
||||
pwallet->WalletLogPrintf("Error importing key for %s\n", EncodeDestination(PKHash(keyid)));
|
||||
fGood = false;
|
||||
continue;
|
||||
}
|
||||
pwallet->mapKeyMetadata[keyid].nCreateTime = time;
|
||||
|
||||
if (has_label)
|
||||
pwallet->SetAddressBook(PKHash(keyid), label, "receive");
|
||||
|
||||
nTimeBegin = std::min(nTimeBegin, time);
|
||||
progress++;
|
||||
}
|
||||
|
@ -683,24 +660,19 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||
pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
|
||||
const CScript& script = script_pair.first;
|
||||
int64_t time = script_pair.second;
|
||||
CScriptID id(script);
|
||||
if (pwallet->HaveCScript(id)) {
|
||||
pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script));
|
||||
continue;
|
||||
}
|
||||
if(!pwallet->AddCScript(script)) {
|
||||
|
||||
if (!pwallet->ImportScripts({script}, time)) {
|
||||
pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script));
|
||||
fGood = false;
|
||||
continue;
|
||||
}
|
||||
if (time > 0) {
|
||||
pwallet->m_script_metadata[id].nCreateTime = time;
|
||||
nTimeBegin = std::min(nTimeBegin, time);
|
||||
}
|
||||
|
||||
progress++;
|
||||
}
|
||||
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||
pwallet->UpdateTimeFirstKey(nTimeBegin);
|
||||
}
|
||||
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
|
||||
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
|
||||
|
@ -1255,7 +1227,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
|
|||
|
||||
// All good, time to import
|
||||
pwallet->MarkDirty();
|
||||
if (!pwallet->ImportScripts(import_data.import_scripts)) {
|
||||
if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
|
||||
}
|
||||
if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
|
||||
|
@ -1264,7 +1236,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
|
|||
if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, internal, timestamp)) {
|
||||
if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
|
||||
}
|
||||
|
||||
|
|
|
@ -1777,14 +1777,27 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::ImportScripts(const std::set<CScript> scripts)
|
||||
bool CWallet::ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
|
||||
{
|
||||
WalletBatch batch(*database);
|
||||
for (const auto& entry : scripts) {
|
||||
if (!HaveCScript(CScriptID(entry)) && !AddCScriptWithDB(batch, entry)) {
|
||||
CScriptID id(entry);
|
||||
if (HaveCScript(id)) {
|
||||
WalletLogPrintf("Already have script %s, skipping\n", HexStr(entry));
|
||||
continue;
|
||||
}
|
||||
if (!AddCScriptWithDB(batch, entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp > 0) {
|
||||
m_script_metadata[CScriptID(entry)].nCreateTime = timestamp;
|
||||
}
|
||||
}
|
||||
if (timestamp > 0) {
|
||||
UpdateTimeFirstKey(timestamp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1796,9 +1809,14 @@ bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const in
|
|||
CPubKey pubkey = key.GetPubKey();
|
||||
const CKeyID& id = entry.first;
|
||||
assert(key.VerifyPubKey(pubkey));
|
||||
// Skip if we already have the key
|
||||
if (HaveKey(id)) {
|
||||
WalletLogPrintf("Already have key with pubkey %s, skipping\n", HexStr(pubkey));
|
||||
continue;
|
||||
}
|
||||
mapKeyMetadata[id].nCreateTime = timestamp;
|
||||
// If the private key is not present in the wallet, insert it.
|
||||
if (!HaveKey(id) && !AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
if (!AddKeyPubKeyWithDB(batch, key, pubkey)) {
|
||||
return false;
|
||||
}
|
||||
UpdateTimeFirstKey(timestamp);
|
||||
|
@ -1819,7 +1837,12 @@ bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const st
|
|||
}
|
||||
const CPubKey& pubkey = entry->second;
|
||||
CPubKey temp;
|
||||
if (!GetPubKey(id, temp) && !AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
|
||||
if (GetPubKey(id, temp)) {
|
||||
// Already have pubkey, skipping
|
||||
WalletLogPrintf("Already have pubkey %s, skipping\n", HexStr(temp));
|
||||
continue;
|
||||
}
|
||||
if (!AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
|
||||
return false;
|
||||
}
|
||||
mapKeyMetadata[id].nCreateTime = timestamp;
|
||||
|
@ -1833,7 +1856,7 @@ bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const st
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool internal, const int64_t timestamp)
|
||||
bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp)
|
||||
{
|
||||
WalletBatch batch(*database);
|
||||
for (const CScript& script : script_pub_keys) {
|
||||
|
@ -1844,7 +1867,7 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
|
|||
}
|
||||
CTxDestination dest;
|
||||
ExtractDestination(script, dest);
|
||||
if (!internal && IsValidDestination(dest)) {
|
||||
if (apply_label && IsValidDestination(dest)) {
|
||||
SetAddressBookWithDB(batch, dest, label, "receive");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1150,10 +1150,10 @@ public:
|
|||
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const;
|
||||
bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig = false) const;
|
||||
|
||||
bool ImportScripts(const std::set<CScript> scripts) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
|
||||
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
|
||||
|
|
Loading…
Reference in a new issue