diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/api/wallet.cpp | 130 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 6 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.cpp | 16 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.h | 7 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 46 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 16 | ||||
-rw-r--r-- | src/wallet/wallet2_api.h | 21 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 2 |
8 files changed, 212 insertions, 32 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index cd4b523c9..9e40d2e02 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -197,6 +197,44 @@ bool Wallet::addressValid(const std::string &str, bool testnet) return get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, str); } +bool Wallet::keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error) +{ + bool has_payment_id; + cryptonote::account_public_address address; + crypto::hash8 pid; + if(!get_account_integrated_address_from_str(address, has_payment_id, pid, testnet, address_string)) { + error = tr("Failed to parse address"); + return false; + } + + cryptonote::blobdata key_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(secret_key_string, key_data) || key_data.size() != sizeof(crypto::secret_key)) + { + error = tr("Failed to parse key"); + return false; + } + crypto::secret_key key = *reinterpret_cast<const crypto::secret_key*>(key_data.data()); + + // check the key match the given address + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(key, pkey)) { + error = tr("failed to verify key"); + return false; + } + bool matchAddress = false; + if(isViewKey) + matchAddress = address.m_view_public_key == pkey; + else + matchAddress = address.m_spend_public_key == pkey; + + if(!matchAddress) { + error = tr("key does not match address"); + return false; + } + + return true; +} + std::string Wallet::paymentIdFromAddress(const std::string &str, bool testnet) { bool has_payment_id; @@ -337,6 +375,98 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas return true; } +bool WalletImpl::recoverFromKeys(const std::string &path, + const std::string &language, + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string) +{ + cryptonote::account_public_address address; + bool has_payment_id; + crypto::hash8 new_payment_id; + if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, m_wallet->testnet(), address_string)) + { + m_errorString = tr("failed to parse address"); + m_status = Status_Error; + return false; + } + + // parse optional spend key + crypto::secret_key spendkey; + bool has_spendkey = false; + if (!spendkey_string.empty()) { + cryptonote::blobdata spendkey_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key)) + { + m_errorString = tr("failed to parse secret spend key"); + m_status = Status_Error; + return false; + } + has_spendkey = true; + spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data()); + } + + // parse view secret key + if (viewkey_string.empty()) { + m_errorString = tr("No view key supplied, cancelled"); + m_status = Status_Error; + 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)) + { + m_errorString = tr("failed to parse secret view key"); + m_status = Status_Error; + return false; + } + 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) { + if (!crypto::secret_key_to_public_key(spendkey, pkey)) { + m_errorString = tr("failed to verify secret spend key"); + m_status = Status_Error; + return false; + } + if (address.m_spend_public_key != pkey) { + m_errorString = tr("spend key does not match address"); + m_status = Status_Error; + return false; + } + } + if (!crypto::secret_key_to_public_key(viewkey, pkey)) { + m_errorString = tr("failed to verify secret view key"); + m_status = Status_Error; + return false; + } + if (address.m_view_public_key != pkey) { + m_errorString = tr("view key does not match address"); + m_status = Status_Error; + return false; + } + + try + { + if (has_spendkey) { + m_wallet->generate(path, "", address, spendkey, viewkey); + LOG_PRINT_L1("Generated new wallet from keys"); + } + else { + m_wallet->generate(path, "", address, viewkey); + LOG_PRINT_L1("Generated new view only wallet from keys"); + } + + } + catch (const std::exception& e) { + m_errorString = string(tr("failed to generate new wallet: ")) + e.what(); + m_status = Status_Error; + return false; + } + return true; +} + + bool WalletImpl::open(const std::string &path, const std::string &password) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 844d552c4..7daf63e43 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -58,6 +58,11 @@ public: const std::string &language) const; bool open(const std::string &path, const std::string &password); bool recover(const std::string &path, const std::string &seed); + bool recoverFromKeys(const std::string &path, + const std::string &language, + const std::string &address_string, + const std::string &viewkey_string, + const std::string &spendkey_string = ""); bool close(); std::string seed() const; std::string getSeedLanguage() const; @@ -94,6 +99,7 @@ public: void setRecoveringFromSeed(bool recoveringFromSeed); bool watchOnly() const; bool rescanSpent(); + bool testnet() const {return m_wallet->testnet();} PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 0601c104e..c761cc6d2 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -81,6 +81,22 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::st return wallet; } +Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString) +{ + WalletImpl * wallet = new WalletImpl(testnet); + if(restoreHeight > 0){ + wallet->setRefreshFromBlockHeight(restoreHeight); + } + wallet->recoverFromKeys(path, language, addressString, viewKeyString, spendKeyString); + return wallet; +} + bool WalletManagerImpl::closeWallet(Wallet *wallet) { WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet); diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index ca9570254..ce9b70e96 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -41,6 +41,13 @@ public: const std::string &language, bool testnet); Wallet * openWallet(const std::string &path, const std::string &password, bool testnet); virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet, uint64_t restoreHeight); + virtual Wallet * createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = ""); virtual bool closeWallet(Wallet *wallet); bool walletExists(const std::string &path); std::vector<std::string> findWallets(const std::string &path); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 676f35e26..2e4550879 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -842,7 +842,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s " not match with daemon response size=" + std::to_string(o_indices.size())); } - BOOST_FOREACH(size_t o, outs) + for(size_t o: outs) { THROW_WALLET_EXCEPTION_IF(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" + std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size())); @@ -946,7 +946,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s uint64_t tx_money_spent_in_ins = 0; // check all outputs for spending (compare key images) - BOOST_FOREACH(auto& in, tx.vin) + for(auto& in: tx.vin) { if(in.type() != typeid(cryptonote::txin_to_key)) continue; @@ -1107,7 +1107,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry TIME_MEASURE_FINISH(miner_tx_handle_time); TIME_MEASURE_START(txs_handle_time); - BOOST_FOREACH(auto& txblob, bche.txs) + for(auto& txblob: bche.txs) { cryptonote::transaction tx; bool r = parse_and_validate_tx_from_blob(txblob, tx); @@ -1276,7 +1276,7 @@ void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote:: } else { - BOOST_FOREACH(auto& bl_entry, blocks) + for(auto& bl_entry: blocks) { cryptonote::block bl; bool r = cryptonote::parse_and_validate_block_from_blob(bl_entry.block, bl); @@ -1557,7 +1557,7 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, } } current_index = blocks_start_height; - BOOST_FOREACH(auto& bl_id, hashes) + for(auto& bl_id: hashes) { if(current_index >= m_blockchain.size()) { @@ -2507,7 +2507,7 @@ void wallet2::store_to(const std::string &path, const std::string &password) uint64_t wallet2::unlocked_balance() const { uint64_t amount = 0; - BOOST_FOREACH(const transfer_details& td, m_transfers) + for(const transfer_details& td: m_transfers) if(!td.m_spent && is_transfer_unlocked(td)) amount += td.amount(); @@ -2517,12 +2517,12 @@ uint64_t wallet2::unlocked_balance() const uint64_t wallet2::balance() const { uint64_t amount = 0; - BOOST_FOREACH(auto& td, m_transfers) + for(auto& td: m_transfers) if(!td.m_spent) amount += td.amount(); - BOOST_FOREACH(auto& utx, m_unconfirmed_txs) + for(auto& utx: m_unconfirmed_txs) if (utx.second.m_state != wallet2::unconfirmed_transfer_details::failed) amount+= utx.second.m_change; @@ -2990,7 +2990,7 @@ void wallet2::commit_tx(pending_tx& ptx) { payment_id = get_payment_id(ptx); dests = ptx.dests; - BOOST_FOREACH(size_t idx, ptx.selected_transfers) + for(size_t idx: ptx.selected_transfers) amount_in += m_transfers[idx].amount(); } add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount); @@ -3001,7 +3001,7 @@ void wallet2::commit_tx(pending_tx& ptx) LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]"); - BOOST_FOREACH(size_t idx, ptx.selected_transfers) + for(size_t idx: ptx.selected_transfers) { set_spent(idx, 0); } @@ -3349,7 +3349,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto ptx_vector.push_back(ptx); // mark transfers to be used as "spent" - BOOST_FOREACH(size_t idx, ptx.selected_transfers) + for(size_t idx: ptx.selected_transfers) { set_spent(idx, 0); } @@ -3361,7 +3361,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto for (auto & ptx : ptx_vector) { // mark transfers to be used as not spent - BOOST_FOREACH(size_t idx2, ptx.selected_transfers) + for(size_t idx2: ptx.selected_transfers) { set_unspent(idx2); } @@ -3380,7 +3380,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto for (auto & ptx : ptx_vector) { // mark transfers to be used as not spent - BOOST_FOREACH(size_t idx2, ptx.selected_transfers) + for(size_t idx2: ptx.selected_transfers) { set_unspent(idx2); } @@ -3399,7 +3399,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto for (auto & ptx : ptx_vector) { // mark transfers to be used as not spent - BOOST_FOREACH(size_t idx2, ptx.selected_transfers) + for(size_t idx2: ptx.selected_transfers) { set_unspent(idx2); } @@ -3660,7 +3660,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -3669,7 +3669,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent } uint64_t found_money = 0; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); } @@ -3685,7 +3685,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent typedef cryptonote::tx_source_entry::output_entry tx_output_entry; size_t i = 0, out_index = 0; std::vector<cryptonote::tx_source_entry> sources; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); cryptonote::tx_source_entry& src = sources.back(); @@ -3736,11 +3736,11 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts; uint64_t dust = 0; destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); } - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { if (!dust_policy.add_to_fee) splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust)); dust += d.amount; @@ -3805,7 +3805,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -3814,7 +3814,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry } uint64_t found_money = 0; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); } @@ -3829,7 +3829,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry LOG_PRINT_L2("preparing outputs"); size_t i = 0, out_index = 0; std::vector<cryptonote::tx_source_entry> sources; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); cryptonote::tx_source_entry& src = sources.back(); @@ -4100,7 +4100,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t needed_money = 0; - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 437729075..91d4db47e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -924,7 +924,7 @@ namespace tools splitted_dsts.clear(); dust_dsts.clear(); - BOOST_FOREACH(auto& de, dsts) + for(auto& de: dsts) { cryptonote::decompose_amount_into_digits(de.amount, 0, [&](uint64_t chunk) { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr)); }, @@ -987,7 +987,7 @@ namespace tools // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t - BOOST_FOREACH(auto& dt, dsts) + for(auto& dt: dsts) { THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; @@ -1008,7 +1008,7 @@ namespace tools { COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req); req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { const transfer_container::const_iterator it = m_transfers.begin() + idx; THROW_WALLET_EXCEPTION_IF(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error, @@ -1028,7 +1028,7 @@ namespace tools std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(selected_transfers.size())); std::unordered_map<uint64_t, uint64_t> scanty_outs; - BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs) + for(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs: daemon_resp.outs) { if (amount_outs.outs.size() < fake_outputs_count) { @@ -1041,7 +1041,7 @@ namespace tools //prepare inputs size_t i = 0; std::vector<cryptonote::tx_source_entry> sources; - BOOST_FOREACH(size_t idx, selected_transfers) + for(size_t idx: selected_transfers) { sources.resize(sources.size()+1); cryptonote::tx_source_entry& src = sources.back(); @@ -1052,7 +1052,7 @@ namespace tools if(daemon_resp.outs.size()) { daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b){return a.global_amount_index < b.global_amount_index;}); - BOOST_FOREACH(out_entry& daemon_oe, daemon_resp.outs[i].outs) + for(out_entry& daemon_oe: daemon_resp.outs[i].outs) { if(td.m_global_output_index == daemon_oe.global_amount_index) continue; @@ -1094,11 +1094,11 @@ namespace tools std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts; uint64_t dust = 0; destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); } - BOOST_FOREACH(auto& d, dust_dsts) { + for(auto& d: dust_dsts) { if (!dust_policy.add_to_fee) splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust)); dust += d.amount; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 78caddc0b..563f16eaa 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -295,6 +295,7 @@ struct Wallet virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; virtual std::string path() const = 0; + virtual bool testnet() const = 0; /*! * \brief integratedAddress - returns integrated address for current wallet address and given payment_id. @@ -434,6 +435,7 @@ struct Wallet static std::string genPaymentId(); static bool paymentIdValid(const std::string &paiment_id); static bool addressValid(const std::string &str, bool testnet); + static bool keyValid(const std::string &secret_key_string, const std::string &address_string, bool isViewKey, bool testnet, std::string &error); static std::string paymentIdFromAddress(const std::string &str, bool testnet); static uint64_t maximumAllowedAmount(); @@ -613,6 +615,25 @@ struct WalletManager */ virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet = false, uint64_t restoreHeight = 0) = 0; + /*! + * \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted + * \param path Name of wallet file to be created + * \param language language + * \param testnet testnet + * \param restoreHeight restore from start height + * \param addressString public address + * \param viewKeyString view key + * \param spendKeyString spend key (optional) + * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) + */ + virtual Wallet * createWalletFromKeys(const std::string &path, + const std::string &language, + bool testnet, + uint64_t restoreHeight, + const std::string &addressString, + const std::string &viewKeyString, + const std::string &spendKeyString = "") = 0; + /*! * \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted * \param wallet previously opened / created wallet instance diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 33e099ceb..d35e51068 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -369,7 +369,7 @@ namespace tools cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, long_payment_id); } /* or short payment ID */ - else if (!wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) { + else if (wallet2::parse_short_payment_id(payment_id_str, short_payment_id)) { cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, short_payment_id); } else { |