Skip to content

Commit dbf4f3f

Browse files
author
MarcoFalke
committed
Merge #16301: Use CWallet::Import* functions in all import* RPCs
40ad2f6 Have importwallet use ImportPrivKeys and ImportScripts (Andrew Chow) 78941da Optionally allow ImportScripts to set script creation timestamp (Andrew Chow) 94bf156 Have importaddress use ImportScripts and ImportScriptPubKeys (Andrew Chow) a00d1e5 Have importpubkey use CWallet's ImportScriptPubKeys and ImportPubKeys functions (Andrew Chow) c6a8274 Have importprivkey use CWallet's ImportPrivKeys, ImportScripts, and ImportScriptPubKeys (Andrew Chow) fae7a5b Log when an import is being skipped because we already have it (Andrew Chow) ab28e31 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: ACK 40ad2f6 (checked that behavior changes are mentioned in the commit body) ryanofsky: utACK 40ad2f6. Only change since last review is a tweaked commit message (mentioning label update in importpubkey commit) Sjors: ACK 40ad2f6. Those extra tests also pass. Tree-SHA512: 910e3bbe20b6f8809a47b7293775db234125615d886c7fd99c194f4cdf00c765eb1e24b1799260f1213b98c88f9bbe696796f36087c182925e567d44e9194c98
2 parents a54a120 + 40ad2f6 commit dbf4f3f

File tree

3 files changed

+70
-75
lines changed

3 files changed

+70
-75
lines changed

src/wallet/rpcdump.cpp

Lines changed: 39 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -185,19 +185,15 @@ UniValue importprivkey(const JSONRPCRequest& request)
185185
}
186186
}
187187

188-
// Don't throw error in case a key is already there
189-
if (pwallet->HaveKey(vchAddress)) {
190-
return NullUniValue;
188+
// Use timestamp of 1 to scan the whole chain
189+
if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
190+
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
191191
}
192192

193-
// whenever a key is imported, we need to scan the whole chain
194-
pwallet->UpdateTimeFirstKey(1);
195-
pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;
196-
197-
if (!pwallet->AddKeyPubKey(key, pubkey)) {
198-
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
193+
// Add the wpkh script for this key if possible
194+
if (pubkey.IsCompressed()) {
195+
pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, 0 /* timestamp */);
199196
}
200-
pwallet->LearnAllRelatedScripts(pubkey);
201197
}
202198
}
203199
if (fRescan) {
@@ -235,42 +231,6 @@ UniValue abortrescan(const JSONRPCRequest& request)
235231
return true;
236232
}
237233

238-
static void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
239-
static void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
240-
{
241-
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
242-
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
243-
}
244-
245-
pwallet->MarkDirty();
246-
247-
if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, 0 /* nCreateTime */)) {
248-
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
249-
}
250-
251-
if (isRedeemScript) {
252-
const CScriptID id(script);
253-
if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) {
254-
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
255-
}
256-
ImportAddress(pwallet, ScriptHash(id), strLabel);
257-
} else {
258-
CTxDestination destination;
259-
if (ExtractDestination(script, destination)) {
260-
pwallet->SetAddressBook(destination, strLabel, "receive");
261-
}
262-
}
263-
}
264-
265-
static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
266-
{
267-
CScript script = GetScriptForDestination(dest);
268-
ImportScript(pwallet, script, strLabel, false);
269-
// add to address book or update label
270-
if (IsValidDestination(dest))
271-
pwallet->SetAddressBook(dest, strLabel, "receive");
272-
}
273-
274234
UniValue importaddress(const JSONRPCRequest& request)
275235
{
276236
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -341,10 +301,22 @@ UniValue importaddress(const JSONRPCRequest& request)
341301
if (fP2SH) {
342302
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
343303
}
344-
ImportAddress(pwallet, dest, strLabel);
304+
305+
pwallet->MarkDirty();
306+
307+
pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
345308
} else if (IsHex(request.params[0].get_str())) {
346309
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
347-
ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);
310+
CScript redeem_script(data.begin(), data.end());
311+
312+
std::set<CScript> scripts = {redeem_script};
313+
pwallet->ImportScripts(scripts, 0 /* timestamp */);
314+
315+
if (fP2SH) {
316+
scripts.insert(GetScriptForDestination(ScriptHash(CScriptID(redeem_script))));
317+
}
318+
319+
pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
348320
} else {
349321
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
350322
}
@@ -529,11 +501,16 @@ UniValue importpubkey(const JSONRPCRequest& request)
529501
auto locked_chain = pwallet->chain().lock();
530502
LOCK(pwallet->cs_wallet);
531503

504+
std::set<CScript> script_pub_keys;
532505
for (const auto& dest : GetAllDestinationsForKey(pubKey)) {
533-
ImportAddress(pwallet, dest, strLabel);
506+
script_pub_keys.insert(GetScriptForDestination(dest));
534507
}
535-
ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
536-
pwallet->LearnAllRelatedScripts(pubKey);
508+
509+
pwallet->MarkDirty();
510+
511+
pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
512+
513+
pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */);
537514
}
538515
if (fRescan)
539516
{
@@ -664,43 +641,38 @@ UniValue importwallet(const JSONRPCRequest& request)
664641
CPubKey pubkey = key.GetPubKey();
665642
assert(key.VerifyPubKey(pubkey));
666643
CKeyID keyid = pubkey.GetID();
667-
if (pwallet->HaveKey(keyid)) {
668-
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(PKHash(keyid)));
669-
continue;
670-
}
644+
671645
pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid)));
672-
if (!pwallet->AddKeyPubKey(key, pubkey)) {
646+
647+
if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
648+
pwallet->WalletLogPrintf("Error importing key for %s\n", EncodeDestination(PKHash(keyid)));
673649
fGood = false;
674650
continue;
675651
}
676-
pwallet->mapKeyMetadata[keyid].nCreateTime = time;
652+
677653
if (has_label)
678654
pwallet->SetAddressBook(PKHash(keyid), label, "receive");
655+
679656
nTimeBegin = std::min(nTimeBegin, time);
680657
progress++;
681658
}
682659
for (const auto& script_pair : scripts) {
683660
pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
684661
const CScript& script = script_pair.first;
685662
int64_t time = script_pair.second;
686-
CScriptID id(script);
687-
if (pwallet->HaveCScript(id)) {
688-
pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script));
689-
continue;
690-
}
691-
if(!pwallet->AddCScript(script)) {
663+
664+
if (!pwallet->ImportScripts({script}, time)) {
692665
pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script));
693666
fGood = false;
694667
continue;
695668
}
696669
if (time > 0) {
697-
pwallet->m_script_metadata[id].nCreateTime = time;
698670
nTimeBegin = std::min(nTimeBegin, time);
699671
}
672+
700673
progress++;
701674
}
702675
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
703-
pwallet->UpdateTimeFirstKey(nTimeBegin);
704676
}
705677
pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
706678
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
@@ -1255,7 +1227,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
12551227

12561228
// All good, time to import
12571229
pwallet->MarkDirty();
1258-
if (!pwallet->ImportScripts(import_data.import_scripts)) {
1230+
if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
12591231
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
12601232
}
12611233
if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
@@ -1264,7 +1236,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
12641236
if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
12651237
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
12661238
}
1267-
if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, internal, timestamp)) {
1239+
if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
12681240
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
12691241
}
12701242

src/wallet/wallet.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,14 +1777,27 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
17771777
return true;
17781778
}
17791779

1780-
bool CWallet::ImportScripts(const std::set<CScript> scripts)
1780+
bool CWallet::ImportScripts(const std::set<CScript> scripts, int64_t timestamp)
17811781
{
17821782
WalletBatch batch(*database);
17831783
for (const auto& entry : scripts) {
1784-
if (!HaveCScript(CScriptID(entry)) && !AddCScriptWithDB(batch, entry)) {
1784+
CScriptID id(entry);
1785+
if (HaveCScript(id)) {
1786+
WalletLogPrintf("Already have script %s, skipping\n", HexStr(entry));
1787+
continue;
1788+
}
1789+
if (!AddCScriptWithDB(batch, entry)) {
17851790
return false;
17861791
}
1792+
1793+
if (timestamp > 0) {
1794+
m_script_metadata[CScriptID(entry)].nCreateTime = timestamp;
1795+
}
1796+
}
1797+
if (timestamp > 0) {
1798+
UpdateTimeFirstKey(timestamp);
17871799
}
1800+
17881801
return true;
17891802
}
17901803

@@ -1796,9 +1809,14 @@ bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const in
17961809
CPubKey pubkey = key.GetPubKey();
17971810
const CKeyID& id = entry.first;
17981811
assert(key.VerifyPubKey(pubkey));
1812+
// Skip if we already have the key
1813+
if (HaveKey(id)) {
1814+
WalletLogPrintf("Already have key with pubkey %s, skipping\n", HexStr(pubkey));
1815+
continue;
1816+
}
17991817
mapKeyMetadata[id].nCreateTime = timestamp;
18001818
// If the private key is not present in the wallet, insert it.
1801-
if (!HaveKey(id) && !AddKeyPubKeyWithDB(batch, key, pubkey)) {
1819+
if (!AddKeyPubKeyWithDB(batch, key, pubkey)) {
18021820
return false;
18031821
}
18041822
UpdateTimeFirstKey(timestamp);
@@ -1819,7 +1837,12 @@ bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const st
18191837
}
18201838
const CPubKey& pubkey = entry->second;
18211839
CPubKey temp;
1822-
if (!GetPubKey(id, temp) && !AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
1840+
if (GetPubKey(id, temp)) {
1841+
// Already have pubkey, skipping
1842+
WalletLogPrintf("Already have pubkey %s, skipping\n", HexStr(temp));
1843+
continue;
1844+
}
1845+
if (!AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
18231846
return false;
18241847
}
18251848
mapKeyMetadata[id].nCreateTime = timestamp;
@@ -1833,7 +1856,7 @@ bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const st
18331856
return true;
18341857
}
18351858

1836-
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)
1859+
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)
18371860
{
18381861
WalletBatch batch(*database);
18391862
for (const CScript& script : script_pub_keys) {
@@ -1844,7 +1867,7 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri
18441867
}
18451868
CTxDestination dest;
18461869
ExtractDestination(script, dest);
1847-
if (!internal && IsValidDestination(dest)) {
1870+
if (apply_label && IsValidDestination(dest)) {
18481871
SetAddressBookWithDB(batch, dest, label, "receive");
18491872
}
18501873
}

src/wallet/wallet.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,10 +1150,10 @@ class CWallet final : public FillableSigningProvider, private interfaces::Chain:
11501150
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const;
11511151
bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig = false) const;
11521152

1153-
bool ImportScripts(const std::set<CScript> scripts) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
1153+
bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
11541154
bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
11551155
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);
1156-
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);
1156+
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);
11571157

11581158
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
11591159
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};

0 commit comments

Comments
 (0)