From f83f3cbd9647b679e5c9460970b99bd2e9141858 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:01:00 +0300 Subject: api implementation splitted over separate files --- src/wallet/api/wallet.cpp | 411 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 411 insertions(+) create mode 100644 src/wallet/api/wallet.cpp (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp new file mode 100644 index 000000000..e42f04cf7 --- /dev/null +++ b/src/wallet/api/wallet.cpp @@ -0,0 +1,411 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + + +#include "wallet.h" +#include "pending_transaction.h" +#include "common_defines.h" + +#include "mnemonics/electrum-words.h" +#include + +using namespace std; +using namespace cryptonote; + +namespace Bitmonero { + +namespace { + // copy-pasted from simplewallet + static const size_t DEFAULT_MIX = 4; +} + +Wallet::~Wallet() {} + +string Wallet::displayAmount(uint64_t amount) +{ + return cryptonote::print_money(amount); +} + +///////////////////////// WalletImpl implementation //////////////////////// +WalletImpl::WalletImpl(bool testnet) + :m_wallet(nullptr), m_status(Wallet::Status_Ok) +{ + m_wallet = new tools::wallet2(testnet); +} + +WalletImpl::~WalletImpl() +{ + delete m_wallet; +} + +bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language) +{ + + clearStatus(); + + bool keys_file_exists; + bool wallet_file_exists; + tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + // TODO: figure out how to setup logger; + 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 or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."; + LOG_ERROR(m_errorString); + m_status = Status_Error; + return false; + } + // TODO: validate language + m_wallet->set_seed_language(language); + crypto::secret_key recovery_val, secret_key; + try { + recovery_val = m_wallet->generate(path, password, secret_key, false, false); + m_password = password; + m_status = Status_Ok; + } catch (const std::exception &e) { + LOG_ERROR("Error creating 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(); + try { + // TODO: handle "deprecated" + m_wallet->load(path, password); + + m_password = password; + } catch (const std::exception &e) { + LOG_ERROR("Error opening wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +bool WalletImpl::recover(const std::string &path, const std::string &seed) +{ + clearStatus(); + m_errorString.clear(); + if (seed.empty()) { + m_errorString = "Electrum seed is empty"; + LOG_ERROR(m_errorString); + m_status = Status_Error; + return false; + } + + crypto::secret_key recovery_key; + std::string old_language; + if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) { + m_errorString = "Electrum-style word list failed verification"; + m_status = Status_Error; + return false; + } + + try { + m_wallet->set_seed_language(old_language); + m_wallet->generate(path, "", recovery_key, true, false); + // TODO: wallet->init(daemon_address); + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +bool WalletImpl::close() +{ + clearStatus(); + bool result = false; + try { + m_wallet->store(); + m_wallet->stop(); + result = true; + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + LOG_ERROR("Error closing wallet: " << e.what()); + } + return result; +} + +std::string WalletImpl::seed() const +{ + std::string seed; + if (m_wallet) + m_wallet->get_seed(seed); + return seed; +} + +std::string WalletImpl::getSeedLanguage() const +{ + return m_wallet->get_seed_language(); +} + +void WalletImpl::setSeedLanguage(const std::string &arg) +{ + m_wallet->set_seed_language(arg); +} + +int WalletImpl::status() const +{ + return m_status; +} + +std::string WalletImpl::errorString() const +{ + return m_errorString; +} + +bool WalletImpl::setPassword(const std::string &password) +{ + clearStatus(); + try { + m_wallet->rewrite(m_wallet->get_wallet_file(), password); + m_password = password; + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +std::string WalletImpl::address() const +{ + return m_wallet->get_account().get_public_address_str(m_wallet->testnet()); +} + +bool WalletImpl::store(const std::string &path) +{ + clearStatus(); + try { + if (path.empty()) { + m_wallet->store(); + } else { + m_wallet->store_to(path, m_password); + } + } catch (const std::exception &e) { + LOG_ERROR("Error storing wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + } + + return m_status == Status_Ok; +} + +bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) +{ + clearStatus(); + try { + m_wallet->init(daemon_address, upper_transaction_size_limit); + } catch (const std::exception &e) { + LOG_ERROR("Error initializing wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + } + + return m_status == Status_Ok; +} + +uint64_t WalletImpl::balance() const +{ + return m_wallet->balance(); +} + +uint64_t WalletImpl::unlockedBalance() const +{ + return m_wallet->unlocked_balance(); +} + + +bool WalletImpl::refresh() +{ + clearStatus(); + try { + m_wallet->refresh(); + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +// TODO: +// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) +// 2 - check / design how "Transaction" can be single interface +// (instead of few different data structures within wallet2 implementation: +// - pending_tx; +// - transfer_details; +// - payment_details; +// - unconfirmed_transfer_details; +// - confirmed_transfer_details) +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) +{ + clearStatus(); + vector dsts; + cryptonote::tx_destination_entry de; + bool has_payment_id; + crypto::hash8 new_payment_id; + + // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) + size_t fake_outs_count = m_wallet->default_mixin(); + if (fake_outs_count == 0) + fake_outs_count = DEFAULT_MIX; + + TransactionImpl * transaction = new TransactionImpl(this); + + do { + + if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), dst_addr)) { + // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 + m_status = Status_Error; + m_errorString = "Invalid destination address"; + break; + } + + de.amount = amount; + if (de.amount <= 0) { + m_status = Status_Error; + m_errorString = "Invalid amount"; + break; + } + + dsts.push_back(de); + //std::vector ptx_vector; + std::vector extra; + + + try { + transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + + } catch (const tools::error::daemon_busy&) { + // TODO: make it translatable with "tr"? + m_errorString = tr("daemon is busy. Please try again later."); + m_status = Status_Error; + } catch (const tools::error::no_connection_to_daemon&) { + m_errorString = tr("no connection to daemon. Please make sure daemon is running."); + m_status = Status_Error; + } catch (const tools::error::wallet_rpc_error& e) { + m_errorString = tr("RPC error: ") + e.to_string(); + m_status = Status_Error; + } catch (const tools::error::get_random_outs_error&) { + m_errorString = tr("failed to get random outputs to mix"); + m_status = Status_Error; + + } catch (const tools::error::not_enough_money& e) { + m_status = Status_Error; + std::ostringstream writer(m_errorString); + + writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % + print_money(e.available()) % + print_money(e.tx_amount() + e.fee()) % + print_money(e.tx_amount()) % + print_money(e.fee()); + + } catch (const tools::error::not_enough_outs_to_mix& e) { + std::ostringstream writer(m_errorString); + writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; + for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { + writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); + } + m_status = Status_Error; + } catch (const tools::error::tx_not_constructed&) { + m_errorString = tr("transaction was not constructed"); + m_status = Status_Error; + } catch (const tools::error::tx_rejected& e) { + std::ostringstream writer(m_errorString); + writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + m_status = Status_Error; + } catch (const tools::error::tx_sum_overflow& e) { + m_errorString = e.what(); + m_status = Status_Error; + } catch (const tools::error::zero_destination&) { + m_errorString = tr("one of destinations is zero"); + m_status = Status_Error; + } catch (const tools::error::tx_too_big& e) { + m_errorString = tr("failed to find a suitable way to split transactions"); + m_status = Status_Error; + } catch (const tools::error::transfer_error& e) { + m_errorString = string(tr("unknown transfer error: ")) + e.what(); + m_status = Status_Error; + } catch (const tools::error::wallet_internal_error& e) { + m_errorString = string(tr("internal error: ")) + e.what(); + m_status = Status_Error; + } catch (const std::exception& e) { + m_errorString = string(tr("unexpected error: ")) + e.what(); + m_status = Status_Error; + } catch (...) { + m_errorString = tr("unknown error"); + m_status = Status_Error; + } + } while (false); + + transaction->m_status = m_status; + transaction->m_errorString = m_errorString; + return transaction; +} + +void WalletImpl::disposeTransaction(PendingTransaction *t) +{ + delete t; +} + +TransactionHistory *WalletImpl::history() const +{ + return nullptr; +} + +bool WalletImpl::connectToDaemon() +{ + bool result = m_wallet->check_connection(); + m_status = result ? Status_Ok : Status_Error; + if (!result) { + m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address(); + } + return result; +} + +void WalletImpl::clearStatus() +{ + m_status = Status_Ok; + m_errorString.clear(); +} + + +} // namespace -- cgit v1.2.3 From b6aaf53a6074e8e7181da5c3275e9fef56bf20da Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:17:27 +0300 Subject: transaction history api in progress --- src/wallet/api/pending_transaction.cpp | 16 +++++++------- src/wallet/api/transaction_history.cpp | 39 ++++++++++++++++++++++++++++++++++ src/wallet/api/transaction_history.h | 17 ++++++++++++--- src/wallet/api/wallet.cpp | 2 +- src/wallet/api/wallet.h | 7 ++++-- src/wallet/wallet2_api.h | 3 +-- 6 files changed, 68 insertions(+), 16 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp index e9791ec35..db40851b4 100644 --- a/src/wallet/api/pending_transaction.cpp +++ b/src/wallet/api/pending_transaction.cpp @@ -48,28 +48,28 @@ namespace Bitmonero { PendingTransaction::~PendingTransaction() {} -TransactionImpl::TransactionImpl(WalletImpl *wallet) +PendingTransactionImpl::PendingTransactionImpl(WalletImpl *wallet) : m_wallet(wallet) { } -TransactionImpl::~TransactionImpl() +PendingTransactionImpl::~PendingTransactionImpl() { } -int TransactionImpl::status() const +int PendingTransactionImpl::status() const { return m_status; } -string TransactionImpl::errorString() const +string PendingTransactionImpl::errorString() const { return m_errorString; } -bool TransactionImpl::commit() +bool PendingTransactionImpl::commit() { LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size()); @@ -105,7 +105,7 @@ bool TransactionImpl::commit() return m_status == Status_Ok; } -uint64_t TransactionImpl::amount() const +uint64_t PendingTransactionImpl::amount() const { uint64_t result = 0; for (const auto &ptx : m_pending_tx) { @@ -116,7 +116,7 @@ uint64_t TransactionImpl::amount() const return result; } -uint64_t TransactionImpl::dust() const +uint64_t PendingTransactionImpl::dust() const { uint32_t result = 0; for (const auto & ptx : m_pending_tx) { @@ -125,7 +125,7 @@ uint64_t TransactionImpl::dust() const return result; } -uint64_t TransactionImpl::fee() const +uint64_t PendingTransactionImpl::fee() const { uint32_t result = 0; for (const auto ptx : m_pending_tx) { diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index f1aba14cb..6cc5a961c 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -30,4 +30,43 @@ #include "transaction_history.h" +#include +namespace Bitmonero { + +TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet) +{ + +} + +TransactionHistoryImpl::~TransactionHistoryImpl() +{ + +} + +int TransactionHistoryImpl::count() const +{ + return 0; +} + +TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const +{ + return nullptr; +} + +std::vector TransactionHistoryImpl::getAll() const +{ + return std::vector(); +} + +void TransactionHistoryImpl::refresh() +{ + +} + +TransactionInfo *TransactionHistoryImpl::transaction(int index) const +{ + return nullptr; +} + +} diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index cab0e0dbc..1ff729b54 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -32,12 +32,23 @@ namespace Bitmonero { +class TransactionInfo; +class WalletImpl; + class TransactionHistoryImpl : public TransactionHistory { +public: + TransactionHistoryImpl(WalletImpl * wallet); + ~TransactionHistoryImpl(); virtual int count() const; - virtual TransactionInfo * transaction(int index) const = 0; - virtual TransactionInfo * transaction(const std::string &id) const = 0; - virtual std::vector getAll() const = 0; + virtual TransactionInfo * transaction(int index) const; + virtual TransactionInfo * transaction(const std::string &id) const; + virtual std::vector getAll() const; + virtual void refresh(); + +private: + std::vector m_history; + WalletImpl *m_wallet; }; } diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e42f04cf7..a665fff95 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -288,7 +288,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIX; - TransactionImpl * transaction = new TransactionImpl(this); + PendingTransactionImpl * transaction = new PendingTransactionImpl(this); do { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 35db38f67..6a654b13e 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -38,7 +38,8 @@ namespace Bitmonero { - +class TransactionHistoryImpl; +class PendingTransactionImpl; class WalletImpl : public Wallet { @@ -72,7 +73,9 @@ private: void clearStatus(); private: - friend class TransactionImpl; + friend class PendingTransactionImpl; + friend class TransactionHistoryImpl; + tools::wallet2 * m_wallet; int m_status; std::string m_errorString; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index cb0211c4a..37d9ee86b 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -63,8 +63,7 @@ struct TransactionHistory virtual TransactionInfo * transaction(int index) const = 0; virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual std::vector getAll() const = 0; - // TODO: - // refresh(); + virtual void refresh() = 0; }; -- cgit v1.2.3 From 02c9df5de247d6f8fb95e1b9272cef2b37be10f8 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 22 Apr 2016 13:21:08 +0300 Subject: Wallet API : transaction history in progress --- src/wallet/api/transaction_history.cpp | 39 ++++++++++++++++++++++++++++------ src/wallet/api/transaction_history.h | 2 ++ src/wallet/api/transaction_info.cpp | 11 +++++++++- src/wallet/api/transaction_info.h | 10 ++++++--- src/wallet/api/wallet.cpp | 5 ++++- src/wallet/api/wallet.h | 1 + src/wallet/wallet2_api.h | 29 +++++++++++++------------ tests/libwallet_api_tests/main.cpp | 28 ++++++++++++++++++++++++ 8 files changed, 100 insertions(+), 25 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 3ebcc041e..185cd164f 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -35,14 +35,20 @@ #include "crypto/hash.h" #include "wallet/wallet2.h" -#include "contrib/epee/include/string_tools.h" + #include #include +using namespace epee; + namespace Bitmonero { +TransactionHistory::~TransactionHistory() {} + + TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet) + : m_wallet(wallet) { } @@ -54,7 +60,7 @@ TransactionHistoryImpl::~TransactionHistoryImpl() int TransactionHistoryImpl::count() const { - return 0; + return m_history.size(); } TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const @@ -64,7 +70,7 @@ TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) cons std::vector TransactionHistoryImpl::getAll() const { - return std::vector(); + return m_history; } void TransactionHistoryImpl::refresh() @@ -73,9 +79,18 @@ void TransactionHistoryImpl::refresh() uint64_t min_height = 0; uint64_t max_height = (uint64_t)-1; - // TODO: delete old transactions; + // delete old transactions; + for (auto t : m_history) + delete t; std::list> payments; + + // transactions are stored in wallet2: + // - confirmed_transfer_details - out transfers + // - unconfirmed_transfer_details - pending out transfers + // - payment_details - input transfers + + // payments are "input transactions"; m_wallet->m_wallet->get_payments(payments, min_height, max_height); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { const tools::wallet2::payment_details &pd = i->second; @@ -83,9 +98,19 @@ void TransactionHistoryImpl::refresh() if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) payment_id = payment_id.substr(0,16); // TODO - TransactionInfo * ti = new TransactionInfo(); - - //output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s") % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % "-").str()))); + TransactionInfoImpl * ti = new TransactionInfoImpl(); + ti->m_paymentid = payment_id; + ti->m_amount = pd.m_amount; + ti->m_direction = TransactionInfo::Direction_In; + ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); + // TODO: + // ti->m_timestamp = pd.m_timestamp; + m_history.push_back(ti); + + /* output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s") + % print_money(pd.m_amount) + % string_tools::pod_to_hex(pd.m_tx_hash) + % payment_id % "-").str())));*/ } } diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index 1ff729b54..171fd2210 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -47,6 +47,8 @@ public: virtual void refresh(); private: + + // TransactionHistory is responsible of memory management std::vector m_history; WalletImpl *m_wallet; }; diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 8de4e555f..c28c52355 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -35,7 +35,16 @@ using namespace std; namespace Bitmonero { +TransactionInfo::~TransactionInfo() {} + TransactionInfoImpl::TransactionInfoImpl() + : m_direction(Direction_Out) + , m_hold(false) + , m_failed(false) + , m_amount(0) + , m_fee(0) + , m_blockheight(0) + , m_timestamp(0) { } @@ -71,7 +80,7 @@ uint64_t TransactionInfoImpl::fee() const return 0; } -string TransactionInfoImpl::address() const +string TransactionInfoImpl::hash() const { return ""; } diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 3aae19a64..945b0d9ed 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -41,12 +41,16 @@ class TransactionInfoImpl : public TransactionInfo public: TransactionInfoImpl(); ~TransactionInfoImpl(); + //! in/out virtual int direction() const; + //! true if hold virtual bool isHold() const; virtual bool isFailed() const; virtual uint64_t amount() const; + //! always 0 for incoming txes virtual uint64_t fee() const; - virtual std::string address() const; + + virtual std::string hash() const; virtual std::time_t timestamp() const; virtual std::string paymentId() const; @@ -56,8 +60,8 @@ private: bool m_failed; uint64_t m_amount; uint64_t m_fee; - uint64_t b_blockheight; - std::string m_address; + uint64_t m_blockheight; + std::string m_hash; std::time_t m_timestamp; std::string m_paymentid; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index a665fff95..5f32908de 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 "transaction_history.h" #include "common_defines.h" #include "mnemonics/electrum-words.h" @@ -58,10 +59,12 @@ WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok) { m_wallet = new tools::wallet2(testnet); + m_history = new TransactionHistoryImpl(this); } WalletImpl::~WalletImpl() { + delete m_history; delete m_wallet; } @@ -388,7 +391,7 @@ void WalletImpl::disposeTransaction(PendingTransaction *t) TransactionHistory *WalletImpl::history() const { - return nullptr; + return m_history; } bool WalletImpl::connectToDaemon() diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 6a654b13e..3eaaec59e 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -80,6 +80,7 @@ private: int m_status; std::string m_errorString; std::string m_password; + TransactionHistoryImpl * m_history; }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 37d9ee86b..c4843d33f 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -56,17 +56,6 @@ struct PendingTransaction virtual uint64_t fee() const = 0; }; -struct TransactionInfo; -struct TransactionHistory -{ - virtual int count() const; - virtual TransactionInfo * transaction(int index) const = 0; - virtual TransactionInfo * transaction(const std::string &id) const = 0; - virtual std::vector getAll() const = 0; - virtual void refresh() = 0; -}; - - /** * @brief The TransactionInfo - interface for displaying transaction information */ @@ -76,16 +65,30 @@ struct TransactionInfo Direction_In, Direction_Out }; - + virtual ~TransactionInfo() = 0; virtual int direction() const = 0; virtual bool isHold() const = 0; virtual bool isFailed() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() const = 0; - virtual std::string address() const = 0; + virtual std::string hash() const = 0; virtual std::time_t timestamp() const = 0; virtual std::string paymentId() const = 0; }; +/** + * @brief The TransactionHistory - interface for displaying transaction history + */ +struct TransactionHistory +{ + virtual ~TransactionHistory() = 0; + virtual int count() const = 0; + virtual TransactionInfo * transaction(int index) const = 0; + virtual TransactionInfo * transaction(const std::string &id) const = 0; + virtual std::vector getAll() const = 0; + virtual void refresh() = 0; +}; + + /** * @brief Interface for wallet operations. diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index dee874cd6..6921e6c3a 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -29,7 +29,10 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include "gtest/gtest.h" + #include "wallet/wallet2_api.h" +#include "cryptonote_core/cryptonote_format_utils.h" + #include #include @@ -284,6 +287,31 @@ TEST_F(WalletManagerTest, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } +TEST_F(WalletManagerTest, WalletHistory) +{ + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + // make sure testnet daemon is running + ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet1->refresh()); + Bitmonero::TransactionHistory * history = wallet1->history(); + history->refresh(); + ASSERT_TRUE(history->count() > 0); + auto transaction_print = [=] (Bitmonero::TransactionInfo * t) { + std::cout << "d: " + << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") + << ", a: " << t->amount() + << ", h: " << t->hash() + << std::endl; + }; + + for (auto t: history->getAll()) { + ASSERT_TRUE(t != nullptr); + transaction_print(t); + } + + +} + int main(int argc, char** argv) -- cgit v1.2.3 From 566166aafd29bbca1f4916d4383752945892eb20 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 26 Apr 2016 13:46:20 +0300 Subject: merged with upstream --- src/wallet/CMakeLists.txt | 3 +- src/wallet/api/utils.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++ src/wallet/api/wallet.cpp | 19 ++++++++++-- src/wallet/api/wallet.h | 3 ++ src/wallet/wallet2_api.h | 5 +++ 5 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/wallet/api/utils.cpp (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 33af4f30d..49f936f5c 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -36,7 +36,8 @@ set(wallet_sources api/wallet_manager.cpp api/transaction_info.cpp api/transaction_history.cpp - api/pending_transaction.cpp) + api/pending_transaction.cpp + api/utils.cpp) set(wallet_headers) diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp new file mode 100644 index 000000000..aa85323f0 --- /dev/null +++ b/src/wallet/api/utils.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + + + +#include "include_base_utils.h" // LOG_PRINT_x +#include "net/http_client.h" // epee::net_utils::... +#include + +using namespace std; + +namespace Bitmonero { +namespace Utils { + + +// copy-pasted from simplewallet. + +bool isAddressLocal(const std::string &address) +{ + // extract host + epee::net_utils::http::url_content u_c; + if (!epee::net_utils::parse_url(address, u_c)) + { + LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); + return false; + } + if (u_c.host.empty()) + { + LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); + return false; + } + + // resolve to IP + boost::asio::io_service io_service; + boost::asio::ip::tcp::resolver resolver(io_service); + boost::asio::ip::tcp::resolver::query query(u_c.host, ""); + boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); + while (i != boost::asio::ip::tcp::resolver::iterator()) + { + const boost::asio::ip::tcp::endpoint &ep = *i; + if (ep.address().is_loopback()) + return true; + ++i; + } + + return false; +} + +} + + +} // namespace diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5f32908de..d9d24b4f0 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -56,7 +56,7 @@ string Wallet::displayAmount(uint64_t amount) ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) - :m_wallet(nullptr), m_status(Wallet::Status_Ok) + :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false) { m_wallet = new tools::wallet2(testnet); m_history = new TransactionHistoryImpl(this); @@ -237,6 +237,10 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact clearStatus(); try { m_wallet->init(daemon_address, upper_transaction_size_limit); + if (Utils::isAddressLocal(daemon_address)) { + this->setTrustedDaemon(true); + } + } catch (const std::exception &e) { LOG_ERROR("Error initializing wallet: " << e.what()); m_status = Status_Error; @@ -315,7 +319,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 try { - transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, + 0 /* unused fee arg*/, extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? @@ -404,6 +409,16 @@ bool WalletImpl::connectToDaemon() return result; } +void WalletImpl::setTrustedDaemon(bool arg) +{ + m_trustedDaemon = arg; +} + +bool WalletImpl::trustedDaemon() const +{ + return m_trustedDaemon; +} + void WalletImpl::clearStatus() { m_status = Status_Ok; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 3eaaec59e..3671c2f7a 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -62,6 +62,8 @@ public: bool store(const std::string &path); bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit); bool connectToDaemon(); + void setTrustedDaemon(bool arg); + bool trustedDaemon() const; uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); @@ -81,6 +83,7 @@ private: std::string m_errorString; std::string m_password; TransactionHistoryImpl * m_history; + bool m_trustedDaemon; }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 4954db0d2..ab715dbf9 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -38,6 +38,9 @@ // Public interface for libwallet library namespace Bitmonero { + namespace Utils { + bool isAddressLocal(const std::string &hostaddr); + } /** * @brief Transaction-like interface for sending money */ @@ -117,6 +120,8 @@ struct Wallet virtual bool store(const std::string &path) = 0; virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; virtual bool connectToDaemon() = 0; + virtual void setTrustedDaemon(bool arg) = 0; + virtual bool trustedDaemon() const = 0; virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; static std::string displayAmount(uint64_t amount); -- cgit v1.2.3 From 5dbd2b8fc3aa97f3a2e14a378cf6b7afd16bd4e2 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 5 May 2016 22:24:00 +0300 Subject: started WalletListener --- src/wallet/api/wallet.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++- src/wallet/api/wallet.h | 4 ++++ src/wallet/wallet2_api.h | 8 +++++++ 3 files changed, 65 insertions(+), 1 deletion(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index d9d24b4f0..6170000b7 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -47,6 +47,47 @@ namespace { static const size_t DEFAULT_MIX = 4; } +struct Wallet2CallbackImpl : public tools::i_wallet2_callback +{ + + ~Wallet2CallbackImpl() + { + + } + + void setListener(WalletListener * listener) + { + // TODO; + } + + WalletListener * getListener() const + { + return m_listener; + } + + virtual void on_new_block(uint64_t height, const cryptonote::block& block) + { + // TODO; + } + virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) + { + // TODO; + + } + virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, + const cryptonote::transaction& spend_tx) + { + // TODO; + } + + virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) + { + // TODO; + } + + WalletListener * m_listener; +}; + Wallet::~Wallet() {} string Wallet::displayAmount(uint64_t amount) @@ -56,14 +97,17 @@ string Wallet::displayAmount(uint64_t amount) ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) - :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false) + :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false), + m_wallet2Callback(nullptr) { m_wallet = new tools::wallet2(testnet); m_history = new TransactionHistoryImpl(this); + m_wallet2Callback = new Wallet2CallbackImpl; } WalletImpl::~WalletImpl() { + delete m_wallet2Callback; delete m_history; delete m_wallet; } @@ -399,6 +443,14 @@ TransactionHistory *WalletImpl::history() const return m_history; } +void WalletImpl::setListener(WalletListener *l) +{ + // TODO thread synchronization; + m_wallet2Callback->setListener(l); +} + + + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 3671c2f7a..c0fa31003 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -40,6 +40,7 @@ namespace Bitmonero { class TransactionHistoryImpl; class PendingTransactionImpl; +struct Wallet2CallbackImpl; class WalletImpl : public Wallet { @@ -70,6 +71,7 @@ public: PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; + virtual void setListener(WalletListener * l); private: void clearStatus(); @@ -84,6 +86,8 @@ private: std::string m_password; TransactionHistoryImpl * m_history; bool m_trustedDaemon; + WalletListener * m_walletListener; + Wallet2CallbackImpl * m_wallet2Callback; }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 43f5c9472..8e0830746 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -103,6 +103,13 @@ struct TransactionHistory }; +struct WalletListener +{ + virtual ~WalletListener() = 0; + virtual void moneySpent(const std::string &txId, uint64_t amount); + virtual void moneyReceived(const std::string &txId, uint64_t amount); +}; + /** * @brief Interface for wallet operations. @@ -141,6 +148,7 @@ struct Wallet virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; + virtual void setListener(WalletListener *) = 0; }; /** -- cgit v1.2.3 From 27d86b73c63c7eea0473f11df348fc6a4a3b3e65 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 13 May 2016 16:25:31 +0300 Subject: WalletListener::moneySpent(), WalletListener::moneyReceived() --- src/wallet/api/wallet.cpp | 23 +++++++++++++++++++++-- src/wallet/wallet2_api.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 6170000b7..5819e42bc 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -57,7 +57,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback void setListener(WalletListener * listener) { - // TODO; + m_listener = listener; } WalletListener * getListener() const @@ -68,16 +68,35 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback virtual void on_new_block(uint64_t height, const cryptonote::block& block) { // TODO; + LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height); } + virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) { - // TODO; + std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx)); + uint64_t amount = tx.vout[out_index].amount; + + LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height + << ", tx: " << tx_hash + << ", amount: " << print_money(amount)); + if (m_listener) { + m_listener->moneyReceived(tx_hash, amount); + } } + virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) { // TODO; + std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx)); + uint64_t amount = in_tx.vout[out_index].amount; + LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height + << ", tx: " << tx_hash + << ", amount: " << print_money(amount)); + if (m_listener) { + m_listener->moneySpent(tx_hash, amount); + } } virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 8e0830746..d38fd6708 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -108,6 +108,7 @@ struct WalletListener virtual ~WalletListener() = 0; virtual void moneySpent(const std::string &txId, uint64_t amount); virtual void moneyReceived(const std::string &txId, uint64_t amount); + // TODO: on_skip_transaction; }; -- cgit v1.2.3 From 40087a745f7677d29642c9ff86e1583c34ed1748 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 16 May 2016 13:11:44 +0300 Subject: WalletListener::moneySpent test --- src/wallet/api/wallet.cpp | 8 ++ src/wallet/wallet2_api.h | 4 +- tests/libwallet_api_tests/main.cpp | 207 +++++++++++++++++++++++++++---------- 3 files changed, 164 insertions(+), 55 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5819e42bc..440642291 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -50,6 +50,12 @@ namespace { struct Wallet2CallbackImpl : public tools::i_wallet2_callback { + Wallet2CallbackImpl() + : m_listener(nullptr) + { + + } + ~Wallet2CallbackImpl() { @@ -109,6 +115,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback Wallet::~Wallet() {} +WalletListener::~WalletListener() {} + string Wallet::displayAmount(uint64_t amount) { return cryptonote::print_money(amount); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index d38fd6708..7841c299d 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -106,8 +106,8 @@ struct TransactionHistory struct WalletListener { virtual ~WalletListener() = 0; - virtual void moneySpent(const std::string &txId, uint64_t amount); - virtual void moneyReceived(const std::string &txId, uint64_t amount); + virtual void moneySpent(const std::string &txId, uint64_t amount) = 0; + virtual void moneyReceived(const std::string &txId, uint64_t amount) = 0; // TODO: on_skip_transaction; }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 35d0c8e9d..bdcf889ef 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -37,12 +37,47 @@ #include #include +#include +#include using namespace std; //unsigned int epee::g_test_dbg_lock_sleep = 0; +namespace Consts +{ + +// TODO: add test wallets to the source tree (as they have some balance mined)? +// TODO: get rid of hardcoded paths + +const char * WALLET_NAME = "testwallet"; +const char * WALLET_NAME_COPY = "testwallet_copy"; +const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test"; +const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test"; +const char * WALLET_PASS = "password"; +const char * WALLET_PASS2 = "password22"; +const char * WALLET_LANG = "English"; + +const char * TESTNET_WALLET_NAME = "/home/mbg033/dev/monero/testnet/wallet_01.bin"; +const char * TESTNET_WALLET3_NAME = "/home/mbg033/dev/monero/testnet/wallet_03.bin"; +const char * TESTNET_WALLET4_NAME = "/home/mbg033/dev/monero/testnet/wallet_04.bin"; +const char * TESTNET_WALLET_PASS = ""; + + +const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; +const uint64_t AMOUNT_10XMR = 10000000000000L; +const uint64_t AMOUNT_5XMR = 50000000000000L; + +const char * RECIPIENT_WALLET_ADDRESS = "9uekQVGj7NjSAREnZ8cUsRagWDdjvdhpwUKhsL95oXngBnZXZ1RzH8R6UJbU1R7wim9yKbSjxuoQ22ERRkEochGECj66oP3"; +const char * TESTNET_WALLET3_ADDRESS = "A11cBpRDqpTCneSL3KNBvGWM6PfxG7QrxNVCcMiZeuAD3fQA9Z366DegFLYHKrMnDm8QixPziRn4kVcWPFtn6aCSR1Hp7sg"; +const char * TESTNET_WALLET4_ADDRESS = "A21wicxbhUSKa6twequhKCCG8wYEGZ7viYRLW7mBXtWyheyY8C8XwUJG5PSjULDs1q7hndkihtFgybWjagvchrNg1Y588hM"; + +} + + +using namespace Consts; + struct Utils { static void deleteWallet(const std::string & walletname) @@ -58,39 +93,29 @@ struct Utils std::cout << "** removing dir recursively: " << path << std::endl; boost::filesystem::remove_all(path); } + + static void print_transaction(Bitmonero::TransactionInfo * t) + { + + std::cout << "d: " + << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") + << ", pe: " << (t->isPending() ? "true" : "false") + << ", bh: " << t->blockHeight() + << ", a: " << Bitmonero::Wallet::displayAmount(t->amount()) + << ", f: " << Bitmonero::Wallet::displayAmount(t->fee()) + << ", h: " << t->hash() + << ", pid: " << t->paymentId() + << std::endl; + } }; -struct WalletManagerTest : public testing::Test +struct DISABLED_WalletManagerTest : public testing::Test { Bitmonero::WalletManager * wmgr; - const char * WALLET_NAME = "testwallet"; - const char * WALLET_NAME_COPY = "testwallet_copy"; - const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test"; - const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test"; - const char * WALLET_PASS = "password"; - const char * WALLET_PASS2 = "password22"; - const char * WALLET_LANG = "English"; - - - // TODO: add test wallets to the source tree (as they have some balance mined)? - const char * TESTNET_WALLET_NAME = "/home/mbg033/dev/monero/testnet/wallet_01.bin"; - const char * TESTNET_WALLET3_NAME = "/home/mbg033/dev/monero/testnet/wallet_03.bin"; - const char * TESTNET_WALLET4_NAME = "/home/mbg033/dev/monero/testnet/wallet_04.bin"; - const char * TESTNET_WALLET_PASS = ""; - - - const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; - const uint64_t AMOUNT_10XMR = 10000000000000L; - const uint64_t AMOUNT_5XMR = 50000000000000L; - - const char * RECIPIENT_WALLET_ADDRESS = "9uekQVGj7NjSAREnZ8cUsRagWDdjvdhpwUKhsL95oXngBnZXZ1RzH8R6UJbU1R7wim9yKbSjxuoQ22ERRkEochGECj66oP3"; - const char * TESTNET_WALLET3_ADDRESS = "A11cBpRDqpTCneSL3KNBvGWM6PfxG7QrxNVCcMiZeuAD3fQA9Z366DegFLYHKrMnDm8QixPziRn4kVcWPFtn6aCSR1Hp7sg"; - const char * TESTNET_WALLET4_ADDRESS = "A21wicxbhUSKa6twequhKCCG8wYEGZ7viYRLW7mBXtWyheyY8C8XwUJG5PSjULDs1q7hndkihtFgybWjagvchrNg1Y588hM"; - - WalletManagerTest() + DISABLED_WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); @@ -99,29 +124,42 @@ struct WalletManagerTest : public testing::Test } - ~WalletManagerTest() + ~DISABLED_WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; //deleteWallet(WALLET_NAME); } - static void print_transaction(Bitmonero::TransactionInfo * t) +}; + + +struct DISABLED_WalletTest1 : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + DISABLED_WalletTest1() { + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + } - std::cout << "d: " - << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") - << ", pe: " << (t->isPending() ? "true" : "false") - << ", bh: " << t->blockHeight() - << ", a: " << Bitmonero::Wallet::displayAmount(t->amount()) - << ", f: " << Bitmonero::Wallet::displayAmount(t->fee()) - << ", h: " << t->hash() - << ", pid: " << t->paymentId() - << std::endl; + +}; + + +struct WalletTest2 : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + WalletTest2() + { + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); } + + }; -TEST_F(WalletManagerTest, WalletManagerCreatesWallet) +TEST_F(DISABLED_WalletManagerTest, WalletManagerCreatesWallet) { Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -138,7 +176,7 @@ TEST_F(WalletManagerTest, WalletManagerCreatesWallet) } -TEST_F(WalletManagerTest, WalletManagerOpensWallet) +TEST_F(DISABLED_WalletManagerTest, WalletManagerOpensWallet) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -151,7 +189,7 @@ TEST_F(WalletManagerTest, WalletManagerOpensWallet) } -TEST_F(WalletManagerTest, WalletManagerChangesPassword) +TEST_F(DISABLED_WalletManagerTest, WalletManagerChangesPassword) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -167,7 +205,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword) -TEST_F(WalletManagerTest, WalletManagerRecoversWallet) +TEST_F(DISABLED_WalletManagerTest, WalletManagerRecoversWallet) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -183,7 +221,7 @@ TEST_F(WalletManagerTest, WalletManagerRecoversWallet) } -TEST_F(WalletManagerTest, WalletManagerStoresWallet1) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet1) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -200,7 +238,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1) } -TEST_F(WalletManagerTest, WalletManagerStoresWallet2) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet2) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -216,7 +254,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletManagerStoresWallet3) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet3) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -238,7 +276,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3) } -TEST_F(WalletManagerTest, WalletManagerStoresWallet4) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet4) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -260,7 +298,8 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4) } -TEST_F(WalletManagerTest, WalletShowsBalance) + +TEST_F(DISABLED_WalletTest1, WalletShowsBalance) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); ASSERT_TRUE(wallet1->balance() > 0); @@ -278,7 +317,7 @@ TEST_F(WalletManagerTest, WalletShowsBalance) ASSERT_TRUE(wmgr->closeWallet(wallet2)); } -TEST_F(WalletManagerTest, WalletRefresh) +TEST_F(DISABLED_WalletTest1, WalletRefresh) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -287,7 +326,7 @@ TEST_F(WalletManagerTest, WalletRefresh) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletTransaction) +TEST_F(DISABLED_WalletTest1, WalletTransaction) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -308,7 +347,7 @@ TEST_F(WalletManagerTest, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletHistory) +TEST_F(DISABLED_WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -321,11 +360,11 @@ TEST_F(WalletManagerTest, WalletHistory) for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); - print_transaction(t); + Utils::print_transaction(t); } } -TEST_F(WalletManagerTest, WalletTransactionAndHistory) +TEST_F(DISABLED_WalletTest1, WalletTransactionAndHistory) { Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -339,7 +378,7 @@ TEST_F(WalletManagerTest, WalletTransactionAndHistory) std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl; for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); - print_transaction(t); + Utils::print_transaction(t); } Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_10XMR * 5); @@ -352,11 +391,73 @@ TEST_F(WalletManagerTest, WalletTransactionAndHistory) std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl; for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); - print_transaction(t); + Utils::print_transaction(t); } } +struct MyWalletListener : public Bitmonero::WalletListener +{ + + Bitmonero::Wallet * wallet; + uint64_t total_tx; + uint64_t total_rx; + std::timed_mutex guard; + + MyWalletListener(Bitmonero::Wallet * wallet) + : total_tx(0), total_rx(0) + { + this->wallet = wallet; + this->wallet->setListener(this); + } + + virtual void moneySpent(const string &txId, uint64_t amount) + { + std::cout << "wallet: " << wallet->address() << " just spent money (" + << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; + total_tx += amount; + guard.unlock(); + } + + virtual void moneyReceived(const string &txId, uint64_t amount) + { + std::cout << "wallet: " << wallet->address() << " just received money (" + << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; + total_rx += amount; + guard.unlock(); + } +}; + +TEST_F(WalletTest2, WalletCallbackSent) +{ + + Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); + // make sure testnet daemon is running + ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_src->refresh()); + MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src); + std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; + /* + Bitmonero::Wallet * wallet_dst = wmgr->openWallet(TESTNET_WALLET4_NAME, TESTNET_WALLET_PASS, true); + ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_dst->refresh()); + MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst); + */ + + + uint64_t amount = AMOUNT_10XMR * 5; + std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS; + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_10XMR * 5); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); + ASSERT_TRUE(tx->commit()); + + std::chrono::seconds wait_for = std::chrono::seconds(60*3); + + wallet_src_listener->guard.lock(); + wallet_src_listener->guard.try_lock_for(wait_for); + ASSERT_TRUE(wallet_src_listener->total_tx != 0); + +} int main(int argc, char** argv) { -- cgit v1.2.3 From c554055ce435ae2752820ba317d801f143804b3c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 10 Jun 2016 12:51:09 +0300 Subject: Wallet::filename, Wallet::keysFilename, tests for move wallet --- src/wallet/api/wallet.cpp | 10 ++++++++++ src/wallet/api/wallet.h | 2 ++ src/wallet/wallet2_api.h | 17 +++++++++++++++++ tests/libwallet_api_tests/main.cpp | 29 +++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 440642291..5b68387ea 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -303,6 +303,16 @@ bool WalletImpl::store(const std::string &path) return m_status == Status_Ok; } +string WalletImpl::filename() const +{ + return m_wallet->get_wallet_file(); +} + +string WalletImpl::keysFilename() const +{ + return m_wallet->get_keys_file(); +} + bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c0fa31003..c402ef53c 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -61,6 +61,8 @@ public: bool setPassword(const std::string &password); std::string address() 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); bool connectToDaemon(); void setTrustedDaemon(bool arg); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index b98bb8661..bf5ddc3c7 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -135,7 +135,24 @@ struct Wallet virtual std::string errorString() const = 0; virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; + /*! + * \brief store - stores wallet to file. + * \param path - main filename to store wallet to. additionally stores address file and keys file. + * to store to the same file - just pass empty string; + * \return + */ virtual bool store(const std::string &path) = 0; + /*! + * \brief filename - returns wallet filename + * \return + */ + virtual std::string filename() const = 0; + /*! + * \brief keysFilename - returns keys filename. usually this formed as "wallet_filename".keys + * \return + */ + virtual std::string keysFilename() const = 0; + virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; virtual bool connectToDaemon() = 0; virtual void setTrustedDaemon(bool arg) = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 91636d522..595e3ccfb 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -210,6 +210,35 @@ TEST_F(WalletManagerTest, WalletManagerOpensWallet) std::cout << "** seed: " << wallet2->seed() << std::endl; } +TEST_F(WalletManagerTest, WalletManagerStoresWallet) +{ + + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + std::string seed1 = wallet1->seed(); + wallet1->store(""); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); + Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet2->seed() == seed1); +} + + +TEST_F(WalletManagerTest, WalletManagerMovesWallet) +{ + + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + std::string WALLET_NAME_MOVED = std::string("/tmp/") + WALLET_NAME + ".moved"; + std::string seed1 = wallet1->seed(); + ASSERT_TRUE(wallet1->store(WALLET_NAME_MOVED)); + + Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_MOVED, WALLET_PASS); + ASSERT_TRUE(wallet2->filename() == WALLET_NAME_MOVED); + ASSERT_TRUE(wallet2->keysFilename() == WALLET_NAME_MOVED + ".keys"); + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet2->seed() == seed1); +} + + /* TEST_F(WalletManagerTest, WalletManagerChangesPassword) { -- cgit v1.2.3 From 3ac20a46b38f88757c57cbcf8581cade312b7936 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 10 Jun 2016 13:52:10 +0300 Subject: wallet::default_mixin exposed to public interface as Wallet::setDefaultMixin, Wallet::defaultMixin; wallet::create_transaction_2 used in Wallet::createTransaction --- src/wallet/api/wallet.cpp | 11 ++++++++++- src/wallet/api/wallet.h | 2 ++ src/wallet/wallet2_api.h | 10 ++++++++++ tests/libwallet_api_tests/main.cpp | 2 ++ 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5b68387ea..f6d7a561e 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -400,7 +400,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 try { - transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { @@ -486,6 +486,15 @@ void WalletImpl::setListener(WalletListener *l) m_wallet2Callback->setListener(l); } +uint32_t WalletImpl::defaultMixin() const +{ + return m_wallet->default_mixin(); +} + +void WalletImpl::setDefaultMixin(uint32_t arg) +{ + m_wallet->default_mixin(arg); +} bool WalletImpl::connectToDaemon() diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c402ef53c..6c8913c25 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -74,6 +74,8 @@ public: virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); + virtual uint32_t defaultMixin() const; + virtual void setDefaultMixin(uint32_t arg); private: void clearStatus(); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index bf5ddc3c7..62231820b 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -167,6 +167,16 @@ struct Wallet virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; + /*! + * \brief defaultMixin - returns number of mixins used in transactions + * \return + */ + virtual uint32_t defaultMixin() const = 0; + /*! + * \brief setDefaultMixin - setum number of mixins to be used for new transactions + * \param arg + */ + virtual void setDefaultMixin(uint32_t arg) = 0; }; /** diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 595e3ccfb..935cfd884 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -401,6 +401,8 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok); std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + wallet1->setDefaultMixin(1); + ASSERT_TRUE(wallet1->defaultMixin() == 1); Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( recepient_address, AMOUNT_10XMR); -- cgit v1.2.3 From 3318addafaf6ac7b5489f7d774083a84dce7dfa0 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 16 Jun 2016 16:42:33 +0300 Subject: double/string to monero integer convertion methods --- src/wallet/api/wallet.cpp | 17 +++++++++++++++++ src/wallet/wallet2_api.h | 2 ++ tests/libwallet_api_tests/main.cpp | 16 ++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index f6d7a561e..1f414b3bf 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -36,6 +36,7 @@ #include "mnemonics/electrum-words.h" #include +#include using namespace std; using namespace cryptonote; @@ -122,6 +123,22 @@ string Wallet::displayAmount(uint64_t amount) return cryptonote::print_money(amount); } +uint64_t Wallet::amountFromString(const string &amount) +{ + uint64_t result; + cryptonote::parse_amount(result, amount); + return result; +} + +uint64_t Wallet::amountFromDouble(double amount) +{ + std::stringstream ss; + ss << std::fixed << std::setprecision(CRYPTONOTE_DISPLAY_DECIMAL_POINT) << amount; + return amountFromString(ss.str()); +} + + + ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false), diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 62231820b..34c18f77f 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -160,6 +160,8 @@ struct Wallet virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; static std::string displayAmount(uint64_t amount); + static uint64_t amountFromString(const std::string &amount); + static uint64_t amountFromDouble(double amount); // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 935cfd884..849d76e1b 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -247,7 +247,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword) ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2)); ASSERT_TRUE(wmgr->closeWallet(wallet1)); Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2); - ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);quint64 ASSERT_TRUE(wallet2->seed() == seed1); ASSERT_TRUE(wmgr->closeWallet(wallet2)); Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); @@ -390,7 +390,19 @@ TEST_F(WalletTest1, WalletRefresh) } +TEST_F(WalletTest1, WalletConvertsToString) +{ + std::string strAmount = Bitmonero::Wallet::displayAmount(AMOUNT_5XMR); + ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromString(strAmount)); + + ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromDouble(5.0)); + ASSERT_TRUE(AMOUNT_10XMR == Bitmonero::Wallet::amountFromDouble(10.0)); + ASSERT_TRUE(AMOUNT_1XMR == Bitmonero::Wallet::amountFromDouble(1.0)); + +} + +/* TEST_F(WalletTest1, WalletTransaction) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -415,7 +427,7 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_FALSE(wallet1->balance() == balance); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } - +*/ TEST_F(WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); -- cgit v1.2.3 From f1c4a376af916604e2b142a1169d610f631bd91c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 20 Jun 2016 22:56:30 +0300 Subject: Wallet::createTransaction: added mixin_count param --- src/wallet/api/wallet.cpp | 18 ++++++++++------- src/wallet/api/wallet.h | 2 +- src/wallet/wallet2_api.h | 13 ++++++++++-- tests/libwallet_api_tests/main.cpp | 41 +++++++++++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 11 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 1f414b3bf..d72ebc8da 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -45,7 +45,7 @@ namespace Bitmonero { namespace { // copy-pasted from simplewallet - static const size_t DEFAULT_MIX = 4; + static const size_t DEFAULT_MIXIN = 4; } struct Wallet2CallbackImpl : public tools::i_wallet2_callback @@ -380,7 +380,7 @@ bool WalletImpl::refresh() // - payment_details; // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount, uint32_t mixin_count) { clearStatus(); vector dsts; @@ -389,9 +389,10 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 crypto::hash8 new_payment_id; // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) - size_t fake_outs_count = m_wallet->default_mixin(); + + size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); if (fake_outs_count == 0) - fake_outs_count = DEFAULT_MIX; + fake_outs_count = DEFAULT_MIXIN; PendingTransactionImpl * transaction = new PendingTransactionImpl(this); @@ -436,27 +437,30 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 } catch (const tools::error::not_enough_money& e) { m_status = Status_Error; - std::ostringstream writer(m_errorString); + std::ostringstream writer; writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % print_money(e.fee()); + m_errorString = writer.str(); } catch (const tools::error::not_enough_outs_to_mix& e) { - std::ostringstream writer(m_errorString); + std::ostringstream writer; writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); } + m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_not_constructed&) { m_errorString = tr("transaction was not constructed"); m_status = Status_Error; } catch (const tools::error::tx_rejected& e) { - std::ostringstream writer(m_errorString); + std::ostringstream writer; writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_sum_overflow& e) { m_errorString = e.what(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 6c8913c25..016116e96 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -70,7 +70,7 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); - PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); + PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count); virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 34c18f77f..de0b50591 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -128,7 +128,6 @@ struct Wallet virtual std::string seed() const = 0; virtual std::string getSeedLanguage() const = 0; virtual void setSeedLanguage(const std::string &arg) = 0; - // virtual void setListener(Listener * listener) = 0; //! returns wallet status (Status_Ok | Status_Error) virtual int status() const = 0; //! in case error status, returns error string @@ -159,13 +158,23 @@ struct Wallet virtual bool trustedDaemon() const = 0; virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; + static std::string displayAmount(uint64_t amount); static uint64_t amountFromString(const std::string &amount); static uint64_t amountFromDouble(double amount); + // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; - virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; + /*! + * \brief createTransaction creates transaction + * \param dst_addr destination address as string + * \param amount amount + * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() + * after object returned + */ + virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count) = 0; virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 849d76e1b..ddd6969c6 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -428,6 +428,45 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } */ + +TEST_F(WalletTest1, WalletTransactionWithMixin) +{ + + std::vector mixins; + // 2,3,4,5,6,7,8,9,10,15,20,25 can we do it like that? + mixins.push_back(2); mixins.push_back(3); mixins.push_back(4); mixins.push_back(5); mixins.push_back(6); + mixins.push_back(7); mixins.push_back(8); mixins.push_back(9); mixins.push_back(10); mixins.push_back(15); + mixins.push_back(20); mixins.push_back(25); + + + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + + + // make sure testnet daemon is running + ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet1->refresh()); + uint64_t balance = wallet1->balance(); + ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok); + + std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + for (auto mixin : mixins) { + std::cerr << "Transaction mixin count: " << mixin << std::endl; + Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( + recepient_address, AMOUNT_5XMR, mixin); + + std::cerr << "Transaction status: " << transaction->status() << std::endl; + std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl; + std::cerr << "Transaction error: " << transaction->errorString() << std::endl; + ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); + wallet1->disposeTransaction(transaction); + } + + wallet1->refresh(); + + ASSERT_TRUE(wallet1->balance() == balance); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} + TEST_F(WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -465,7 +504,7 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, AMOUNT_10XMR * 5); + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, AMOUNT_10XMR * 5, 0); ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); history = wallet_src->history(); -- cgit v1.2.3 From 12345d382c3ae4d751119edde4464397f93d96b3 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:01:00 +0300 Subject: api implementation splitted over separate files --- src/wallet/CMakeLists.txt | 14 +- src/wallet/api/common_defines.h | 7 + src/wallet/api/pending_transaction.cpp | 138 +++++++ src/wallet/api/pending_transaction.h | 64 +++ src/wallet/api/transaction_history.cpp | 33 ++ src/wallet/api/transaction_history.h | 44 ++ src/wallet/api/transaction_info.cpp | 89 +++++ src/wallet/api/transaction_info.h | 52 +++ src/wallet/api/wallet.cpp | 411 +++++++++++++++++++ src/wallet/api/wallet.h | 86 ++++ src/wallet/api/wallet_manager.cpp | 108 +++++ src/wallet/api/wallet_manager.h | 55 +++ src/wallet/wallet2_api.cpp | 706 --------------------------------- src/wallet/wallet2_api.h | 8 +- 14 files changed, 1105 insertions(+), 710 deletions(-) create mode 100644 src/wallet/api/common_defines.h create mode 100644 src/wallet/api/pending_transaction.cpp create mode 100644 src/wallet/api/pending_transaction.h create mode 100644 src/wallet/api/transaction_history.cpp create mode 100644 src/wallet/api/transaction_history.h create mode 100644 src/wallet/api/transaction_info.cpp create mode 100644 src/wallet/api/transaction_info.h create mode 100644 src/wallet/api/wallet.cpp create mode 100644 src/wallet/api/wallet.h create mode 100644 src/wallet/api/wallet_manager.cpp create mode 100644 src/wallet/api/wallet_manager.h delete mode 100644 src/wallet/wallet2_api.cpp (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index a6fc37dec..33af4f30d 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -32,17 +32,27 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(wallet_sources wallet2.cpp wallet_rpc_server.cpp - wallet2_api.cpp) + api/wallet.cpp + api/wallet_manager.cpp + api/transaction_info.cpp + api/transaction_history.cpp + api/pending_transaction.cpp) set(wallet_headers) set(wallet_private_headers wallet2.h + wallet2_api.h wallet_errors.h wallet_rpc_server.h wallet_rpc_server_commands_defs.h wallet_rpc_server_error_codes.h - wallet2_api.h) + api/wallet.h + api/wallet_manager.h + api/transaction_info.h + api/transaction_history.h + api/pending_transaction.h + api/common_defines.h) bitmonero_private_headers(wallet ${wallet_private_headers}) diff --git a/src/wallet/api/common_defines.h b/src/wallet/api/common_defines.h new file mode 100644 index 000000000..60a40a45a --- /dev/null +++ b/src/wallet/api/common_defines.h @@ -0,0 +1,7 @@ +#ifndef WALLET_API_COMMON_DEFINES_H__ +#define WALLET_API_COMMON_DEFINES_H__ + +#define tr(x) (x) + +#endif + diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp new file mode 100644 index 000000000..e9791ec35 --- /dev/null +++ b/src/wallet/api/pending_transaction.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "pending_transaction.h" +#include "wallet.h" +#include "common_defines.h" + +#include "cryptonote_core/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_basic_impl.h" +#include "cryptonote_core/cryptonote_format_utils.h" + +#include +#include +#include +#include + +using namespace std; + +namespace Bitmonero { + +PendingTransaction::~PendingTransaction() {} + + +TransactionImpl::TransactionImpl(WalletImpl *wallet) + : m_wallet(wallet) +{ + +} + +TransactionImpl::~TransactionImpl() +{ + +} + +int TransactionImpl::status() const +{ + return m_status; +} + +string TransactionImpl::errorString() const +{ + return m_errorString; +} + +bool TransactionImpl::commit() +{ + + LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size()); + assert(m_pending_tx.size() == 1); + try { + while (!m_pending_tx.empty()) { + auto & ptx = m_pending_tx.back(); + m_wallet->m_wallet->commit_tx(ptx); + // success_msg_writer(true) << tr("Money successfully sent, transaction ") << get_transaction_hash(ptx.tx); + // if no exception, remove element from vector + m_pending_tx.pop_back(); + } // TODO: extract method; + } catch (const tools::error::daemon_busy&) { + // TODO: make it translatable with "tr"? + m_errorString = tr("daemon is busy. Please try again later."); + m_status = Status_Error; + } catch (const tools::error::no_connection_to_daemon&) { + m_errorString = tr("no connection to daemon. Please make sure daemon is running."); + m_status = Status_Error; + } catch (const tools::error::tx_rejected& e) { + std::ostringstream writer(m_errorString); + writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + m_status = Status_Error; + } catch (std::exception &e) { + m_errorString = string(tr("Unknown exception: ")) + e.what(); + m_status = Status_Error; + } catch (...) { + m_errorString = tr("Unhandled exception"); + LOG_ERROR(m_errorString); + m_status = Status_Error; + } + + return m_status == Status_Ok; +} + +uint64_t TransactionImpl::amount() const +{ + uint64_t result = 0; + for (const auto &ptx : m_pending_tx) { + for (const auto &dest : ptx.dests) { + result += dest.amount; + } + } + return result; +} + +uint64_t TransactionImpl::dust() const +{ + uint32_t result = 0; + for (const auto & ptx : m_pending_tx) { + result += ptx.dust; + } + return result; +} + +uint64_t TransactionImpl::fee() const +{ + uint32_t result = 0; + for (const auto ptx : m_pending_tx) { + result += ptx.fee; + } + return result; +} + +} + diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h new file mode 100644 index 000000000..0ae3eb8e2 --- /dev/null +++ b/src/wallet/api/pending_transaction.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "wallet/wallet2_api.h" +#include "wallet/wallet2.h" + +#include +#include + + +namespace Bitmonero { + +class WalletImpl; +class PendingTransactionImpl : public PendingTransaction +{ +public: + PendingTransactionImpl(WalletImpl * wallet); + ~PendingTransactionImpl(); + int status() const; + std::string errorString() const; + bool commit(); + uint64_t amount() const; + uint64_t dust() const; + uint64_t fee() const; + // TODO: continue with interface; + +private: + friend class WalletImpl; + WalletImpl * m_wallet; + + int m_status; + std::string m_errorString; + std::vector m_pending_tx; +}; + + +} diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp new file mode 100644 index 000000000..f1aba14cb --- /dev/null +++ b/src/wallet/api/transaction_history.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "transaction_history.h" + + diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h new file mode 100644 index 000000000..cab0e0dbc --- /dev/null +++ b/src/wallet/api/transaction_history.h @@ -0,0 +1,44 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "wallet/wallet2_api.h" + +namespace Bitmonero { + +class TransactionHistoryImpl : public TransactionHistory +{ + virtual int count() const; + virtual TransactionInfo * transaction(int index) const = 0; + virtual TransactionInfo * transaction(const std::string &id) const = 0; + virtual std::vector getAll() const = 0; +}; + +} + diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp new file mode 100644 index 000000000..8de4e555f --- /dev/null +++ b/src/wallet/api/transaction_info.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "transaction_info.h" + + +using namespace std; + +namespace Bitmonero { + +TransactionInfoImpl::TransactionInfoImpl() +{ + +} + +TransactionInfoImpl::~TransactionInfoImpl() +{ + +} + +int TransactionInfoImpl::direction() const +{ + return TransactionInfo::Direction_In; +} + + +bool TransactionInfoImpl::isHold() const +{ + return false; +} + +bool TransactionInfoImpl::isFailed() const +{ + return false; +} + +uint64_t TransactionInfoImpl::amount() const +{ + return 0; +} + +uint64_t TransactionInfoImpl::fee() const +{ + return 0; +} + +string TransactionInfoImpl::address() const +{ + return ""; +} + +std::time_t TransactionInfoImpl::timestamp() const +{ + return std::time_t(0); +} + +string TransactionInfoImpl::paymentId() const +{ + return ""; +} + +} // namespace diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h new file mode 100644 index 000000000..2ed8157f7 --- /dev/null +++ b/src/wallet/api/transaction_info.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include "wallet/wallet2_api.h" +#include +#include + +namespace Bitmonero { + +class TransactionInfoImpl : public TransactionInfo +{ +public: + TransactionInfoImpl(); + ~TransactionInfoImpl(); + virtual int direction() const; + virtual bool isHold() const; + virtual bool isFailed() const; + virtual uint64_t amount() const; + virtual uint64_t fee() const; + virtual std::string address() const; + virtual std::time_t timestamp() const; + virtual std::string paymentId() const; +}; + +} // namespace diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp new file mode 100644 index 000000000..e42f04cf7 --- /dev/null +++ b/src/wallet/api/wallet.cpp @@ -0,0 +1,411 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + + +#include "wallet.h" +#include "pending_transaction.h" +#include "common_defines.h" + +#include "mnemonics/electrum-words.h" +#include + +using namespace std; +using namespace cryptonote; + +namespace Bitmonero { + +namespace { + // copy-pasted from simplewallet + static const size_t DEFAULT_MIX = 4; +} + +Wallet::~Wallet() {} + +string Wallet::displayAmount(uint64_t amount) +{ + return cryptonote::print_money(amount); +} + +///////////////////////// WalletImpl implementation //////////////////////// +WalletImpl::WalletImpl(bool testnet) + :m_wallet(nullptr), m_status(Wallet::Status_Ok) +{ + m_wallet = new tools::wallet2(testnet); +} + +WalletImpl::~WalletImpl() +{ + delete m_wallet; +} + +bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language) +{ + + clearStatus(); + + bool keys_file_exists; + bool wallet_file_exists; + tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); + // TODO: figure out how to setup logger; + 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 or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."; + LOG_ERROR(m_errorString); + m_status = Status_Error; + return false; + } + // TODO: validate language + m_wallet->set_seed_language(language); + crypto::secret_key recovery_val, secret_key; + try { + recovery_val = m_wallet->generate(path, password, secret_key, false, false); + m_password = password; + m_status = Status_Ok; + } catch (const std::exception &e) { + LOG_ERROR("Error creating 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(); + try { + // TODO: handle "deprecated" + m_wallet->load(path, password); + + m_password = password; + } catch (const std::exception &e) { + LOG_ERROR("Error opening wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +bool WalletImpl::recover(const std::string &path, const std::string &seed) +{ + clearStatus(); + m_errorString.clear(); + if (seed.empty()) { + m_errorString = "Electrum seed is empty"; + LOG_ERROR(m_errorString); + m_status = Status_Error; + return false; + } + + crypto::secret_key recovery_key; + std::string old_language; + if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) { + m_errorString = "Electrum-style word list failed verification"; + m_status = Status_Error; + return false; + } + + try { + m_wallet->set_seed_language(old_language); + m_wallet->generate(path, "", recovery_key, true, false); + // TODO: wallet->init(daemon_address); + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +bool WalletImpl::close() +{ + clearStatus(); + bool result = false; + try { + m_wallet->store(); + m_wallet->stop(); + result = true; + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + LOG_ERROR("Error closing wallet: " << e.what()); + } + return result; +} + +std::string WalletImpl::seed() const +{ + std::string seed; + if (m_wallet) + m_wallet->get_seed(seed); + return seed; +} + +std::string WalletImpl::getSeedLanguage() const +{ + return m_wallet->get_seed_language(); +} + +void WalletImpl::setSeedLanguage(const std::string &arg) +{ + m_wallet->set_seed_language(arg); +} + +int WalletImpl::status() const +{ + return m_status; +} + +std::string WalletImpl::errorString() const +{ + return m_errorString; +} + +bool WalletImpl::setPassword(const std::string &password) +{ + clearStatus(); + try { + m_wallet->rewrite(m_wallet->get_wallet_file(), password); + m_password = password; + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +std::string WalletImpl::address() const +{ + return m_wallet->get_account().get_public_address_str(m_wallet->testnet()); +} + +bool WalletImpl::store(const std::string &path) +{ + clearStatus(); + try { + if (path.empty()) { + m_wallet->store(); + } else { + m_wallet->store_to(path, m_password); + } + } catch (const std::exception &e) { + LOG_ERROR("Error storing wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + } + + return m_status == Status_Ok; +} + +bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) +{ + clearStatus(); + try { + m_wallet->init(daemon_address, upper_transaction_size_limit); + } catch (const std::exception &e) { + LOG_ERROR("Error initializing wallet: " << e.what()); + m_status = Status_Error; + m_errorString = e.what(); + } + + return m_status == Status_Ok; +} + +uint64_t WalletImpl::balance() const +{ + return m_wallet->balance(); +} + +uint64_t WalletImpl::unlockedBalance() const +{ + return m_wallet->unlocked_balance(); +} + + +bool WalletImpl::refresh() +{ + clearStatus(); + try { + m_wallet->refresh(); + } catch (const std::exception &e) { + m_status = Status_Error; + m_errorString = e.what(); + } + return m_status == Status_Ok; +} + +// TODO: +// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) +// 2 - check / design how "Transaction" can be single interface +// (instead of few different data structures within wallet2 implementation: +// - pending_tx; +// - transfer_details; +// - payment_details; +// - unconfirmed_transfer_details; +// - confirmed_transfer_details) +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) +{ + clearStatus(); + vector dsts; + cryptonote::tx_destination_entry de; + bool has_payment_id; + crypto::hash8 new_payment_id; + + // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) + size_t fake_outs_count = m_wallet->default_mixin(); + if (fake_outs_count == 0) + fake_outs_count = DEFAULT_MIX; + + TransactionImpl * transaction = new TransactionImpl(this); + + do { + + if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), dst_addr)) { + // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 + m_status = Status_Error; + m_errorString = "Invalid destination address"; + break; + } + + de.amount = amount; + if (de.amount <= 0) { + m_status = Status_Error; + m_errorString = "Invalid amount"; + break; + } + + dsts.push_back(de); + //std::vector ptx_vector; + std::vector extra; + + + try { + transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + + } catch (const tools::error::daemon_busy&) { + // TODO: make it translatable with "tr"? + m_errorString = tr("daemon is busy. Please try again later."); + m_status = Status_Error; + } catch (const tools::error::no_connection_to_daemon&) { + m_errorString = tr("no connection to daemon. Please make sure daemon is running."); + m_status = Status_Error; + } catch (const tools::error::wallet_rpc_error& e) { + m_errorString = tr("RPC error: ") + e.to_string(); + m_status = Status_Error; + } catch (const tools::error::get_random_outs_error&) { + m_errorString = tr("failed to get random outputs to mix"); + m_status = Status_Error; + + } catch (const tools::error::not_enough_money& e) { + m_status = Status_Error; + std::ostringstream writer(m_errorString); + + writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % + print_money(e.available()) % + print_money(e.tx_amount() + e.fee()) % + print_money(e.tx_amount()) % + print_money(e.fee()); + + } catch (const tools::error::not_enough_outs_to_mix& e) { + std::ostringstream writer(m_errorString); + writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; + for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { + writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); + } + m_status = Status_Error; + } catch (const tools::error::tx_not_constructed&) { + m_errorString = tr("transaction was not constructed"); + m_status = Status_Error; + } catch (const tools::error::tx_rejected& e) { + std::ostringstream writer(m_errorString); + writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + m_status = Status_Error; + } catch (const tools::error::tx_sum_overflow& e) { + m_errorString = e.what(); + m_status = Status_Error; + } catch (const tools::error::zero_destination&) { + m_errorString = tr("one of destinations is zero"); + m_status = Status_Error; + } catch (const tools::error::tx_too_big& e) { + m_errorString = tr("failed to find a suitable way to split transactions"); + m_status = Status_Error; + } catch (const tools::error::transfer_error& e) { + m_errorString = string(tr("unknown transfer error: ")) + e.what(); + m_status = Status_Error; + } catch (const tools::error::wallet_internal_error& e) { + m_errorString = string(tr("internal error: ")) + e.what(); + m_status = Status_Error; + } catch (const std::exception& e) { + m_errorString = string(tr("unexpected error: ")) + e.what(); + m_status = Status_Error; + } catch (...) { + m_errorString = tr("unknown error"); + m_status = Status_Error; + } + } while (false); + + transaction->m_status = m_status; + transaction->m_errorString = m_errorString; + return transaction; +} + +void WalletImpl::disposeTransaction(PendingTransaction *t) +{ + delete t; +} + +TransactionHistory *WalletImpl::history() const +{ + return nullptr; +} + +bool WalletImpl::connectToDaemon() +{ + bool result = m_wallet->check_connection(); + m_status = result ? Status_Ok : Status_Error; + if (!result) { + m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address(); + } + return result; +} + +void WalletImpl::clearStatus() +{ + m_status = Status_Ok; + m_errorString.clear(); +} + + +} // namespace diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h new file mode 100644 index 000000000..35db38f67 --- /dev/null +++ b/src/wallet/api/wallet.h @@ -0,0 +1,86 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#ifndef WALLET_IMPL_H +#define WALLET_IMPL_H + +#include "wallet/wallet2_api.h" +#include "wallet/wallet2.h" + +#include + + +namespace Bitmonero { + + +class WalletImpl : public Wallet +{ +public: + WalletImpl(bool testnet = false); + ~WalletImpl(); + bool create(const std::string &path, const std::string &password, + const std::string &language); + bool open(const std::string &path, const std::string &password); + bool recover(const std::string &path, const std::string &seed); + bool close(); + std::string seed() const; + std::string getSeedLanguage() const; + void setSeedLanguage(const std::string &arg); + // void setListener(Listener *) {} + int status() const; + std::string errorString() const; + bool setPassword(const std::string &password); + std::string address() const; + bool store(const std::string &path); + bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit); + bool connectToDaemon(); + uint64_t balance() const; + uint64_t unlockedBalance() const; + bool refresh(); + PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); + virtual void disposeTransaction(PendingTransaction * t); + virtual TransactionHistory * history() const; + +private: + void clearStatus(); + +private: + friend class TransactionImpl; + tools::wallet2 * m_wallet; + int m_status; + std::string m_errorString; + std::string m_password; +}; + + +} // namespace + +#endif + diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp new file mode 100644 index 000000000..c056ada2c --- /dev/null +++ b/src/wallet/api/wallet_manager.cpp @@ -0,0 +1,108 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + + +#include "wallet_manager.h" +#include "wallet.h" + +namespace epee { + unsigned int g_test_dbg_lock_sleep = 0; +} + +namespace Bitmonero { + +Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, + const std::string &language, bool testnet) +{ + WalletImpl * wallet = new WalletImpl(testnet); + wallet->create(path, password, language); + return wallet; +} + +Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, bool testnet) +{ + WalletImpl * wallet = new WalletImpl(testnet); + wallet->open(path, password); + return wallet; +} + +Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo, bool testnet) +{ + WalletImpl * wallet = new WalletImpl(testnet); + wallet->recover(path, memo); + return wallet; +} + +bool WalletManagerImpl::closeWallet(Wallet *wallet) +{ + WalletImpl * wallet_ = dynamic_cast(wallet); + bool result = wallet_->close(); + if (!result) { + m_errorString = wallet_->errorString(); + } else { + delete wallet_; + } + return result; +} + +bool WalletManagerImpl::walletExists(const std::string &path) +{ + return false; +} + +std::string WalletManagerImpl::errorString() const +{ + return m_errorString; +} + +void WalletManagerImpl::setDaemonHost(const std::string &hostname) +{ + +} + + + +///////////////////// WalletManagerFactory implementation ////////////////////// +WalletManager *WalletManagerFactory::getWalletManager() +{ + + static WalletManagerImpl * g_walletManager = nullptr; + + if (!g_walletManager) { + epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_MAX); + g_walletManager = new WalletManagerImpl(); + } + + return g_walletManager; +} + + + +} diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h new file mode 100644 index 000000000..d608eb7f0 --- /dev/null +++ b/src/wallet/api/wallet_manager.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + + +#include "wallet/wallet2_api.h" +#include + +namespace Bitmonero { + +class WalletManagerImpl : public WalletManager +{ +public: + Wallet * createWallet(const std::string &path, const std::string &password, + 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); + virtual bool closeWallet(Wallet *wallet); + bool walletExists(const std::string &path); + std::string errorString() const; + void setDaemonHost(const std::string &hostname); + +private: + WalletManagerImpl() {} + friend struct WalletManagerFactory; + std::string m_errorString; +}; + +} // namespace diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp deleted file mode 100644 index a6fc6ecc5..000000000 --- a/src/wallet/wallet2_api.cpp +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright (c) 2014-2016, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list -// of conditions and the following disclaimer in the documentation and/or other -// materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be -// used to endorse or promote products derived from this software without specific -// prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#include "wallet2_api.h" -#include "wallet2.h" -#include "mnemonics/electrum-words.h" -#include "cryptonote_core/cryptonote_format_utils.h" -#include "cryptonote_core/cryptonote_basic_impl.h" -#include "cryptonote_core/cryptonote_format_utils.h" - - -#include -#include -#include -#include - - -#define tr(x) (x) - -namespace epee { - unsigned int g_test_dbg_lock_sleep = 0; -} - -namespace Bitmonero { - -struct WalletManagerImpl; - -namespace { - static WalletManagerImpl * g_walletManager = nullptr; - // copy-pasted from - static const size_t DEFAULT_MIX = 4; - -} - - - -using namespace std; -using namespace cryptonote; - -Wallet::~Wallet() {} -PendingTransaction::~PendingTransaction() {} - - - - - -///////////////////////// Wallet implementation /////////////////////////////// -class WalletImpl : public Wallet -{ -public: - WalletImpl(bool testnet = false); - ~WalletImpl(); - bool create(const std::string &path, const std::string &password, - const std::string &language); - bool open(const std::string &path, const std::string &password); - bool recover(const std::string &path, const std::string &seed); - bool close(); - std::string seed() const; - std::string getSeedLanguage() const; - void setSeedLanguage(const std::string &arg); - // void setListener(Listener *) {} - int status() const; - std::string errorString() const; - bool setPassword(const std::string &password); - std::string address() const; - bool store(const std::string &path); - bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit); - bool connectToDaemon(); - uint64_t balance() const; - uint64_t unlockedBalance() const; - bool refresh(); - PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); - virtual void disposeTransaction(PendingTransaction * t); - virtual TransactionHistory * history() const; - -private: - void clearStatus(); - -private: - friend class TransactionImpl; - tools::wallet2 * m_wallet; - int m_status; - std::string m_errorString; - std::string m_password; -}; - - -///////////////////////////////////////////////////////////////////////////////// -string Wallet::displayAmount(uint64_t amount) -{ - return cryptonote::print_money(amount); -} - -///////////////////////// Transaction implementation /////////////////////////// - -class TransactionImpl : public PendingTransaction -{ -public: - TransactionImpl(WalletImpl * wallet); - ~TransactionImpl(); - int status() const; - std::string errorString() const; - bool commit(); - uint64_t amount() const; - uint64_t dust() const; - uint64_t fee() const; - // TODO: continue with interface; - -private: - friend class WalletImpl; - WalletImpl * m_wallet; - - int m_status; - std::string m_errorString; - std::vector m_pending_tx; -}; - -TransactionImpl::TransactionImpl(WalletImpl *wallet) - : m_wallet(wallet) -{ - -} - -TransactionImpl::~TransactionImpl() -{ - -} - -int TransactionImpl::status() const -{ - return m_status; -} - -string TransactionImpl::errorString() const -{ - return m_errorString; -} - -bool TransactionImpl::commit() -{ - - LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size()); - assert(m_pending_tx.size() == 1); - try { - while (!m_pending_tx.empty()) { - auto & ptx = m_pending_tx.back(); - m_wallet->m_wallet->commit_tx(ptx); - // success_msg_writer(true) << tr("Money successfully sent, transaction ") << get_transaction_hash(ptx.tx); - // if no exception, remove element from vector - m_pending_tx.pop_back(); - } // TODO: extract method; - } catch (const tools::error::daemon_busy&) { - // TODO: make it translatable with "tr"? - m_errorString = tr("daemon is busy. Please try again later."); - m_status = Status_Error; - } catch (const tools::error::no_connection_to_daemon&) { - m_errorString = tr("no connection to daemon. Please make sure daemon is running."); - m_status = Status_Error; - } catch (const tools::error::tx_rejected& e) { - std::ostringstream writer(m_errorString); - writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); - m_status = Status_Error; - } catch (std::exception &e) { - m_errorString = string(tr("Unknown exception: ")) + e.what(); - m_status = Status_Error; - } catch (...) { - m_errorString = tr("Unhandled exception"); - LOG_ERROR(m_errorString); - m_status = Status_Error; - } - - return m_status == Status_Ok; -} - -uint64_t TransactionImpl::amount() const -{ - uint64_t result = 0; - for (const auto &ptx : m_pending_tx) { - for (const auto &dest : ptx.dests) { - result += dest.amount; - } - } - return result; -} - -uint64_t TransactionImpl::dust() const -{ - uint32_t result = 0; - for (const auto & ptx : m_pending_tx) { - result += ptx.dust; - } - return result; -} - -uint64_t TransactionImpl::fee() const -{ - uint32_t result = 0; - for (const auto ptx : m_pending_tx) { - result += ptx.fee; - } - return result; -} - - -///////////////////////// TransactionInfo implementation //////////////////////// -class TransactionInfoImpl : public TransactionInfo -{ -public: - TransactionInfoImpl(); - ~TransactionInfoImpl(); - virtual bool isHold() const; -}; - -TransactionInfoImpl::TransactionInfoImpl() -{ - -} - -TransactionInfoImpl::~TransactionInfoImpl() -{ - -} - -bool TransactionInfoImpl::isHold() const -{ - return false; -} - - - - -WalletImpl::WalletImpl(bool testnet) - :m_wallet(nullptr), m_status(Wallet::Status_Ok) -{ - m_wallet = new tools::wallet2(testnet); -} - -WalletImpl::~WalletImpl() -{ - delete m_wallet; -} - -bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language) -{ - - clearStatus(); - - bool keys_file_exists; - bool wallet_file_exists; - tools::wallet2::wallet_exists(path, keys_file_exists, wallet_file_exists); - // TODO: figure out how to setup logger; - 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 or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."; - LOG_ERROR(m_errorString); - m_status = Status_Error; - return false; - } - // TODO: validate language - m_wallet->set_seed_language(language); - crypto::secret_key recovery_val, secret_key; - try { - recovery_val = m_wallet->generate(path, password, secret_key, false, false); - m_password = password; - m_status = Status_Ok; - } catch (const std::exception &e) { - LOG_ERROR("Error creating 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(); - try { - // TODO: handle "deprecated" - m_wallet->load(path, password); - - m_password = password; - } catch (const std::exception &e) { - LOG_ERROR("Error opening wallet: " << e.what()); - m_status = Status_Error; - m_errorString = e.what(); - } - return m_status == Status_Ok; -} - -bool WalletImpl::recover(const std::string &path, const std::string &seed) -{ - clearStatus(); - m_errorString.clear(); - if (seed.empty()) { - m_errorString = "Electrum seed is empty"; - LOG_ERROR(m_errorString); - m_status = Status_Error; - return false; - } - - crypto::secret_key recovery_key; - std::string old_language; - if (!crypto::ElectrumWords::words_to_bytes(seed, recovery_key, old_language)) { - m_errorString = "Electrum-style word list failed verification"; - m_status = Status_Error; - return false; - } - - try { - m_wallet->set_seed_language(old_language); - m_wallet->generate(path, "", recovery_key, true, false); - // TODO: wallet->init(daemon_address); - } catch (const std::exception &e) { - m_status = Status_Error; - m_errorString = e.what(); - } - return m_status == Status_Ok; -} - -bool WalletImpl::close() -{ - clearStatus(); - bool result = false; - try { - m_wallet->store(); - m_wallet->stop(); - result = true; - } catch (const std::exception &e) { - m_status = Status_Error; - m_errorString = e.what(); - LOG_ERROR("Error closing wallet: " << e.what()); - } - return result; -} - -std::string WalletImpl::seed() const -{ - std::string seed; - if (m_wallet) - m_wallet->get_seed(seed); - return seed; -} - -std::string WalletImpl::getSeedLanguage() const -{ - return m_wallet->get_seed_language(); -} - -void WalletImpl::setSeedLanguage(const std::string &arg) -{ - m_wallet->set_seed_language(arg); -} - -int WalletImpl::status() const -{ - return m_status; -} - -std::string WalletImpl::errorString() const -{ - return m_errorString; -} - -bool WalletImpl::setPassword(const std::string &password) -{ - clearStatus(); - try { - m_wallet->rewrite(m_wallet->get_wallet_file(), password); - m_password = password; - } catch (const std::exception &e) { - m_status = Status_Error; - m_errorString = e.what(); - } - return m_status == Status_Ok; -} - -std::string WalletImpl::address() const -{ - return m_wallet->get_account().get_public_address_str(m_wallet->testnet()); -} - -bool WalletImpl::store(const std::string &path) -{ - clearStatus(); - try { - if (path.empty()) { - m_wallet->store(); - } else { - m_wallet->store_to(path, m_password); - } - } catch (const std::exception &e) { - LOG_ERROR("Error storing wallet: " << e.what()); - m_status = Status_Error; - m_errorString = e.what(); - } - - return m_status == Status_Ok; -} - -bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) -{ - clearStatus(); - try { - m_wallet->init(daemon_address, upper_transaction_size_limit); - } catch (const std::exception &e) { - LOG_ERROR("Error initializing wallet: " << e.what()); - m_status = Status_Error; - m_errorString = e.what(); - } - - return m_status == Status_Ok; -} - -uint64_t WalletImpl::balance() const -{ - return m_wallet->balance(); -} - -uint64_t WalletImpl::unlockedBalance() const -{ - return m_wallet->unlocked_balance(); -} - - -bool WalletImpl::refresh() -{ - clearStatus(); - try { - m_wallet->refresh(); - } catch (const std::exception &e) { - m_status = Status_Error; - m_errorString = e.what(); - } - return m_status == Status_Ok; -} - -// TODO: -// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) -// 2 - check / design how "Transaction" can be single interface -// (instead of few different data structures within wallet2 implementation: -// - pending_tx; -// - transfer_details; -// - payment_details; -// - unconfirmed_transfer_details; -// - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) -{ - clearStatus(); - vector dsts; - cryptonote::tx_destination_entry de; - bool has_payment_id; - crypto::hash8 new_payment_id; - - // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) - size_t fake_outs_count = m_wallet->default_mixin(); - if (fake_outs_count == 0) - fake_outs_count = DEFAULT_MIX; - - TransactionImpl * transaction = new TransactionImpl(this); - - do { - - if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), dst_addr)) { - // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 - m_status = Status_Error; - m_errorString = "Invalid destination address"; - break; - } - - de.amount = amount; - if (de.amount <= 0) { - m_status = Status_Error; - m_errorString = "Invalid amount"; - break; - } - - dsts.push_back(de); - //std::vector ptx_vector; - std::vector extra; - - - try { - transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); - - } catch (const tools::error::daemon_busy&) { - // TODO: make it translatable with "tr"? - m_errorString = tr("daemon is busy. Please try again later."); - m_status = Status_Error; - } catch (const tools::error::no_connection_to_daemon&) { - m_errorString = tr("no connection to daemon. Please make sure daemon is running."); - m_status = Status_Error; - } catch (const tools::error::wallet_rpc_error& e) { - m_errorString = tr("RPC error: ") + e.to_string(); - m_status = Status_Error; - } catch (const tools::error::get_random_outs_error&) { - m_errorString = tr("failed to get random outputs to mix"); - m_status = Status_Error; - - } catch (const tools::error::not_enough_money& e) { - m_status = Status_Error; - std::ostringstream writer(m_errorString); - - writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % - print_money(e.available()) % - print_money(e.tx_amount() + e.fee()) % - print_money(e.tx_amount()) % - print_money(e.fee()); - - } catch (const tools::error::not_enough_outs_to_mix& e) { - std::ostringstream writer(m_errorString); - writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; - for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { - writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); - } - m_status = Status_Error; - } catch (const tools::error::tx_not_constructed&) { - m_errorString = tr("transaction was not constructed"); - m_status = Status_Error; - } catch (const tools::error::tx_rejected& e) { - std::ostringstream writer(m_errorString); - writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); - m_status = Status_Error; - } catch (const tools::error::tx_sum_overflow& e) { - m_errorString = e.what(); - m_status = Status_Error; - } catch (const tools::error::zero_destination&) { - m_errorString = tr("one of destinations is zero"); - m_status = Status_Error; - } catch (const tools::error::tx_too_big& e) { - m_errorString = tr("failed to find a suitable way to split transactions"); - m_status = Status_Error; - } catch (const tools::error::transfer_error& e) { - m_errorString = string(tr("unknown transfer error: ")) + e.what(); - m_status = Status_Error; - } catch (const tools::error::wallet_internal_error& e) { - m_errorString = string(tr("internal error: ")) + e.what(); - m_status = Status_Error; - } catch (const std::exception& e) { - m_errorString = string(tr("unexpected error: ")) + e.what(); - m_status = Status_Error; - } catch (...) { - m_errorString = tr("unknown error"); - m_status = Status_Error; - } - } while (false); - - transaction->m_status = m_status; - transaction->m_errorString = m_errorString; - return transaction; -} - -void WalletImpl::disposeTransaction(PendingTransaction *t) -{ - delete t; -} - -TransactionHistory *WalletImpl::history() const -{ - return nullptr; -} - -bool WalletImpl::connectToDaemon() -{ - bool result = m_wallet->check_connection(); - m_status = result ? Status_Ok : Status_Error; - if (!result) { - m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address(); - } - return result; -} - -void WalletImpl::clearStatus() -{ - m_status = Status_Ok; - m_errorString.clear(); -} - - - - - - -///////////////////////// WalletManager implementation ///////////////////////// -class WalletManagerImpl : public WalletManager -{ -public: - Wallet * createWallet(const std::string &path, const std::string &password, - 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); - virtual bool closeWallet(Wallet *wallet); - bool walletExists(const std::string &path); - std::string errorString() const; - void setDaemonHost(const std::string &hostname); - - -private: - WalletManagerImpl() {} - friend struct WalletManagerFactory; - - std::string m_errorString; -}; - -Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, - const std::string &language, bool testnet) -{ - WalletImpl * wallet = new WalletImpl(testnet); - wallet->create(path, password, language); - return wallet; -} - -Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, bool testnet) -{ - WalletImpl * wallet = new WalletImpl(testnet); - wallet->open(path, password); - return wallet; -} - -Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo, bool testnet) -{ - WalletImpl * wallet = new WalletImpl(testnet); - wallet->recover(path, memo); - return wallet; -} - -bool WalletManagerImpl::closeWallet(Wallet *wallet) -{ - WalletImpl * wallet_ = dynamic_cast(wallet); - bool result = wallet_->close(); - if (!result) { - m_errorString = wallet_->errorString(); - } else { - delete wallet_; - } - return result; -} - -bool WalletManagerImpl::walletExists(const std::string &path) -{ - return false; -} - -std::string WalletManagerImpl::errorString() const -{ - return m_errorString; -} - -void WalletManagerImpl::setDaemonHost(const std::string &hostname) -{ - -} - - - -///////////////////// WalletManagerFactory implementation ////////////////////// -WalletManager *WalletManagerFactory::getWalletManager() -{ - - if (!g_walletManager) { - epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_MAX); - g_walletManager = new WalletManagerImpl(); - } - - return g_walletManager; -} - - - - - - -} diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index a675d8b31..cb0211c4a 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -33,6 +33,7 @@ #include #include +#include // Public interface for libwallet library namespace Bitmonero { @@ -62,6 +63,8 @@ struct TransactionHistory virtual TransactionInfo * transaction(int index) const = 0; virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual std::vector getAll() const = 0; + // TODO: + // refresh(); }; @@ -75,13 +78,14 @@ struct TransactionInfo Direction_Out }; + virtual int direction() const = 0; virtual bool isHold() const = 0; virtual bool isFailed() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() const = 0; virtual std::string address() const = 0; - virtual int direction() const = 0; - // TODO + virtual std::time_t timestamp() const = 0; + virtual std::string paymentId() const = 0; }; /** -- cgit v1.2.3 From 663ed04eb83c7185c7f7c480c685647bfd29b376 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:17:27 +0300 Subject: transaction history api in progress --- src/wallet/api/pending_transaction.cpp | 16 ++++----- src/wallet/api/transaction_history.cpp | 64 ++++++++++++++++++++++++++++++++++ src/wallet/api/transaction_history.h | 17 +++++++-- src/wallet/api/transaction_info.h | 17 +++++++++ src/wallet/api/wallet.cpp | 2 +- src/wallet/api/wallet.h | 7 ++-- src/wallet/wallet2_api.h | 3 +- 7 files changed, 110 insertions(+), 16 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp index e9791ec35..db40851b4 100644 --- a/src/wallet/api/pending_transaction.cpp +++ b/src/wallet/api/pending_transaction.cpp @@ -48,28 +48,28 @@ namespace Bitmonero { PendingTransaction::~PendingTransaction() {} -TransactionImpl::TransactionImpl(WalletImpl *wallet) +PendingTransactionImpl::PendingTransactionImpl(WalletImpl *wallet) : m_wallet(wallet) { } -TransactionImpl::~TransactionImpl() +PendingTransactionImpl::~PendingTransactionImpl() { } -int TransactionImpl::status() const +int PendingTransactionImpl::status() const { return m_status; } -string TransactionImpl::errorString() const +string PendingTransactionImpl::errorString() const { return m_errorString; } -bool TransactionImpl::commit() +bool PendingTransactionImpl::commit() { LOG_PRINT_L0("m_pending_tx size: " << m_pending_tx.size()); @@ -105,7 +105,7 @@ bool TransactionImpl::commit() return m_status == Status_Ok; } -uint64_t TransactionImpl::amount() const +uint64_t PendingTransactionImpl::amount() const { uint64_t result = 0; for (const auto &ptx : m_pending_tx) { @@ -116,7 +116,7 @@ uint64_t TransactionImpl::amount() const return result; } -uint64_t TransactionImpl::dust() const +uint64_t PendingTransactionImpl::dust() const { uint32_t result = 0; for (const auto & ptx : m_pending_tx) { @@ -125,7 +125,7 @@ uint64_t TransactionImpl::dust() const return result; } -uint64_t TransactionImpl::fee() const +uint64_t PendingTransactionImpl::fee() const { uint32_t result = 0; for (const auto ptx : m_pending_tx) { diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index f1aba14cb..3ebcc041e 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -28,6 +28,70 @@ // // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + #include "transaction_history.h" +#include "transaction_info.h" +#include "wallet.h" + +#include "crypto/hash.h" +#include "wallet/wallet2.h" +#include "contrib/epee/include/string_tools.h" + +#include +#include + +namespace Bitmonero { + +TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet) +{ + +} + +TransactionHistoryImpl::~TransactionHistoryImpl() +{ + +} + +int TransactionHistoryImpl::count() const +{ + return 0; +} + +TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const +{ + return nullptr; +} + +std::vector TransactionHistoryImpl::getAll() const +{ + return std::vector(); +} + +void TransactionHistoryImpl::refresh() +{ + // TODO: configurable values; + uint64_t min_height = 0; + uint64_t max_height = (uint64_t)-1; + + // TODO: delete old transactions; + + std::list> payments; + m_wallet->m_wallet->get_payments(payments, min_height, max_height); + for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + const tools::wallet2::payment_details &pd = i->second; + std::string payment_id = string_tools::pod_to_hex(i->first); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + // TODO + TransactionInfo * ti = new TransactionInfo(); + + //output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s") % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % "-").str()))); + } +} +TransactionInfo *TransactionHistoryImpl::transaction(int index) const +{ + return nullptr; +} +} diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index cab0e0dbc..1ff729b54 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -32,12 +32,23 @@ namespace Bitmonero { +class TransactionInfo; +class WalletImpl; + class TransactionHistoryImpl : public TransactionHistory { +public: + TransactionHistoryImpl(WalletImpl * wallet); + ~TransactionHistoryImpl(); virtual int count() const; - virtual TransactionInfo * transaction(int index) const = 0; - virtual TransactionInfo * transaction(const std::string &id) const = 0; - virtual std::vector getAll() const = 0; + virtual TransactionInfo * transaction(int index) const; + virtual TransactionInfo * transaction(const std::string &id) const; + virtual std::vector getAll() const; + virtual void refresh(); + +private: + std::vector m_history; + WalletImpl *m_wallet; }; } diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 2ed8157f7..3aae19a64 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -34,6 +34,8 @@ namespace Bitmonero { +class TransactionHistoryImpl; + class TransactionInfoImpl : public TransactionInfo { public: @@ -47,6 +49,21 @@ public: virtual std::string address() const; virtual std::time_t timestamp() const; virtual std::string paymentId() const; + +private: + int m_direction; + bool m_hold; + bool m_failed; + uint64_t m_amount; + uint64_t m_fee; + uint64_t b_blockheight; + std::string m_address; + std::time_t m_timestamp; + std::string m_paymentid; + + + friend class TransactionHistoryImpl; + }; } // namespace diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e42f04cf7..a665fff95 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -288,7 +288,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIX; - TransactionImpl * transaction = new TransactionImpl(this); + PendingTransactionImpl * transaction = new PendingTransactionImpl(this); do { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 35db38f67..6a654b13e 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -38,7 +38,8 @@ namespace Bitmonero { - +class TransactionHistoryImpl; +class PendingTransactionImpl; class WalletImpl : public Wallet { @@ -72,7 +73,9 @@ private: void clearStatus(); private: - friend class TransactionImpl; + friend class PendingTransactionImpl; + friend class TransactionHistoryImpl; + tools::wallet2 * m_wallet; int m_status; std::string m_errorString; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index cb0211c4a..37d9ee86b 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -63,8 +63,7 @@ struct TransactionHistory virtual TransactionInfo * transaction(int index) const = 0; virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual std::vector getAll() const = 0; - // TODO: - // refresh(); + virtual void refresh() = 0; }; -- cgit v1.2.3 From d500272fa87bea70054e1f97e1d64741721722bf Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 22 Apr 2016 13:21:08 +0300 Subject: Wallet API : transaction history in progress --- src/wallet/api/transaction_history.cpp | 40 ++++++++++++++++++++++++++++------ src/wallet/api/transaction_history.h | 2 ++ src/wallet/api/transaction_info.cpp | 30 ++++++++++++++++++------- src/wallet/api/transaction_info.h | 11 +++++++--- src/wallet/api/wallet.cpp | 5 ++++- src/wallet/api/wallet.h | 1 + src/wallet/wallet2_api.h | 30 ++++++++++++++----------- tests/libwallet_api_tests/main.cpp | 28 ++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 32 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 3ebcc041e..c7e7472e9 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -35,14 +35,20 @@ #include "crypto/hash.h" #include "wallet/wallet2.h" -#include "contrib/epee/include/string_tools.h" + #include #include +using namespace epee; + namespace Bitmonero { +TransactionHistory::~TransactionHistory() {} + + TransactionHistoryImpl::TransactionHistoryImpl(WalletImpl *wallet) + : m_wallet(wallet) { } @@ -54,7 +60,7 @@ TransactionHistoryImpl::~TransactionHistoryImpl() int TransactionHistoryImpl::count() const { - return 0; + return m_history.size(); } TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) const @@ -64,7 +70,7 @@ TransactionInfo *TransactionHistoryImpl::transaction(const std::string &id) cons std::vector TransactionHistoryImpl::getAll() const { - return std::vector(); + return m_history; } void TransactionHistoryImpl::refresh() @@ -73,9 +79,18 @@ void TransactionHistoryImpl::refresh() uint64_t min_height = 0; uint64_t max_height = (uint64_t)-1; - // TODO: delete old transactions; + // delete old transactions; + for (auto t : m_history) + delete t; std::list> payments; + + // transactions are stored in wallet2: + // - confirmed_transfer_details - out transfers + // - unconfirmed_transfer_details - pending out transfers + // - payment_details - input transfers + + // payments are "input transactions"; m_wallet->m_wallet->get_payments(payments, min_height, max_height); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { const tools::wallet2::payment_details &pd = i->second; @@ -83,9 +98,20 @@ void TransactionHistoryImpl::refresh() if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) payment_id = payment_id.substr(0,16); // TODO - TransactionInfo * ti = new TransactionInfo(); - - //output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s") % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % "-").str()))); + TransactionInfoImpl * ti = new TransactionInfoImpl(); + ti->m_paymentid = payment_id; + ti->m_amount = pd.m_amount; + ti->m_direction = TransactionInfo::Direction_In; + ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); + ti->m_blockheight = pd.m_block_height; + // TODO: + // ti->m_timestamp = pd.m_timestamp; + m_history.push_back(ti); + + /* output.insert(std::make_pair(pd.m_block_height, std::make_pair(true, (boost::format("%20.20s %s %s %s") + % print_money(pd.m_amount) + % string_tools::pod_to_hex(pd.m_tx_hash) + % payment_id % "-").str())));*/ } } diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index 1ff729b54..171fd2210 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -47,6 +47,8 @@ public: virtual void refresh(); private: + + // TransactionHistory is responsible of memory management std::vector m_history; WalletImpl *m_wallet; }; diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 8de4e555f..578b84832 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -35,7 +35,16 @@ using namespace std; namespace Bitmonero { +TransactionInfo::~TransactionInfo() {} + TransactionInfoImpl::TransactionInfoImpl() + : m_direction(Direction_Out) + , m_hold(false) + , m_failed(false) + , m_amount(0) + , m_fee(0) + , m_blockheight(0) + , m_timestamp(0) { } @@ -53,37 +62,42 @@ int TransactionInfoImpl::direction() const bool TransactionInfoImpl::isHold() const { - return false; + return m_hold; } bool TransactionInfoImpl::isFailed() const { - return false; + return m_failed; } uint64_t TransactionInfoImpl::amount() const { - return 0; + return m_amount; } uint64_t TransactionInfoImpl::fee() const { - return 0; + return m_fee; +} + +uint64_t TransactionInfoImpl::blockHeight() const +{ + return m_blockheight; } -string TransactionInfoImpl::address() const +string TransactionInfoImpl::hash() const { - return ""; + return m_hash; } std::time_t TransactionInfoImpl::timestamp() const { - return std::time_t(0); + return m_timestamp; } string TransactionInfoImpl::paymentId() const { - return ""; + return m_paymentid; } } // namespace diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 3aae19a64..a06bc367e 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -41,12 +41,17 @@ class TransactionInfoImpl : public TransactionInfo public: TransactionInfoImpl(); ~TransactionInfoImpl(); + //! in/out virtual int direction() const; + //! true if hold virtual bool isHold() const; virtual bool isFailed() const; virtual uint64_t amount() const; + //! always 0 for incoming txes virtual uint64_t fee() const; - virtual std::string address() const; + virtual uint64_t blockHeight() const; + + virtual std::string hash() const; virtual std::time_t timestamp() const; virtual std::string paymentId() const; @@ -56,8 +61,8 @@ private: bool m_failed; uint64_t m_amount; uint64_t m_fee; - uint64_t b_blockheight; - std::string m_address; + uint64_t m_blockheight; + std::string m_hash; std::time_t m_timestamp; std::string m_paymentid; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index a665fff95..5f32908de 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 "transaction_history.h" #include "common_defines.h" #include "mnemonics/electrum-words.h" @@ -58,10 +59,12 @@ WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok) { m_wallet = new tools::wallet2(testnet); + m_history = new TransactionHistoryImpl(this); } WalletImpl::~WalletImpl() { + delete m_history; delete m_wallet; } @@ -388,7 +391,7 @@ void WalletImpl::disposeTransaction(PendingTransaction *t) TransactionHistory *WalletImpl::history() const { - return nullptr; + return m_history; } bool WalletImpl::connectToDaemon() diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 6a654b13e..3eaaec59e 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -80,6 +80,7 @@ private: int m_status; std::string m_errorString; std::string m_password; + TransactionHistoryImpl * m_history; }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 37d9ee86b..4954db0d2 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -56,17 +56,6 @@ struct PendingTransaction virtual uint64_t fee() const = 0; }; -struct TransactionInfo; -struct TransactionHistory -{ - virtual int count() const; - virtual TransactionInfo * transaction(int index) const = 0; - virtual TransactionInfo * transaction(const std::string &id) const = 0; - virtual std::vector getAll() const = 0; - virtual void refresh() = 0; -}; - - /** * @brief The TransactionInfo - interface for displaying transaction information */ @@ -76,16 +65,31 @@ struct TransactionInfo Direction_In, Direction_Out }; - + virtual ~TransactionInfo() = 0; virtual int direction() const = 0; virtual bool isHold() const = 0; virtual bool isFailed() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() const = 0; - virtual std::string address() const = 0; + virtual uint64_t blockHeight() const = 0; + virtual std::string hash() const = 0; virtual std::time_t timestamp() const = 0; virtual std::string paymentId() const = 0; }; +/** + * @brief The TransactionHistory - interface for displaying transaction history + */ +struct TransactionHistory +{ + virtual ~TransactionHistory() = 0; + virtual int count() const = 0; + virtual TransactionInfo * transaction(int index) const = 0; + virtual TransactionInfo * transaction(const std::string &id) const = 0; + virtual std::vector getAll() const = 0; + virtual void refresh() = 0; +}; + + /** * @brief Interface for wallet operations. diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index dee874cd6..51c0a3ca3 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -29,7 +29,9 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #include "gtest/gtest.h" + #include "wallet/wallet2_api.h" + #include #include @@ -284,6 +286,32 @@ TEST_F(WalletManagerTest, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } +TEST_F(WalletManagerTest, WalletHistory) +{ + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + // make sure testnet daemon is running + ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet1->refresh()); + Bitmonero::TransactionHistory * history = wallet1->history(); + history->refresh(); + ASSERT_TRUE(history->count() > 0); + auto transaction_print = [=] (Bitmonero::TransactionInfo * t) { + std::cout << "d: " + << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") + << ", bh: " << t->blockHeight() + << ", a: " << Bitmonero::Wallet::displayAmount(t->amount()) + << ", f: " << Bitmonero::Wallet::displayAmount(t->fee()) + << ", h: " << t->hash() + << ", pid: " << t->paymentId() + << std::endl; + }; + + for (auto t: history->getAll()) { + ASSERT_TRUE(t != nullptr); + transaction_print(t); + } +} + int main(int argc, char** argv) -- cgit v1.2.3 From 3dd4b4ccf978338dd270184f1e955a163cf7fa52 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 26 Apr 2016 13:46:20 +0300 Subject: merged with upstream --- src/wallet/CMakeLists.txt | 3 +- src/wallet/api/utils.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++++ src/wallet/api/wallet.cpp | 19 ++++++++++-- src/wallet/api/wallet.h | 3 ++ src/wallet/wallet2_api.h | 5 +++ 5 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/wallet/api/utils.cpp (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 33af4f30d..49f936f5c 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -36,7 +36,8 @@ set(wallet_sources api/wallet_manager.cpp api/transaction_info.cpp api/transaction_history.cpp - api/pending_transaction.cpp) + api/pending_transaction.cpp + api/utils.cpp) set(wallet_headers) diff --git a/src/wallet/api/utils.cpp b/src/wallet/api/utils.cpp new file mode 100644 index 000000000..aa85323f0 --- /dev/null +++ b/src/wallet/api/utils.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2014-2016, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + + + +#include "include_base_utils.h" // LOG_PRINT_x +#include "net/http_client.h" // epee::net_utils::... +#include + +using namespace std; + +namespace Bitmonero { +namespace Utils { + + +// copy-pasted from simplewallet. + +bool isAddressLocal(const std::string &address) +{ + // extract host + epee::net_utils::http::url_content u_c; + if (!epee::net_utils::parse_url(address, u_c)) + { + LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); + return false; + } + if (u_c.host.empty()) + { + LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not"); + return false; + } + + // resolve to IP + boost::asio::io_service io_service; + boost::asio::ip::tcp::resolver resolver(io_service); + boost::asio::ip::tcp::resolver::query query(u_c.host, ""); + boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); + while (i != boost::asio::ip::tcp::resolver::iterator()) + { + const boost::asio::ip::tcp::endpoint &ep = *i; + if (ep.address().is_loopback()) + return true; + ++i; + } + + return false; +} + +} + + +} // namespace diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5f32908de..d9d24b4f0 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -56,7 +56,7 @@ string Wallet::displayAmount(uint64_t amount) ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) - :m_wallet(nullptr), m_status(Wallet::Status_Ok) + :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false) { m_wallet = new tools::wallet2(testnet); m_history = new TransactionHistoryImpl(this); @@ -237,6 +237,10 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact clearStatus(); try { m_wallet->init(daemon_address, upper_transaction_size_limit); + if (Utils::isAddressLocal(daemon_address)) { + this->setTrustedDaemon(true); + } + } catch (const std::exception &e) { LOG_ERROR("Error initializing wallet: " << e.what()); m_status = Status_Error; @@ -315,7 +319,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 try { - transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, + 0 /* unused fee arg*/, extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? @@ -404,6 +409,16 @@ bool WalletImpl::connectToDaemon() return result; } +void WalletImpl::setTrustedDaemon(bool arg) +{ + m_trustedDaemon = arg; +} + +bool WalletImpl::trustedDaemon() const +{ + return m_trustedDaemon; +} + void WalletImpl::clearStatus() { m_status = Status_Ok; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 3eaaec59e..3671c2f7a 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -62,6 +62,8 @@ public: bool store(const std::string &path); bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit); bool connectToDaemon(); + void setTrustedDaemon(bool arg); + bool trustedDaemon() const; uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); @@ -81,6 +83,7 @@ private: std::string m_errorString; std::string m_password; TransactionHistoryImpl * m_history; + bool m_trustedDaemon; }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 4954db0d2..ab715dbf9 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -38,6 +38,9 @@ // Public interface for libwallet library namespace Bitmonero { + namespace Utils { + bool isAddressLocal(const std::string &hostaddr); + } /** * @brief Transaction-like interface for sending money */ @@ -117,6 +120,8 @@ struct Wallet virtual bool store(const std::string &path) = 0; virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; virtual bool connectToDaemon() = 0; + virtual void setTrustedDaemon(bool arg) = 0; + virtual bool trustedDaemon() const = 0; virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; static std::string displayAmount(uint64_t amount); -- cgit v1.2.3 From 374577018d9e32a6f50e9fb23deb27b98da8ae67 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 5 May 2016 22:24:00 +0300 Subject: started WalletListener --- src/wallet/api/wallet.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++- src/wallet/api/wallet.h | 4 ++++ src/wallet/wallet2_api.h | 8 +++++++ 3 files changed, 65 insertions(+), 1 deletion(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index d9d24b4f0..6170000b7 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -47,6 +47,47 @@ namespace { static const size_t DEFAULT_MIX = 4; } +struct Wallet2CallbackImpl : public tools::i_wallet2_callback +{ + + ~Wallet2CallbackImpl() + { + + } + + void setListener(WalletListener * listener) + { + // TODO; + } + + WalletListener * getListener() const + { + return m_listener; + } + + virtual void on_new_block(uint64_t height, const cryptonote::block& block) + { + // TODO; + } + virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) + { + // TODO; + + } + virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, + const cryptonote::transaction& spend_tx) + { + // TODO; + } + + virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) + { + // TODO; + } + + WalletListener * m_listener; +}; + Wallet::~Wallet() {} string Wallet::displayAmount(uint64_t amount) @@ -56,14 +97,17 @@ string Wallet::displayAmount(uint64_t amount) ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) - :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false) + :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false), + m_wallet2Callback(nullptr) { m_wallet = new tools::wallet2(testnet); m_history = new TransactionHistoryImpl(this); + m_wallet2Callback = new Wallet2CallbackImpl; } WalletImpl::~WalletImpl() { + delete m_wallet2Callback; delete m_history; delete m_wallet; } @@ -399,6 +443,14 @@ TransactionHistory *WalletImpl::history() const return m_history; } +void WalletImpl::setListener(WalletListener *l) +{ + // TODO thread synchronization; + m_wallet2Callback->setListener(l); +} + + + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 3671c2f7a..c0fa31003 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -40,6 +40,7 @@ namespace Bitmonero { class TransactionHistoryImpl; class PendingTransactionImpl; +struct Wallet2CallbackImpl; class WalletImpl : public Wallet { @@ -70,6 +71,7 @@ public: PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; + virtual void setListener(WalletListener * l); private: void clearStatus(); @@ -84,6 +86,8 @@ private: std::string m_password; TransactionHistoryImpl * m_history; bool m_trustedDaemon; + WalletListener * m_walletListener; + Wallet2CallbackImpl * m_wallet2Callback; }; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 43f5c9472..8e0830746 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -103,6 +103,13 @@ struct TransactionHistory }; +struct WalletListener +{ + virtual ~WalletListener() = 0; + virtual void moneySpent(const std::string &txId, uint64_t amount); + virtual void moneyReceived(const std::string &txId, uint64_t amount); +}; + /** * @brief Interface for wallet operations. @@ -141,6 +148,7 @@ struct Wallet virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; + virtual void setListener(WalletListener *) = 0; }; /** -- cgit v1.2.3 From 060bb62e29ba7e08707942b51734a57c149039e6 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 13 May 2016 16:25:31 +0300 Subject: WalletListener::moneySpent(), WalletListener::moneyReceived() --- src/wallet/api/wallet.cpp | 23 +++++++++++++++++++++-- src/wallet/wallet2_api.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 6170000b7..5819e42bc 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -57,7 +57,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback void setListener(WalletListener * listener) { - // TODO; + m_listener = listener; } WalletListener * getListener() const @@ -68,16 +68,35 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback virtual void on_new_block(uint64_t height, const cryptonote::block& block) { // TODO; + LOG_PRINT_L3(__FUNCTION__ << ": new block. height: " << height); } + virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) { - // TODO; + std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(tx)); + uint64_t amount = tx.vout[out_index].amount; + + LOG_PRINT_L3(__FUNCTION__ << ": money received. height: " << height + << ", tx: " << tx_hash + << ", amount: " << print_money(amount)); + if (m_listener) { + m_listener->moneyReceived(tx_hash, amount); + } } + virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) { // TODO; + std::string tx_hash = epee::string_tools::pod_to_hex(get_transaction_hash(spend_tx)); + uint64_t amount = in_tx.vout[out_index].amount; + LOG_PRINT_L3(__FUNCTION__ << ": money spent. height: " << height + << ", tx: " << tx_hash + << ", amount: " << print_money(amount)); + if (m_listener) { + m_listener->moneySpent(tx_hash, amount); + } } virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 8e0830746..d38fd6708 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -108,6 +108,7 @@ struct WalletListener virtual ~WalletListener() = 0; virtual void moneySpent(const std::string &txId, uint64_t amount); virtual void moneyReceived(const std::string &txId, uint64_t amount); + // TODO: on_skip_transaction; }; -- cgit v1.2.3 From 64348a2d11e47893edd283639e5615e4c90ecd4c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 16 May 2016 13:11:44 +0300 Subject: WalletListener::moneySpent test --- src/wallet/api/wallet.cpp | 8 ++ src/wallet/wallet2_api.h | 4 +- tests/libwallet_api_tests/main.cpp | 207 +++++++++++++++++++++++++++---------- 3 files changed, 164 insertions(+), 55 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5819e42bc..440642291 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -50,6 +50,12 @@ namespace { struct Wallet2CallbackImpl : public tools::i_wallet2_callback { + Wallet2CallbackImpl() + : m_listener(nullptr) + { + + } + ~Wallet2CallbackImpl() { @@ -109,6 +115,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback Wallet::~Wallet() {} +WalletListener::~WalletListener() {} + string Wallet::displayAmount(uint64_t amount) { return cryptonote::print_money(amount); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index d38fd6708..7841c299d 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -106,8 +106,8 @@ struct TransactionHistory struct WalletListener { virtual ~WalletListener() = 0; - virtual void moneySpent(const std::string &txId, uint64_t amount); - virtual void moneyReceived(const std::string &txId, uint64_t amount); + virtual void moneySpent(const std::string &txId, uint64_t amount) = 0; + virtual void moneyReceived(const std::string &txId, uint64_t amount) = 0; // TODO: on_skip_transaction; }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 35d0c8e9d..bdcf889ef 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -37,12 +37,47 @@ #include #include +#include +#include using namespace std; //unsigned int epee::g_test_dbg_lock_sleep = 0; +namespace Consts +{ + +// TODO: add test wallets to the source tree (as they have some balance mined)? +// TODO: get rid of hardcoded paths + +const char * WALLET_NAME = "testwallet"; +const char * WALLET_NAME_COPY = "testwallet_copy"; +const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test"; +const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test"; +const char * WALLET_PASS = "password"; +const char * WALLET_PASS2 = "password22"; +const char * WALLET_LANG = "English"; + +const char * TESTNET_WALLET_NAME = "/home/mbg033/dev/monero/testnet/wallet_01.bin"; +const char * TESTNET_WALLET3_NAME = "/home/mbg033/dev/monero/testnet/wallet_03.bin"; +const char * TESTNET_WALLET4_NAME = "/home/mbg033/dev/monero/testnet/wallet_04.bin"; +const char * TESTNET_WALLET_PASS = ""; + + +const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; +const uint64_t AMOUNT_10XMR = 10000000000000L; +const uint64_t AMOUNT_5XMR = 50000000000000L; + +const char * RECIPIENT_WALLET_ADDRESS = "9uekQVGj7NjSAREnZ8cUsRagWDdjvdhpwUKhsL95oXngBnZXZ1RzH8R6UJbU1R7wim9yKbSjxuoQ22ERRkEochGECj66oP3"; +const char * TESTNET_WALLET3_ADDRESS = "A11cBpRDqpTCneSL3KNBvGWM6PfxG7QrxNVCcMiZeuAD3fQA9Z366DegFLYHKrMnDm8QixPziRn4kVcWPFtn6aCSR1Hp7sg"; +const char * TESTNET_WALLET4_ADDRESS = "A21wicxbhUSKa6twequhKCCG8wYEGZ7viYRLW7mBXtWyheyY8C8XwUJG5PSjULDs1q7hndkihtFgybWjagvchrNg1Y588hM"; + +} + + +using namespace Consts; + struct Utils { static void deleteWallet(const std::string & walletname) @@ -58,39 +93,29 @@ struct Utils std::cout << "** removing dir recursively: " << path << std::endl; boost::filesystem::remove_all(path); } + + static void print_transaction(Bitmonero::TransactionInfo * t) + { + + std::cout << "d: " + << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") + << ", pe: " << (t->isPending() ? "true" : "false") + << ", bh: " << t->blockHeight() + << ", a: " << Bitmonero::Wallet::displayAmount(t->amount()) + << ", f: " << Bitmonero::Wallet::displayAmount(t->fee()) + << ", h: " << t->hash() + << ", pid: " << t->paymentId() + << std::endl; + } }; -struct WalletManagerTest : public testing::Test +struct DISABLED_WalletManagerTest : public testing::Test { Bitmonero::WalletManager * wmgr; - const char * WALLET_NAME = "testwallet"; - const char * WALLET_NAME_COPY = "testwallet_copy"; - const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test"; - const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test"; - const char * WALLET_PASS = "password"; - const char * WALLET_PASS2 = "password22"; - const char * WALLET_LANG = "English"; - - - // TODO: add test wallets to the source tree (as they have some balance mined)? - const char * TESTNET_WALLET_NAME = "/home/mbg033/dev/monero/testnet/wallet_01.bin"; - const char * TESTNET_WALLET3_NAME = "/home/mbg033/dev/monero/testnet/wallet_03.bin"; - const char * TESTNET_WALLET4_NAME = "/home/mbg033/dev/monero/testnet/wallet_04.bin"; - const char * TESTNET_WALLET_PASS = ""; - - - const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; - const uint64_t AMOUNT_10XMR = 10000000000000L; - const uint64_t AMOUNT_5XMR = 50000000000000L; - - const char * RECIPIENT_WALLET_ADDRESS = "9uekQVGj7NjSAREnZ8cUsRagWDdjvdhpwUKhsL95oXngBnZXZ1RzH8R6UJbU1R7wim9yKbSjxuoQ22ERRkEochGECj66oP3"; - const char * TESTNET_WALLET3_ADDRESS = "A11cBpRDqpTCneSL3KNBvGWM6PfxG7QrxNVCcMiZeuAD3fQA9Z366DegFLYHKrMnDm8QixPziRn4kVcWPFtn6aCSR1Hp7sg"; - const char * TESTNET_WALLET4_ADDRESS = "A21wicxbhUSKa6twequhKCCG8wYEGZ7viYRLW7mBXtWyheyY8C8XwUJG5PSjULDs1q7hndkihtFgybWjagvchrNg1Y588hM"; - - WalletManagerTest() + DISABLED_WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); @@ -99,29 +124,42 @@ struct WalletManagerTest : public testing::Test } - ~WalletManagerTest() + ~DISABLED_WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; //deleteWallet(WALLET_NAME); } - static void print_transaction(Bitmonero::TransactionInfo * t) +}; + + +struct DISABLED_WalletTest1 : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + DISABLED_WalletTest1() { + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + } - std::cout << "d: " - << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") - << ", pe: " << (t->isPending() ? "true" : "false") - << ", bh: " << t->blockHeight() - << ", a: " << Bitmonero::Wallet::displayAmount(t->amount()) - << ", f: " << Bitmonero::Wallet::displayAmount(t->fee()) - << ", h: " << t->hash() - << ", pid: " << t->paymentId() - << std::endl; + +}; + + +struct WalletTest2 : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + WalletTest2() + { + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); } + + }; -TEST_F(WalletManagerTest, WalletManagerCreatesWallet) +TEST_F(DISABLED_WalletManagerTest, WalletManagerCreatesWallet) { Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -138,7 +176,7 @@ TEST_F(WalletManagerTest, WalletManagerCreatesWallet) } -TEST_F(WalletManagerTest, WalletManagerOpensWallet) +TEST_F(DISABLED_WalletManagerTest, WalletManagerOpensWallet) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -151,7 +189,7 @@ TEST_F(WalletManagerTest, WalletManagerOpensWallet) } -TEST_F(WalletManagerTest, WalletManagerChangesPassword) +TEST_F(DISABLED_WalletManagerTest, WalletManagerChangesPassword) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -167,7 +205,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword) -TEST_F(WalletManagerTest, WalletManagerRecoversWallet) +TEST_F(DISABLED_WalletManagerTest, WalletManagerRecoversWallet) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -183,7 +221,7 @@ TEST_F(WalletManagerTest, WalletManagerRecoversWallet) } -TEST_F(WalletManagerTest, WalletManagerStoresWallet1) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet1) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -200,7 +238,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1) } -TEST_F(WalletManagerTest, WalletManagerStoresWallet2) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet2) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -216,7 +254,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletManagerStoresWallet3) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet3) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -238,7 +276,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3) } -TEST_F(WalletManagerTest, WalletManagerStoresWallet4) +TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet4) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -260,7 +298,8 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4) } -TEST_F(WalletManagerTest, WalletShowsBalance) + +TEST_F(DISABLED_WalletTest1, WalletShowsBalance) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); ASSERT_TRUE(wallet1->balance() > 0); @@ -278,7 +317,7 @@ TEST_F(WalletManagerTest, WalletShowsBalance) ASSERT_TRUE(wmgr->closeWallet(wallet2)); } -TEST_F(WalletManagerTest, WalletRefresh) +TEST_F(DISABLED_WalletTest1, WalletRefresh) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -287,7 +326,7 @@ TEST_F(WalletManagerTest, WalletRefresh) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletTransaction) +TEST_F(DISABLED_WalletTest1, WalletTransaction) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -308,7 +347,7 @@ TEST_F(WalletManagerTest, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletHistory) +TEST_F(DISABLED_WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -321,11 +360,11 @@ TEST_F(WalletManagerTest, WalletHistory) for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); - print_transaction(t); + Utils::print_transaction(t); } } -TEST_F(WalletManagerTest, WalletTransactionAndHistory) +TEST_F(DISABLED_WalletTest1, WalletTransactionAndHistory) { Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -339,7 +378,7 @@ TEST_F(WalletManagerTest, WalletTransactionAndHistory) std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl; for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); - print_transaction(t); + Utils::print_transaction(t); } Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_10XMR * 5); @@ -352,11 +391,73 @@ TEST_F(WalletManagerTest, WalletTransactionAndHistory) std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl; for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); - print_transaction(t); + Utils::print_transaction(t); } } +struct MyWalletListener : public Bitmonero::WalletListener +{ + + Bitmonero::Wallet * wallet; + uint64_t total_tx; + uint64_t total_rx; + std::timed_mutex guard; + + MyWalletListener(Bitmonero::Wallet * wallet) + : total_tx(0), total_rx(0) + { + this->wallet = wallet; + this->wallet->setListener(this); + } + + virtual void moneySpent(const string &txId, uint64_t amount) + { + std::cout << "wallet: " << wallet->address() << " just spent money (" + << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; + total_tx += amount; + guard.unlock(); + } + + virtual void moneyReceived(const string &txId, uint64_t amount) + { + std::cout << "wallet: " << wallet->address() << " just received money (" + << txId << ", " << wallet->displayAmount(amount) << ")" << std::endl; + total_rx += amount; + guard.unlock(); + } +}; + +TEST_F(WalletTest2, WalletCallbackSent) +{ + + Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); + // make sure testnet daemon is running + ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_src->refresh()); + MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src); + std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl; + /* + Bitmonero::Wallet * wallet_dst = wmgr->openWallet(TESTNET_WALLET4_NAME, TESTNET_WALLET_PASS, true); + ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_dst->refresh()); + MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst); + */ + + + uint64_t amount = AMOUNT_10XMR * 5; + std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS; + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_10XMR * 5); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); + ASSERT_TRUE(tx->commit()); + + std::chrono::seconds wait_for = std::chrono::seconds(60*3); + + wallet_src_listener->guard.lock(); + wallet_src_listener->guard.try_lock_for(wait_for); + ASSERT_TRUE(wallet_src_listener->total_tx != 0); + +} int main(int argc, char** argv) { -- cgit v1.2.3 From a5374897f89837d1373f6dcc4c92053320e5b9db Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 10 Jun 2016 12:51:09 +0300 Subject: Wallet::filename, Wallet::keysFilename, tests for move wallet --- src/wallet/api/wallet.cpp | 10 ++++++++++ src/wallet/api/wallet.h | 2 ++ src/wallet/wallet2_api.h | 17 +++++++++++++++++ tests/libwallet_api_tests/main.cpp | 29 +++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 440642291..5b68387ea 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -303,6 +303,16 @@ bool WalletImpl::store(const std::string &path) return m_status == Status_Ok; } +string WalletImpl::filename() const +{ + return m_wallet->get_wallet_file(); +} + +string WalletImpl::keysFilename() const +{ + return m_wallet->get_keys_file(); +} + bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c0fa31003..c402ef53c 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -61,6 +61,8 @@ public: bool setPassword(const std::string &password); std::string address() 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); bool connectToDaemon(); void setTrustedDaemon(bool arg); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index b98bb8661..bf5ddc3c7 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -135,7 +135,24 @@ struct Wallet virtual std::string errorString() const = 0; virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; + /*! + * \brief store - stores wallet to file. + * \param path - main filename to store wallet to. additionally stores address file and keys file. + * to store to the same file - just pass empty string; + * \return + */ virtual bool store(const std::string &path) = 0; + /*! + * \brief filename - returns wallet filename + * \return + */ + virtual std::string filename() const = 0; + /*! + * \brief keysFilename - returns keys filename. usually this formed as "wallet_filename".keys + * \return + */ + virtual std::string keysFilename() const = 0; + virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; virtual bool connectToDaemon() = 0; virtual void setTrustedDaemon(bool arg) = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 91636d522..595e3ccfb 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -210,6 +210,35 @@ TEST_F(WalletManagerTest, WalletManagerOpensWallet) std::cout << "** seed: " << wallet2->seed() << std::endl; } +TEST_F(WalletManagerTest, WalletManagerStoresWallet) +{ + + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + std::string seed1 = wallet1->seed(); + wallet1->store(""); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); + Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet2->seed() == seed1); +} + + +TEST_F(WalletManagerTest, WalletManagerMovesWallet) +{ + + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + std::string WALLET_NAME_MOVED = std::string("/tmp/") + WALLET_NAME + ".moved"; + std::string seed1 = wallet1->seed(); + ASSERT_TRUE(wallet1->store(WALLET_NAME_MOVED)); + + Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_MOVED, WALLET_PASS); + ASSERT_TRUE(wallet2->filename() == WALLET_NAME_MOVED); + ASSERT_TRUE(wallet2->keysFilename() == WALLET_NAME_MOVED + ".keys"); + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet2->seed() == seed1); +} + + /* TEST_F(WalletManagerTest, WalletManagerChangesPassword) { -- cgit v1.2.3 From e7d8f2a085b05c2c1ec25f75ff7a892deedcf666 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 10 Jun 2016 13:52:10 +0300 Subject: wallet::default_mixin exposed to public interface as Wallet::setDefaultMixin, Wallet::defaultMixin; wallet::create_transaction_2 used in Wallet::createTransaction --- src/wallet/api/wallet.cpp | 11 ++++++++++- src/wallet/api/wallet.h | 2 ++ src/wallet/wallet2_api.h | 10 ++++++++++ tests/libwallet_api_tests/main.cpp | 2 ++ 4 files changed, 24 insertions(+), 1 deletion(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5b68387ea..f6d7a561e 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -400,7 +400,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 try { - transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { @@ -486,6 +486,15 @@ void WalletImpl::setListener(WalletListener *l) m_wallet2Callback->setListener(l); } +uint32_t WalletImpl::defaultMixin() const +{ + return m_wallet->default_mixin(); +} + +void WalletImpl::setDefaultMixin(uint32_t arg) +{ + m_wallet->default_mixin(arg); +} bool WalletImpl::connectToDaemon() diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index c402ef53c..6c8913c25 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -74,6 +74,8 @@ public: virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); + virtual uint32_t defaultMixin() const; + virtual void setDefaultMixin(uint32_t arg); private: void clearStatus(); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index bf5ddc3c7..62231820b 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -167,6 +167,16 @@ struct Wallet virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; + /*! + * \brief defaultMixin - returns number of mixins used in transactions + * \return + */ + virtual uint32_t defaultMixin() const = 0; + /*! + * \brief setDefaultMixin - setum number of mixins to be used for new transactions + * \param arg + */ + virtual void setDefaultMixin(uint32_t arg) = 0; }; /** diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 595e3ccfb..935cfd884 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -401,6 +401,8 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok); std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + wallet1->setDefaultMixin(1); + ASSERT_TRUE(wallet1->defaultMixin() == 1); Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( recepient_address, AMOUNT_10XMR); -- cgit v1.2.3 From 85a632244ef97a500a17a9954914c52487422c5e Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 16 Jun 2016 16:42:33 +0300 Subject: double/string to monero integer convertion methods --- src/wallet/api/wallet.cpp | 17 +++++++++++++++++ src/wallet/wallet2_api.h | 2 ++ tests/libwallet_api_tests/main.cpp | 16 ++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index f6d7a561e..1f414b3bf 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -36,6 +36,7 @@ #include "mnemonics/electrum-words.h" #include +#include using namespace std; using namespace cryptonote; @@ -122,6 +123,22 @@ string Wallet::displayAmount(uint64_t amount) return cryptonote::print_money(amount); } +uint64_t Wallet::amountFromString(const string &amount) +{ + uint64_t result; + cryptonote::parse_amount(result, amount); + return result; +} + +uint64_t Wallet::amountFromDouble(double amount) +{ + std::stringstream ss; + ss << std::fixed << std::setprecision(CRYPTONOTE_DISPLAY_DECIMAL_POINT) << amount; + return amountFromString(ss.str()); +} + + + ///////////////////////// WalletImpl implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok), m_trustedDaemon(false), diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 62231820b..34c18f77f 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -160,6 +160,8 @@ struct Wallet virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; static std::string displayAmount(uint64_t amount); + static uint64_t amountFromString(const std::string &amount); + static uint64_t amountFromDouble(double amount); // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 935cfd884..849d76e1b 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -247,7 +247,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword) ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2)); ASSERT_TRUE(wmgr->closeWallet(wallet1)); Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2); - ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);quint64 ASSERT_TRUE(wallet2->seed() == seed1); ASSERT_TRUE(wmgr->closeWallet(wallet2)); Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); @@ -390,7 +390,19 @@ TEST_F(WalletTest1, WalletRefresh) } +TEST_F(WalletTest1, WalletConvertsToString) +{ + std::string strAmount = Bitmonero::Wallet::displayAmount(AMOUNT_5XMR); + ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromString(strAmount)); + + ASSERT_TRUE(AMOUNT_5XMR == Bitmonero::Wallet::amountFromDouble(5.0)); + ASSERT_TRUE(AMOUNT_10XMR == Bitmonero::Wallet::amountFromDouble(10.0)); + ASSERT_TRUE(AMOUNT_1XMR == Bitmonero::Wallet::amountFromDouble(1.0)); + +} + +/* TEST_F(WalletTest1, WalletTransaction) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -415,7 +427,7 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_FALSE(wallet1->balance() == balance); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } - +*/ TEST_F(WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); -- cgit v1.2.3 From 2efec04f74b8767d86b4b85aac1b6ec1fdc7e1b3 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 20 Jun 2016 22:56:30 +0300 Subject: Wallet::createTransaction: added mixin_count param --- src/wallet/api/wallet.cpp | 18 ++++++++++------- src/wallet/api/wallet.h | 2 +- src/wallet/wallet2_api.h | 13 ++++++++++-- tests/libwallet_api_tests/main.cpp | 41 +++++++++++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 11 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 1f414b3bf..d72ebc8da 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -45,7 +45,7 @@ namespace Bitmonero { namespace { // copy-pasted from simplewallet - static const size_t DEFAULT_MIX = 4; + static const size_t DEFAULT_MIXIN = 4; } struct Wallet2CallbackImpl : public tools::i_wallet2_callback @@ -380,7 +380,7 @@ bool WalletImpl::refresh() // - payment_details; // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount, uint32_t mixin_count) { clearStatus(); vector dsts; @@ -389,9 +389,10 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 crypto::hash8 new_payment_id; // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) - size_t fake_outs_count = m_wallet->default_mixin(); + + size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); if (fake_outs_count == 0) - fake_outs_count = DEFAULT_MIX; + fake_outs_count = DEFAULT_MIXIN; PendingTransactionImpl * transaction = new PendingTransactionImpl(this); @@ -436,27 +437,30 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 } catch (const tools::error::not_enough_money& e) { m_status = Status_Error; - std::ostringstream writer(m_errorString); + std::ostringstream writer; writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % print_money(e.fee()); + m_errorString = writer.str(); } catch (const tools::error::not_enough_outs_to_mix& e) { - std::ostringstream writer(m_errorString); + std::ostringstream writer; writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); } + m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_not_constructed&) { m_errorString = tr("transaction was not constructed"); m_status = Status_Error; } catch (const tools::error::tx_rejected& e) { - std::ostringstream writer(m_errorString); + std::ostringstream writer; writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_sum_overflow& e) { m_errorString = e.what(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 6c8913c25..016116e96 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -70,7 +70,7 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); - PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); + PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count); virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 34c18f77f..de0b50591 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -128,7 +128,6 @@ struct Wallet virtual std::string seed() const = 0; virtual std::string getSeedLanguage() const = 0; virtual void setSeedLanguage(const std::string &arg) = 0; - // virtual void setListener(Listener * listener) = 0; //! returns wallet status (Status_Ok | Status_Error) virtual int status() const = 0; //! in case error status, returns error string @@ -159,13 +158,23 @@ struct Wallet virtual bool trustedDaemon() const = 0; virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; + static std::string displayAmount(uint64_t amount); static uint64_t amountFromString(const std::string &amount); static uint64_t amountFromDouble(double amount); + // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; - virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; + /*! + * \brief createTransaction creates transaction + * \param dst_addr destination address as string + * \param amount amount + * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() + * after object returned + */ + virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count) = 0; virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 849d76e1b..ddd6969c6 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -428,6 +428,45 @@ TEST_F(WalletTest1, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } */ + +TEST_F(WalletTest1, WalletTransactionWithMixin) +{ + + std::vector mixins; + // 2,3,4,5,6,7,8,9,10,15,20,25 can we do it like that? + mixins.push_back(2); mixins.push_back(3); mixins.push_back(4); mixins.push_back(5); mixins.push_back(6); + mixins.push_back(7); mixins.push_back(8); mixins.push_back(9); mixins.push_back(10); mixins.push_back(15); + mixins.push_back(20); mixins.push_back(25); + + + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + + + // make sure testnet daemon is running + ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet1->refresh()); + uint64_t balance = wallet1->balance(); + ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok); + + std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + for (auto mixin : mixins) { + std::cerr << "Transaction mixin count: " << mixin << std::endl; + Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( + recepient_address, AMOUNT_5XMR, mixin); + + std::cerr << "Transaction status: " << transaction->status() << std::endl; + std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl; + std::cerr << "Transaction error: " << transaction->errorString() << std::endl; + ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); + wallet1->disposeTransaction(transaction); + } + + wallet1->refresh(); + + ASSERT_TRUE(wallet1->balance() == balance); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} + TEST_F(WalletTest1, WalletHistory) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -465,7 +504,7 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, AMOUNT_10XMR * 5); + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, AMOUNT_10XMR * 5, 0); ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); history = wallet_src->history(); -- cgit v1.2.3 From ca6115300315e9d34c0134933345019672d2f0c0 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 23 Jun 2016 14:38:22 +0300 Subject: Wallet: payment id and integrated address --- src/wallet/api/wallet.cpp | 58 ++++++++++++++++++++++++---- src/wallet/api/wallet.h | 4 +- src/wallet/wallet2_api.h | 17 +++++++- tests/libwallet_api_tests/main.cpp | 79 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 144 insertions(+), 14 deletions(-) (limited to 'src/wallet/api/wallet.cpp') diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index d72ebc8da..354e27ac6 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -36,6 +36,7 @@ #include "mnemonics/electrum-words.h" #include +#include #include using namespace std; @@ -137,6 +138,13 @@ uint64_t Wallet::amountFromDouble(double amount) return amountFromString(ss.str()); } +std::string Wallet::genPaymentId() +{ + crypto::hash8 payment_id = crypto::rand(); + return epee::string_tools::pod_to_hex(payment_id); + +} + ///////////////////////// WalletImpl implementation //////////////////////// @@ -302,6 +310,15 @@ std::string WalletImpl::address() const return m_wallet->get_account().get_public_address_str(m_wallet->testnet()); } +std::string WalletImpl::integratedAddress(const std::string &payment_id) const +{ + crypto::hash8 pid; + if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) { + pid = crypto::rand(); + } + return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet()); +} + bool WalletImpl::store(const std::string &path) { clearStatus(); @@ -380,31 +397,56 @@ bool WalletImpl::refresh() // - payment_details; // - unconfirmed_transfer_details; // - confirmed_transfer_details) -PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount, uint32_t mixin_count) +PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count) { clearStatus(); vector dsts; cryptonote::tx_destination_entry de; + // indicates if dst_addr is integrated address (address + payment_id) bool has_payment_id; - crypto::hash8 new_payment_id; - + crypto::hash8 payment_id_short; // TODO: (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) - size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIXIN; - PendingTransactionImpl * transaction = new PendingTransactionImpl(this); + PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); do { - - if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), dst_addr)) { + if(!cryptonote::get_account_integrated_address_from_str(de.addr, has_payment_id, payment_id_short, m_wallet->testnet(), dst_addr)) { // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982 m_status = Status_Error; m_errorString = "Invalid destination address"; break; } + std::vector extra; + // if dst_addr is not an integrated address, parse payment_id + if (!has_payment_id && !payment_id.empty()) { + // copy-pasted from simplewallet.cpp:2212 + crypto::hash payment_id_long; + bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long); + if (r) { + std::string extra_nonce; + cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } else { + r = tools::wallet2::parse_short_payment_id(payment_id, payment_id_short); + if (r) { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_short); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + } + + if (!r) { + m_status = Status_Error; + m_errorString = tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id; + break; + } + } + + de.amount = amount; if (de.amount <= 0) { m_status = Status_Error; @@ -414,7 +456,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, uint64 dsts.push_back(de); //std::vector ptx_vector; - std::vector extra; + try { diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 016116e96..164aede1a 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -60,6 +60,7 @@ public: std::string errorString() const; bool setPassword(const std::string &password); std::string address() const; + std::string integratedAddress(const std::string &payment_id) const; bool store(const std::string &path); std::string filename() const; std::string keysFilename() const; @@ -70,7 +71,8 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); - PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count); + PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, + uint64_t amount, uint32_t mixin_count); virtual void disposeTransaction(PendingTransaction * t); virtual TransactionHistory * history() const; virtual void setListener(WalletListener * l); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index de0b50591..c0c3d436a 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -134,6 +134,16 @@ struct Wallet virtual std::string errorString() const = 0; virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; + /*! + * \brief integratedAddress - returns integrated address for current wallet address and given payment_id. + * if passed "payment_id" param is an empty string or not-valid payment id string + * (16 characters hexadecimal string) - random payment_id will be generated + * + * \param payment_id - 16 characters hexadecimal string or empty string if new random payment id needs to be + * generated + * \return - 106 characters string representing integrated address + */ + virtual std::string integratedAddress(const std::string &payment_id) const = 0; /*! * \brief store - stores wallet to file. * \param path - main filename to store wallet to. additionally stores address file and keys file. @@ -162,19 +172,22 @@ struct Wallet static std::string displayAmount(uint64_t amount); static uint64_t amountFromString(const std::string &amount); static uint64_t amountFromDouble(double amount); + static std::string genPaymentId(); // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; /*! - * \brief createTransaction creates transaction + * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored * \param dst_addr destination address as string + * \param payment_id optional payment_id, can be empty string * \param amount amount * \param mixin_count mixin count. if 0 passed, wallet will use default value * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() * after object returned */ - virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount, uint32_t mixin_count) = 0; + virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, + uint64_t amount, uint32_t mixin_count) = 0; virtual void disposeTransaction(PendingTransaction * t) = 0; virtual TransactionHistory * history() const = 0; virtual void setListener(WalletListener *) = 0; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index ddd6969c6..471427c0c 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -75,6 +75,7 @@ const std::string TESTNET_WALLET4_NAME = WALLETS_ROOT_DIR + "wallet_04.bin"; const std::string TESTNET_WALLET5_NAME = WALLETS_ROOT_DIR + "wallet_05.bin"; const std::string TESTNET_WALLET6_NAME = WALLETS_ROOT_DIR + "wallet_06.bin"; + const char * TESTNET_WALLET_PASS = ""; const std::string CURRENT_SRC_WALLET = TESTNET_WALLET1_NAME; @@ -85,6 +86,8 @@ const uint64_t AMOUNT_10XMR = 10000000000000L; const uint64_t AMOUNT_5XMR = 5000000000000L; const uint64_t AMOUNT_1XMR = 1000000000000L; +const std::string PAYMENT_ID_EMPTY = ""; + } @@ -247,7 +250,7 @@ TEST_F(WalletManagerTest, WalletManagerChangesPassword) ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2)); ASSERT_TRUE(wmgr->closeWallet(wallet1)); Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2); - ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);quint64 + ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet2->seed() == seed1); ASSERT_TRUE(wmgr->closeWallet(wallet2)); Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); @@ -359,6 +362,24 @@ TEST_F(WalletManagerTest, WalletManagerFindsWallet) } } +TEST_F(WalletManagerTest, WalletGeneratesPaymentId) +{ + std::string payment_id = Bitmonero::Wallet::genPaymentId(); + ASSERT_TRUE(payment_id.length() == 16); +} + + +TEST_F(WalletManagerTest, WalletGeneratesIntegratedAddress) +{ + std::string payment_id = Bitmonero::Wallet::genPaymentId(); + + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + std::string integrated_address = wallet1->integratedAddress(payment_id); + ASSERT_TRUE(integrated_address.length() == 106); +} + + + TEST_F(WalletTest1, WalletShowsBalance) { @@ -438,6 +459,8 @@ TEST_F(WalletTest1, WalletTransactionWithMixin) mixins.push_back(7); mixins.push_back(8); mixins.push_back(9); mixins.push_back(10); mixins.push_back(15); mixins.push_back(20); mixins.push_back(25); + std::string payment_id = ""; + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); @@ -452,7 +475,7 @@ TEST_F(WalletTest1, WalletTransactionWithMixin) for (auto mixin : mixins) { std::cerr << "Transaction mixin count: " << mixin << std::endl; Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( - recepient_address, AMOUNT_5XMR, mixin); + recepient_address, payment_id, AMOUNT_5XMR, mixin); std::cerr << "Transaction status: " << transaction->status() << std::endl; std::cerr << "Transaction fee: " << Bitmonero::Wallet::displayAmount(transaction->fee()) << std::endl; @@ -504,18 +527,68 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, AMOUNT_10XMR * 5, 0); + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, + PAYMENT_ID_EMPTY, + AMOUNT_10XMR * 5, 0); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); + ASSERT_TRUE(tx->commit()); + history = wallet_src->history(); + history->refresh(); + ASSERT_TRUE(count1 != history->count()); + + std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl; + for (auto t: history->getAll()) { + ASSERT_TRUE(t != nullptr); + Utils::print_transaction(t); + } +} + +TEST_F(WalletTest1, WalletTransactionWithPaymentId) +{ + + Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); + // make sure testnet daemon is running + ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0)); + ASSERT_TRUE(wallet_src->refresh()); + Bitmonero::TransactionHistory * history = wallet_src->history(); + history->refresh(); + ASSERT_TRUE(history->count() > 0); + size_t count1 = history->count(); + + std::cout << "**** Transactions before transfer (" << count1 << ")" << std::endl; + for (auto t: history->getAll()) { + ASSERT_TRUE(t != nullptr); + Utils::print_transaction(t); + } + + std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + + std::string payment_id = Bitmonero::Wallet::genPaymentId(); + ASSERT_TRUE(payment_id.length() == 16); + + + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr, + payment_id, + AMOUNT_1XMR, 1); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); history = wallet_src->history(); history->refresh(); ASSERT_TRUE(count1 != history->count()); + bool payment_id_in_history = false; + std::cout << "**** Transactions after transfer (" << history->count() << ")" << std::endl; for (auto t: history->getAll()) { ASSERT_TRUE(t != nullptr); Utils::print_transaction(t); + if (t->paymentId() == payment_id) { + payment_id_in_history = true; + } } + + ASSERT_TRUE(payment_id_in_history); } struct MyWalletListener : public Bitmonero::WalletListener -- cgit v1.2.3