diff options
Diffstat (limited to 'src/wallet/api/wallet.cpp')
-rw-r--r-- | src/wallet/api/wallet.cpp | 151 |
1 files changed, 147 insertions, 4 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index da5f776f4..5c2a5045c 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -31,6 +31,7 @@ #include "wallet.h" #include "pending_transaction.h" +#include "unsigned_transaction.h" #include "transaction_history.h" #include "address_book.h" #include "common_defines.h" @@ -51,6 +52,8 @@ namespace { static const int DEFAULT_REFRESH_INTERVAL_MILLIS = 1000 * 10; // limit maximum refresh interval as one minute static const int MAX_REFRESH_INTERVAL_MILLIS = 1000 * 60 * 1; + // Default refresh interval when connected to remote node + static const int DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS = 1000 * 10; } struct Wallet2CallbackImpl : public tools::i_wallet2_callback @@ -103,6 +106,21 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback } } + virtual void on_unconfirmed_money_received(uint64_t height, const cryptonote::transaction& tx, uint64_t amount) + { + + std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx)); + + LOG_PRINT_L3(__FUNCTION__ << ": unconfirmed money received. height: " << height + << ", tx: " << tx_hash + << ", amount: " << print_money(amount)); + // do not signal on received tx if wallet is not syncronized completely + if (m_listener && m_wallet->synchronized()) { + m_listener->unconfirmedMoneyReceived(tx_hash, amount); + m_listener->updated(); + } + } + virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx) { @@ -277,6 +295,46 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co return true; } +bool WalletImpl::createWatchOnly(const std::string &path, const std::string &password, const std::string &language) const +{ + clearStatus(); + std::unique_ptr<tools::wallet2> view_wallet(new tools::wallet2(m_wallet->testnet())); + + // Store same refresh height as original wallet + view_wallet->set_refresh_from_block_height(m_wallet->get_refresh_from_block_height()); + + bool keys_file_exists; + bool wallet_file_exists; + tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + LOG_PRINT_L3("wallet_path: " << path << ""); + LOG_PRINT_L3("keys_file_exists: " << std::boolalpha << keys_file_exists << std::noboolalpha + << " wallet_file_exists: " << std::boolalpha << wallet_file_exists << std::noboolalpha); + + // add logic to error out if new wallet requested but named wallet file exists + if (keys_file_exists || wallet_file_exists) { + m_errorString = "attempting to generate view only wallet, but specified file(s) exist. Exiting to not risk overwriting."; + LOG_ERROR(m_errorString); + m_status = Status_Error; + return false; + } + // TODO: validate language + view_wallet->set_seed_language(language); + + const crypto::secret_key viewkey = m_wallet->get_account().get_keys().m_view_secret_key; + const cryptonote::account_public_address address = m_wallet->get_account().get_keys().m_account_address; + + try { + view_wallet->generate(path, password, address, viewkey); + m_status = Status_Ok; + } catch (const std::exception &e) { + LOG_ERROR("Error creating view only wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + return false; + } + return true; +} + bool WalletImpl::open(const std::string &path, const std::string &password) { clearStatus(); @@ -415,6 +473,11 @@ std::string WalletImpl::integratedAddress(const std::string &payment_id) const return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet()); } +std::string WalletImpl::privateViewKey() const +{ + return epee::string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key); +} + std::string WalletImpl::path() const { return m_wallet->path(); @@ -578,6 +641,50 @@ int WalletImpl::autoRefreshInterval() const return m_refreshIntervalMillis; } +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)){ + m_errorString = tr("Failed to load unsigned transactions"); + m_status = Status_Error; + } + + // Check tx data and construct confirmation message + std::string extra_message; + if (!transaction->m_unsigned_tx_set.transfers.empty()) + extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.size()).str(); + transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message); + m_status = transaction->status(); + m_errorString = transaction->errorString(); + + return transaction; +} + +bool WalletImpl::submitTransaction(const string &fileName) { + clearStatus(); + PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); + +// bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); }); + bool r = m_wallet->load_tx(fileName, transaction->m_pending_tx); + if (!r) { + m_errorString = tr("Failed to load transaction from file"); + m_status = Status_Ok; + delete transaction; + return false; + } + + if(!transaction->commit()) { + m_errorString = transaction->m_errorString; + m_status = Status_Error; + delete transaction; + return false; + } + + delete transaction; + + return true; +} + // TODO: // 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) // 2 - check / design how "Transaction" can be single interface @@ -595,6 +702,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const clearStatus(); // Pause refresh thread while creating transaction pauseRefresh(); + cryptonote::account_public_address addr; // indicates if dst_addr is integrated address (address + payment_id) @@ -966,7 +1074,12 @@ bool WalletImpl::trustedDaemon() const return m_trustedDaemon; } -void WalletImpl::clearStatus() +bool WalletImpl::watchOnly() const +{ + return m_wallet->watch_only(); +} + +void WalletImpl::clearStatus() const { m_status = Status_Ok; m_errorString.clear(); @@ -1020,7 +1133,9 @@ void WalletImpl::doRefresh() if (m_history->count() == 0) { m_history->refresh(); } - } + } else { + LOG_PRINT_L3(__FUNCTION__ << ": skipping refresh - daemon is not synced"); + } } catch (const std::exception &e) { m_status = Status_Error; m_errorString = e.what(); @@ -1067,8 +1182,9 @@ bool WalletImpl::isNewWallet() const // in case wallet created without daemon connection, closed and opened again, // it's the same case as if it created from scratch, i.e. we need "fast sync" // with the daemon (pull hashes instead of pull blocks). - // If wallet cache is rebuilt, creation height stored in .keys is used. - return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_rebuildWalletCache); + // If wallet cache is rebuilt, creation height stored in .keys is used. + // Watch only wallet is a copy of an existing wallet. + return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_rebuildWalletCache) && !watchOnly(); } void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit) @@ -1078,12 +1194,21 @@ void WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction // in case new wallet, this will force fast-refresh (pulling hashes instead of blocks) // If daemon isn't synced a calculated block height will be used instead if (isNewWallet() && daemonSynced()) { + LOG_PRINT_L2(__FUNCTION__ << ":New Wallet - fast refresh until " << daemonBlockChainHeight()); m_wallet->set_refresh_from_block_height(daemonBlockChainHeight()); } + if (m_rebuildWalletCache) + LOG_PRINT_L2(__FUNCTION__ << ": Rebuilding wallet cache, fast refresh until block " << m_wallet->get_refresh_from_block_height()); + if (Utils::isAddressLocal(daemon_address)) { this->setTrustedDaemon(true); + m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS; + } else { + this->setTrustedDaemon(false); + m_refreshIntervalMillis = DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS; } + } @@ -1092,6 +1217,24 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); } +bool WalletImpl::rescanSpent() +{ + clearStatus(); + if (!trustedDaemon()) { + m_status = Status_Error; + m_errorString = tr("Rescan spent can only be used with a trusted daemon"); + return false; + } + try { + m_wallet->rescan_spent(); + } catch (const std::exception &e) { + LOG_ERROR(__FUNCTION__ << " error: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + return false; + } + return true; +} } // namespace namespace Bitmonero = Monero; |