Move some of ProcessImport into CWallet::Import*

This maintains encapsulation of CWallet::database in the face of
batching, e.g. allows making the `WithDB` methods private.
This commit is contained in:
Ben Woosley 2019-04-04 02:12:50 -07:00 committed by Andrew Chow
parent ccb26cf347
commit 6154a09e01
3 changed files with 101 additions and 54 deletions

View file

@ -1261,56 +1261,17 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
// All good, time to import // All good, time to import
pwallet->MarkDirty(); pwallet->MarkDirty();
WalletBatch batch(pwallet->GetDBHandle()); if (!pwallet->ImportScripts(import_data.import_scripts)) {
for (const auto& entry : import_data.import_scripts) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
if (!pwallet->HaveCScript(CScriptID(entry)) && !pwallet->AddCScriptWithDB(batch, entry)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
}
}
for (const auto& entry : privkey_map) {
const CKey& key = entry.second;
CPubKey pubkey = key.GetPubKey();
const CKeyID& id = entry.first;
assert(key.VerifyPubKey(pubkey));
pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
// If the private key is not present in the wallet, insert it.
if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKeyWithDB(batch, key, pubkey)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
}
pwallet->UpdateTimeFirstKey(timestamp);
} }
for (const auto& entry : import_data.key_origins) { if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
pwallet->AddKeyOriginWithDB(batch, entry.second.first, entry.second.second); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
} }
for (const CKeyID& id : ordered_pubkeys) { if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
auto entry = pubkey_map.find(id); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
if (entry == pubkey_map.end()) {
continue;
}
const CPubKey& pubkey = entry->second;
CPubKey temp;
if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
// Add to keypool only works with pubkeys
if (add_keypool) {
pwallet->AddKeypoolPubkeyWithDB(pubkey, internal, batch);
}
} }
if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, internal, timestamp)) {
for (const CScript& script : script_pub_keys) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
if (!pwallet->AddWatchOnlyWithDB(batch, script, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
}
CTxDestination dest;
ExtractDestination(script, dest);
if (!internal && IsValidDestination(dest)) {
pwallet->SetAddressBook(dest, label, "receive");
}
} }
result.pushKV("success", UniValue(true)); result.pushKV("success", UniValue(true));

View file

@ -1625,6 +1625,80 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
return true; return true;
} }
bool CWallet::ImportScripts(const std::set<CScript> scripts)
{
WalletBatch batch(*database);
for (const auto& entry : scripts) {
if (!HaveCScript(CScriptID(entry)) && !AddCScriptWithDB(batch, entry)) {
return false;
}
}
return true;
}
bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp)
{
WalletBatch batch(*database);
for (const auto& entry : privkey_map) {
const CKey& key = entry.second;
CPubKey pubkey = key.GetPubKey();
const CKeyID& id = entry.first;
assert(key.VerifyPubKey(pubkey));
mapKeyMetadata[id].nCreateTime = timestamp;
// If the private key is not present in the wallet, insert it.
if (!HaveKey(id) && !AddKeyPubKeyWithDB(batch, key, pubkey)) {
return false;
}
UpdateTimeFirstKey(timestamp);
}
return true;
}
bool CWallet::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)
{
WalletBatch batch(*database);
for (const auto& entry : key_origins) {
AddKeyOriginWithDB(batch, entry.second.first, entry.second.second);
}
for (const CKeyID& id : ordered_pubkeys) {
auto entry = pubkey_map.find(id);
if (entry == pubkey_map.end()) {
continue;
}
const CPubKey& pubkey = entry->second;
CPubKey temp;
if (!GetPubKey(id, temp) && !AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
return false;
}
mapKeyMetadata[id].nCreateTime = timestamp;
// Add to keypool only works with pubkeys
if (add_keypool) {
AddKeypoolPubkeyWithDB(pubkey, internal, batch);
NotifyCanGetAddressesChanged();
}
}
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)
{
WalletBatch batch(*database);
for (const CScript& script : script_pub_keys) {
if (!have_solving_data || !::IsMine(*this, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
if (!AddWatchOnlyWithDB(batch, script, timestamp)) {
return false;
}
}
CTxDestination dest;
ExtractDestination(script, dest);
if (!internal && IsValidDestination(dest)) {
SetAddressBook(dest, label, "receive");
}
}
return true;
}
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig) int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig)
{ {
std::vector<CTxOut> txouts; std::vector<CTxOut> txouts;

View file

@ -704,6 +704,20 @@ private:
bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** Add a KeyOriginInfo to the wallet */
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
//! Adds a script to the store and saves it to disk
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
/** Interface for accessing chain state. */ /** Interface for accessing chain state. */
interfaces::Chain* m_chain; interfaces::Chain* m_chain;
@ -854,7 +868,6 @@ public:
CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, and saves it to disk. //! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, without saving it to disk (used by LoadWallet) //! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet) //! Load metadata (used by LoadWallet)
@ -871,7 +884,6 @@ public:
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddCScript(const CScript& redeemScript) override; bool AddCScript(const CScript& redeemScript) override;
bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
bool LoadCScript(const CScript& redeemScript); bool LoadCScript(const CScript& redeemScript);
//! Adds a destination data tuple to the store, and saves it to disk //! Adds a destination data tuple to the store, and saves it to disk
@ -887,7 +899,6 @@ public:
//! Adds a watch-only address to the store, and saves it to disk. //! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool RemoveWatchOnly(const CScript &dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool RemoveWatchOnly(const CScript &dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest); bool LoadWatchOnly(const CScript &dest);
@ -975,6 +986,11 @@ public:
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const; 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 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 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);
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE}; bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
@ -994,7 +1010,6 @@ public:
bool NewKeyPool(); bool NewKeyPool();
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0); bool TopUpKeyPool(unsigned int kpSize = 0);
void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
/** /**
* Reserves a key from the keypool and sets nIndex to its index * Reserves a key from the keypool and sets nIndex to its index
@ -1211,9 +1226,6 @@ public:
/** Implement lookup of key origin information through wallet key metadata. */ /** Implement lookup of key origin information through wallet key metadata. */
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
/** Add a KeyOriginInfo to the wallet */
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
}; };
/** /**