diff options
Diffstat (limited to 'src/wallet/api/wallet.cpp')
-rw-r--r-- | src/wallet/api/wallet.cpp | 214 |
1 files changed, 210 insertions, 4 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 58cb84947..51e4f78ee 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -58,6 +58,40 @@ using namespace cryptonote; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "WalletAPI" +#define LOCK_REFRESH() \ + bool refresh_enabled = m_refreshEnabled; \ + m_refreshEnabled = false; \ + m_wallet->stop(); \ + m_refreshCV.notify_one(); \ + boost::mutex::scoped_lock lock(m_refreshMutex); \ + boost::mutex::scoped_lock lock2(m_refreshMutex2); \ + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \ + /* m_refreshMutex's still locked here */ \ + if (refresh_enabled) \ + startRefresh(); \ + }) + +#define PRE_VALIDATE_BACKGROUND_SYNC() \ + do \ + { \ + clearStatus(); \ + if (m_wallet->key_on_device()) \ + { \ + setStatusError(tr("HW wallet cannot use background sync")); \ + return false; \ + } \ + if (m_wallet->watch_only()) \ + { \ + setStatusError(tr("View only wallet cannot use background sync")); \ + return false; \ + } \ + if (m_wallet->get_multisig_status().multisig_is_active) \ + { \ + setStatusError(tr("Multisig wallet cannot use background sync")); \ + return false; \ + } \ + } while (0) + namespace Monero { namespace { @@ -766,6 +800,8 @@ bool WalletImpl::close(bool store) std::string WalletImpl::seed(const std::string& seed_offset) const { + if (checkBackgroundSync("cannot get seed")) + return std::string(); epee::wipeable_string seed; if (m_wallet) m_wallet->get_seed(seed, seed_offset); @@ -779,6 +815,8 @@ std::string WalletImpl::getSeedLanguage() const void WalletImpl::setSeedLanguage(const std::string &arg) { + if (checkBackgroundSync("cannot set seed language")) + return; m_wallet->set_seed_language(arg); } @@ -802,6 +840,8 @@ void WalletImpl::statusWithErrorString(int& status, std::string& errorString) co bool WalletImpl::setPassword(const std::string &password) { + if (checkBackgroundSync("cannot change password")) + return false; clearStatus(); try { m_wallet->change_password(m_wallet->get_wallet_file(), m_password, password); @@ -931,6 +971,8 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact void WalletImpl::setRefreshFromBlockHeight(uint64_t refresh_from_block_height) { + if (checkBackgroundSync("cannot change refresh height")) + return; m_wallet->set_refresh_from_block_height(refresh_from_block_height); } @@ -1039,6 +1081,8 @@ void WalletImpl::refreshAsync() bool WalletImpl::rescanBlockchain() { + if (checkBackgroundSync("cannot rescan blockchain")) + return false; clearStatus(); m_refreshShouldRescan = true; doRefresh(); @@ -1047,6 +1091,8 @@ bool WalletImpl::rescanBlockchain() void WalletImpl::rescanBlockchainAsync() { + if (checkBackgroundSync("cannot rescan blockchain")) + return; m_refreshShouldRescan = true; refreshAsync(); } @@ -1070,7 +1116,7 @@ int WalletImpl::autoRefreshInterval() const UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_filename) { clearStatus(); UnsignedTransactionImpl * transaction = new UnsignedTransactionImpl(*this); - if (!m_wallet->load_unsigned_tx(unsigned_filename, transaction->m_unsigned_tx_set)){ + if (checkBackgroundSync("cannot load tx") || !m_wallet->load_unsigned_tx(unsigned_filename, transaction->m_unsigned_tx_set)){ setStatusError(tr("Failed to load unsigned transactions")); transaction->m_status = UnsignedTransaction::Status::Status_Error; transaction->m_errorString = errorString(); @@ -1090,6 +1136,8 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file bool WalletImpl::submitTransaction(const string &fileName) { clearStatus(); + if (checkBackgroundSync("cannot submit tx")) + return false; std::unique_ptr<PendingTransactionImpl> transaction(new PendingTransactionImpl(*this)); bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx); @@ -1113,6 +1161,8 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all) setStatusError(tr("Wallet is view only")); return false; } + if (checkBackgroundSync("cannot export key images")) + return false; try { @@ -1133,6 +1183,8 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all) bool WalletImpl::importKeyImages(const string &filename) { + if (checkBackgroundSync("cannot import key images")) + return false; if (!trustedDaemon()) { setStatusError(tr("Key images can only be imported with a trusted daemon")); return false; @@ -1156,6 +1208,8 @@ bool WalletImpl::importKeyImages(const string &filename) bool WalletImpl::exportOutputs(const string &filename, bool all) { + if (checkBackgroundSync("cannot export outputs")) + return false; if (m_wallet->key_on_device()) { setStatusError(string(tr("Not supported on HW wallets.")) + filename); @@ -1186,6 +1240,8 @@ bool WalletImpl::exportOutputs(const string &filename, bool all) bool WalletImpl::importOutputs(const string &filename) { + if (checkBackgroundSync("cannot import outputs")) + return false; if (m_wallet->key_on_device()) { setStatusError(string(tr("Not supported on HW wallets.")) + filename); @@ -1218,6 +1274,8 @@ bool WalletImpl::importOutputs(const string &filename) bool WalletImpl::scanTransactions(const std::vector<std::string> &txids) { + if (checkBackgroundSync("cannot scan transactions")) + return false; if (txids.empty()) { setStatusError(string(tr("Failed to scan transactions: no transaction ids provided."))); @@ -1256,8 +1314,86 @@ bool WalletImpl::scanTransactions(const std::vector<std::string> &txids) return true; } +bool WalletImpl::setupBackgroundSync(const Wallet::BackgroundSyncType background_sync_type, const std::string &wallet_password, const optional<std::string> &background_cache_password) +{ + try + { + PRE_VALIDATE_BACKGROUND_SYNC(); + + tools::wallet2::BackgroundSyncType bgs_type; + switch (background_sync_type) + { + case Wallet::BackgroundSync_Off: bgs_type = tools::wallet2::BackgroundSyncOff; break; + case Wallet::BackgroundSync_ReusePassword: bgs_type = tools::wallet2::BackgroundSyncReusePassword; break; + case Wallet::BackgroundSync_CustomPassword: bgs_type = tools::wallet2::BackgroundSyncCustomPassword; break; + default: setStatusError(tr("Unknown background sync type")); return false; + } + + boost::optional<epee::wipeable_string> bgc_password = background_cache_password + ? boost::optional<epee::wipeable_string>(*background_cache_password) + : boost::none; + + LOCK_REFRESH(); + m_wallet->setup_background_sync(bgs_type, wallet_password, bgc_password); + } + catch (const std::exception &e) + { + LOG_ERROR("Failed to setup background sync: " << e.what()); + setStatusError(string(tr("Failed to setup background sync: ")) + e.what()); + return false; + } + return true; +} + +Wallet::BackgroundSyncType WalletImpl::getBackgroundSyncType() const +{ + switch (m_wallet->background_sync_type()) + { + case tools::wallet2::BackgroundSyncOff: return Wallet::BackgroundSync_Off; + case tools::wallet2::BackgroundSyncReusePassword: return Wallet::BackgroundSync_ReusePassword; + case tools::wallet2::BackgroundSyncCustomPassword: return Wallet::BackgroundSync_CustomPassword; + default: setStatusError(tr("Unknown background sync type")); return Wallet::BackgroundSync_Off; + } +} + +bool WalletImpl::startBackgroundSync() +{ + try + { + PRE_VALIDATE_BACKGROUND_SYNC(); + LOCK_REFRESH(); + m_wallet->start_background_sync(); + } + catch (const std::exception &e) + { + LOG_ERROR("Failed to start background sync: " << e.what()); + setStatusError(string(tr("Failed to start background sync: ")) + e.what()); + return false; + } + return true; +} + +bool WalletImpl::stopBackgroundSync(const std::string &wallet_password) +{ + try + { + PRE_VALIDATE_BACKGROUND_SYNC(); + LOCK_REFRESH(); + m_wallet->stop_background_sync(epee::wipeable_string(wallet_password)); + } + catch (const std::exception &e) + { + LOG_ERROR("Failed to stop background sync: " << e.what()); + setStatusError(string(tr("Failed to stop background sync: ")) + e.what()); + return false; + } + return true; +} + void WalletImpl::addSubaddressAccount(const std::string& label) { + if (checkBackgroundSync("cannot add account")) + return; m_wallet->add_subaddress_account(label); } size_t WalletImpl::numSubaddressAccounts() const @@ -1270,10 +1406,14 @@ size_t WalletImpl::numSubaddresses(uint32_t accountIndex) const } void WalletImpl::addSubaddress(uint32_t accountIndex, const std::string& label) { + if (checkBackgroundSync("cannot add subbaddress")) + return; m_wallet->add_subaddress(accountIndex, label); } std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const { + if (checkBackgroundSync("cannot get subbaddress label")) + return ""; try { return m_wallet->get_subaddress_label({accountIndex, addressIndex}); @@ -1287,6 +1427,8 @@ std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addre } void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) { + if (checkBackgroundSync("cannot set subbaddress label")) + return; try { return m_wallet->set_subaddress_label({accountIndex, addressIndex}, label); @@ -1300,6 +1442,9 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex MultisigState WalletImpl::multisig() const { MultisigState state; + if (checkBackgroundSync("cannot use multisig")) + return state; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; state.isMultisig = ms_status.multisig_is_active; @@ -1312,6 +1457,8 @@ MultisigState WalletImpl::multisig() const { } string WalletImpl::getMultisigInfo() const { + if (checkBackgroundSync("cannot use multisig")) + return string(); try { clearStatus(); return m_wallet->get_multisig_first_kex_msg(); @@ -1324,6 +1471,8 @@ string WalletImpl::getMultisigInfo() const { } string WalletImpl::makeMultisig(const vector<string>& info, const uint32_t threshold) { + if (checkBackgroundSync("cannot make multisig")) + return string(); try { clearStatus(); @@ -1464,6 +1613,9 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { + if (checkBackgroundSync("cannot create transactions")) + break; + std::vector<uint8_t> extra; std::string extra_nonce; vector<cryptonote::tx_destination_entry> dsts; @@ -1630,6 +1782,9 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { + if (checkBackgroundSync("cannot sweep")) + break; + try { transaction->m_pending_tx = m_wallet->create_unmixable_sweep_transactions(); pendingTxPostProcess(transaction); @@ -1763,11 +1918,15 @@ uint32_t WalletImpl::defaultMixin() const void WalletImpl::setDefaultMixin(uint32_t arg) { + if (checkBackgroundSync("cannot set default mixin")) + return; m_wallet->default_mixin(arg); } bool WalletImpl::setCacheAttribute(const std::string &key, const std::string &val) { + if (checkBackgroundSync("cannot set cache attribute")) + return false; m_wallet->set_attribute(key, val); return true; } @@ -1781,6 +1940,8 @@ std::string WalletImpl::getCacheAttribute(const std::string &key) const bool WalletImpl::setUserNote(const std::string &txid, const std::string ¬e) { + if (checkBackgroundSync("cannot set user note")) + return false; cryptonote::blobdata txid_data; if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash)) return false; @@ -1792,6 +1953,8 @@ bool WalletImpl::setUserNote(const std::string &txid, const std::string ¬e) std::string WalletImpl::getUserNote(const std::string &txid) const { + if (checkBackgroundSync("cannot get user note")) + return ""; cryptonote::blobdata txid_data; if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash)) return ""; @@ -1802,6 +1965,9 @@ std::string WalletImpl::getUserNote(const std::string &txid) const std::string WalletImpl::getTxKey(const std::string &txid_str) const { + if (checkBackgroundSync("cannot get tx key")) + return ""; + crypto::hash txid; if(!epee::string_tools::hex_to_pod(txid_str, txid)) { @@ -1886,6 +2052,9 @@ bool WalletImpl::checkTxKey(const std::string &txid_str, std::string tx_key_str, std::string WalletImpl::getTxProof(const std::string &txid_str, const std::string &address_str, const std::string &message) const { + if (checkBackgroundSync("cannot get tx proof")) + return ""; + crypto::hash txid; if (!epee::string_tools::hex_to_pod(txid_str, txid)) { @@ -1942,6 +2111,9 @@ bool WalletImpl::checkTxProof(const std::string &txid_str, const std::string &ad } std::string WalletImpl::getSpendProof(const std::string &txid_str, const std::string &message) const { + if (checkBackgroundSync("cannot get spend proof")) + return ""; + crypto::hash txid; if(!epee::string_tools::hex_to_pod(txid_str, txid)) { @@ -1984,6 +2156,9 @@ bool WalletImpl::checkSpendProof(const std::string &txid_str, const std::string } std::string WalletImpl::getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const { + if (checkBackgroundSync("cannot get reserve proof")) + return ""; + try { clearStatus(); @@ -2030,6 +2205,9 @@ bool WalletImpl::checkReserveProof(const std::string &address, const std::string std::string WalletImpl::signMessage(const std::string &message, const std::string &address) { + if (checkBackgroundSync("cannot sign message")) + return ""; + if (address.empty()) { return m_wallet->sign(message, tools::wallet2::sign_with_spend_key); } @@ -2156,6 +2334,16 @@ bool WalletImpl::isDeterministic() const return m_wallet->is_deterministic(); } +bool WalletImpl::isBackgroundSyncing() const +{ + return m_wallet->is_background_syncing(); +} + +bool WalletImpl::isBackgroundWallet() const +{ + return m_wallet->is_background_wallet(); +} + void WalletImpl::clearStatus() const { boost::lock_guard<boost::mutex> l(m_statusMutex); @@ -2224,9 +2412,7 @@ void WalletImpl::doRefresh() if(rescan) m_wallet->rescan_blockchain(false); m_wallet->refresh(trustedDaemon()); - if (!m_synchronized) { - m_synchronized = true; - } + m_synchronized = m_wallet->is_synced(); // assuming if we have empty history, it wasn't initialized yet // for further history changes client need to update history in // "on_money_received" and "on_money_sent" callbacks @@ -2329,6 +2515,24 @@ bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_a return true; } +bool WalletImpl::checkBackgroundSync(const std::string &message) const +{ + clearStatus(); + if (m_wallet->is_background_wallet()) + { + LOG_ERROR("Background wallets " + message); + setStatusError(tr("Background wallets ") + message); + return true; + } + if (m_wallet->is_background_syncing()) + { + LOG_ERROR(message + " while background syncing"); + setStatusError(message + tr(" while background syncing. Stop background syncing first.")); + return true; + } + return false; +} + bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) { return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); @@ -2347,6 +2551,8 @@ std::string WalletImpl::getDefaultDataDir() const bool WalletImpl::rescanSpent() { clearStatus(); + if (checkBackgroundSync("cannot rescan spent")) + return false; if (!trustedDaemon()) { setStatusError(tr("Rescan spent can only be used with a trusted daemon")); return false; |