From 2cce32995b840901ce656dd8ec3fcefefff706bf Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 21 Mar 2016 16:17:03 +0300 Subject: [PATCH 01/39] wallet2::store() implemented within wallet2::store_to --- src/wallet/wallet2.cpp | 122 +++++++++++++---------------- src/wallet/wallet2_api.cpp | 6 ++ src/wallet/wallet2_api.h | 3 + tests/libwallet_api_tests/main.cpp | 25 ++++++ 4 files changed, 87 insertions(+), 69 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2afe08cb1..9592810e7 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1424,6 +1424,42 @@ void wallet2::check_genesis(const crypto::hash& genesis_hash) const { //---------------------------------------------------------------------------------------------------- void wallet2::store() { + store_to("", ""); +} +//---------------------------------------------------------------------------------------------------- +void wallet2::store_to(const std::string &path, const std::string &password) +{ + // if file is the same, we do: + // 1. save wallet to the *.new file + // 2. remove old wallet file + // 3. rename *.new to wallet_name + + // handle if we want just store wallet state to current files (ex store() replacement); + bool same_file = true; + if (!path.empty()) + { + std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string(); + size_t pos = canonical_path.find(path); + same_file = pos != std::string::npos; + } + + + if (!same_file) + { + // check if we want to store to directory which doesn't exists yet + boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path(); + + // if path is not exists, try to create it + if (!parent_path.empty() && !boost::filesystem::exists(parent_path)) + { + boost::system::error_code ec; + if (!boost::filesystem::create_directories(parent_path, ec)) + { + throw std::logic_error(ec.message()); + } + } + } + // preparing wallet data std::stringstream oss; boost::archive::binary_oarchive ar(oss); ar << *this; @@ -1438,10 +1474,10 @@ void wallet2::store() crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]); cache_file_data.cache_data = cipher; - // save to new file, rename main to old, rename new to main - // at all times, there should be a valid file on disk - const std::string new_file = m_wallet_file + ".new"; - const std::string old_file = m_wallet_file + ".old"; + const std::string new_file = same_file ? m_wallet_file + ".new" : path; + const std::string old_file = m_wallet_file; + const std::string old_keys_file = m_keys_file; + const std::string old_address_file = m_wallet_file + ".address.txt"; // save to new file std::ofstream ostr; @@ -1451,87 +1487,35 @@ void wallet2::store() ostr.close(); THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file); - // rename - boost::filesystem::remove(old_file); // probably does not exist - if (boost::filesystem::exists(m_wallet_file)) { - std::error_code e = tools::replace_file(m_wallet_file, old_file); - THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e); - } - std::error_code e = tools::replace_file(new_file, m_wallet_file); - THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e); - boost::filesystem::remove(old_file); -} - -void wallet2::store_to(const std::string &path, const std::string &password) -{ - // TODO: merge it with wallet2::store() function - - // check if we want to store to directory which doesn't exists yet - boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path(); - - // if path is not exists, try to create it - if (!parent_path.empty() && !boost::filesystem::exists(parent_path)) { - boost::system::error_code ec; - if (!boost::filesystem::create_directories(parent_path, ec)) { - throw std::logic_error(ec.message()); - } - } - - - std::stringstream oss; - boost::archive::binary_oarchive ar(oss); - ar << *this; - - wallet2::cache_file_data cache_file_data = boost::value_initialized(); - cache_file_data.cache_data = oss.str(); - crypto::chacha8_key key; - generate_chacha8_key_from_secret_keys(key); - std::string cipher; - cipher.resize(cache_file_data.cache_data.size()); - cache_file_data.iv = crypto::rand(); - crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]); - cache_file_data.cache_data = cipher; - - - const std::string new_file = path; - const std::string old_file = m_wallet_file; - const std::string old_keys_file = m_keys_file; - const std::string old_address_file = m_wallet_file + ".address.txt"; - - // save to new file - std::ofstream ostr; - ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); - binary_archive oar(ostr); - bool success = ::serialization::serialize(oar, cache_file_data); - ostr.close(); - THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file); - - // save keys to the new file - // if we here, main wallet file is saved and we only need to save keys and address files + // save keys to the new file + // if we here, main wallet file is saved and we only need to save keys and address files + if (!same_file) { prepare_file_names(path); store_keys(m_keys_file, password, false); - // save address to the new file const std::string address_file = m_wallet_file + ".address.txt"; bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet)); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); - - // remove old wallet file r = boost::filesystem::remove(old_file); if (!r) { - LOG_ERROR("error removing file: " << old_file); + LOG_ERROR("error removing file: " << old_file); } // remove old keys file r = boost::filesystem::remove(old_keys_file); if (!r) { - LOG_ERROR("error removing file: " << old_keys_file); + LOG_ERROR("error removing file: " << old_keys_file); } // remove old address file r = boost::filesystem::remove(old_address_file); if (!r) { - LOG_ERROR("error removing file: " << old_address_file); + LOG_ERROR("error removing file: " << old_address_file); } + } else { + // here we have "*.new" file, we need to rename it to be without ".new" + std::error_code e = tools::replace_file(new_file, m_wallet_file); + THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e); + } } //---------------------------------------------------------------------------------------------------- uint64_t wallet2::unlocked_balance() const @@ -2769,12 +2753,12 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) c std::string wallet2::get_wallet_file() const { - return m_wallet_file; + return m_wallet_file; } std::string wallet2::get_keys_file() const { - return m_keys_file; + return m_keys_file; } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 0644e3690..cf1a2bf24 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -276,6 +276,7 @@ public: virtual bool closeWallet(Wallet *wallet); bool walletExists(const std::string &path); std::string errorString() const; + void setDaemonHost(const std::string &hostname); private: @@ -329,6 +330,11 @@ std::string WalletManagerImpl::errorString() const return m_errorString; } +void WalletManagerImpl::setDaemonHost(const std::string &hostname) +{ + +} + ///////////////////// WalletManagerFactory implementation ////////////////////// diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index c7e7c536c..013a260b7 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -112,6 +112,9 @@ struct WalletManager virtual std::string errorString() const = 0; + virtual void setDaemonHost(const std::string &hostname) = 0; + + }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 9701c300c..da2624387 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -165,6 +165,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1) ASSERT_TRUE(wmgr->closeWallet(wallet2)); } + TEST_F(WalletManagerTest, WalletManagerStoresWallet2) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -181,6 +182,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } + TEST_F(WalletManagerTest, WalletManagerStoresWallet3) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -204,6 +206,29 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3) } +TEST_F(WalletManagerTest, WalletManagerStoresWallet4) +{ + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + std::string seed1 = wallet1->seed(); + std::string address1 = wallet1->address(); + + ASSERT_TRUE(wallet1->store("")); + ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok); + + ASSERT_TRUE(wallet1->store("")); + ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok); + + ASSERT_TRUE(wmgr->closeWallet(wallet1)); + + wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); + ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok); + ASSERT_TRUE(wallet1->seed() == seed1); + ASSERT_TRUE(wallet1->address() == address1); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); + +} + + int main(int argc, char** argv) { //epee::debug::get_set_enable_assert(true, false); From 8790904cf9ccba56a1cbab51b01f2cbb0a5cb143 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 25 Mar 2016 17:06:30 +0300 Subject: [PATCH 02/39] - testnet option added to api; --- src/wallet/wallet2.cpp | 5 +++ src/wallet/wallet2.h | 1 + src/wallet/wallet2_api.cpp | 50 ++++++++++++++++++---- src/wallet/wallet2_api.h | 11 +++-- tests/libwallet_api_tests/main.cpp | 68 +++++++++++++++++++----------- 5 files changed, 98 insertions(+), 37 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 9592810e7..f263346a7 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2761,6 +2761,11 @@ std::string wallet2::get_keys_file() const return m_keys_file; } +std::string wallet2::get_daemon_address() const +{ + return m_daemon_address; +} + //---------------------------------------------------------------------------------------------------- void wallet2::generate_genesis(cryptonote::block& b) { if (m_testnet) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f798f404d..60814b7ed 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -359,6 +359,7 @@ namespace tools std::string get_wallet_file() const; std::string get_keys_file() const; + std::string get_daemon_address() const; private: /*! * \brief Stores wallet information to wallet file. diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index cf1a2bf24..31015b355 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -54,7 +54,7 @@ Wallet::~Wallet() {} class WalletImpl : public Wallet { public: - WalletImpl(); + WalletImpl(bool testnet = false); ~WalletImpl(); bool create(const std::string &path, const std::string &password, const std::string &language); @@ -70,6 +70,9 @@ public: 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); + uint64_t balance() const; + bool connectToDaemon(); private: void clearStatus(); @@ -82,10 +85,10 @@ private: std::string m_password; }; -WalletImpl::WalletImpl() +WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok) { - m_wallet = new tools::wallet2(); + m_wallet = new tools::wallet2(testnet); } WalletImpl::~WalletImpl() @@ -257,6 +260,35 @@ bool WalletImpl::store(const std::string &path) 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(); +} + +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; @@ -270,8 +302,8 @@ class WalletManagerImpl : public WalletManager { public: Wallet * createWallet(const std::string &path, const std::string &password, - const std::string &language); - Wallet * openWallet(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); virtual bool closeWallet(Wallet *wallet); bool walletExists(const std::string &path); @@ -287,16 +319,16 @@ private: }; Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, - const std::string &language) + const std::string &language, bool testnet) { - WalletImpl * wallet = new WalletImpl(); + WalletImpl * wallet = new WalletImpl(testnet); wallet->create(path, password, language); return wallet; } -Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password) +Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, bool testnet) { - WalletImpl * wallet = new WalletImpl(); + WalletImpl * wallet = new WalletImpl(testnet); wallet->open(path, password); return wallet; } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 013a260b7..ad1e08fe3 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -67,6 +67,9 @@ struct Wallet virtual bool setPassword(const std::string &password) = 0; virtual std::string address() const = 0; 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 uint64_t balance() const = 0; }; /** @@ -82,7 +85,7 @@ struct WalletManager * \param language Language to be used to generate electrum seed memo * \return Wallet instance (Wallet::status() needs to be called to check if created successfully) */ - virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language) = 0; + virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet) = 0; /*! * \brief Opens existing wallet @@ -90,7 +93,7 @@ struct WalletManager * \param password Password of wallet file * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) */ - virtual Wallet * openWallet(const std::string &path, const std::string &password) = 0; + virtual Wallet * openWallet(const std::string &path, const std::string &password, bool testnet) = 0; /*! * \brief recovers existing wallet using memo (electrum seed) @@ -111,8 +114,8 @@ struct WalletManager virtual bool walletExists(const std::string &path) = 0; virtual std::string errorString() const = 0; - - virtual void setDaemonHost(const std::string &hostname) = 0; +// //! set +// virtual void setDaemonAddress(const std::string &address) = 0; }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index da2624387..841b5df27 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -41,6 +41,23 @@ using namespace std; //unsigned int epee::g_test_dbg_lock_sleep = 0; +struct Utils +{ + static void deleteWallet(const std::string & walletname) + { + std::cout << "** deleting wallet: " << walletname << std::endl; + boost::filesystem::remove(walletname); + boost::filesystem::remove(walletname + ".address.txt"); + boost::filesystem::remove(walletname + ".keys"); + } + + static void deleteDir(const std::string &path) + { + std::cout << "** removing dir recursively: " << path << std::endl; + boost::filesystem::remove_all(path); + } +}; + struct WalletManagerTest : public testing::Test { @@ -54,12 +71,16 @@ struct WalletManagerTest : public testing::Test 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_WALLET_PASS = ""; + WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); - deleteWallet(WALLET_NAME); - deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string()); + Utils::deleteWallet(WALLET_NAME); + Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string()); } @@ -68,29 +89,13 @@ struct WalletManagerTest : public testing::Test std::cout << __FUNCTION__ << std::endl; //deleteWallet(WALLET_NAME); } - - - void deleteWallet(const std::string & walletname) - { - std::cout << "** deleting wallet: " << walletname << std::endl; - boost::filesystem::remove(walletname); - boost::filesystem::remove(walletname + ".address.txt"); - boost::filesystem::remove(walletname + ".keys"); - } - - void deleteDir(const std::string &path) - { - std::cout << "** removing dir recursively: " << path << std::endl; - boost::filesystem::remove_all(path); - } - }; TEST_F(WalletManagerTest, WalletManagerCreatesWallet) { - Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, true); ASSERT_TRUE(wallet->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(!wallet->seed().empty()); std::vector words; @@ -107,16 +112,16 @@ TEST_F(WalletManagerTest, WalletManagerCreatesWallet) TEST_F(WalletManagerTest, WalletManagerOpensWallet) { - Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, true); std::string seed1 = wallet1->seed(); ASSERT_TRUE(wmgr->closeWallet(wallet1)); - Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); + Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, true); ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet2->seed() == seed1); std::cout << "** seed: " << wallet2->seed() << std::endl; } - +/* TEST_F(WalletManagerTest, WalletManagerChangesPassword) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -182,7 +187,6 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } - TEST_F(WalletManagerTest, WalletManagerStoresWallet3) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -205,7 +209,6 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3) } - TEST_F(WalletManagerTest, WalletManagerStoresWallet4) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -225,7 +228,24 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4) ASSERT_TRUE(wallet1->seed() == seed1); ASSERT_TRUE(wallet1->address() == address1); ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} +*/ +TEST_F(WalletManagerTest, WalletShowsBalance) +{ + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + std::string seed1 = wallet1->seed(); + std::string address1 = wallet1->address(); + ASSERT_TRUE(wallet1->balance() > 0); + + uint64_t balance1 = wallet1->balance(); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); + + Bitmonero::Wallet * wallet2 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + ASSERT_TRUE(seed1 == wallet2->seed()); + ASSERT_TRUE(address1 == wallet2->address()); + ASSERT_TRUE(balance1 == wallet2->balance()); + ASSERT_TRUE(wmgr->closeWallet(wallet2)); } From 2157a9ac4876c2f50421d0e5ad13be3123ff1201 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 31 Mar 2016 12:48:41 +0300 Subject: [PATCH 03/39] testnet option, Wallet::balance(), Wallet::unlockedBalance() --- src/wallet/wallet2_api.cpp | 12 +++++++++--- src/wallet/wallet2_api.h | 9 ++++++--- tests/libwallet_api_tests/main.cpp | 23 ++++++++++++----------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 31015b355..3c7dffa26 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -72,6 +72,7 @@ public: bool store(const std::string &path); bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit); uint64_t balance() const; + uint64_t unlockedBalance() const; bool connectToDaemon(); private: @@ -279,6 +280,11 @@ uint64_t WalletImpl::balance() const return m_wallet->balance(); } +uint64_t WalletImpl::unlockedBalance() const +{ + return m_wallet->unlocked_balance(); +} + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); @@ -304,7 +310,7 @@ 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); + 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; @@ -333,9 +339,9 @@ Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string return wallet; } -Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo) +Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &memo, bool testnet) { - WalletImpl * wallet = new WalletImpl(); + WalletImpl * wallet = new WalletImpl(testnet); wallet->recover(path, memo); return wallet; } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index ad1e08fe3..ec37358d4 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -70,6 +70,9 @@ struct Wallet virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0; virtual bool connectToDaemon() = 0; virtual uint64_t balance() const = 0; + virtual uint64_t unlockedBalance() const = 0; + // TODO? + // virtual uint64_t unlockedDustBalance() const = 0; }; /** @@ -85,7 +88,7 @@ struct WalletManager * \param language Language to be used to generate electrum seed memo * \return Wallet instance (Wallet::status() needs to be called to check if created successfully) */ - virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet) = 0; + virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) = 0; /*! * \brief Opens existing wallet @@ -93,7 +96,7 @@ struct WalletManager * \param password Password of wallet file * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) */ - virtual Wallet * openWallet(const std::string &path, const std::string &password, bool testnet) = 0; + virtual Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) = 0; /*! * \brief recovers existing wallet using memo (electrum seed) @@ -101,7 +104,7 @@ struct WalletManager * \param memo memo (25 words electrum seed) * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ - virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo) = 0; + virtual Wallet * recoveryWallet(const std::string &path, const std::string &memo, bool testnet = false) = 0; /*! * \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 841b5df27..d5bdc8d67 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -95,7 +95,7 @@ struct WalletManagerTest : public testing::Test TEST_F(WalletManagerTest, WalletManagerCreatesWallet) { - Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, true); + Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); ASSERT_TRUE(wallet->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(!wallet->seed().empty()); std::vector words; @@ -112,16 +112,16 @@ TEST_F(WalletManagerTest, WalletManagerCreatesWallet) TEST_F(WalletManagerTest, WalletManagerOpensWallet) { - Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, true); + Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); ASSERT_TRUE(wmgr->closeWallet(wallet1)); - Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, true); + Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS); ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet2->seed() == seed1); std::cout << "** seed: " << wallet2->seed() << std::endl; } -/* + TEST_F(WalletManagerTest, WalletManagerChangesPassword) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -145,7 +145,7 @@ TEST_F(WalletManagerTest, WalletManagerRecoversWallet) std::string address1 = wallet1->address(); ASSERT_FALSE(address1.empty()); ASSERT_TRUE(wmgr->closeWallet(wallet1)); - deleteWallet(WALLET_NAME); + Utils::deleteWallet(WALLET_NAME); Bitmonero::Wallet * wallet2 = wmgr->recoveryWallet(WALLET_NAME, seed1); ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok); ASSERT_TRUE(wallet2->seed() == seed1); @@ -229,22 +229,23 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4) ASSERT_TRUE(wallet1->address() == address1); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -*/ + TEST_F(WalletManagerTest, WalletShowsBalance) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); - std::string seed1 = wallet1->seed(); - std::string address1 = wallet1->address(); ASSERT_TRUE(wallet1->balance() > 0); + ASSERT_TRUE(wallet1->unlockedBalance() > 0); uint64_t balance1 = wallet1->balance(); + uint64_t unlockedBalance1 = wallet1->unlockedBalance(); ASSERT_TRUE(wmgr->closeWallet(wallet1)); - Bitmonero::Wallet * wallet2 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); - ASSERT_TRUE(seed1 == wallet2->seed()); - ASSERT_TRUE(address1 == wallet2->address()); + ASSERT_TRUE(balance1 == wallet2->balance()); + std::cout << "wallet balance: " << wallet2->balance() << std::endl; + ASSERT_TRUE(unlockedBalance1 == wallet2->unlockedBalance()); + std::cout << "wallet unlocked balance: " << wallet2->unlockedBalance() << std::endl; ASSERT_TRUE(wmgr->closeWallet(wallet2)); } From 1ae9cdc6bf7cc8798a95595c5c2cd076cd411c64 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 31 Mar 2016 15:39:28 +0300 Subject: [PATCH 04/39] "testnet" is default parameter --- src/wallet/wallet2_api.cpp | 11 ++++++++++- src/wallet/wallet2_api.h | 3 +-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 3c7dffa26..faf2778d3 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -31,6 +31,7 @@ #include "wallet2_api.h" #include "wallet2.h" #include "mnemonics/electrum-words.h" +#include "cryptonote_core/cryptonote_format_utils.h" #include namespace epee { @@ -71,9 +72,11 @@ public: 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 connectToDaemon(); + std::string displayAmount(uint64_t amount) const; + private: void clearStatus(); @@ -285,6 +288,11 @@ uint64_t WalletImpl::unlockedBalance() const return m_wallet->unlocked_balance(); } +std::string WalletImpl::displayAmount(uint64_t amount) const +{ + return cryptonote::print_money(amount); +} + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); @@ -387,4 +395,5 @@ WalletManager *WalletManagerFactory::getWalletManager() return g_walletManager; } + } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index ec37358d4..a56043e9e 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -71,6 +71,7 @@ struct Wallet virtual bool connectToDaemon() = 0; virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; + virtual std::string displayAmount(uint64_t amount) const = 0; // TODO? // virtual uint64_t unlockedDustBalance() const = 0; }; @@ -119,8 +120,6 @@ struct WalletManager virtual std::string errorString() const = 0; // //! set // virtual void setDaemonAddress(const std::string &address) = 0; - - }; From 830c19c934f1c621cf8f268772d5ab92f35d75b3 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 31 Mar 2016 16:38:57 +0300 Subject: [PATCH 05/39] Wallet::refresh + tests --- src/wallet/wallet2_api.cpp | 13 +++++++++++++ src/wallet/wallet2_api.h | 3 +++ tests/libwallet_api_tests/main.cpp | 12 ++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index faf2778d3..e6ed249cc 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -76,6 +76,7 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; std::string displayAmount(uint64_t amount) const; + bool refresh(); private: @@ -293,6 +294,18 @@ std::string WalletImpl::displayAmount(uint64_t amount) const return cryptonote::print_money(amount); } +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; +} + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index a56043e9e..c818608ed 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -74,6 +74,9 @@ struct Wallet virtual std::string displayAmount(uint64_t amount) const = 0; // TODO? // virtual uint64_t unlockedDustBalance() const = 0; + // TODO refresh + virtual bool refresh() = 0; + // TODO transfer }; /** diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index d5bdc8d67..d935a38b7 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -71,10 +71,13 @@ struct WalletManagerTest : public testing::Test 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_WALLET_PASS = ""; + const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; + WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; @@ -249,6 +252,15 @@ TEST_F(WalletManagerTest, WalletShowsBalance) ASSERT_TRUE(wmgr->closeWallet(wallet2)); } +TEST_F(WalletManagerTest, WalletRefresh) +{ + 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()); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} + int main(int argc, char** argv) { From c37c856d6d9694da33866145f1b69339fed787b1 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Sun, 3 Apr 2016 14:34:38 +0300 Subject: [PATCH 06/39] Wallet::transfer in progress --- src/wallet/wallet2_api.cpp | 40 ++++++++++++++++++++++++++++++++++++++ src/wallet/wallet2_api.h | 3 ++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index e6ed249cc..dcd17d804 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -32,7 +32,11 @@ #include "wallet2.h" #include "mnemonics/electrum-words.h" #include "cryptonote_core/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_basic_impl.h" + + #include +#include namespace epee { unsigned int g_test_dbg_lock_sleep = 0; @@ -44,11 +48,16 @@ struct WalletManagerImpl; namespace { static WalletManagerImpl * g_walletManager = nullptr; + // copy-pasted from + static const size_t DEFAULT_MIX = 4; } + +using namespace std; + Wallet::~Wallet() {} ///////////////////////// Wallet implementation //////////////////////////////// @@ -77,6 +86,7 @@ public: uint64_t unlockedBalance() const; std::string displayAmount(uint64_t amount) const; bool refresh(); + bool transfer(const std::string &dst_addr, uint64_t amount); private: @@ -306,6 +316,36 @@ bool WalletImpl::refresh() return m_status == Status_Ok; } +bool WalletImpl::transfer(const std::string &dst_addr, uint64_t amount) +{ + clearStatus(); + vector dsts; + cryptonote::tx_destination_entry de; + bool has_payment_id; + bool payment_id_seen = false; + crypto::hash8 new_payment_id; + size_t fake_outs_count = DEFAULT_MIX; + 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"; + return false; + } + + de.amount = amount; + if (de.amount <= 0) { + m_status = Status_Error; + m_errorString = "Invalid amount"; + return false; + } + dsts.push_back(de); + + + + + return m_status == Status_Ok; +} + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index c818608ed..1c3cd595a 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -74,9 +74,10 @@ struct Wallet virtual std::string displayAmount(uint64_t amount) const = 0; // TODO? // virtual uint64_t unlockedDustBalance() const = 0; - // TODO refresh virtual bool refresh() = 0; // TODO transfer + virtual bool transfer(const std::string &dst_addr, uint64_t amount) = 0; + }; /** From ee5bb17f26390ceb55dd277932585b0020077e9e Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 4 Apr 2016 14:56:17 +0300 Subject: [PATCH 07/39] Wallet::transfer() continued --- src/wallet/wallet2_api.cpp | 149 ++++++++++++++++++++++++++++- src/wallet/wallet2_api.h | 14 +++ tests/libwallet_api_tests/main.cpp | 16 ++++ 3 files changed, 175 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index dcd17d804..60e75802c 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -33,10 +33,16 @@ #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; @@ -51,14 +57,75 @@ namespace { // copy-pasted from static const size_t DEFAULT_MIX = 4; +} + + + +using namespace std; +using namespace cryptonote; + +Wallet::~Wallet() {} + +///////////////////////// Transaction implementation /////////////////////////// + +class TransactionImpl : public Transaction +{ +public: + TransactionImpl(Wallet * wallet); + ~TransactionImpl(); + int status() const; + std::string errorString() const; + bool commit(); + + +private: + std::vector & transactions(); + +private: + friend class WalletImpl; + Wallet * m_wallet; + int m_status; + std::string m_errorString; + std::vector m_pending_tx; + + +}; + + +TransactionImpl::TransactionImpl(Wallet *wallet) + : m_wallet(wallet) +{ + +} + +TransactionImpl::~TransactionImpl() +{ + +} + +int TransactionImpl::status() const +{ + return m_status; +} + +string TransactionImpl::errorString() const +{ + return m_errorString; +} + +bool TransactionImpl::commit() +{ +// while (!m_pending_tx.empty()) { + +// } + return false; } -using namespace std; -Wallet::~Wallet() {} + ///////////////////////// Wallet implementation //////////////////////////////// class WalletImpl : public Wallet @@ -324,7 +391,11 @@ bool WalletImpl::transfer(const std::string &dst_addr, uint64_t amount) bool has_payment_id; bool payment_id_seen = false; crypto::hash8 new_payment_id; - size_t fake_outs_count = DEFAULT_MIX; + size_t fake_outs_count = m_wallet->default_mixin(); + if (fake_outs_count == 0) + fake_outs_count = DEFAULT_MIX; + + 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; @@ -339,10 +410,78 @@ bool WalletImpl::transfer(const std::string &dst_addr, uint64_t amount) return false; } dsts.push_back(de); + std::vector ptx_vector; + std::vector extra; + try { + ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); +// TODO: move it to transaction class + while (!ptx_vector.empty()) { + auto & ptx = ptx_vector.back(); + 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 + ptx_vector.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::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; + } return m_status == Status_Ok; } @@ -449,4 +588,6 @@ WalletManager *WalletManagerFactory::getWalletManager() } + + } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 1c3cd595a..662264f50 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -36,6 +36,20 @@ // Public interface for libwallet library namespace Bitmonero { +/** + * @brief Transaction interface + */ +struct Transaction +{ + enum Status { + Status_Ok, + Status_Error + }; + + virtual int status() const = 0; + virtual std::string errorString() const = 0; + virtual bool commit() = 0; +}; /** * @brief Interface for wallet operations. diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index d935a38b7..970d9a74e 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -77,6 +77,9 @@ struct WalletManagerTest : public testing::Test 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"; WalletManagerTest() { @@ -261,6 +264,19 @@ TEST_F(WalletManagerTest, WalletRefresh) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } +TEST_F(WalletManagerTest, WalletTransfer) +{ + 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()); + uint64_t balance = wallet1->balance(); + ASSERT_TRUE(wallet1->transfer(RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR)); + ASSERT_FALSE(wallet1->balance() == balance); + ASSERT_TRUE(wmgr->closeWallet(wallet1)); +} + + int main(int argc, char** argv) { From 079fbd3d42f74d9bdc268c83677878b9ac5c1047 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 5 Apr 2016 15:24:44 +0300 Subject: [PATCH 08/39] Wallet::createTransaction API introduced --- src/wallet/wallet2_api.cpp | 322 +++++++++++++++++------------ src/wallet/wallet2_api.h | 11 +- tests/libwallet_api_tests/main.cpp | 10 +- 3 files changed, 204 insertions(+), 139 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 60e75802c..ae26a1eb3 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -66,65 +66,43 @@ using namespace cryptonote; Wallet::~Wallet() {} +Transaction::~Transaction() {} + + +class WalletImpl; + ///////////////////////// Transaction implementation /////////////////////////// class TransactionImpl : public Transaction { public: - TransactionImpl(Wallet * wallet); + TransactionImpl(WalletImpl * wallet); ~TransactionImpl(); int status() const; std::string errorString() const; bool commit(); - - -private: - std::vector & transactions(); + uint64_t dust() const; + uint64_t fee() const; + // TODO: continue with interface; private: friend class WalletImpl; - Wallet * m_wallet; + WalletImpl * m_wallet; + int m_status; std::string m_errorString; std::vector m_pending_tx; - - }; -TransactionImpl::TransactionImpl(Wallet *wallet) - : m_wallet(wallet) + + +///////////////////////////////////////////////////////////////////////////////// +string Wallet::displayAmount(uint64_t amount) { - + return cryptonote::print_money(amount); } -TransactionImpl::~TransactionImpl() -{ - -} - -int TransactionImpl::status() const -{ - return m_status; -} - -string TransactionImpl::errorString() const -{ - return m_errorString; -} - -bool TransactionImpl::commit() -{ -// while (!m_pending_tx.empty()) { - -// } - return false; - - -} - - - ///////////////////////// Wallet implementation //////////////////////////////// @@ -151,16 +129,15 @@ public: bool connectToDaemon(); uint64_t balance() const; uint64_t unlockedBalance() const; - std::string displayAmount(uint64_t amount) const; bool refresh(); - bool transfer(const std::string &dst_addr, uint64_t amount); - + Transaction * createTransaction(const std::string &dst_addr, uint64_t amount); + virtual void disposeTransaction(Transaction * t); private: void clearStatus(); private: - //std::unique_ptr m_wallet; + friend class TransactionImpl; tools::wallet2 * m_wallet; int m_status; std::string m_errorString; @@ -366,10 +343,6 @@ uint64_t WalletImpl::unlockedBalance() const return m_wallet->unlocked_balance(); } -std::string WalletImpl::displayAmount(uint64_t amount) const -{ - return cryptonote::print_money(amount); -} bool WalletImpl::refresh() { @@ -383,7 +356,8 @@ bool WalletImpl::refresh() return m_status == Status_Ok; } -bool WalletImpl::transfer(const std::string &dst_addr, uint64_t amount) + +Transaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) { clearStatus(); vector dsts; @@ -395,94 +369,103 @@ bool WalletImpl::transfer(const std::string &dst_addr, uint64_t amount) 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"; - return false; - } + 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"; - return false; - } - dsts.push_back(de); - std::vector ptx_vector; - std::vector extra; - try { - ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); -// TODO: move it to transaction class - while (!ptx_vector.empty()) { - auto & ptx = ptx_vector.back(); - 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 - ptx_vector.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::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; - } - return m_status == Status_Ok; + + 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); + // TODO: move it to transaction class + + } 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(Transaction *t) +{ + delete t; } bool WalletImpl::connectToDaemon() @@ -503,6 +486,81 @@ void WalletImpl::clearStatus() + +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() +{ + 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::dust() const +{ + uint32_t result = 0; + for (auto ptx : m_pending_tx) { + result += ptx.dust; + } + return result; +} + +uint64_t TransactionImpl::fee() const +{ + uint32_t result = 0; + for (auto ptx : m_pending_tx) { + result += ptx.fee; + } + return result; +} + + + ///////////////////////// WalletManager implementation ///////////////////////// class WalletManagerImpl : public WalletManager { diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 662264f50..c85cda2de 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -45,10 +45,12 @@ struct Transaction Status_Ok, Status_Error }; - + virtual ~Transaction() = 0; virtual int status() const = 0; virtual std::string errorString() const = 0; virtual bool commit() = 0; + virtual uint64_t dust() const = 0; + virtual uint64_t fee() const = 0; }; /** @@ -85,13 +87,12 @@ struct Wallet virtual bool connectToDaemon() = 0; virtual uint64_t balance() const = 0; virtual uint64_t unlockedBalance() const = 0; - virtual std::string displayAmount(uint64_t amount) const = 0; + static std::string displayAmount(uint64_t amount); // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; - // TODO transfer - virtual bool transfer(const std::string &dst_addr, uint64_t amount) = 0; - + virtual Transaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; + virtual void disposeTransaction(Transaction * t) = 0; }; /** diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 970d9a74e..f073b47b9 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -264,14 +264,20 @@ TEST_F(WalletManagerTest, WalletRefresh) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(WalletManagerTest, WalletTransfer) +TEST_F(WalletManagerTest, WalletTransaction) { 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()); uint64_t balance = wallet1->balance(); - ASSERT_TRUE(wallet1->transfer(RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR)); + + Bitmonero::Transaction * transaction = wallet1->createTransaction( + RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR); + ASSERT_TRUE(transaction->status() == Bitmonero::Transaction::Status_Ok); + + ASSERT_TRUE(wallet1->balance() == balance); + ASSERT_TRUE(transaction->commit()); ASSERT_FALSE(wallet1->balance() == balance); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } From d97e9ef8a55f92841b30dd31807beb1c06ec264b Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 6 Apr 2016 13:56:57 +0300 Subject: [PATCH 09/39] Transaction API continued --- src/wallet/wallet2_api.cpp | 24 ++++++++++++++++++++---- src/wallet/wallet2_api.h | 1 + tests/libwallet_api_tests/main.cpp | 2 ++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index ae26a1eb3..3947084e3 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -81,6 +81,7 @@ public: 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; @@ -365,11 +366,13 @@ Transaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amou bool has_payment_id; bool payment_id_seen = false; crypto::hash8 new_payment_id; + // TODO: how this number affects (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)) { @@ -377,7 +380,6 @@ Transaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amou m_status = Status_Error; m_errorString = "Invalid destination address"; break; - } de.amount = amount; @@ -510,6 +512,9 @@ string TransactionImpl::errorString() const 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(); @@ -541,10 +546,21 @@ bool TransactionImpl::commit() 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 (auto ptx : m_pending_tx) { + for (const auto & ptx : m_pending_tx) { result += ptx.dust; } return result; @@ -553,7 +569,7 @@ uint64_t TransactionImpl::dust() const uint64_t TransactionImpl::fee() const { uint32_t result = 0; - for (auto ptx : m_pending_tx) { + for (const auto ptx : m_pending_tx) { result += ptx.fee; } return result; @@ -638,7 +654,7 @@ WalletManager *WalletManagerFactory::getWalletManager() { if (!g_walletManager) { - epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_0); + epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_MAX); g_walletManager = new WalletManagerImpl(); } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index c85cda2de..c064aeba8 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -49,6 +49,7 @@ struct Transaction virtual int status() const = 0; virtual std::string errorString() const = 0; virtual bool commit() = 0; + virtual uint64_t amount() const = 0; virtual uint64_t dust() const = 0; virtual uint64_t fee() const = 0; }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index f073b47b9..6e993d70c 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -271,12 +271,14 @@ TEST_F(WalletManagerTest, WalletTransaction) ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet1->refresh()); uint64_t balance = wallet1->balance(); + ASSERT_TRUE(wallet1->status() == Bitmonero::Transaction::Status_Ok); Bitmonero::Transaction * transaction = wallet1->createTransaction( RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR); ASSERT_TRUE(transaction->status() == Bitmonero::Transaction::Status_Ok); ASSERT_TRUE(wallet1->balance() == balance); + ASSERT_TRUE(transaction->amount() == AMOUNT_10XMR); ASSERT_TRUE(transaction->commit()); ASSERT_FALSE(wallet1->balance() == balance); ASSERT_TRUE(wmgr->closeWallet(wallet1)); From 1774d9574b5c6ebc55b3f4a6adf82d995bfad42f Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 12 Apr 2016 22:30:20 +0300 Subject: [PATCH 10/39] TODOs for Transaction/Transfer interface --- src/wallet/wallet2_api.cpp | 27 +++++++++++++++++---------- src/wallet/wallet2_api.h | 17 ++++++++--------- tests/libwallet_api_tests/main.cpp | 8 ++++---- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index 3947084e3..edf7d9931 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -66,14 +66,14 @@ using namespace cryptonote; Wallet::~Wallet() {} -Transaction::~Transaction() {} +PendingTransaction::~PendingTransaction() {} class WalletImpl; ///////////////////////// Transaction implementation /////////////////////////// -class TransactionImpl : public Transaction +class TransactionImpl : public PendingTransaction { public: TransactionImpl(WalletImpl * wallet); @@ -131,8 +131,8 @@ public: uint64_t balance() const; uint64_t unlockedBalance() const; bool refresh(); - Transaction * createTransaction(const std::string &dst_addr, uint64_t amount); - virtual void disposeTransaction(Transaction * t); + PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount); + virtual void disposeTransaction(PendingTransaction * t); private: void clearStatus(); @@ -357,16 +357,24 @@ bool WalletImpl::refresh() return m_status == Status_Ok; } - -Transaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amount) +// 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; - bool payment_id_seen = false; crypto::hash8 new_payment_id; - // TODO: how this number affects (https://bitcointalk.org/index.php?topic=753252.msg9985441#msg9985441) + + // 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; @@ -396,7 +404,6 @@ Transaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amou try { transaction->m_pending_tx = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); - // TODO: move it to transaction class } catch (const tools::error::daemon_busy&) { // TODO: make it translatable with "tr"? @@ -465,7 +472,7 @@ Transaction *WalletImpl::createTransaction(const string &dst_addr, uint64_t amou return transaction; } -void WalletImpl::disposeTransaction(Transaction *t) +void WalletImpl::disposeTransaction(PendingTransaction *t) { delete t; } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index c064aeba8..56a91bfbb 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -39,13 +39,13 @@ namespace Bitmonero { /** * @brief Transaction interface */ -struct Transaction +struct PendingTransaction { enum Status { Status_Ok, Status_Error }; - virtual ~Transaction() = 0; + virtual ~PendingTransaction() = 0; virtual int status() const = 0; virtual std::string errorString() const = 0; virtual bool commit() = 0; @@ -60,17 +60,12 @@ struct Transaction */ struct Wallet { - // TODO define wallet interface (decide what needed from wallet2) enum Status { Status_Ok, Status_Error }; - struct Listener - { - // TODO - }; virtual ~Wallet() = 0; virtual std::string seed() const = 0; @@ -92,8 +87,12 @@ struct Wallet // TODO? // virtual uint64_t unlockedDustBalance() const = 0; virtual bool refresh() = 0; - virtual Transaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; - virtual void disposeTransaction(Transaction * t) = 0; + virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; + virtual void disposeTransaction(PendingTransaction * t) = 0; + // TODO + virtual void getPayments() const; + + }; /** diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 6e993d70c..dee874cd6 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -271,11 +271,11 @@ TEST_F(WalletManagerTest, WalletTransaction) ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet1->refresh()); uint64_t balance = wallet1->balance(); - ASSERT_TRUE(wallet1->status() == Bitmonero::Transaction::Status_Ok); + ASSERT_TRUE(wallet1->status() == Bitmonero::PendingTransaction::Status_Ok); - Bitmonero::Transaction * transaction = wallet1->createTransaction( + Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR); - ASSERT_TRUE(transaction->status() == Bitmonero::Transaction::Status_Ok); + ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(wallet1->balance() == balance); ASSERT_TRUE(transaction->amount() == AMOUNT_10XMR); @@ -288,7 +288,7 @@ TEST_F(WalletManagerTest, WalletTransaction) int main(int argc, char** argv) { - //epee::debug::get_set_enable_assert(true, false); + ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } From 4e1c2dc365f58817e371ac9f86de079ae096adce Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 19 Apr 2016 12:25:03 +0300 Subject: [PATCH 11/39] TransactionInfo / TransactionHistory APIs design --- src/wallet/wallet2_api.cpp | 296 ++++++++++++++++++++----------------- src/wallet/wallet2_api.h | 40 ++++- 2 files changed, 197 insertions(+), 139 deletions(-) diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp index edf7d9931..a6fc6ecc5 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/wallet2_api.cpp @@ -65,11 +65,58 @@ using namespace std; using namespace cryptonote; Wallet::~Wallet() {} - PendingTransaction::~PendingTransaction() {} -class WalletImpl; + + + +///////////////////////// 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 /////////////////////////// @@ -95,55 +142,119 @@ private: std::vector m_pending_tx; }; - - - -///////////////////////////////////////////////////////////////////////////////// -string Wallet::displayAmount(uint64_t amount) +TransactionImpl::TransactionImpl(WalletImpl *wallet) + : m_wallet(wallet) { - return cryptonote::print_money(amount); + +} + +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; } -///////////////////////// 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); - -private: - void clearStatus(); - -private: - friend class TransactionImpl; - tools::wallet2 * m_wallet; - int m_status; - std::string m_errorString; - std::string m_password; -}; WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok) @@ -477,6 +588,11 @@ void WalletImpl::disposeTransaction(PendingTransaction *t) delete t; } +TransactionHistory *WalletImpl::history() const +{ + return nullptr; +} + bool WalletImpl::connectToDaemon() { bool result = m_wallet->check_connection(); @@ -496,92 +612,6 @@ void WalletImpl::clearStatus() -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; -} - ///////////////////////// WalletManager implementation ///////////////////////// @@ -671,4 +701,6 @@ WalletManager *WalletManagerFactory::getWalletManager() + + } diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 56a91bfbb..a675d8b31 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -32,12 +32,13 @@ #include +#include // Public interface for libwallet library namespace Bitmonero { /** - * @brief Transaction interface + * @brief Transaction-like interface for sending money */ struct PendingTransaction { @@ -54,6 +55,35 @@ 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; +}; + + +/** + * @brief The TransactionInfo - interface for displaying transaction information + */ +struct TransactionInfo +{ + enum Direction { + Direction_In, + Direction_Out + }; + + 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 +}; + /** * @brief Interface for wallet operations. * TODO: check if /include/IWallet.h is still actual @@ -66,12 +96,11 @@ struct Wallet Status_Error }; - virtual ~Wallet() = 0; 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; + // 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 @@ -89,10 +118,7 @@ struct Wallet virtual bool refresh() = 0; virtual PendingTransaction * createTransaction(const std::string &dst_addr, uint64_t amount) = 0; virtual void disposeTransaction(PendingTransaction * t) = 0; - // TODO - virtual void getPayments() const; - - + virtual TransactionHistory * history() const = 0; }; /** From f83f3cbd9647b679e5c9460970b99bd2e9141858 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:01:00 +0300 Subject: [PATCH 12/39] 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 +++ .../{wallet2_api.cpp => api/wallet.cpp} | 337 ++---------------- src/wallet/api/wallet.h | 86 +++++ src/wallet/api/wallet_manager.cpp | 108 ++++++ src/wallet/api/wallet_manager.h | 55 +++ src/wallet/wallet2_api.h | 8 +- 13 files changed, 715 insertions(+), 320 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 rename src/wallet/{wallet2_api.cpp => api/wallet.cpp} (63%) 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 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/wallet2_api.cpp b/src/wallet/api/wallet.cpp similarity index 63% rename from src/wallet/wallet2_api.cpp rename to src/wallet/api/wallet.cpp index a6fc6ecc5..e42f04cf7 100644 --- a/src/wallet/wallet2_api.cpp +++ b/src/wallet/api/wallet.cpp @@ -1,21 +1,21 @@ // 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 @@ -25,237 +25,35 @@ // 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 "wallet.h" +#include "pending_transaction.h" +#include "common_defines.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; +namespace Bitmonero { + +namespace { + // copy-pasted from simplewallet + static const size_t DEFAULT_MIX = 4; +} + 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 implementation //////////////////////// WalletImpl::WalletImpl(bool testnet) :m_wallet(nullptr), m_status(Wallet::Status_Ok) { @@ -610,97 +408,4 @@ void WalletImpl::clearStatus() } - - - - -///////////////////////// 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; -} - - - - - - -} +} // 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.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; }; /** From b6aaf53a6074e8e7181da5c3275e9fef56bf20da Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:17:27 +0300 Subject: [PATCH 13/39] 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(-) 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; }; From a213887476136148c9162455d37d4337ef152b68 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 20 Apr 2016 13:33:54 +0300 Subject: [PATCH 14/39] transaction history api in progress --- src/wallet/api/transaction_history.cpp | 25 +++++++++++++++++++++++++ src/wallet/api/transaction_info.h | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 6cc5a961c..3ebcc041e 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -28,9 +28,17 @@ // // 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 { @@ -61,7 +69,24 @@ std::vector TransactionHistoryImpl::getAll() const 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 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 From 02c9df5de247d6f8fb95e1b9272cef2b37be10f8 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 22 Apr 2016 13:21:08 +0300 Subject: [PATCH 15/39] Wallet API : transaction history in progress --- src/wallet/api/transaction_history.cpp | 37 +++++++++++++++++++++----- 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, 99 insertions(+), 24 deletions(-) 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(); + 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()))); + /* 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) From 53a97bdcd381342bc7d738946a628654a2261a52 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 22 Apr 2016 13:33:09 +0300 Subject: [PATCH 16/39] Wallet API: transaction history in progress --- src/wallet/api/transaction_history.cpp | 1 + src/wallet/api/transaction_info.cpp | 19 ++++++++++++------- src/wallet/api/transaction_info.h | 1 + src/wallet/wallet2_api.h | 1 + tests/libwallet_api_tests/main.cpp | 8 ++++---- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index 185cd164f..c7e7472e9 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -103,6 +103,7 @@ void TransactionHistoryImpl::refresh() 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); diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index c28c52355..578b84832 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -62,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::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 945b0d9ed..a06bc367e 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -49,6 +49,7 @@ public: virtual uint64_t amount() const; //! always 0 for incoming txes virtual uint64_t fee() const; + virtual uint64_t blockHeight() const; virtual std::string hash() const; virtual std::time_t timestamp() const; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index c4843d33f..4954db0d2 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -71,6 +71,7 @@ struct TransactionInfo virtual bool isFailed() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() 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; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 6921e6c3a..51c0a3ca3 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -31,7 +31,6 @@ #include "gtest/gtest.h" #include "wallet/wallet2_api.h" -#include "cryptonote_core/cryptonote_format_utils.h" #include #include @@ -299,8 +298,11 @@ TEST_F(WalletManagerTest, WalletHistory) auto transaction_print = [=] (Bitmonero::TransactionInfo * t) { std::cout << "d: " << (t->direction() == Bitmonero::TransactionInfo::Direction_In ? "in" : "out") - << ", a: " << t->amount() + << ", bh: " << t->blockHeight() + << ", a: " << Bitmonero::Wallet::displayAmount(t->amount()) + << ", f: " << Bitmonero::Wallet::displayAmount(t->fee()) << ", h: " << t->hash() + << ", pid: " << t->paymentId() << std::endl; }; @@ -308,8 +310,6 @@ TEST_F(WalletManagerTest, WalletHistory) ASSERT_TRUE(t != nullptr); transaction_print(t); } - - } From 566166aafd29bbca1f4916d4383752945892eb20 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 26 Apr 2016 13:46:20 +0300 Subject: [PATCH 17/39] 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 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); From 93119344ecb3326b452f2f8e91bc101fe1896f8c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 29 Apr 2016 16:26:14 +0300 Subject: [PATCH 18/39] TransactionHistory continued --- src/simplewallet/simplewallet.cpp | 5 ++ src/wallet/api/transaction_history.cpp | 79 ++++++++++++++++++++++++-- src/wallet/api/transaction_info.cpp | 17 ++++-- src/wallet/api/transaction_info.h | 7 ++- src/wallet/wallet2_api.h | 12 +++- tests/libwallet_api_tests/main.cpp | 66 +++++++++++++++++---- 6 files changed, 163 insertions(+), 23 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 29c92e049..226b9559f 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2641,6 +2641,10 @@ bool simple_wallet::show_transfers(const std::vector &args_) return true; } + if (in) { + + } + // optional in/out selector if (local_args.size() > 0) { if (local_args[0] == "in" || local_args[0] == "incoming") { @@ -2702,6 +2706,7 @@ bool simple_wallet::show_transfers(const std::vector &args_) } } + if (out) { std::list> payments; m_wallet->get_payments_out(payments, min_height, max_height); diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index c7e7472e9..db42e2141 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -82,8 +82,9 @@ void TransactionHistoryImpl::refresh() // delete old transactions; for (auto t : m_history) delete t; + m_history.clear(); + - std::list> payments; // transactions are stored in wallet2: // - confirmed_transfer_details - out transfers @@ -91,8 +92,11 @@ void TransactionHistoryImpl::refresh() // - 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) { + // one input transaction contains only one transfer. e.g. - <100XMR> + + std::list> in_payments; + m_wallet->m_wallet->get_payments(in_payments, min_height, max_height); + for (std::list>::const_iterator i = in_payments.begin(); i != in_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) @@ -111,8 +115,75 @@ void TransactionHistoryImpl::refresh() /* 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())));*/ + % payment_id % "-").str()))); */ } + + // confirmed output transactions + // one output transaction may contain more than one money transfer, e.g. + // : + // transfer1: 100XMR to + // transfer2: 50XMR to + // fee: fee charged per transaction + // + + std::list> out_payments; + m_wallet->m_wallet->get_payments_out(out_payments, min_height, max_height); + + for (std::list>::const_iterator i = out_payments.begin(); + i != out_payments.end(); ++i) { + + const crypto::hash &hash = i->first; + const tools::wallet2::confirmed_transfer_details &pd = i->second; + + uint64_t fee = pd.m_amount_in - pd.m_amount_out; + uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known + + + std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + + + TransactionInfoImpl * ti = new TransactionInfoImpl(); + ti->m_paymentid = payment_id; + ti->m_amount = pd.m_amount_in - change - fee; + ti->m_fee = fee; + ti->m_direction = TransactionInfo::Direction_Out; + ti->m_hash = string_tools::pod_to_hex(hash); + ti->m_blockheight = pd.m_block_height; + + // single output transaction might contain multiple transfers + for (const auto &d: pd.m_dests) { + ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->testnet(), d.addr)}); + } + m_history.push_back(ti); + } + + // unconfirmed output transactions + std::list> upayments; + m_wallet->m_wallet->get_unconfirmed_payments_out(upayments); + for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { + const tools::wallet2::unconfirmed_transfer_details &pd = i->second; + const crypto::hash &hash = i->first; + uint64_t amount = 0; + cryptonote::get_inputs_money_amount(pd.m_tx, amount); + uint64_t fee = amount - get_outs_money_amount(pd.m_tx); + std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; + + TransactionInfoImpl * ti = new TransactionInfoImpl(); + ti->m_paymentid = payment_id; + ti->m_amount = amount - pd.m_change; + ti->m_fee = fee; + ti->m_direction = TransactionInfo::Direction_Out; + ti->m_failed = is_failed; + ti->m_pending = true; + ti->m_hash = string_tools::pod_to_hex(hash); + m_history.push_back(ti); + } + } TransactionInfo *TransactionHistoryImpl::transaction(int index) const diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 578b84832..f25c53a90 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -37,9 +37,13 @@ namespace Bitmonero { TransactionInfo::~TransactionInfo() {} +TransactionInfo::Transfer::Transfer(uint64_t _amount, const string &_address) + : amount(_amount), address(_address) {} + + TransactionInfoImpl::TransactionInfoImpl() : m_direction(Direction_Out) - , m_hold(false) + , m_pending(false) , m_failed(false) , m_amount(0) , m_fee(0) @@ -56,13 +60,13 @@ TransactionInfoImpl::~TransactionInfoImpl() int TransactionInfoImpl::direction() const { - return TransactionInfo::Direction_In; + return m_direction; } -bool TransactionInfoImpl::isHold() const +bool TransactionInfoImpl::isPending() const { - return m_hold; + return m_pending; } bool TransactionInfoImpl::isFailed() const @@ -100,4 +104,9 @@ string TransactionInfoImpl::paymentId() const return m_paymentid; } +const std::vector &TransactionInfoImpl::transfers() const +{ + return m_transfers; +} + } // namespace diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index a06bc367e..82ab2cc6b 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -44,7 +44,7 @@ public: //! in/out virtual int direction() const; //! true if hold - virtual bool isHold() const; + virtual bool isPending() const; virtual bool isFailed() const; virtual uint64_t amount() const; //! always 0 for incoming txes @@ -54,10 +54,11 @@ public: virtual std::string hash() const; virtual std::time_t timestamp() const; virtual std::string paymentId() const; + virtual const std::vector &transfers() const; private: int m_direction; - bool m_hold; + bool m_pending; bool m_failed; uint64_t m_amount; uint64_t m_fee; @@ -65,7 +66,7 @@ private: std::string m_hash; std::time_t m_timestamp; std::string m_paymentid; - + std::vector m_transfers; friend class TransactionHistoryImpl; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index ab715dbf9..43f5c9472 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -68,16 +68,26 @@ struct TransactionInfo Direction_In, Direction_Out }; + + struct Transfer { + Transfer(uint64_t _amount, const std::string &address); + const uint64_t amount; + const std::string address; + }; + virtual ~TransactionInfo() = 0; virtual int direction() const = 0; - virtual bool isHold() const = 0; + virtual bool isPending() const = 0; virtual bool isFailed() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() const = 0; virtual uint64_t blockHeight() const = 0; + //! transaction_id virtual std::string hash() const = 0; virtual std::time_t timestamp() const = 0; virtual std::string paymentId() const = 0; + //! only applicable for output transactions + virtual const std::vector & transfers() const = 0; }; /** * @brief The TransactionHistory - interface for displaying transaction history diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 51c0a3ca3..35d0c8e9d 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -76,12 +76,19 @@ struct WalletManagerTest : public testing::Test // 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() { @@ -97,6 +104,20 @@ struct WalletManagerTest : public testing::Test std::cout << __FUNCTION__ << std::endl; //deleteWallet(WALLET_NAME); } + + 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; + } }; @@ -279,6 +300,7 @@ TEST_F(WalletManagerTest, WalletTransaction) RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR); ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); + ASSERT_TRUE(wallet1->balance() == balance); ASSERT_TRUE(transaction->amount() == AMOUNT_10XMR); ASSERT_TRUE(transaction->commit()); @@ -295,20 +317,42 @@ TEST_F(WalletManagerTest, WalletHistory) 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); + print_transaction(t); + } +} + +TEST_F(WalletManagerTest, WalletTransactionAndHistory) +{ + 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()); + 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); + print_transaction(t); + } + + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_10XMR * 5); + 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); + print_transaction(t); } } From 71131a84ea4e8ef8b3ad8084a14e0b5d2ec85e7a Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 5 May 2016 21:30:25 +0300 Subject: [PATCH 19/39] TransactionHistory continued --- src/simplewallet/simplewallet.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 226b9559f..29c92e049 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2641,10 +2641,6 @@ bool simple_wallet::show_transfers(const std::vector &args_) return true; } - if (in) { - - } - // optional in/out selector if (local_args.size() > 0) { if (local_args[0] == "in" || local_args[0] == "incoming") { @@ -2706,7 +2702,6 @@ bool simple_wallet::show_transfers(const std::vector &args_) } } - if (out) { std::list> payments; m_wallet->get_payments_out(payments, min_height, max_height); From 5dbd2b8fc3aa97f3a2e14a378cf6b7afd16bd4e2 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 5 May 2016 22:24:00 +0300 Subject: [PATCH 20/39] 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(-) 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; }; /** From ff52c67aa91cfb0042a5fdace708b7067dbe7271 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 13 May 2016 12:59:29 +0300 Subject: [PATCH 21/39] i_wallet_callback: virtual dtor --- src/wallet/wallet2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index d1127cae8..faddf9c70 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -61,6 +61,7 @@ namespace tools virtual void on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) {} virtual void on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) {} virtual void on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) {} + virtual ~i_wallet2_callback() {} }; struct tx_dust_policy From 27d86b73c63c7eea0473f11df348fc6a4a3b3e65 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 13 May 2016 16:25:31 +0300 Subject: [PATCH 22/39] WalletListener::moneySpent(), WalletListener::moneyReceived() --- src/wallet/api/wallet.cpp | 23 +++++++++++++++++++++-- src/wallet/wallet2_api.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) 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; }; From 40087a745f7677d29642c9ff86e1583c34ed1748 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 16 May 2016 13:11:44 +0300 Subject: [PATCH 23/39] WalletListener::moneySpent test --- src/wallet/api/wallet.cpp | 8 + src/wallet/wallet2_api.h | 4 +- tests/libwallet_api_tests/main.cpp | 225 +++++++++++++++++++++-------- 3 files changed, 173 insertions(+), 64 deletions(-) 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,52 +93,6 @@ struct Utils std::cout << "** removing dir recursively: " << path << std::endl; boost::filesystem::remove_all(path); } -}; - - -struct 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() - { - std::cout << __FUNCTION__ << std::endl; - wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); - Utils::deleteWallet(WALLET_NAME); - Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string()); - } - - - ~WalletManagerTest() - { - std::cout << __FUNCTION__ << std::endl; - //deleteWallet(WALLET_NAME); - } static void print_transaction(Bitmonero::TransactionInfo * t) { @@ -121,7 +110,56 @@ struct WalletManagerTest : public testing::Test }; -TEST_F(WalletManagerTest, WalletManagerCreatesWallet) +struct DISABLED_WalletManagerTest : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + + DISABLED_WalletManagerTest() + { + std::cout << __FUNCTION__ << std::endl; + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + Utils::deleteWallet(WALLET_NAME); + Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string()); + } + + + ~DISABLED_WalletManagerTest() + { + std::cout << __FUNCTION__ << std::endl; + //deleteWallet(WALLET_NAME); + } + +}; + + +struct DISABLED_WalletTest1 : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + DISABLED_WalletTest1() + { + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + } + + +}; + + +struct WalletTest2 : public testing::Test +{ + Bitmonero::WalletManager * wmgr; + + WalletTest2() + { + wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + } + + +}; + + +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) { From 9ae4e871a3617c931f21456ff30d2fd551a77a26 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Tue, 17 May 2016 12:16:11 +0300 Subject: [PATCH 24/39] WalletListener::moneyReceived test --- tests/libwallet_api_tests/main.cpp | 50 +++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index bdcf889ef..9ff2fb7c2 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -67,15 +67,16 @@ 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"; +const uint64_t AMOUNT_5XMR = 5000000000000L; +const uint64_t AMOUNT_1XMR = 1000000000000L; +const char * RECIPIENT_WALLET_ADDRESS = "9v9wAZ1aNj3CTgTPhEqLameUB25AkXknNHhPNjUozRxX1jrHLb9cdnn8kVf4r8GDJHjCjM5XKAWHp6Z38wsCudGWJ992byk"; +const char * TESTNET_WALLET3_ADDRESS = "A1koTipJ3Y8btatXupU3yYVAZrNG6W9z2WeYcirwHDmfZLaBGMPswq7CrYvemvCvp4atrqRhV1TBj3jYZv133CkAUeykAny"; +const char * TESTNET_WALLET4_ADDRESS = "A1R2sxZb2vY7fBjDxubxNDYfmzPmoWSrSAa7uokvWW2n7beJJnigAP43gfVpopdfd7YCFvMfVCpwQX39sXayicRr32hscyX"; } + using namespace Consts; struct Utils @@ -427,6 +428,7 @@ struct MyWalletListener : public Bitmonero::WalletListener } }; +/* TEST_F(WalletTest2, WalletCallbackSent) { @@ -436,17 +438,11 @@ TEST_F(WalletTest2, WalletCallbackSent) 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); + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5); ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); @@ -456,6 +452,36 @@ TEST_F(WalletTest2, WalletCallbackSent) wallet_src_listener->guard.try_lock_for(wait_for); ASSERT_TRUE(wallet_src_listener->total_tx != 0); +} +*/ + +TEST_F(WalletTest2, WalletCallbackReceived) +{ + + 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()); + 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_1XMR * 5; + std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS; + Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5); + ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); + ASSERT_TRUE(tx->commit()); + + std::chrono::seconds wait_for = std::chrono::seconds(60*3); + + wallet_dst_listener->guard.lock(); + wallet_dst_listener->guard.try_lock_for(wait_for); + + ASSERT_TRUE(wallet_dst_listener->total_tx != 0); } From d43ad225959fec0acdb23ed311b7b98c35968209 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 27 May 2016 10:00:01 +0300 Subject: [PATCH 25/39] all wallet dependencies merged to single static lib --- cmake/MergeStaticLibs.cmake | 118 ++++++++++++ cmake/libutils.cmake | 296 +++++++++++++++++++++++++++++ cmake/merge_archives_unix.cmake.in | 62 ++++++ src/wallet/CMakeLists.txt | 17 +- 4 files changed, 491 insertions(+), 2 deletions(-) create mode 100644 cmake/MergeStaticLibs.cmake create mode 100644 cmake/libutils.cmake create mode 100644 cmake/merge_archives_unix.cmake.in diff --git a/cmake/MergeStaticLibs.cmake b/cmake/MergeStaticLibs.cmake new file mode 100644 index 000000000..346687a72 --- /dev/null +++ b/cmake/MergeStaticLibs.cmake @@ -0,0 +1,118 @@ + + +# Merge_static_libs(outlib lib1 lib2 ... libn) merges a number of static +# libs into a single static library +function(merge_static_libs outlib ) + set(libs ${ARGV}) + list(REMOVE_AT libs 0) +# Create a dummy file that the target will depend on + set(dummyfile ${CMAKE_CURRENT_BINARY_DIR}/${outlib}_dummy.c) + file(WRITE ${dummyfile} "const char * dummy = \"${dummyfile}\";") + + add_library(${outlib} STATIC ${dummyfile}) + + if("${CMAKE_CFG_INTDIR}" STREQUAL ".") + set(multiconfig FALSE) + else() + set(multiconfig TRUE) + endif() + +# First get the file names of the libraries to be merged + foreach(lib ${libs}) + get_target_property(libtype ${lib} TYPE) + if(NOT libtype STREQUAL "STATIC_LIBRARY") + message(FATAL_ERROR "Merge_static_libs can only process static libraries") + endif() + if(multiconfig) + foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + get_target_property("libfile_${CONFIG_TYPE}" ${lib} "LOCATION_${CONFIG_TYPE}") + list(APPEND libfiles_${CONFIG_TYPE} ${libfile_${CONFIG_TYPE}}) + endforeach() + else() + get_target_property(libfile ${lib} LOCATION) + list(APPEND libfiles "${libfile}") + endif(multiconfig) + endforeach() + message(STATUS "will be merging ${libfiles}") +# Just to be sure: cleanup from duplicates + if(multiconfig) + foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + list(REMOVE_DUPLICATES libfiles_${CONFIG_TYPE}) + set(libfiles ${libfiles} ${libfiles_${CONFIG_TYPE}}) + endforeach() + endif() + list(REMOVE_DUPLICATES libfiles) + +# Now the easy part for MSVC and for MAC + if(MSVC) + # lib.exe does the merging of libraries just need to conver the list into string + foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + set(flags "") + foreach(lib ${libfiles_${CONFIG_TYPE}}) + set(flags "${flags} ${lib}") + endforeach() + string(TOUPPER "STATIC_LIBRARY_FLAGS_${CONFIG_TYPE}" PROPNAME) + set_target_properties(${outlib} PROPERTIES ${PROPNAME} "${flags}") + endforeach() + + elseif(APPLE) + # Use OSX's libtool to merge archives + if(multiconfig) + message(FATAL_ERROR "Multiple configurations are not supported") + endif() + get_target_property(outfile ${outlib} LOCATION) + add_custom_command(TARGET ${outlib} POST_BUILD + COMMAND rm ${outfile} + COMMAND /usr/bin/libtool -static -o ${outfile} + ${libfiles} + ) + else() + # general UNIX - need to "ar -x" and then "ar -ru" + if(multiconfig) + message(FATAL_ERROR "Multiple configurations are not supported") + endif() + get_target_property(outfile ${outlib} LOCATION) + message(STATUS "outfile location is ${outfile}") + foreach(lib ${libfiles}) +# objlistfile will contain the list of object files for the library + set(objlistfile ${lib}.objlist) + set(objdir ${lib}.objdir) + set(objlistcmake ${objlistfile}.cmake) +# we only need to extract files once + if(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/cmake.check_cache IS_NEWER_THAN ${objlistcmake}) +#--------------------------------- + FILE(WRITE ${objlistcmake} +"# Extract object files from the library +message(STATUS \"Extracting object files from ${lib}\") +EXECUTE_PROCESS(COMMAND ${CMAKE_AR} -x ${lib} + WORKING_DIRECTORY ${objdir}) +# save the list of object files +EXECUTE_PROCESS(COMMAND ls . + OUTPUT_FILE ${objlistfile} + WORKING_DIRECTORY ${objdir})") +#--------------------------------- + file(MAKE_DIRECTORY ${objdir}) + add_custom_command( + OUTPUT ${objlistfile} + COMMAND ${CMAKE_COMMAND} -P ${objlistcmake} + DEPENDS ${lib}) + endif() + list(APPEND extrafiles "${objlistfile}") + # relative path is needed by ar under MSYS + file(RELATIVE_PATH objlistfilerpath ${objdir} ${objlistfile}) + add_custom_command(TARGET ${outlib} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_AR} ru ${outfile} @${objlistfilerpath}" + COMMAND ${CMAKE_AR} ru "${outfile}" @"${objlistfilerpath}" + WORKING_DIRECTORY ${objdir}) + endforeach() + add_custom_command(TARGET ${outlib} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_RANLIB} ${outfile}" + COMMAND ${CMAKE_RANLIB} ${outfile}) + endif() + file(WRITE ${dummyfile}.base "const char* ${outlib}_sublibs=\"${libs}\";") + add_custom_command( + OUTPUT ${dummyfile} + COMMAND ${CMAKE_COMMAND} -E copy ${dummyfile}.base ${dummyfile} + DEPENDS ${libs} ${extrafiles}) + + endfunction() diff --git a/cmake/libutils.cmake b/cmake/libutils.cmake new file mode 100644 index 000000000..2263b146e --- /dev/null +++ b/cmake/libutils.cmake @@ -0,0 +1,296 @@ +# Copyright (C) 2009 Sun Microsystems, Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +# This file exports macros that emulate some functionality found in GNU libtool +# on Unix systems. One such feature is convenience libraries. In this context, +# convenience library is a static library that can be linked to shared library +# On systems that force position-independent code, linking into shared library +# normally requires compilation with a special flag (often -fPIC). To enable +# linking static libraries to shared, we compile source files that come into +# static library with the PIC flag (${CMAKE_SHARED_LIBRARY_C_FLAGS} in CMake) +# Some systems, like Windows or OSX do not need special compilation (Windows +# never uses PIC and OSX always uses it). +# +# The intention behind convenience libraries is simplify the build and to reduce +# excessive recompiles. + +# Except for convenience libraries, this file provides macros to merge static +# libraries (we need it for mysqlclient) and to create shared library out of +# convenience libraries(again, for mysqlclient) + +# Following macros are exported +# - ADD_CONVENIENCE_LIBRARY(target source1...sourceN) +# This macro creates convenience library. The functionality is similar to +# ADD_LIBRARY(target STATIC source1...sourceN), the difference is that resulting +# library can always be linked to shared library +# +# - MERGE_LIBRARIES(target [STATIC|SHARED|MODULE] [linklib1 .... linklibN] +# [EXPORTS exported_func1 .... exported_func_N] +# [OUTPUT_NAME output_name] +# This macro merges several static libraries into a single one or creates a shared +# library from several convenience libraries + +# Important global flags +# - WITH_PIC : If set, it is assumed that everything is compiled as position +# independent code (that is CFLAGS/CMAKE_C_FLAGS contain -fPIC or equivalent) +# If defined, ADD_CONVENIENCE_LIBRARY does not add PIC flag to compile flags +# +# - DISABLE_SHARED: If set, it is assumed that shared libraries are not produced +# during the build. ADD_CONVENIENCE_LIBRARY does not add anything to compile flags + + +GET_FILENAME_COMPONENT(MYSQL_CMAKE_SCRIPT_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) +IF(WIN32 OR CYGWIN OR APPLE OR WITH_PIC OR DISABLE_SHARED OR NOT CMAKE_SHARED_LIBRARY_C_FLAGS) + SET(_SKIP_PIC 1) +ENDIF() + +INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/cmake_parse_arguments.cmake) +# CREATE_EXPORT_FILE (VAR target api_functions) +# Internal macro, used to create source file for shared libraries that +# otherwise consists entirely of "convenience" libraries. On Windows, +# also exports API functions as dllexport. On unix, creates a dummy file +# that references all exports and this prevents linker from creating an +# empty library(there are unportable alternatives, --whole-archive) +MACRO(CREATE_EXPORT_FILE VAR TARGET API_FUNCTIONS) + IF(WIN32) + SET(DUMMY ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_dummy.c) + SET(EXPORTS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_exports.def) + CONFIGURE_FILE_CONTENT("" ${DUMMY}) + SET(CONTENT "EXPORTS\n") + FOREACH(FUNC ${API_FUNCTIONS}) + SET(CONTENT "${CONTENT} ${FUNC}\n") + ENDFOREACH() + CONFIGURE_FILE_CONTENT(${CONTENT} ${EXPORTS}) + SET(${VAR} ${DUMMY} ${EXPORTS}) + ELSE() + SET(EXPORTS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_exports_file.cc) + SET(CONTENT) + FOREACH(FUNC ${API_FUNCTIONS}) + SET(CONTENT "${CONTENT} extern void* ${FUNC}\;\n") + ENDFOREACH() + SET(CONTENT "${CONTENT} void *${TARGET}_api_funcs[] = {\n") + FOREACH(FUNC ${API_FUNCTIONS}) + SET(CONTENT "${CONTENT} &${FUNC},\n") + ENDFOREACH() + SET(CONTENT "${CONTENT} (void *)0\n}\;") + CONFIGURE_FILE_CONTENT(${CONTENT} ${EXPORTS}) + SET(${VAR} ${EXPORTS}) + ENDIF() +ENDMACRO() + + +# MYSQL_ADD_CONVENIENCE_LIBRARY(name source1...sourceN) +# Create static library that can be linked to shared library. +# On systems that force position-independent code, adds -fPIC or +# equivalent flag to compile flags. +MACRO(ADD_CONVENIENCE_LIBRARY) + SET(TARGET ${ARGV0}) + SET(SOURCES ${ARGN}) + LIST(REMOVE_AT SOURCES 0) + ADD_LIBRARY(${TARGET} STATIC ${SOURCES}) + IF(NOT _SKIP_PIC) + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES COMPILE_FLAGS + "${CMAKE_SHARED_LIBRARY_C_FLAGS}") + ENDIF() +ENDMACRO() + + +# Write content to file, using CONFIGURE_FILE +# The advantage compared to FILE(WRITE) is that timestamp +# does not change if file already has the same content +MACRO(CONFIGURE_FILE_CONTENT content file) + SET(CMAKE_CONFIGURABLE_FILE_CONTENT + "${content}\n") + CONFIGURE_FILE( + ${MYSQL_CMAKE_SCRIPT_DIR}/configurable_file_content.in + ${file} + @ONLY) +ENDMACRO() + +# Merge static libraries into a big static lib. The resulting library +# should not not have dependencies on other static libraries. +# We use it in MySQL to merge mysys,dbug,vio etc into mysqlclient + +MACRO(MERGE_STATIC_LIBS TARGET OUTPUT_NAME LIBS_TO_MERGE) + # To produce a library we need at least one source file. + # It is created by ADD_CUSTOM_COMMAND below and will helps + # also help to track dependencies. + SET(SOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_depends.c) + ADD_LIBRARY(${TARGET} STATIC ${SOURCE_FILE}) + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES OUTPUT_NAME ${OUTPUT_NAME}) + + SET(OSLIBS) + FOREACH(LIB ${LIBS_TO_MERGE}) + GET_TARGET_PROPERTY(LIB_LOCATION ${LIB} LOCATION) + GET_TARGET_PROPERTY(LIB_TYPE ${LIB} TYPE) + IF(NOT LIB_LOCATION) + # 3rd party library like libz.so. Make sure that everything + # that links to our library links to this one as well. + LIST(APPEND OSLIBS ${LIB}) + ELSE() + # This is a target in current project + # (can be a static or shared lib) + IF(LIB_TYPE STREQUAL "STATIC_LIBRARY") + SET(STATIC_LIBS ${STATIC_LIBS} ${LIB_LOCATION}) + ADD_DEPENDENCIES(${TARGET} ${LIB}) + # Extract dependend OS libraries + GET_DEPENDEND_OS_LIBS(${LIB} LIB_OSLIBS) + LIST(APPEND OSLIBS ${LIB_OSLIBS}) + ELSE() + # This is a shared library our static lib depends on. + LIST(APPEND OSLIBS ${LIB}) + ENDIF() + ENDIF() + ENDFOREACH() + IF(OSLIBS) + LIST(REMOVE_DUPLICATES OSLIBS) + TARGET_LINK_LIBRARIES(${TARGET} ${OSLIBS}) + ENDIF() + + # Make the generated dummy source file depended on all static input + # libs. If input lib changes,the source file is touched + # which causes the desired effect (relink). + ADD_CUSTOM_COMMAND( + OUTPUT ${SOURCE_FILE} + COMMAND ${CMAKE_COMMAND} -E touch ${SOURCE_FILE} + DEPENDS ${STATIC_LIBS}) + + IF(MSVC) + # To merge libs, just pass them to lib.exe command line. + SET(LINKER_EXTRA_FLAGS "") + FOREACH(LIB ${STATIC_LIBS}) + SET(LINKER_EXTRA_FLAGS "${LINKER_EXTRA_FLAGS} ${LIB}") + ENDFOREACH() + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES STATIC_LIBRARY_FLAGS + "${LINKER_EXTRA_FLAGS}") + ELSE() + GET_TARGET_PROPERTY(TARGET_LOCATION ${TARGET} LOCATION) + IF(APPLE) + # Use OSX's libtool to merge archives (ihandles universal + # binaries properly) + ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD + COMMAND rm ${TARGET_LOCATION} + COMMAND /usr/bin/libtool -static -o ${TARGET_LOCATION} + ${STATIC_LIBS} + ) + ELSE() + # Generic Unix, Cygwin or MinGW. In post-build step, call + # script, that extracts objects from archives with "ar x" + # and repacks them with "ar r" + SET(TARGET ${TARGET}) + CONFIGURE_FILE( + ${MYSQL_CMAKE_SCRIPT_DIR}/merge_archives_unix.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/merge_archives_${TARGET}.cmake + @ONLY + ) + ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD + COMMAND rm ${TARGET_LOCATION} + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_BINARY_DIR}/merge_archives_${TARGET}.cmake + ) + ENDIF() + ENDIF() +ENDMACRO() + +# Create libs from libs. +# Merges static libraries, creates shared libraries out of convenience libraries. +# MERGE_LIBRARIES(target [STATIC|SHARED|MODULE] +# [linklib1 .... linklibN] +# [EXPORTS exported_func1 .... exportedFuncN] +# [OUTPUT_NAME output_name] +#) +MACRO(MERGE_LIBRARIES) + CMAKE_PARSE_ARGUMENTS(ARG + "EXPORTS;OUTPUT_NAME" + "STATIC;SHARED;MODULE;NOINSTALL" + ${ARGN} + ) + LIST(GET ARG_DEFAULT_ARGS 0 TARGET) + SET(LIBS ${ARG_DEFAULT_ARGS}) + LIST(REMOVE_AT LIBS 0) + IF(ARG_STATIC) + IF (NOT ARG_OUTPUT_NAME) + SET(ARG_OUTPUT_NAME ${TARGET}) + ENDIF() + MERGE_STATIC_LIBS(${TARGET} ${ARG_OUTPUT_NAME} "${LIBS}") + ELSEIF(ARG_SHARED OR ARG_MODULE) + IF(ARG_SHARED) + SET(LIBTYPE SHARED) + ELSE() + SET(LIBTYPE MODULE) + ENDIF() + # check for non-PIC libraries + IF(NOT _SKIP_PIC) + FOREACH(LIB ${LIBS}) + GET_TARGET_PROPERTY(${LIB} TYPE LIBTYPE) + IF(LIBTYPE STREQUAL "STATIC_LIBRARY") + GET_TARGET_PROPERTY(LIB COMPILE_FLAGS LIB_COMPILE_FLAGS) + STRING(REPLACE "${CMAKE_SHARED_LIBRARY_C_FLAGS}" + "" LIB_COMPILE_FLAGS ${LIB_COMPILE_FLAG}) + IF(NOT LIB_COMPILE_FLAGS MATCHES "") + MESSAGE(FATAL_ERROR + "Attempted to link non-PIC static library ${LIB} to shared library ${TARGET}\n" + "Please use ADD_CONVENIENCE_LIBRARY, instead of ADD_LIBRARY for ${LIB}" + ) + ENDIF() + ENDIF() + ENDFOREACH() + ENDIF() + CREATE_EXPORT_FILE(SRC ${TARGET} "${ARG_EXPORTS}") + ADD_LIBRARY(${TARGET} ${LIBTYPE} ${SRC}) + TARGET_LINK_LIBRARIES(${TARGET} ${LIBS}) + IF(ARG_OUTPUT_NAME) + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES OUTPUT_NAME "${ARG_OUTPUT_NAME}") + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Unknown library type") + ENDIF() + IF(NOT ARG_NOINSTALL) + MYSQL_INSTALL_TARGETS(${TARGET} DESTINATION "${INSTALL_LIBDIR}") + ENDIF() + SET_TARGET_PROPERTIES(${TARGET} PROPERTIES LINK_INTERFACE_LIBRARIES "") +ENDMACRO() + +FUNCTION(GET_DEPENDEND_OS_LIBS target result) + SET(deps ${${target}_LIB_DEPENDS}) + IF(deps) + FOREACH(lib ${deps}) + # Filter out keywords for used for debug vs optimized builds + IF(NOT lib MATCHES "general" AND NOT lib MATCHES "debug" AND NOT lib MATCHES "optimized") + GET_TARGET_PROPERTY(lib_location ${lib} LOCATION) + IF(NOT lib_location) + SET(ret ${ret} ${lib}) + ENDIF() + ENDIF() + ENDFOREACH() + ENDIF() + SET(${result} ${ret} PARENT_SCOPE) +ENDFUNCTION() + +MACRO(RESTRICT_SYMBOL_EXPORTS target) + IF(CMAKE_COMPILER_IS_GNUCXX AND UNIX) + CHECK_C_COMPILER_FLAG("-fvisibility=hidden" HAVE_VISIBILITY_HIDDEN) + IF(HAVE_VISIBILITY_HIDDEN) + GET_TARGET_PROPERTY(COMPILE_FLAGS ${target} COMPILE_FLAGS) + IF(NOT COMPILE_FLAGS) + # Avoid COMPILE_FLAGS-NOTFOUND + SET(COMPILE_FLAGS) + ENDIF() + SET_TARGET_PROPERTIES(${target} PROPERTIES + COMPILE_FLAGS "${COMPILE_FLAGS} -fvisibility=hidden") + ENDIF() + ENDIF() +ENDMACRO() diff --git a/cmake/merge_archives_unix.cmake.in b/cmake/merge_archives_unix.cmake.in new file mode 100644 index 000000000..a9a060ab4 --- /dev/null +++ b/cmake/merge_archives_unix.cmake.in @@ -0,0 +1,62 @@ +# Copyright (C) 2009 Sun Microsystems, Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# This script merges many static libraries into +# one big library on Unix. +SET(TARGET_LOCATION "@TARGET_LOCATION@") +SET(TARGET "@TARGET@") +SET(STATIC_LIBS "@STATIC_LIBS@") +SET(CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@") +SET(CMAKE_AR "@CMAKE_AR@") +SET(CMAKE_RANLIB "@CMAKE_RANLIB@") + + +SET(TEMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/merge_archives_${TARGET}) +MAKE_DIRECTORY(${TEMP_DIR}) +# Extract each archive to its own subdirectory(avoid object filename clashes) +FOREACH(LIB ${STATIC_LIBS}) + GET_FILENAME_COMPONENT(NAME_NO_EXT ${LIB} NAME_WE) + SET(TEMP_SUBDIR ${TEMP_DIR}/${NAME_NO_EXT}) + MAKE_DIRECTORY(${TEMP_SUBDIR}) + EXECUTE_PROCESS( + COMMAND ${CMAKE_AR} -x ${LIB} + WORKING_DIRECTORY ${TEMP_SUBDIR} + ) + + FILE(GLOB_RECURSE LIB_OBJECTS "${TEMP_SUBDIR}/*") + SET(OBJECTS ${OBJECTS} ${LIB_OBJECTS}) +ENDFOREACH() + +# Use relative paths, makes command line shorter. +GET_FILENAME_COMPONENT(ABS_TEMP_DIR ${TEMP_DIR} ABSOLUTE) +FOREACH(OBJ ${OBJECTS}) + FILE(RELATIVE_PATH OBJ ${ABS_TEMP_DIR} ${OBJ}) + FILE(TO_NATIVE_PATH ${OBJ} OBJ) + SET(ALL_OBJECTS ${ALL_OBJECTS} ${OBJ}) +ENDFOREACH() + +FILE(TO_NATIVE_PATH ${TARGET_LOCATION} ${TARGET_LOCATION}) +# Now pack the objects into library with ar. +EXECUTE_PROCESS( + COMMAND ${CMAKE_AR} -r ${TARGET_LOCATION} ${ALL_OBJECTS} + WORKING_DIRECTORY ${TEMP_DIR} +) +EXECUTE_PROCESS( + COMMAND ${CMAKE_RANLIB} ${TARGET_LOCATION} + WORKING_DIRECTORY ${TEMP_DIR} +) + +# Cleanup +FILE(REMOVE_RECURSE ${TEMP_DIR}) diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index 49f936f5c..df31acf48 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -26,6 +26,7 @@ # 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. +include (${PROJECT_SOURCE_DIR}/cmake/libutils.cmake) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -39,11 +40,12 @@ set(wallet_sources api/pending_transaction.cpp api/utils.cpp) -set(wallet_headers) +set(wallet_headers + wallet2_api.h) + set(wallet_private_headers wallet2.h - wallet2_api.h wallet_errors.h wallet_rpc_server.h wallet_rpc_server_commands_defs.h @@ -72,3 +74,14 @@ target_link_libraries(wallet ${Boost_REGEX_LIBRARY} ${EXTRA_LIBRARIES}) + +set(libs_to_merge wallet cryptonote_core mnemonics common crypto) +MERGE_STATIC_LIBS(wallet_merged wallet_merged "${libs_to_merge}") + +install(TARGETS wallet_merged + ARCHIVE DESTINATION lib) + +install(FILES ${wallet_api_headers} + DESTINATION include/wallet) + + From 1f0d016f44d602d82941594c7d3965e604d9ca78 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 27 May 2016 10:08:25 +0300 Subject: [PATCH 26/39] cmake libutils dependency added --- cmake/cmake_parse_arguments.cmake | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 cmake/cmake_parse_arguments.cmake diff --git a/cmake/cmake_parse_arguments.cmake b/cmake/cmake_parse_arguments.cmake new file mode 100644 index 000000000..72200ad5b --- /dev/null +++ b/cmake/cmake_parse_arguments.cmake @@ -0,0 +1,46 @@ +# Copyright (C) 2007 MySQL AB, 2009 Sun Microsystems,Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Handy macro to parse macro arguments +MACRO(MYSQL_PARSE_ARGUMENTS prefix arg_names option_names) + SET(DEFAULT_ARGS) + FOREACH(arg_name ${arg_names}) + SET(${prefix}_${arg_name}) + ENDFOREACH(arg_name) + FOREACH(option ${option_names}) + SET(${prefix}_${option} FALSE) + ENDFOREACH(option) + + SET(current_arg_name DEFAULT_ARGS) + SET(current_arg_list) + FOREACH(arg ${ARGN}) + SET(larg_names ${arg_names}) + LIST(FIND larg_names "${arg}" is_arg_name) + IF (is_arg_name GREATER -1) + SET(${prefix}_${current_arg_name} ${current_arg_list}) + SET(current_arg_name ${arg}) + SET(current_arg_list) + ELSE (is_arg_name GREATER -1) + SET(loption_names ${option_names}) + LIST(FIND loption_names "${arg}" is_option) + IF (is_option GREATER -1) + SET(${prefix}_${arg} TRUE) + ELSE (is_option GREATER -1) + SET(current_arg_list ${current_arg_list} ${arg}) + ENDIF (is_option GREATER -1) + ENDIF (is_arg_name GREATER -1) + ENDFOREACH(arg) + SET(${prefix}_${current_arg_name} ${current_arg_list}) +ENDMACRO() From 7ac134254f68b7a82fdc364d0ea1a41598089eb8 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 27 May 2016 10:42:31 +0300 Subject: [PATCH 27/39] cmake: BUILD_TESTS as option explicitly; added missed dependency --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9674404bb..c375defe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -436,6 +436,9 @@ include(version.cmake) add_subdirectory(contrib) add_subdirectory(src) + +option(BUILD_TESTS "Build tests." OFF) + if(BUILD_TESTS) add_subdirectory(tests) endif() From 4327548915bbeb78d2ed3b5153543d97b62f8b4b Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 27 May 2016 10:58:07 +0300 Subject: [PATCH 28/39] installing wallet_api header --- src/wallet/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index df31acf48..119d46540 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -40,7 +40,7 @@ set(wallet_sources api/pending_transaction.cpp api/utils.cpp) -set(wallet_headers +set(wallet_api_headers wallet2_api.h) @@ -61,7 +61,7 @@ bitmonero_private_headers(wallet ${wallet_private_headers}) bitmonero_add_library(wallet ${wallet_sources} - ${wallet_headers} + ${wallet_api_headers} ${wallet_private_headers}) target_link_libraries(wallet LINK_PUBLIC From 7f3d28fe1bb730fb4aa8430418f7c207a87dc78b Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 27 May 2016 13:35:00 +0300 Subject: [PATCH 29/39] regenerated test wallets, basic functions got broken --- tests/libwallet_api_tests/main.cpp | 37 ++++++++++++++++-------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index 9ff2fb7c2..ed85555cd 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -59,7 +59,7 @@ 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_WALLET1_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 = ""; @@ -70,9 +70,10 @@ const uint64_t AMOUNT_10XMR = 10000000000000L; const uint64_t AMOUNT_5XMR = 5000000000000L; const uint64_t AMOUNT_1XMR = 1000000000000L; -const char * RECIPIENT_WALLET_ADDRESS = "9v9wAZ1aNj3CTgTPhEqLameUB25AkXknNHhPNjUozRxX1jrHLb9cdnn8kVf4r8GDJHjCjM5XKAWHp6Z38wsCudGWJ992byk"; -const char * TESTNET_WALLET3_ADDRESS = "A1koTipJ3Y8btatXupU3yYVAZrNG6W9z2WeYcirwHDmfZLaBGMPswq7CrYvemvCvp4atrqRhV1TBj3jYZv133CkAUeykAny"; -const char * TESTNET_WALLET4_ADDRESS = "A1R2sxZb2vY7fBjDxubxNDYfmzPmoWSrSAa7uokvWW2n7beJJnigAP43gfVpopdfd7YCFvMfVCpwQX39sXayicRr32hscyX"; + +const char * TESTNET_WALLET3_ADDRESS = "A2N8LNKkzH2ddepepgvmz9e4JRe5QXkoPjg9kHW5CLWvH7eQNqEvNWmjJziVSqVLfUXVz7CYe5MZ32qJryVr8eBCLG5yJXP"; +const char * TESTNET_WALLET4_ADDRESS = "9yMPpGDhXrPMEFk2AueB9EVP3oJtovj1zRiSKz481xVAFW6tDyft8H6WE9otfBLzzHCUQ98xRogjk3oiPQA2Qy5tKpsNhyE"; +const char * RECIPIENT_WALLET_ADDRESS = TESTNET_WALLET4_ADDRESS; } @@ -134,11 +135,11 @@ struct DISABLED_WalletManagerTest : public testing::Test }; -struct DISABLED_WalletTest1 : public testing::Test +struct WalletTest1 : public testing::Test { Bitmonero::WalletManager * wmgr; - DISABLED_WalletTest1() + WalletTest1() { wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); } @@ -300,16 +301,16 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet4) -TEST_F(DISABLED_WalletTest1, WalletShowsBalance) +TEST_F(WalletTest1, WalletShowsBalance) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); ASSERT_TRUE(wallet1->balance() > 0); ASSERT_TRUE(wallet1->unlockedBalance() > 0); uint64_t balance1 = wallet1->balance(); uint64_t unlockedBalance1 = wallet1->unlockedBalance(); ASSERT_TRUE(wmgr->closeWallet(wallet1)); - Bitmonero::Wallet * wallet2 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet2 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); ASSERT_TRUE(balance1 == wallet2->balance()); std::cout << "wallet balance: " << wallet2->balance() << std::endl; @@ -318,18 +319,18 @@ TEST_F(DISABLED_WalletTest1, WalletShowsBalance) ASSERT_TRUE(wmgr->closeWallet(wallet2)); } -TEST_F(DISABLED_WalletTest1, WalletRefresh) +TEST_F(WalletTest1, WalletRefresh) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet1->refresh()); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(DISABLED_WalletTest1, WalletTransaction) +TEST_F(WalletTest1, WalletTransaction) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet1->refresh()); @@ -348,9 +349,9 @@ TEST_F(DISABLED_WalletTest1, WalletTransaction) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(DISABLED_WalletTest1, WalletHistory) +TEST_F(WalletTest1, WalletHistory) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0)); ASSERT_TRUE(wallet1->refresh()); @@ -365,7 +366,7 @@ TEST_F(DISABLED_WalletTest1, WalletHistory) } } -TEST_F(DISABLED_WalletTest1, WalletTransactionAndHistory) +TEST_F(WalletTest1, WalletTransactionAndHistory) { Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); // make sure testnet daemon is running @@ -455,6 +456,7 @@ TEST_F(WalletTest2, WalletCallbackSent) } */ +/* TEST_F(WalletTest2, WalletCallbackReceived) { @@ -476,7 +478,7 @@ TEST_F(WalletTest2, WalletCallbackReceived) ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); - std::chrono::seconds wait_for = std::chrono::seconds(60*3); + std::chrono::seconds wait_for = std::chrono::seconds(60*4); wallet_dst_listener->guard.lock(); wallet_dst_listener->guard.try_lock_for(wait_for); @@ -484,6 +486,7 @@ TEST_F(WalletTest2, WalletCallbackReceived) ASSERT_TRUE(wallet_dst_listener->total_tx != 0); } +*/ int main(int argc, char** argv) { From ec949c383c1829536874550b84d9966d20707f60 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 1 Jun 2016 17:06:10 +0300 Subject: [PATCH 30/39] scripts for faster test wallets generation --- tests/libwallet_api_tests/main.cpp | 66 +++++++++++++------ .../scripts/create_wallets.sh | 20 ++++++ .../scripts/mining_start.sh | 4 ++ .../scripts/mining_stop.sh | 4 ++ .../scripts/open_wallet_1.sh | 5 ++ .../scripts/open_wallet_2.sh | 5 ++ .../scripts/open_wallet_3.sh | 4 ++ .../scripts/open_wallet_4.sh | 4 ++ .../scripts/open_wallet_5.sh | 4 ++ .../scripts/open_wallet_miner.sh | 4 ++ .../libwallet_api_tests/scripts/send_funds.sh | 21 ++++++ 11 files changed, 121 insertions(+), 20 deletions(-) create mode 100755 tests/libwallet_api_tests/scripts/create_wallets.sh create mode 100755 tests/libwallet_api_tests/scripts/mining_start.sh create mode 100755 tests/libwallet_api_tests/scripts/mining_stop.sh create mode 100755 tests/libwallet_api_tests/scripts/open_wallet_1.sh create mode 100755 tests/libwallet_api_tests/scripts/open_wallet_2.sh create mode 100755 tests/libwallet_api_tests/scripts/open_wallet_3.sh create mode 100755 tests/libwallet_api_tests/scripts/open_wallet_4.sh create mode 100755 tests/libwallet_api_tests/scripts/open_wallet_5.sh create mode 100755 tests/libwallet_api_tests/scripts/open_wallet_miner.sh create mode 100755 tests/libwallet_api_tests/scripts/send_funds.sh diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index ed85555cd..ebd29ee1e 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -44,11 +44,10 @@ 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"; @@ -59,21 +58,32 @@ const char * WALLET_PASS = "password"; const char * WALLET_PASS2 = "password22"; const char * WALLET_LANG = "English"; -const char * TESTNET_WALLET1_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"; +// change this according your environment + +const std::string WALLETS_ROOT_DIR = "/home/mbg033/dev/monero/testnet/"; + +//const char * TESTNET_WALLET1_NAME = "/home/mbg033/dev/monero/testnet/wallet_01.bin"; +//const char * TESTNET_WALLET2_NAME = "/home/mbg033/dev/monero/testnet/wallet_02.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_WALLET5_NAME = "/home/mbg033/dev/monero/testnet/wallet_05.bin"; + +const std::string TESTNET_WALLET1_NAME = WALLETS_ROOT_DIR + "wallet_01.bin"; +const std::string TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "wallet_02.bin"; +const std::string TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "wallet_03.bin"; +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 char * TESTNET_WALLET_PASS = ""; +const std::string CURRENT_SRC_WALLET = TESTNET_WALLET1_NAME; +const std::string CURRENT_DST_WALLET = TESTNET_WALLET5_NAME; const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; -const uint64_t AMOUNT_10XMR = 10000000000000L; +const uint64_t AMOUNT_10XMR = 10000000000000L; const uint64_t AMOUNT_5XMR = 5000000000000L; const uint64_t AMOUNT_1XMR = 1000000000000L; - -const char * TESTNET_WALLET3_ADDRESS = "A2N8LNKkzH2ddepepgvmz9e4JRe5QXkoPjg9kHW5CLWvH7eQNqEvNWmjJziVSqVLfUXVz7CYe5MZ32qJryVr8eBCLG5yJXP"; -const char * TESTNET_WALLET4_ADDRESS = "9yMPpGDhXrPMEFk2AueB9EVP3oJtovj1zRiSKz481xVAFW6tDyft8H6WE9otfBLzzHCUQ98xRogjk3oiPQA2Qy5tKpsNhyE"; -const char * RECIPIENT_WALLET_ADDRESS = TESTNET_WALLET4_ADDRESS; } @@ -109,6 +119,15 @@ struct Utils << ", pid: " << t->paymentId() << std::endl; } + + static std::string get_wallet_address(const std::string &filename, const std::string &password) + { + Bitmonero::WalletManager *wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); + Bitmonero::Wallet * w = wmgr->openWallet(filename, password, true); + std::string result = w->address(); + wmgr->closeWallet(w); + return result; + } }; @@ -303,14 +322,16 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet4) TEST_F(WalletTest1, WalletShowsBalance) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); + // TODO: temporary disabled; + return; + Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); ASSERT_TRUE(wallet1->balance() > 0); ASSERT_TRUE(wallet1->unlockedBalance() > 0); uint64_t balance1 = wallet1->balance(); uint64_t unlockedBalance1 = wallet1->unlockedBalance(); ASSERT_TRUE(wmgr->closeWallet(wallet1)); - Bitmonero::Wallet * wallet2 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); + Bitmonero::Wallet * wallet2 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); ASSERT_TRUE(balance1 == wallet2->balance()); std::cout << "wallet balance: " << wallet2->balance() << std::endl; @@ -321,7 +342,7 @@ TEST_F(WalletTest1, WalletShowsBalance) TEST_F(WalletTest1, WalletRefresh) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); + 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()); @@ -330,17 +351,19 @@ TEST_F(WalletTest1, WalletRefresh) TEST_F(WalletTest1, WalletTransaction) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); + 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); - Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( - RECIPIENT_WALLET_ADDRESS, AMOUNT_10XMR); - ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); + std::string recepient_address = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS); + Bitmonero::PendingTransaction * transaction = wallet1->createTransaction( + recepient_address, AMOUNT_10XMR); + ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok); + wallet1->refresh(); ASSERT_TRUE(wallet1->balance() == balance); ASSERT_TRUE(transaction->amount() == AMOUNT_10XMR); @@ -351,7 +374,7 @@ TEST_F(WalletTest1, WalletTransaction) TEST_F(WalletTest1, WalletHistory) { - Bitmonero::Wallet * wallet1 = wmgr->openWallet(TESTNET_WALLET1_NAME, TESTNET_WALLET_PASS, true); + 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()); @@ -368,7 +391,8 @@ TEST_F(WalletTest1, WalletHistory) TEST_F(WalletTest1, WalletTransactionAndHistory) { - Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true); + return; + 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()); @@ -383,7 +407,9 @@ TEST_F(WalletTest1, WalletTransactionAndHistory) Utils::print_transaction(t); } - Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_10XMR * 5); + 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); ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok); ASSERT_TRUE(tx->commit()); history = wallet_src->history(); diff --git a/tests/libwallet_api_tests/scripts/create_wallets.sh b/tests/libwallet_api_tests/scripts/create_wallets.sh new file mode 100755 index 000000000..fd3db838c --- /dev/null +++ b/tests/libwallet_api_tests/scripts/create_wallets.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +function create_wallet { + wallet_name=$1 + echo 0 | simplewallet --testnet --trusted-daemon --daemon-address localhost:38081 --generate-new-wallet $wallet_name --password "" --restore-height=1 +} + + + +create_wallet wallet_01.bin +create_wallet wallet_02.bin +create_wallet wallet_03.bin +#create_wallet wallet_04.bin +create_wallet wallet_05.bin +create_wallet wallet_06.bin + + +#create_wallet wallet_m + + diff --git a/tests/libwallet_api_tests/scripts/mining_start.sh b/tests/libwallet_api_tests/scripts/mining_start.sh new file mode 100755 index 000000000..76eabfc55 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/mining_start.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log start_mining + diff --git a/tests/libwallet_api_tests/scripts/mining_stop.sh b/tests/libwallet_api_tests/scripts/mining_stop.sh new file mode 100755 index 000000000..640e56943 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/mining_stop.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_miner.log stop_mining + diff --git a/tests/libwallet_api_tests/scripts/open_wallet_1.sh b/tests/libwallet_api_tests/scripts/open_wallet_1.sh new file mode 100755 index 000000000..08f4e28ab --- /dev/null +++ b/tests/libwallet_api_tests/scripts/open_wallet_1.sh @@ -0,0 +1,5 @@ +#!/bin/bash + + +rlwrap simplewallet --wallet-file wallet_01.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log + diff --git a/tests/libwallet_api_tests/scripts/open_wallet_2.sh b/tests/libwallet_api_tests/scripts/open_wallet_2.sh new file mode 100755 index 000000000..8a16a6647 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/open_wallet_2.sh @@ -0,0 +1,5 @@ +#!/bin/bash + + +rlwrap simplewallet --wallet-file wallet_02.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log + diff --git a/tests/libwallet_api_tests/scripts/open_wallet_3.sh b/tests/libwallet_api_tests/scripts/open_wallet_3.sh new file mode 100755 index 000000000..64a04b3c4 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/open_wallet_3.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rlwrap simplewallet --wallet-file wallet_03.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_03.log + diff --git a/tests/libwallet_api_tests/scripts/open_wallet_4.sh b/tests/libwallet_api_tests/scripts/open_wallet_4.sh new file mode 100755 index 000000000..8ebf0a4c7 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/open_wallet_4.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rlwrap simplewallet --wallet-file wallet_04.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_04.log + diff --git a/tests/libwallet_api_tests/scripts/open_wallet_5.sh b/tests/libwallet_api_tests/scripts/open_wallet_5.sh new file mode 100755 index 000000000..8ebf0a4c7 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/open_wallet_5.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rlwrap simplewallet --wallet-file wallet_04.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_04.log + diff --git a/tests/libwallet_api_tests/scripts/open_wallet_miner.sh b/tests/libwallet_api_tests/scripts/open_wallet_miner.sh new file mode 100755 index 000000000..07a4e58ea --- /dev/null +++ b/tests/libwallet_api_tests/scripts/open_wallet_miner.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rlwrap simplewallet --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address 127.0.0.1:38081 --log-file wallet_m.log + diff --git a/tests/libwallet_api_tests/scripts/send_funds.sh b/tests/libwallet_api_tests/scripts/send_funds.sh new file mode 100755 index 000000000..801d63609 --- /dev/null +++ b/tests/libwallet_api_tests/scripts/send_funds.sh @@ -0,0 +1,21 @@ +#!/bin/bash + + + +function send_funds { + local amount=$1 + local dest=$(cat "$2.address.txt") + + simplewallet --wallet-file wallet_m --password "" \ + --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log \ + --command transfer $dest $amount +} + + +send_funds 100 wallet_01.bin +send_funds 100 wallet_02.bin +send_funds 100 wallet_03.bin +send_funds 100 wallet_04.bin +send_funds 100 wallet_05.bin + + From 2facbe77e485e8a824a08d862aa63f3f179480e9 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 3 Jun 2016 14:52:58 +0300 Subject: [PATCH 31/39] Wallet API : WalletManager::findWallets() added --- src/wallet/api/wallet_manager.cpp | 37 ++++++++++++++++++ src/wallet/api/wallet_manager.h | 1 + src/wallet/wallet2.h | 2 +- src/wallet/wallet2_api.h | 21 ++++++++-- tests/libwallet_api_tests/main.cpp | 39 ++++++++++++------- .../scripts/create_wallets.sh | 2 +- .../scripts/open_wallet_5.sh | 2 +- .../libwallet_api_tests/scripts/send_funds.sh | 1 + 8 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index c056ada2c..c578098cc 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -32,6 +32,11 @@ #include "wallet_manager.h" #include "wallet.h" +#include +#include + +namespace fs = ::boost::filesystem; + namespace epee { unsigned int g_test_dbg_lock_sleep = 0; } @@ -77,6 +82,38 @@ bool WalletManagerImpl::walletExists(const std::string &path) return false; } + +std::vector WalletManagerImpl::findWallets(const std::string &path) +{ + std::vector result; + const boost::regex wallet_rx("(.*)\\.(address\\.txt)$"); + boost::filesystem::recursive_directory_iterator end_itr; // Default ctor yields past-the-end + boost::filesystem::path work_dir(path); + + for (boost::filesystem::recursive_directory_iterator itr(path); itr != end_itr; ++itr) { + // Skip if not a file + if (!boost::filesystem::is_regular_file(itr->status())) + continue; + boost::smatch what; + std::string filename = itr->path().filename().string(); + + LOG_PRINT_L3("Checking filename: " << filename); + + bool matched = boost::regex_match(filename, what, wallet_rx); + if (matched) { + // if address file found, checking if there's corresponding .keys file and wallet file itself + std::string wallet_file = (itr->path().parent_path() /= what[1]).string(); + std::string wallet_key_file = wallet_file + std::string(".keys"); + if (boost::filesystem::exists(wallet_file) + && boost::filesystem::exists(wallet_key_file)) { + LOG_PRINT_L3("Found wallet: " << wallet_file); + result.push_back(wallet_file); + } + } + } + return result; +} + std::string WalletManagerImpl::errorString() const { return m_errorString; diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index d608eb7f0..7585c1af7 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -43,6 +43,7 @@ public: 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::vector findWallets(const std::string &path); std::string errorString() const; void setDaemonHost(const std::string &hostname); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 85bf33e3f..e7e4e7772 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -219,7 +219,7 @@ namespace tools void store(); /*! * \brief store_to - stores wallet to another file(s), deleting old ones - * \param path - path to the wallet file (keys and address filenames will be generated based on this filename) + * \param path - path to the wallet file (withkeys and address filenames will be generated based on this filename) * \param password - password to protect new wallet (TODO: probably better save the password in the wallet object?) */ void store_to(const std::string &path, const std::string &password); diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index 7841c299d..b98bb8661 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -190,12 +190,27 @@ struct WalletManager */ virtual bool closeWallet(Wallet *wallet) = 0; - //! checks if wallet with the given name already exists + /* + * ! checks if wallet with the given name already exists + */ + + /*! + * @brief TODO: delme walletExists - check if the given filename is the wallet + * @param path - filename + * @return + */ virtual bool walletExists(const std::string &path) = 0; + /*! + * \brief findWallets - searches for the wallet files by given path name recursively + * \param path - starting point to search + * \return - list of strings with found wallets (absolute paths); + */ + virtual std::vector findWallets(const std::string &path) = 0; + + //! returns verbose error string regarding last error; virtual std::string errorString() const = 0; -// //! set -// virtual void setDaemonAddress(const std::string &address) = 0; + }; diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp index ebd29ee1e..91636d522 100644 --- a/tests/libwallet_api_tests/main.cpp +++ b/tests/libwallet_api_tests/main.cpp @@ -73,11 +73,12 @@ const std::string TESTNET_WALLET2_NAME = WALLETS_ROOT_DIR + "wallet_02.bin"; const std::string TESTNET_WALLET3_NAME = WALLETS_ROOT_DIR + "wallet_03.bin"; 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; -const std::string CURRENT_DST_WALLET = TESTNET_WALLET5_NAME; +const std::string CURRENT_DST_WALLET = TESTNET_WALLET6_NAME; const char * TESTNET_DAEMON_ADDRESS = "localhost:38081"; const uint64_t AMOUNT_10XMR = 10000000000000L; @@ -131,12 +132,12 @@ struct Utils }; -struct DISABLED_WalletManagerTest : public testing::Test +struct WalletManagerTest : public testing::Test { Bitmonero::WalletManager * wmgr; - DISABLED_WalletManagerTest() + WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; wmgr = Bitmonero::WalletManagerFactory::getWalletManager(); @@ -145,7 +146,7 @@ struct DISABLED_WalletManagerTest : public testing::Test } - ~DISABLED_WalletManagerTest() + ~WalletManagerTest() { std::cout << __FUNCTION__ << std::endl; //deleteWallet(WALLET_NAME); @@ -180,7 +181,7 @@ struct WalletTest2 : public testing::Test }; -TEST_F(DISABLED_WalletManagerTest, WalletManagerCreatesWallet) +TEST_F(WalletManagerTest, WalletManagerCreatesWallet) { Bitmonero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -197,7 +198,7 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerCreatesWallet) } -TEST_F(DISABLED_WalletManagerTest, WalletManagerOpensWallet) +TEST_F(WalletManagerTest, WalletManagerOpensWallet) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); @@ -209,8 +210,8 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerOpensWallet) std::cout << "** seed: " << wallet2->seed() << std::endl; } - -TEST_F(DISABLED_WalletManagerTest, WalletManagerChangesPassword) +/* +TEST_F(WalletManagerTest, WalletManagerChangesPassword) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -226,7 +227,7 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerChangesPassword) -TEST_F(DISABLED_WalletManagerTest, WalletManagerRecoversWallet) +TEST_F(WalletManagerTest, WalletManagerRecoversWallet) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -242,7 +243,7 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerRecoversWallet) } -TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet1) +TEST_F(WalletManagerTest, WalletManagerStoresWallet1) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -259,7 +260,7 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet1) } -TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet2) +TEST_F(WalletManagerTest, WalletManagerStoresWallet2) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -275,7 +276,7 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet2) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } -TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet3) +TEST_F(WalletManagerTest, WalletManagerStoresWallet3) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -297,7 +298,7 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet3) } -TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet4) +TEST_F(WalletManagerTest, WalletManagerStoresWallet4) { Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); std::string seed1 = wallet1->seed(); @@ -317,7 +318,17 @@ TEST_F(DISABLED_WalletManagerTest, WalletManagerStoresWallet4) ASSERT_TRUE(wallet1->address() == address1); ASSERT_TRUE(wmgr->closeWallet(wallet1)); } +*/ +TEST_F(WalletManagerTest, WalletManagerFindsWallet) +{ + std::vector wallets = wmgr->findWallets(WALLETS_ROOT_DIR); + ASSERT_FALSE(wallets.empty()); + std::cout << "Found wallets: " << std::endl; + for (auto wallet_path: wallets) { + std::cout << wallet_path << std::endl; + } +} TEST_F(WalletTest1, WalletShowsBalance) @@ -349,6 +360,8 @@ TEST_F(WalletTest1, WalletRefresh) ASSERT_TRUE(wmgr->closeWallet(wallet1)); } + + TEST_F(WalletTest1, WalletTransaction) { Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true); diff --git a/tests/libwallet_api_tests/scripts/create_wallets.sh b/tests/libwallet_api_tests/scripts/create_wallets.sh index fd3db838c..6abad84f9 100755 --- a/tests/libwallet_api_tests/scripts/create_wallets.sh +++ b/tests/libwallet_api_tests/scripts/create_wallets.sh @@ -10,7 +10,7 @@ function create_wallet { create_wallet wallet_01.bin create_wallet wallet_02.bin create_wallet wallet_03.bin -#create_wallet wallet_04.bin +create_wallet wallet_04.bin create_wallet wallet_05.bin create_wallet wallet_06.bin diff --git a/tests/libwallet_api_tests/scripts/open_wallet_5.sh b/tests/libwallet_api_tests/scripts/open_wallet_5.sh index 8ebf0a4c7..bbeb702c0 100755 --- a/tests/libwallet_api_tests/scripts/open_wallet_5.sh +++ b/tests/libwallet_api_tests/scripts/open_wallet_5.sh @@ -1,4 +1,4 @@ #!/bin/bash -rlwrap simplewallet --wallet-file wallet_04.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_04.log +rlwrap simplewallet --wallet-file wallet_05.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_05.log diff --git a/tests/libwallet_api_tests/scripts/send_funds.sh b/tests/libwallet_api_tests/scripts/send_funds.sh index 801d63609..306b06a40 100755 --- a/tests/libwallet_api_tests/scripts/send_funds.sh +++ b/tests/libwallet_api_tests/scripts/send_funds.sh @@ -17,5 +17,6 @@ send_funds 100 wallet_02.bin send_funds 100 wallet_03.bin send_funds 100 wallet_04.bin send_funds 100 wallet_05.bin +send_funds 100 wallet_06.bin From 8f9d98b3e0cc552074ddb3f59da6399e855af311 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 3 Jun 2016 16:56:13 +0300 Subject: [PATCH 32/39] removed unused "using" --- src/wallet/api/wallet_manager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index c578098cc..2327d11f8 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -35,7 +35,6 @@ #include #include -namespace fs = ::boost::filesystem; namespace epee { unsigned int g_test_dbg_lock_sleep = 0; From c554055ce435ae2752820ba317d801f143804b3c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 10 Jun 2016 12:51:09 +0300 Subject: [PATCH 33/39] 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(+) 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) { From 3ac20a46b38f88757c57cbcf8581cade312b7936 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Fri, 10 Jun 2016 13:52:10 +0300 Subject: [PATCH 34/39] 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(-) 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); From 3318addafaf6ac7b5489f7d774083a84dce7dfa0 Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Thu, 16 Jun 2016 16:42:33 +0300 Subject: [PATCH 35/39] 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(-) 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); From f1c4a376af916604e2b142a1169d610f631bd91c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Mon, 20 Jun 2016 22:56:30 +0300 Subject: [PATCH 36/39] 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(-) 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(); From eec0f57d60a8c2f69b18566b2baecfb65a2f641d Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 22 Jun 2016 14:37:53 +0300 Subject: [PATCH 37/39] Typo fixed --- src/wallet/wallet2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index e7e4e7772..85bf33e3f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -219,7 +219,7 @@ namespace tools void store(); /*! * \brief store_to - stores wallet to another file(s), deleting old ones - * \param path - path to the wallet file (withkeys and address filenames will be generated based on this filename) + * \param path - path to the wallet file (keys and address filenames will be generated based on this filename) * \param password - password to protect new wallet (TODO: probably better save the password in the wallet object?) */ void store_to(const std::string &path, const std::string &password); From 7b7cf21644f013cc9d43716b72bca8b42362832c Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 22 Jun 2016 15:06:19 +0300 Subject: [PATCH 38/39] commented regex --- src/wallet/api/wallet_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 2327d11f8..3a97538b4 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -85,7 +85,7 @@ bool WalletManagerImpl::walletExists(const std::string &path) std::vector WalletManagerImpl::findWallets(const std::string &path) { std::vector result; - const boost::regex wallet_rx("(.*)\\.(address\\.txt)$"); + const boost::regex wallet_rx("(.*)\\.(address\\.txt)$"); // searching for .address.txt files boost::filesystem::recursive_directory_iterator end_itr; // Default ctor yields past-the-end boost::filesystem::path work_dir(path); From 4e5521d87d3897e8ce547e7bf11ef24024a9dbdf Mon Sep 17 00:00:00 2001 From: Ilya Kitaev Date: Wed, 22 Jun 2016 15:50:59 +0300 Subject: [PATCH 39/39] PendingTransactionImpl: pointer->reference --- src/wallet/api/pending_transaction.cpp | 4 ++-- src/wallet/api/pending_transaction.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp index db40851b4..c4a770f87 100644 --- a/src/wallet/api/pending_transaction.cpp +++ b/src/wallet/api/pending_transaction.cpp @@ -48,7 +48,7 @@ namespace Bitmonero { PendingTransaction::~PendingTransaction() {} -PendingTransactionImpl::PendingTransactionImpl(WalletImpl *wallet) +PendingTransactionImpl::PendingTransactionImpl(WalletImpl &wallet) : m_wallet(wallet) { @@ -77,7 +77,7 @@ bool PendingTransactionImpl::commit() try { while (!m_pending_tx.empty()) { auto & ptx = m_pending_tx.back(); - m_wallet->m_wallet->commit_tx(ptx); + 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(); diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h index 0ae3eb8e2..8e09bec91 100644 --- a/src/wallet/api/pending_transaction.h +++ b/src/wallet/api/pending_transaction.h @@ -41,7 +41,7 @@ class WalletImpl; class PendingTransactionImpl : public PendingTransaction { public: - PendingTransactionImpl(WalletImpl * wallet); + PendingTransactionImpl(WalletImpl &wallet); ~PendingTransactionImpl(); int status() const; std::string errorString() const; @@ -53,7 +53,7 @@ public: private: friend class WalletImpl; - WalletImpl * m_wallet; + WalletImpl &m_wallet; int m_status; std::string m_errorString;