diff options
Diffstat (limited to 'src/wallet/api')
-rw-r--r-- | src/wallet/api/address_book.h | 14 | ||||
-rw-r--r-- | src/wallet/api/pending_transaction.cpp | 6 | ||||
-rw-r--r-- | src/wallet/api/pending_transaction.h | 26 | ||||
-rw-r--r-- | src/wallet/api/subaddress.h | 8 | ||||
-rw-r--r-- | src/wallet/api/transaction_info.h | 30 | ||||
-rw-r--r-- | src/wallet/api/unsigned_transaction.h | 23 | ||||
-rw-r--r-- | src/wallet/api/utils.cpp | 3 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 306 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 215 | ||||
-rw-r--r-- | src/wallet/api/wallet2_api.h | 111 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.cpp | 51 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.h | 54 |
12 files changed, 582 insertions, 265 deletions
diff --git a/src/wallet/api/address_book.h b/src/wallet/api/address_book.h index 7d9200550..f4ca68efd 100644 --- a/src/wallet/api/address_book.h +++ b/src/wallet/api/address_book.h @@ -42,16 +42,16 @@ public: ~AddressBookImpl(); // Fetches addresses from Wallet2 - void refresh(); - std::vector<AddressBookRow*> getAll() const; - bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description); - bool deleteRow(std::size_t rowId); + void refresh() override; + std::vector<AddressBookRow*> getAll() const override; + bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) override; + bool deleteRow(std::size_t rowId) override; // Error codes. See AddressBook:ErrorCode enum in wallet2_api.h - std::string errorString() const {return m_errorString;} - int errorCode() const {return m_errorCode;} + std::string errorString() const override {return m_errorString;} + int errorCode() const override {return m_errorCode;} - int lookupPaymentID(const std::string &payment_id) const; + int lookupPaymentID(const std::string &payment_id) const override; private: void clearRows(); diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp index 8d200220d..913e3156f 100644 --- a/src/wallet/api/pending_transaction.cpp +++ b/src/wallet/api/pending_transaction.cpp @@ -200,7 +200,11 @@ std::string PendingTransactionImpl::multisigSignData() { throw std::runtime_error("wallet is not multisig"); } - auto cipher = m_wallet.m_wallet->save_multisig_tx(m_pending_tx); + tools::wallet2::multisig_tx_set txSet; + txSet.m_ptx = m_pending_tx; + txSet.m_signers = m_signers; + auto cipher = m_wallet.m_wallet->save_multisig_tx(txSet); + return epee::string_tools::buff_to_hex_nodelimer(cipher); } catch (const std::exception& e) { m_status = Status_Error; diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h index 4f963c134..50b9f07ef 100644 --- a/src/wallet/api/pending_transaction.h +++ b/src/wallet/api/pending_transaction.h @@ -43,21 +43,21 @@ class PendingTransactionImpl : public PendingTransaction public: PendingTransactionImpl(WalletImpl &wallet); ~PendingTransactionImpl(); - int status() const; - std::string errorString() const; - bool commit(const std::string &filename = "", bool overwrite = false); - uint64_t amount() const; - uint64_t dust() const; - uint64_t fee() const; - std::vector<std::string> txid() const; - uint64_t txCount() const; - std::vector<uint32_t> subaddrAccount() const; - std::vector<std::set<uint32_t>> subaddrIndices() const; + int status() const override; + std::string errorString() const override; + bool commit(const std::string &filename = "", bool overwrite = false) override; + uint64_t amount() const override; + uint64_t dust() const override; + uint64_t fee() const override; + std::vector<std::string> txid() const override; + uint64_t txCount() const override; + std::vector<uint32_t> subaddrAccount() const override; + std::vector<std::set<uint32_t>> subaddrIndices() const override; // TODO: continue with interface; - std::string multisigSignData(); - void signMultisigTx(); - std::vector<std::string> signersKeys() const; + std::string multisigSignData() override; + void signMultisigTx() override; + std::vector<std::string> signersKeys() const override; private: friend class WalletImpl; diff --git a/src/wallet/api/subaddress.h b/src/wallet/api/subaddress.h index 3f9e37ac8..f3db7d97b 100644 --- a/src/wallet/api/subaddress.h +++ b/src/wallet/api/subaddress.h @@ -40,10 +40,10 @@ public: ~SubaddressImpl(); // Fetches addresses from Wallet2 - void refresh(uint32_t accountIndex); - std::vector<SubaddressRow*> getAll() const; - void addRow(uint32_t accountIndex, const std::string &label); - void setLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label); + void refresh(uint32_t accountIndex) override; + std::vector<SubaddressRow*> getAll() const override; + void addRow(uint32_t accountIndex, const std::string &label) override; + void setLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) override; private: void clearRows(); diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 5df9a44ef..37e0445d9 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -42,24 +42,24 @@ public: TransactionInfoImpl(); ~TransactionInfoImpl(); //! in/out - virtual int direction() const; + virtual int direction() const override; //! true if hold - virtual bool isPending() const; - virtual bool isFailed() const; - virtual uint64_t amount() const; + virtual bool isPending() const override; + virtual bool isFailed() const override; + virtual uint64_t amount() const override; //! always 0 for incoming txes - virtual uint64_t fee() const; - virtual uint64_t blockHeight() const; - virtual std::set<uint32_t> subaddrIndex() const; - virtual uint32_t subaddrAccount() const; - virtual std::string label() const; + virtual uint64_t fee() const override; + virtual uint64_t blockHeight() const override; + virtual std::set<uint32_t> subaddrIndex() const override; + virtual uint32_t subaddrAccount() const override; + virtual std::string label() const override; - virtual std::string hash() const; - virtual std::time_t timestamp() const; - virtual std::string paymentId() const; - virtual const std::vector<Transfer> &transfers() const; - virtual uint64_t confirmations() const; - virtual uint64_t unlockTime() const; + virtual std::string hash() const override; + virtual std::time_t timestamp() const override; + virtual std::string paymentId() const override; + virtual const std::vector<Transfer> &transfers() const override; + virtual uint64_t confirmations() const override; + virtual uint64_t unlockTime() const override; private: int m_direction; diff --git a/src/wallet/api/unsigned_transaction.h b/src/wallet/api/unsigned_transaction.h index a35630535..8a3330014 100644 --- a/src/wallet/api/unsigned_transaction.h +++ b/src/wallet/api/unsigned_transaction.h @@ -43,19 +43,18 @@ class UnsignedTransactionImpl : public UnsignedTransaction public: UnsignedTransactionImpl(WalletImpl &wallet); ~UnsignedTransactionImpl(); - int status() const; - std::string errorString() const; - std::vector<uint64_t> amount() const; - std::vector<uint64_t> dust() const; - std::vector<uint64_t> fee() const; - std::vector<uint64_t> mixin() const; - std::vector<std::string> paymentId() const; - std::vector<std::string> recipientAddress() const; - uint64_t txCount() const; + int status() const override; + std::string errorString() const override; + std::vector<uint64_t> amount() const override; + std::vector<uint64_t> fee() const override; + std::vector<uint64_t> mixin() const override; + std::vector<std::string> paymentId() const override; + std::vector<std::string> recipientAddress() const override; + uint64_t txCount() const override; // sign txs and save to file - bool sign(const std::string &signedFileName); - std::string confirmationMessage() const {return m_confirmationMessage;} - uint64_t minMixinCount() const; + bool sign(const std::string &signedFileName) override; + std::string confirmationMessage() const override {return m_confirmationMessage;} + uint64_t minMixinCount() const override; private: // Callback function to check all loaded tx's and generate confirmationMessage diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp index aebe41e59..86fe56564 100644 --- a/src/wallet/api/utils.cpp +++ b/src/wallet/api/utils.cpp @@ -51,6 +51,9 @@ bool isAddressLocal(const std::string &address) void onStartup() { tools::on_startup(); +#ifdef NDEBUG + tools::disable_core_dumps(); +#endif } } diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 908e2db2e..ddf2d74ff 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -96,6 +96,9 @@ namespace { throw runtime_error("Multisig wallet is not finalized yet"); } } + void checkMultisigWalletReady(const std::unique_ptr<tools::wallet2> &wallet) { + return checkMultisigWalletReady(wallet.get()); + } void checkMultisigWalletNotReady(const tools::wallet2* wallet) { if (!wallet) { @@ -111,6 +114,9 @@ namespace { throw runtime_error("Multisig wallet is already finalized"); } } + void checkMultisigWalletNotReady(const std::unique_ptr<tools::wallet2> &wallet) { + return checkMultisigWalletNotReady(wallet.get()); + } } struct Wallet2CallbackImpl : public tools::i_wallet2_callback @@ -366,25 +372,26 @@ void Wallet::error(const std::string &category, const std::string &str) { } ///////////////////////// WalletImpl implementation //////////////////////// -WalletImpl::WalletImpl(NetworkType nettype) +WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds) :m_wallet(nullptr) , m_status(Wallet::Status_Ok) - , m_trustedDaemon(false) , m_wallet2Callback(nullptr) , m_recoveringFromSeed(false) + , m_recoveringFromDevice(false) , m_synchronized(false) , m_rebuildWalletCache(false) , m_is_connected(false) + , m_refreshShouldRescan(false) { - m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype)); - m_history = new TransactionHistoryImpl(this); - m_wallet2Callback = new Wallet2CallbackImpl(this); - m_wallet->callback(m_wallet2Callback); + m_wallet.reset(new tools::wallet2(static_cast<cryptonote::network_type>(nettype), kdf_rounds, true)); + m_history.reset(new TransactionHistoryImpl(this)); + m_wallet2Callback.reset(new Wallet2CallbackImpl(this)); + m_wallet->callback(m_wallet2Callback.get()); m_refreshThreadDone = false; m_refreshEnabled = false; - m_addressBook = new AddressBookImpl(this); - m_subaddress = new SubaddressImpl(this); - m_subaddressAccount = new SubaddressAccountImpl(this); + m_addressBook.reset(new AddressBookImpl(this)); + m_subaddress.reset(new SubaddressImpl(this)); + m_subaddressAccount.reset(new SubaddressAccountImpl(this)); m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS; @@ -399,18 +406,13 @@ WalletImpl::~WalletImpl() { LOG_PRINT_L1(__FUNCTION__); + m_wallet->callback(NULL); // Pause refresh thread - prevents refresh from starting again pauseRefresh(); // Close wallet - stores cache and stops ongoing refresh operation close(false); // do not store wallet as part of the closing activities // Stop refresh thread stopRefresh(); - delete m_wallet2Callback; - delete m_history; - delete m_addressBook; - delete m_subaddress; - delete m_subaddressAccount; - delete m_wallet; LOG_PRINT_L1(__FUNCTION__ << " finished"); } @@ -419,6 +421,7 @@ bool WalletImpl::create(const std::string &path, const std::string &password, co clearStatus(); m_recoveringFromSeed = false; + m_recoveringFromDevice = false; bool keys_file_exists; bool wallet_file_exists; tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); @@ -554,18 +557,26 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path, } // parse view secret key + bool has_viewkey = true; + crypto::secret_key viewkey; if (viewkey_string.empty()) { - setStatusError(tr("No view key supplied, cancelled")); - return false; + if(has_spendkey) { + has_viewkey = false; + } + else { + setStatusError(tr("Neither view key nor spend key supplied, cancelled")); + return false; + } } - cryptonote::blobdata viewkey_data; - if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key)) - { - setStatusError(tr("failed to parse secret view key")); - return false; + if(has_viewkey) { + cryptonote::blobdata viewkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key)) + { + setStatusError(tr("failed to parse secret view key")); + return false; + } + viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data()); } - crypto::secret_key viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data()); - // check the spend and view keys match the given address crypto::public_key pkey; if(has_spendkey) { @@ -578,26 +589,32 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path, return false; } } - if (!crypto::secret_key_to_public_key(viewkey, pkey)) { - setStatusError(tr("failed to verify secret view key")); - return false; - } - if (info.address.m_view_public_key != pkey) { - setStatusError(tr("view key does not match address")); - return false; + if(has_viewkey) { + if (!crypto::secret_key_to_public_key(viewkey, pkey)) { + setStatusError(tr("failed to verify secret view key")); + return false; + } + if (info.address.m_view_public_key != pkey) { + setStatusError(tr("view key does not match address")); + return false; + } } try { - if (has_spendkey) { + if (has_spendkey && has_viewkey) { m_wallet->generate(path, password, info.address, spendkey, viewkey); - setSeedLanguage(language); - LOG_PRINT_L1("Generated new wallet from keys with seed language: " + language); + LOG_PRINT_L1("Generated new wallet from spend key and view key"); } - else { + if(!has_spendkey && has_viewkey) { m_wallet->generate(path, password, info.address, viewkey); LOG_PRINT_L1("Generated new view only wallet from keys"); } + if(has_spendkey && !has_viewkey) { + m_wallet->generate(path, password, spendkey, true, false); + setSeedLanguage(language); + LOG_PRINT_L1("Generated deterministic wallet from spend key with seed language: " + language); + } } catch (const std::exception& e) { @@ -607,11 +624,33 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path, return true; } +bool WalletImpl::recoverFromDevice(const std::string &path, const std::string &password, const std::string &device_name) +{ + clearStatus(); + m_recoveringFromSeed = false; + m_recoveringFromDevice = true; + try + { + m_wallet->restore(path, password, device_name); + LOG_PRINT_L1("Generated new wallet from device: " + device_name); + } + catch (const std::exception& e) { + setStatusError(string(tr("failed to generate new wallet: ")) + e.what()); + return false; + } + return true; +} + +Wallet::Device WalletImpl::getDeviceType() const +{ + return static_cast<Wallet::Device>(m_wallet->get_device_type()); +} bool WalletImpl::open(const std::string &path, const std::string &password) { clearStatus(); m_recoveringFromSeed = false; + m_recoveringFromDevice = false; try { // TODO: handle "deprecated" // Check if wallet cache exists @@ -649,6 +688,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c } m_recoveringFromSeed = true; + m_recoveringFromDevice = false; crypto::secret_key recovery_key; std::string old_language; if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) { @@ -687,6 +727,7 @@ bool WalletImpl::close(bool store) LOG_PRINT_L1("Calling wallet::stop..."); m_wallet->stop(); LOG_PRINT_L1("wallet::stop done"); + m_wallet->deinit(); result = true; clearStatus(); } catch (const std::exception &e) { @@ -698,10 +739,10 @@ bool WalletImpl::close(bool store) std::string WalletImpl::seed() const { - std::string seed; + epee::wipeable_string seed; if (m_wallet) m_wallet->get_seed(seed); - return seed; + return std::string(seed.data(), seed.size()); // TODO } std::string WalletImpl::getSeedLanguage() const @@ -736,7 +777,7 @@ bool WalletImpl::setPassword(const std::string &password) { clearStatus(); try { - m_wallet->rewrite(m_wallet->get_wallet_file(), password); + m_wallet->change_password(m_wallet->get_wallet_file(), m_password, password); m_password = password; } catch (const std::exception &e) { setStatusError(e.what()); @@ -870,6 +911,16 @@ void WalletImpl::setRecoveringFromSeed(bool recoveringFromSeed) m_recoveringFromSeed = recoveringFromSeed; } +void WalletImpl::setRecoveringFromDevice(bool recoveringFromDevice) +{ + m_recoveringFromDevice = recoveringFromDevice; +} + +void WalletImpl::setSubaddressLookahead(uint32_t major, uint32_t minor) +{ + m_wallet->set_subaddress_lookahead(major, minor); +} + uint64_t WalletImpl::balance(uint32_t accountIndex) const { return m_wallet->balance(accountIndex); @@ -961,6 +1012,20 @@ void WalletImpl::refreshAsync() m_refreshCV.notify_one(); } +bool WalletImpl::rescanBlockchain() +{ + clearStatus(); + m_refreshShouldRescan = true; + doRefresh(); + return status() == Status_Ok; +} + +void WalletImpl::rescanBlockchainAsync() +{ + m_refreshShouldRescan = true; + refreshAsync(); +} + void WalletImpl::setAutoRefreshInterval(int millis) { if (millis > MAX_REFRESH_INTERVAL_MILLIS) { @@ -1138,6 +1203,20 @@ string WalletImpl::makeMultisig(const vector<string>& info, uint32_t threshold) return string(); } +std::string WalletImpl::exchangeMultisigKeys(const std::vector<std::string> &info) { + try { + clearStatus(); + checkMultisigWalletNotReady(m_wallet); + + return m_wallet->exchange_multisig_keys(epee::wipeable_string(m_password), info); + } catch (const exception& e) { + LOG_ERROR("Error on exchanging multisig keys: ") << e.what(); + setStatusError(string(tr("Failed to make multisig: ")) + e.what()); + } + + return string(); +} + bool WalletImpl::finalizeMultisig(const vector<string>& extraMultisigInfo) { try { clearStatus(); @@ -1200,6 +1279,20 @@ size_t WalletImpl::importMultisigImages(const vector<string>& images) { return 0; } +bool WalletImpl::hasMultisigPartialKeyImages() const { + try { + clearStatus(); + checkMultisigWalletReady(m_wallet); + + return m_wallet->has_multisig_partial_key_images(); + } catch (const exception& e) { + LOG_ERROR("Error on checking for partial multisig key images: ") << e.what(); + setStatusError(string(tr("Failed to check for partial multisig key images: ")) + e.what()); + } + + return false; +} + PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signData) { try { clearStatus(); @@ -1253,6 +1346,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIXIN; + fake_outs_count = m_wallet->adjust_mixin(fake_outs_count); uint32_t adjusted_priority = m_wallet->adjust_priority(static_cast<uint32_t>(priority)); @@ -1313,7 +1407,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const dsts.push_back(de); transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, adjusted_priority, - extra, subaddr_account, subaddr_indices, m_trustedDaemon); + extra, subaddr_account, subaddr_indices); } else { // for the GUI, sweep_all (i.e. amount set as "(all)") will always sweep all the funds in all the addresses if (subaddr_indices.empty()) @@ -1321,9 +1415,9 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index) subaddr_indices.insert(index); } - transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, adjusted_priority, - extra, subaddr_account, subaddr_indices, m_trustedDaemon); + extra, subaddr_account, subaddr_indices); } if (multisig().isMultisig) { @@ -1336,8 +1430,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const setStatusError(tr("no connection to daemon. Please make sure daemon is running.")); } catch (const tools::error::wallet_rpc_error& e) { setStatusError(tr("RPC error: ") + e.to_string()); - } catch (const tools::error::get_random_outs_error &e) { - setStatusError((boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str()); + } catch (const tools::error::get_outs_error &e) { + setStatusError((boost::format(tr("failed to get outputs to mix: %s")) % e.what()).str()); } catch (const tools::error::not_enough_unlocked_money& e) { std::ostringstream writer; @@ -1409,7 +1503,7 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() do { try { - transaction->m_pending_tx = m_wallet->create_unmixable_sweep_transactions(m_trustedDaemon); + transaction->m_pending_tx = m_wallet->create_unmixable_sweep_transactions(); } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? @@ -1418,8 +1512,8 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() setStatusError(tr("no connection to daemon. Please make sure daemon is running.")); } catch (const tools::error::wallet_rpc_error& e) { setStatusError(tr("RPC error: ") + e.to_string()); - } catch (const tools::error::get_random_outs_error&) { - setStatusError(tr("failed to get random outputs to mix")); + } catch (const tools::error::get_outs_error&) { + setStatusError(tr("failed to get outputs to mix")); } catch (const tools::error::not_enough_unlocked_money& e) { setStatusError(""); std::ostringstream writer; @@ -1487,22 +1581,22 @@ void WalletImpl::disposeTransaction(PendingTransaction *t) TransactionHistory *WalletImpl::history() { - return m_history; + return m_history.get(); } AddressBook *WalletImpl::addressBook() { - return m_addressBook; + return m_addressBook.get(); } Subaddress *WalletImpl::subaddress() { - return m_subaddress; + return m_subaddress.get(); } SubaddressAccount *WalletImpl::subaddressAccount() { - return m_subaddressAccount; + return m_subaddressAccount.get(); } void WalletImpl::setListener(WalletListener *l) @@ -1846,12 +1940,12 @@ Wallet::ConnectionStatus WalletImpl::connected() const void WalletImpl::setTrustedDaemon(bool arg) { - m_trustedDaemon = arg; + m_wallet->set_trusted_daemon(arg); } bool WalletImpl::trustedDaemon() const { - return m_trustedDaemon; + return m_wallet->is_trusted_daemon(); } bool WalletImpl::watchOnly() const @@ -1896,7 +1990,7 @@ void WalletImpl::refreshThreadFunc() // if auto refresh enabled, we wait for the "m_refreshIntervalSeconds" interval. // if not - we wait forever if (m_refreshIntervalMillis > 0) { - boost::posix_time::milliseconds wait_for_ms(m_refreshIntervalMillis); + boost::posix_time::milliseconds wait_for_ms(m_refreshIntervalMillis.load()); m_refreshCV.timed_wait(lock, wait_for_ms); } else { m_refreshCV.wait(lock); @@ -1905,6 +1999,7 @@ void WalletImpl::refreshThreadFunc() LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired..."); LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled); LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << status()); + LOG_PRINT_L3(__FUNCTION__ << ": m_refreshShouldRescan: " << m_refreshShouldRescan); if (m_refreshEnabled) { LOG_PRINT_L3(__FUNCTION__ << ": refreshing..."); doRefresh(); @@ -1915,13 +2010,17 @@ void WalletImpl::refreshThreadFunc() void WalletImpl::doRefresh() { + bool rescan = m_refreshShouldRescan.exchange(false); // synchronizing async and sync refresh calls boost::lock_guard<boost::mutex> guarg(m_refreshMutex2); - try { + do try { + LOG_PRINT_L3(__FUNCTION__ << ": doRefresh, rescan = "<<rescan); // Syncing daemon and refreshing wallet simultaneously is very resource intensive. // Disable refresh if wallet is disconnected or daemon isn't synced. if (m_wallet->light_wallet() || daemonSynced()) { - m_wallet->refresh(); + if(rescan) + m_wallet->rescan_blockchain(false); + m_wallet->refresh(trustedDaemon()); if (!m_synchronized) { m_synchronized = true; } @@ -1937,7 +2036,9 @@ void WalletImpl::doRefresh() } } catch (const std::exception &e) { setStatusError(e.what()); - } + break; + }while(!rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested + if (m_wallet2Callback->getListener()) { m_wallet2Callback->getListener()->refreshed(); } @@ -1982,11 +2083,12 @@ bool WalletImpl::isNewWallet() const // with the daemon (pull hashes instead of pull blocks). // 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(); + return !(blockChainHeight() > 1 || m_recoveringFromSeed || m_recoveringFromDevice || m_rebuildWalletCache) && !watchOnly(); } bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit, bool ssl) { + // claim RPC so there's no in-memory encryption for now if (!m_wallet->init(daemon_address, m_daemon_login, upper_transaction_size_limit, ssl)) return false; @@ -2049,41 +2151,83 @@ bool WalletImpl::useForkRules(uint8_t version, int64_t early_blocks) const return m_wallet->use_fork_rules(version,early_blocks); } -bool WalletImpl::blackballOutputs(const std::vector<std::string> &pubkeys, bool add) +bool WalletImpl::blackballOutputs(const std::vector<std::string> &outputs, bool add) { - std::vector<crypto::public_key> raw_pubkeys; - raw_pubkeys.reserve(pubkeys.size()); - for (const std::string &str: pubkeys) + std::vector<std::pair<uint64_t, uint64_t>> raw_outputs; + raw_outputs.reserve(outputs.size()); + uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets; + for (const std::string &str: outputs) { - crypto::public_key pkey; - if (!epee::string_tools::hex_to_pod(str, pkey)) + if (sscanf(str.c_str(), "@%" PRIu64, &amount) == 1) + continue; + if (amount == std::numeric_limits<uint64_t>::max()) { - setStatusError(tr("Failed to parse output public key")); - return false; + setStatusError("First line is not an amount"); + return true; + } + if (sscanf(str.c_str(), "%" PRIu64 "*%" PRIu64, &offset, &num_offsets) == 2 && num_offsets <= std::numeric_limits<uint64_t>::max() - offset) + { + while (num_offsets--) + raw_outputs.push_back(std::make_pair(amount, offset++)); + } + else if (sscanf(str.c_str(), "%" PRIu64, &offset) == 1) + { + raw_outputs.push_back(std::make_pair(amount, offset)); + } + else + { + setStatusError(tr("Invalid output: ") + str); + return false; } - raw_pubkeys.push_back(pkey); } - bool ret = m_wallet->set_blackballed_outputs(raw_pubkeys, add); + bool ret = m_wallet->set_blackballed_outputs(raw_outputs, add); if (!ret) { - setStatusError(tr("Failed to set blackballed outputs")); + setStatusError(tr("Failed to mark outputs as spent")); return false; } return true; } -bool WalletImpl::unblackballOutput(const std::string &pubkey) +bool WalletImpl::blackballOutput(const std::string &amount, const std::string &offset) { - crypto::public_key raw_pubkey; - if (!epee::string_tools::hex_to_pod(pubkey, raw_pubkey)) + uint64_t raw_amount, raw_offset; + if (!epee::string_tools::get_xtype_from_string(raw_amount, amount)) { - setStatusError(tr("Failed to parse output public key")); + setStatusError(tr("Failed to parse output amount")); return false; } - bool ret = m_wallet->unblackball_output(raw_pubkey); + if (!epee::string_tools::get_xtype_from_string(raw_offset, offset)) + { + setStatusError(tr("Failed to parse output offset")); + return false; + } + bool ret = m_wallet->blackball_output(std::make_pair(raw_amount, raw_offset)); if (!ret) { - setStatusError(tr("Failed to unblackball output")); + setStatusError(tr("Failed to mark output as spent")); + return false; + } + return true; +} + +bool WalletImpl::unblackballOutput(const std::string &amount, const std::string &offset) +{ + uint64_t raw_amount, raw_offset; + if (!epee::string_tools::get_xtype_from_string(raw_amount, amount)) + { + setStatusError(tr("Failed to parse output amount")); + return false; + } + if (!epee::string_tools::get_xtype_from_string(raw_offset, offset)) + { + setStatusError(tr("Failed to parse output offset")); + return false; + } + bool ret = m_wallet->unblackball_output(std::make_pair(raw_amount, raw_offset)); + if (!ret) + { + setStatusError(tr("Failed to mark output as unspent")); return false; } return true; @@ -2160,6 +2304,20 @@ void WalletImpl::keyReuseMitigation2(bool mitigation) m_wallet->key_reuse_mitigation2(mitigation); } +bool WalletImpl::lockKeysFile() +{ + return m_wallet->lock_keys_file(); +} + +bool WalletImpl::unlockKeysFile() +{ + return m_wallet->unlock_keys_file(); +} + +bool WalletImpl::isKeysFileLocked() +{ + return m_wallet->is_keys_file_locked(); +} } // namespace namespace Bitmonero = Monero; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 813ca4b30..b4637b8e6 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -52,12 +52,12 @@ struct Wallet2CallbackImpl; class WalletImpl : public Wallet { public: - WalletImpl(NetworkType nettype = MAINNET); + WalletImpl(NetworkType nettype = MAINNET, uint64_t kdf_rounds = 1); ~WalletImpl(); bool create(const std::string &path, const std::string &password, const std::string &language); bool createWatchOnly(const std::string &path, const std::string &password, - const std::string &language) const; + const std::string &language) const override; bool open(const std::string &path, const std::string &password); bool recover(const std::string &path,const std::string &password, const std::string &seed); @@ -76,113 +76,127 @@ public: const std::string &address_string, const std::string &viewkey_string, const std::string &spendkey_string = ""); + bool recoverFromDevice(const std::string &path, + const std::string &password, + const std::string &device_name); + Device getDeviceType() const override; bool close(bool store = true); - std::string seed() const; - std::string getSeedLanguage() const; - void setSeedLanguage(const std::string &arg); + std::string seed() const override; + std::string getSeedLanguage() const override; + void setSeedLanguage(const std::string &arg) override; // void setListener(Listener *) {} - int status() const; - std::string errorString() const; + int status() const override; + std::string errorString() const override; void statusWithErrorString(int& status, std::string& errorString) const override; - bool setPassword(const std::string &password); - std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const; - std::string integratedAddress(const std::string &payment_id) const; - std::string secretViewKey() const; - std::string publicViewKey() const; - std::string secretSpendKey() const; - std::string publicSpendKey() const; - std::string publicMultisigSignerKey() const; - std::string path() const; - bool store(const std::string &path); - std::string filename() const; - std::string keysFilename() const; - bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false); - bool connectToDaemon(); - ConnectionStatus connected() const; - void setTrustedDaemon(bool arg); - bool trustedDaemon() const; - uint64_t balance(uint32_t accountIndex = 0) const; - uint64_t unlockedBalance(uint32_t accountIndex = 0) const; - uint64_t blockChainHeight() const; - uint64_t approximateBlockChainHeight() const; - uint64_t daemonBlockChainHeight() const; - uint64_t daemonBlockChainTargetHeight() const; - bool synchronized() const; - bool refresh(); - void refreshAsync(); - void setAutoRefreshInterval(int millis); - int autoRefreshInterval() const; - void setRefreshFromBlockHeight(uint64_t refresh_from_block_height); - uint64_t getRefreshFromBlockHeight() const { return m_wallet->get_refresh_from_block_height(); }; - void setRecoveringFromSeed(bool recoveringFromSeed); - bool watchOnly() const; - bool rescanSpent(); - NetworkType nettype() const {return static_cast<NetworkType>(m_wallet->nettype());} - void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const; - bool useForkRules(uint8_t version, int64_t early_blocks) const; - - void addSubaddressAccount(const std::string& label); - size_t numSubaddressAccounts() const; - size_t numSubaddresses(uint32_t accountIndex) const; - void addSubaddress(uint32_t accountIndex, const std::string& label); - std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const; - void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label); + bool setPassword(const std::string &password) override; + std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const override; + std::string integratedAddress(const std::string &payment_id) const override; + std::string secretViewKey() const override; + std::string publicViewKey() const override; + std::string secretSpendKey() const override; + std::string publicSpendKey() const override; + std::string publicMultisigSignerKey() const override; + std::string path() const override; + bool store(const std::string &path) override; + std::string filename() const override; + std::string keysFilename() const override; + bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false) override; + bool connectToDaemon() override; + ConnectionStatus connected() const override; + void setTrustedDaemon(bool arg) override; + bool trustedDaemon() const override; + uint64_t balance(uint32_t accountIndex = 0) const override; + uint64_t unlockedBalance(uint32_t accountIndex = 0) const override; + uint64_t blockChainHeight() const override; + uint64_t approximateBlockChainHeight() const override; + uint64_t daemonBlockChainHeight() const override; + uint64_t daemonBlockChainTargetHeight() const override; + bool synchronized() const override; + bool refresh() override; + void refreshAsync() override; + bool rescanBlockchain() override; + void rescanBlockchainAsync() override; + void setAutoRefreshInterval(int millis) override; + int autoRefreshInterval() const override; + void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) override; + uint64_t getRefreshFromBlockHeight() const override { return m_wallet->get_refresh_from_block_height(); }; + void setRecoveringFromSeed(bool recoveringFromSeed) override; + void setRecoveringFromDevice(bool recoveringFromDevice) override; + void setSubaddressLookahead(uint32_t major, uint32_t minor) override; + bool watchOnly() const override; + bool rescanSpent() override; + NetworkType nettype() const override {return static_cast<NetworkType>(m_wallet->nettype());} + void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const override; + bool useForkRules(uint8_t version, int64_t early_blocks) const override; + + void addSubaddressAccount(const std::string& label) override; + size_t numSubaddressAccounts() const override; + size_t numSubaddresses(uint32_t accountIndex) const override; + void addSubaddress(uint32_t accountIndex, const std::string& label) override; + std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const override; + void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) override; MultisigState multisig() const override; std::string getMultisigInfo() const override; std::string makeMultisig(const std::vector<std::string>& info, uint32_t threshold) override; + std::string exchangeMultisigKeys(const std::vector<std::string> &info) override; bool finalizeMultisig(const std::vector<std::string>& extraMultisigInfo) override; bool exportMultisigImages(std::string& images) override; size_t importMultisigImages(const std::vector<std::string>& images) override; + bool hasMultisigPartialKeyImages() const override; PendingTransaction* restoreMultisigTransaction(const std::string& signData) override; PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, optional<uint64_t> amount, uint32_t mixin_count, PendingTransaction::Priority priority = PendingTransaction::Priority_Low, uint32_t subaddr_account = 0, - std::set<uint32_t> subaddr_indices = {}); - virtual PendingTransaction * createSweepUnmixableTransaction(); - bool submitTransaction(const std::string &fileName); - virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename); - bool exportKeyImages(const std::string &filename); - bool importKeyImages(const std::string &filename); - - virtual void disposeTransaction(PendingTransaction * t); - virtual TransactionHistory * history(); - virtual AddressBook * addressBook(); - virtual Subaddress * subaddress(); - virtual SubaddressAccount * subaddressAccount(); - virtual void setListener(WalletListener * l); - virtual uint32_t defaultMixin() const; - virtual void setDefaultMixin(uint32_t arg); - virtual bool setUserNote(const std::string &txid, const std::string ¬e); - virtual std::string getUserNote(const std::string &txid) const; - virtual std::string getTxKey(const std::string &txid) const; - virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received, bool &in_pool, uint64_t &confirmations); - virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const; - virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations); - virtual std::string getSpendProof(const std::string &txid, const std::string &message) const; - virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const; - virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const; - virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const; - virtual std::string signMessage(const std::string &message); - virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const; - virtual std::string signMultisigParticipant(const std::string &message) const; - virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const; - virtual void startRefresh(); - virtual void pauseRefresh(); - virtual bool 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); - virtual std::string getDefaultDataDir() const; - virtual bool lightWalletLogin(bool &isNewWallet) const; - virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status); - virtual bool blackballOutputs(const std::vector<std::string> &pubkeys, bool add); - virtual bool unblackballOutput(const std::string &pubkey); - virtual bool getRing(const std::string &key_image, std::vector<uint64_t> &ring) const; - virtual bool getRings(const std::string &txid, std::vector<std::pair<std::string, std::vector<uint64_t>>> &rings) const; - virtual bool setRing(const std::string &key_image, const std::vector<uint64_t> &ring, bool relative); - virtual void segregatePreForkOutputs(bool segregate); - virtual void segregationHeight(uint64_t height); - virtual void keyReuseMitigation2(bool mitigation); + std::set<uint32_t> subaddr_indices = {}) override; + virtual PendingTransaction * createSweepUnmixableTransaction() override; + bool submitTransaction(const std::string &fileName) override; + virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override; + bool exportKeyImages(const std::string &filename) override; + bool importKeyImages(const std::string &filename) override; + + virtual void disposeTransaction(PendingTransaction * t) override; + virtual TransactionHistory * history() override; + virtual AddressBook * addressBook() override; + virtual Subaddress * subaddress() override; + virtual SubaddressAccount * subaddressAccount() override; + virtual void setListener(WalletListener * l) override; + virtual uint32_t defaultMixin() const override; + virtual void setDefaultMixin(uint32_t arg) override; + virtual bool setUserNote(const std::string &txid, const std::string ¬e) override; + virtual std::string getUserNote(const std::string &txid) const override; + virtual std::string getTxKey(const std::string &txid) const override; + virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) override; + virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const override; + virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations) override; + virtual std::string getSpendProof(const std::string &txid, const std::string &message) const override; + virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const override; + virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const override; + virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const override; + virtual std::string signMessage(const std::string &message) override; + virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const override; + virtual std::string signMultisigParticipant(const std::string &message) const override; + virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const override; + virtual void startRefresh() override; + virtual void pauseRefresh() override; + virtual bool 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) override; + virtual std::string getDefaultDataDir() const override; + virtual bool lightWalletLogin(bool &isNewWallet) const override; + virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) override; + virtual bool blackballOutputs(const std::vector<std::string> &outputs, bool add) override; + virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; + virtual bool unblackballOutput(const std::string &amount, const std::string &offset) override; + virtual bool getRing(const std::string &key_image, std::vector<uint64_t> &ring) const override; + virtual bool getRings(const std::string &txid, std::vector<std::pair<std::string, std::vector<uint64_t>>> &rings) const override; + virtual bool setRing(const std::string &key_image, const std::vector<uint64_t> &ring, bool relative) override; + virtual void segregatePreForkOutputs(bool segregate) override; + virtual void segregationHeight(uint64_t height) override; + virtual void keyReuseMitigation2(bool mitigation) override; + virtual bool lockKeysFile() override; + virtual bool unlockKeysFile() override; + virtual bool isKeysFileLocked() override; private: void clearStatus() const; @@ -205,22 +219,22 @@ private: friend class SubaddressImpl; friend class SubaddressAccountImpl; - tools::wallet2 * m_wallet; + std::unique_ptr<tools::wallet2> m_wallet; mutable boost::mutex m_statusMutex; mutable int m_status; mutable std::string m_errorString; std::string m_password; - TransactionHistoryImpl * m_history; - bool m_trustedDaemon; - Wallet2CallbackImpl * m_wallet2Callback; - AddressBookImpl * m_addressBook; - SubaddressImpl * m_subaddress; - SubaddressAccountImpl * m_subaddressAccount; + std::unique_ptr<TransactionHistoryImpl> m_history; + std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback; + std::unique_ptr<AddressBookImpl> m_addressBook; + std::unique_ptr<SubaddressImpl> m_subaddress; + std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount; // multi-threaded refresh stuff std::atomic<bool> m_refreshEnabled; std::atomic<bool> m_refreshThreadDone; std::atomic<int> m_refreshIntervalMillis; + std::atomic<bool> m_refreshShouldRescan; // synchronizing refresh loop; boost::mutex m_refreshMutex; @@ -232,6 +246,7 @@ private: // so it shouldn't be considered as new and pull blocks (slow-refresh) // instead of pulling hashes (fast-refresh) std::atomic<bool> m_recoveringFromSeed; + std::atomic<bool> m_recoveringFromDevice; std::atomic<bool> m_synchronized; std::atomic<bool> m_rebuildWalletCache; // cache connection status to avoid unnecessary RPC calls diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 5b99bd975..82627de29 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -373,6 +373,10 @@ struct WalletListener */ struct Wallet { + enum Device { + Device_Software = 0, + Device_Ledger = 1 + }; enum Status { Status_Ok, @@ -509,6 +513,21 @@ struct Wallet */ virtual void setRecoveringFromSeed(bool recoveringFromSeed) = 0; + /*! + * \brief setRecoveringFromDevice - set state to recovering from device + * + * \param recoveringFromDevice - true/false + */ + virtual void setRecoveringFromDevice(bool recoveringFromDevice) = 0; + + /*! + * \brief setSubaddressLookahead - set size of subaddress lookahead + * + * \param major - size fot the major index + * \param minor - size fot the minor index + */ + virtual void setSubaddressLookahead(uint32_t major, uint32_t minor) = 0; + /** * @brief connectToDaemon - connects to the daemon. TODO: check if it can be removed * @return @@ -625,6 +644,17 @@ struct Wallet virtual void refreshAsync() = 0; /** + * @brief rescanBlockchain - rescans the wallet, updating transactions from daemon + * @return - true if refreshed successfully; + */ + virtual bool rescanBlockchain() = 0; + + /** + * @brief rescanBlockchainAsync - rescans wallet asynchronously, starting from genesys + */ + virtual void rescanBlockchainAsync() = 0; + + /** * @brief setAutoRefreshInterval - setup interval for automatic refresh. * @param seconds - interval in millis. if zero or less than zero - automatic refresh disabled; */ @@ -688,6 +718,12 @@ struct Wallet */ virtual std::string makeMultisig(const std::vector<std::string>& info, uint32_t threshold) = 0; /** + * @brief exchange_multisig_keys - provides additional key exchange round for arbitrary multisig schemes (like N-1/N, M/N) + * @param info - base58 encoded key derivations returned by makeMultisig or exchangeMultisigKeys function call + * @return new info string if more rounds required or an empty string if wallet creation is done + */ + virtual std::string exchangeMultisigKeys(const std::vector<std::string> &info) = 0; + /** * @brief finalizeMultisig - finalizes N - 1 / N multisig wallets creation * @param extraMultisigInfo - wallet participants' extra multisig info obtained with makeMultisig call * @return true if success @@ -705,6 +741,11 @@ struct Wallet * @return number of imported images */ virtual size_t importMultisigImages(const std::vector<std::string>& images) = 0; + /** + * @brief hasMultisigPartialKeyImages - checks if wallet needs to import multisig key images from other participants + * @return true if there are partial key images + */ + virtual bool hasMultisigPartialKeyImages() const = 0; /** * @brief restoreMultisigTransaction creates PendingTransaction from signData @@ -857,10 +898,13 @@ struct Wallet virtual bool rescanSpent() = 0; //! blackballs a set of outputs - virtual bool blackballOutputs(const std::vector<std::string> &pubkeys, bool add) = 0; + virtual bool blackballOutputs(const std::vector<std::string> &outputs, bool add) = 0; + + //! blackballs an output + virtual bool blackballOutput(const std::string &amount, const std::string &offset) = 0; //! unblackballs an output - virtual bool unblackballOutput(const std::string &pubkey) = 0; + virtual bool unblackballOutput(const std::string &amount, const std::string &offset) = 0; //! gets the ring used for a key image, if any virtual bool getRing(const std::string &key_image, std::vector<uint64_t> &ring) const = 0; @@ -885,6 +929,18 @@ struct Wallet //! Initiates a light wallet import wallet request virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) = 0; + + //! locks/unlocks the keys file; returns true on success + virtual bool lockKeysFile() = 0; + virtual bool unlockKeysFile() = 0; + //! returns true if the keys file is locked + virtual bool isKeysFileLocked() = 0; + + /*! + * \brief Queries backing device for wallet keys + * \return Device they are on + */ + virtual Device getDeviceType() const = 0; }; /** @@ -899,9 +955,10 @@ struct WalletManager * \param password Password of wallet file * \param language Language to be used to generate electrum seed mnemonic * \param nettype Network type + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if created successfully) */ - virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype) = 0; + virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) = 0; Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) // deprecated { return createWallet(path, password, language, testnet ? TESTNET : MAINNET); @@ -912,9 +969,10 @@ struct WalletManager * \param path Name of wallet file * \param password Password of wallet file * \param nettype Network type + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) */ - virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype) = 0; + virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) = 0; Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated { return openWallet(path, password, testnet ? TESTNET : MAINNET); @@ -927,10 +985,11 @@ struct WalletManager * \param mnemonic mnemonic (25 words electrum seed) * \param nettype Network type * \param restoreHeight restore from start height + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, - NetworkType nettype = MAINNET, uint64_t restoreHeight = 0) = 0; + NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1) = 0; Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, bool testnet = false, uint64_t restoreHeight = 0) // deprecated { @@ -962,6 +1021,7 @@ struct WalletManager * \param addressString public address * \param viewKeyString view key * \param spendKeyString spend key (optional) + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * createWalletFromKeys(const std::string &path, @@ -971,7 +1031,8 @@ struct WalletManager uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString = "") = 0; + const std::string &spendKeyString = "", + uint64_t kdf_rounds = 1) = 0; Wallet * createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, @@ -1015,6 +1076,25 @@ struct WalletManager } /*! + * \brief creates wallet using hardware device. + * \param path Name of wallet file to be created + * \param password Password of wallet file + * \param nettype Network type + * \param deviceName Device name + * \param restoreHeight restore from start height (0 sets to current height) + * \param subaddressLookahead Size of subaddress lookahead (empty sets to some default low value) + * \param kdf_rounds Number of rounds for key derivation function + * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) + */ + virtual Wallet * createWalletFromDevice(const std::string &path, + const std::string &password, + NetworkType nettype, + const std::string &deviceName, + uint64_t restoreHeight = 0, + const std::string &subaddressLookahead = "", + uint64_t kdf_rounds = 1) = 0; + + /*! * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted * \param wallet previously opened / created wallet instance * \return None @@ -1037,9 +1117,26 @@ struct WalletManager * @param keys_file_name - location of keys file * @param password - password to verify * @param no_spend_key - verify only view keys? + * @param kdf_rounds - number of rounds for key derivation function * @return - true if password is correct + * + * @note + * This function will fail when the wallet keys file is opened because the wallet program locks the keys file. + * In this case, Wallet::unlockKeysFile() and Wallet::lockKeysFile() need to be called before and after the call to this function, respectively. + */ + virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const = 0; + + /*! + * \brief determine the key storage for the specified wallet file + * \param device_type (OUT) wallet backend as enumerated in Wallet::Device + * \param keys_file_name Keys file to verify password for + * \param password Password to verify + * \return true if password correct, else false + * + * for verification only - determines key storage hardware + * */ - virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const = 0; + virtual bool queryWalletDevice(Wallet::Device& device_type, const std::string &keys_file_name, const std::string &password, uint64_t kdf_rounds = 1) const = 0; /*! * \brief findWallets - searches for the wallet files by given path name recursively diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index a63716576..5b262f1b7 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -50,16 +50,16 @@ namespace epee { namespace Monero { Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, - const std::string &language, NetworkType nettype) + const std::string &language, NetworkType nettype, uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); wallet->create(path, password, language); return wallet; } -Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype) +Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); wallet->open(path, password); //Refresh addressBook wallet->addressBook()->refresh(); @@ -87,9 +87,10 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, NetworkType nettype, - uint64_t restoreHeight) + uint64_t restoreHeight, + uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -104,9 +105,10 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString) + const std::string &spendKeyString, + uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -114,6 +116,27 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, return wallet; } +Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path, + const std::string &password, + NetworkType nettype, + const std::string &deviceName, + uint64_t restoreHeight, + const std::string &subaddressLookahead, + uint64_t kdf_rounds) +{ + WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds); + if(restoreHeight > 0){ + wallet->setRefreshFromBlockHeight(restoreHeight); + } + auto lookahead = tools::parse_subaddress_lookahead(subaddressLookahead); + if (lookahead) + { + wallet->setSubaddressLookahead(lookahead->first, lookahead->second); + } + wallet->recoverFromDevice(path, password, deviceName); + return wallet; +} + bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store) { WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet); @@ -139,9 +162,17 @@ bool WalletManagerImpl::walletExists(const std::string &path) return false; } -bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const +bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds) const +{ + return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default"), kdf_rounds); +} + +bool WalletManagerImpl::queryWalletDevice(Wallet::Device& device_type, const std::string &keys_file_name, const std::string &password, uint64_t kdf_rounds) const { - return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default")); + hw::device::device_type type; + bool r = tools::wallet2::query_device(type, keys_file_name, password, kdf_rounds); + device_type = static_cast<Wallet::Device>(type); + return r; } std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index 26238b658..b3c0d6c00 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -39,13 +39,14 @@ class WalletManagerImpl : public WalletManager { public: Wallet * createWallet(const std::string &path, const std::string &password, - const std::string &language, NetworkType nettype); - Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype); + const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) override; + Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) override; virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, NetworkType nettype, - uint64_t restoreHeight); + uint64_t restoreHeight, + uint64_t kdf_rounds = 1) override; virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, @@ -53,9 +54,10 @@ public: uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString = ""); + const std::string &spendKeyString = "", + uint64_t kdf_rounds = 1) override; // next two methods are deprecated - use the above version which allow setting of a password - virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight); + virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight) override; // deprecated: use createWalletFromKeys(..., password, ...) instead virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &language, @@ -63,23 +65,31 @@ public: uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString = ""); - virtual bool closeWallet(Wallet *wallet, bool store = true); - bool walletExists(const std::string &path); - bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const; - std::vector<std::string> findWallets(const std::string &path); - std::string errorString() const; - void setDaemonAddress(const std::string &address); - bool connected(uint32_t *version = NULL); - uint64_t blockchainHeight(); - uint64_t blockchainTargetHeight(); - uint64_t networkDifficulty(); - double miningHashRate(); - uint64_t blockTarget(); - bool isMining(); - bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true); - bool stopMining(); - std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const; + const std::string &spendKeyString = "") override; + virtual Wallet * createWalletFromDevice(const std::string &path, + const std::string &password, + NetworkType nettype, + const std::string &deviceName, + uint64_t restoreHeight = 0, + const std::string &subaddressLookahead = "", + uint64_t kdf_rounds = 1) override; + virtual bool closeWallet(Wallet *wallet, bool store = true) override; + bool walletExists(const std::string &path) override; + bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override; + bool queryWalletDevice(Wallet::Device& device_type, const std::string &keys_file_name, const std::string &password, uint64_t kdf_rounds = 1) const override; + std::vector<std::string> findWallets(const std::string &path) override; + std::string errorString() const override; + void setDaemonAddress(const std::string &address) override; + bool connected(uint32_t *version = NULL) override; + uint64_t blockchainHeight() override; + uint64_t blockchainTargetHeight() override; + uint64_t networkDifficulty() override; + double miningHashRate() override; + uint64_t blockTarget() override; + bool isMining() override; + bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true) override; + bool stopMining() override; + std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const override; private: WalletManagerImpl() {} |