aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml8
-rw-r--r--CMakeLists.txt50
-rw-r--r--README.md10
-rw-r--r--src/simplewallet/simplewallet.cpp2
-rw-r--r--src/wallet/CMakeLists.txt21
-rw-r--r--src/wallet/api/pending_transaction.cpp4
-rw-r--r--src/wallet/api/wallet.cpp148
-rw-r--r--src/wallet/api/wallet.h30
-rw-r--r--src/wallet/api/wallet_manager.cpp5
-rw-r--r--src/wallet/wallet2_api.h77
-rw-r--r--tests/hash-target.cpp2
-rw-r--r--tests/libwallet_api_tests/main.cpp220
-rwxr-xr-xtests/libwallet_api_tests/scripts/send_funds.sh24
13 files changed, 496 insertions, 105 deletions
diff --git a/.travis.yml b/.travis.yml
index 2026cba5f..ba4df1cc9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,3 +26,11 @@ addons:
script: make -j2 && HAVE_DOT=YES doxygen Doxyfile
notifications:
email: false
+ irc:
+ on_success: change
+ on_failure: change
+ channels:
+ - "chat.freenode.net#monero-dev"
+ nick: monero
+ template:
+ - "%{result} | %{repository}#%{build_number} (%{commit} : %{author}) | Build details : %{build_url}"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 46c5b2e1d..70c0c89f7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -294,7 +294,7 @@ link_directories(${LIBUNWIND_LIBRARY_DIRS})
if(MSVC)
add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__")
- # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline")
+ # set(COMMON_C_FLAGS "${COMMON_C_FLAGS} /Dinline=__inline")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760")
if(STATIC)
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE)
@@ -315,14 +315,11 @@ else()
endif()
endif()
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized")
- if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
- set(WARNINGS "${WARNINGS} -Wno-deprecated-register")
- endif()
if(NOT MINGW)
- set(WARNINGS "${WARNINGS} -Werror") # to allow pedantic but not stop compilation
+ set(WARNINGS_AS_ERRORS_FLAG "-Werror")
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
- set(WARNINGS "${WARNINGS} -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration")
+ set(WARNINGS "${WARNINGS} -Wno-deprecated-register -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration")
if(ARM6 OR ARM7)
set(WARNINGS "${WARNINGS} -Wno-error=inline-asm")
endif()
@@ -350,20 +347,20 @@ else()
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
endif()
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
+ set(COMMON_C_FLAGS "${COMMON_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
# is fixed in the code (Issue #847), force compiler to be conservative.
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
+ set(COMMON_C_FLAGS "${COMMON_C_FLAGS} -fno-strict-aliasing")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -fno-strict-aliasing")
option(NO_AES "Explicitly disable AES support" ${NO_AES})
if(NOT NO_AES AND NOT (ARM6 OR ARM7))
message(STATUS "AES support enabled")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
+ set(COMMON_C_FLAGS "${COMMON_C_FLAGS} -maes")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -maes")
elseif(ARM7 OR ARM6)
message(STATUS "AES support disabled (not available on ARM)")
else()
@@ -372,18 +369,18 @@ else()
if(ARM6)
message(STATUS "Setting ARM6 C and C++ flags")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp -mfloat-abi=hard")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=vfp -mfloat-abi=hard")
+ set(COMMON_C_FLAGS "${COMMON_C_FLAGS} -mfpu=vfp -mfloat-abi=hard")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -mfpu=vfp -mfloat-abi=hard")
endif()
if(ARM7)
message(STATUS "Setting ARM7 C and C++ flags")
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -mfloat-abi=hard")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -mfloat-abi=hard")
+ set(COMMON_C_FLAGS "${COMMON_C_FLAGS} -O2 -mfloat-abi=hard")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -O2 -mfloat-abi=hard")
endif()
if(APPLE)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0")
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8))
set(DEBUG_FLAGS "-g3 -Og")
@@ -401,8 +398,8 @@ else()
set(USE_LTO false)
# explicitly define stdlib for older versions of clang
if(CMAKE_C_COMPILER_VERSION VERSION_LESS 3.7)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
+ set(COMMON_CXX_FLAGS "${COMMON_CXX_FLAGS} -stdlib=libc++")
+ set(COMMON_EXE_LINKER_FLAGS "${COMMON_EXE_LINKER_FLAGS} -stdlib=libc++")
endif()
endif()
@@ -465,13 +462,19 @@ endif()
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
-if(NOT MINGW AND NOT APPLE)
- find_library(ATOMIC atomic)
- list(APPEND EXTRA_LIBRARIES ${ATOMIC})
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ if(NOT MINGW AND NOT APPLE)
+ find_library(ATOMIC atomic)
+ list(APPEND EXTRA_LIBRARIES ${ATOMIC})
+ endif()
endif()
include(version.cmake)
+# When building the following sources, treat warnings as errors
+set(CMAKE_C_FLAGS "${COMMON_C_FLAGS} ${WARNINGS_AS_ERRORS_FLAG}")
+set(CMAKE_CXX_FLAGS "${COMMON_CXX_FLAGS} ${WARNINGS_AS_ERRORS_FLAG}")
+
add_subdirectory(contrib)
add_subdirectory(src)
@@ -479,6 +482,9 @@ add_subdirectory(src)
option(BUILD_TESTS "Build tests." OFF)
if(BUILD_TESTS)
+ # When building tests, do *not* treat warnings as errors
+ set(CMAKE_C_FLAGS "${COMMON_C_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${COMMON_CXX_FLAGS}")
add_subdirectory(tests)
endif()
diff --git a/README.md b/README.md
index 5647cf6a3..14652d0eb 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,11 @@ Copyright (c) 2014-2016, The Monero Project
## Development Resources
-Web: [getmonero.org](https://getmonero.org)
-Forum: [forum.getmonero.org](https://forum.getmonero.org)
-Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
-GitHub: [https://github.com/monero-project/bitmonero](https://github.com/monero-project/bitmonero)
-IRC: [#monero-dev on Freenode](irc://chat.freenode.net/#monero-dev)
+- Web: [getmonero.org](https://getmonero.org)
+- Forum: [forum.getmonero.org](https://forum.getmonero.org)
+- Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
+- GitHub: [https://github.com/monero-project/bitmonero](https://github.com/monero-project/bitmonero)
+- IRC: [#monero-dev on Freenode](irc://chat.freenode.net/#monero-dev)
## Introduction
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 75344bf21..9dd5f0c6e 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -3263,6 +3263,8 @@ bool simple_wallet::run()
// check and display warning, but go on anyway
try_connect_to_daemon();
+ refresh_main(0, false);
+
std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6);
m_auto_refresh_run = m_wallet->auto_refresh();
if (m_auto_refresh_run)
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 0b8fe4cb1..086758c39 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -75,13 +75,26 @@ target_link_libraries(wallet
${Boost_REGEX_LIBRARY}
${EXTRA_LIBRARIES})
+
+# in case of static build, randon.c.obj from UNBOUND_LIBARY conflicts with the same file from 'crypto'
+# and in case of dynamic build, merge_static_libs called with ${UNBOUND_LIBRARY} will fail
+if (STATIC)
+ set(libs_to_merge wallet cryptonote_core mnemonics common crypto)
+ # hack - repack libunbound into another static lib - there's conflicting object file "random.c.obj"
+ merge_static_libs(wallet_merged "${libs_to_merge}")
+ merge_static_libs(wallet_merged2 "${UNBOUND_LIBRARY}")
+ install(TARGETS wallet_merged wallet_merged2
+ ARCHIVE DESTINATION lib)
+else (STATIC)
+ set(libs_to_merge wallet cryptonote_core mnemonics common crypto ${UNBOUND_LIBRARY} )
+ merge_static_libs(wallet_merged "${libs_to_merge}")
+ install(TARGETS wallet_merged
+ ARCHIVE DESTINATION lib)
+endif (STATIC)
-set(libs_to_merge wallet cryptonote_core mnemonics common crypto)
#MERGE_STATIC_LIBS(wallet_merged wallet_merged "${libs_to_merge}")
-merge_static_libs(wallet_merged "${libs_to_merge}")
-install(TARGETS wallet_merged
- ARCHIVE DESTINATION lib)
+
install(FILES ${wallet_api_headers}
DESTINATION include/wallet)
diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp
index c4a770f87..26ce9fc7e 100644
--- a/src/wallet/api/pending_transaction.cpp
+++ b/src/wallet/api/pending_transaction.cpp
@@ -118,7 +118,7 @@ uint64_t PendingTransactionImpl::amount() const
uint64_t PendingTransactionImpl::dust() const
{
- uint32_t result = 0;
+ uint64_t result = 0;
for (const auto & ptx : m_pending_tx) {
result += ptx.dust;
}
@@ -127,7 +127,7 @@ uint64_t PendingTransactionImpl::dust() const
uint64_t PendingTransactionImpl::fee() const
{
- uint32_t result = 0;
+ uint64_t result = 0;
for (const auto ptx : m_pending_tx) {
result += ptx.fee;
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index be379cb99..67d2ebecb 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -46,6 +46,7 @@ namespace Bitmonero {
namespace {
// copy-pasted from simplewallet
static const size_t DEFAULT_MIXIN = 4;
+ static const int DEFAULT_REFRESH_INTERVAL_SECONDS = 10;
}
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
@@ -89,6 +90,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
<< ", amount: " << print_money(amount));
if (m_listener) {
m_listener->moneyReceived(tx_hash, amount);
+ m_listener->updated();
}
}
@@ -103,6 +105,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
<< ", amount: " << print_money(amount));
if (m_listener) {
m_listener->moneySpent(tx_hash, amount);
+ m_listener->updated();
}
}
@@ -118,6 +121,7 @@ Wallet::~Wallet() {}
WalletListener::~WalletListener() {}
+
string Wallet::displayAmount(uint64_t amount)
{
return cryptonote::print_money(amount);
@@ -144,6 +148,12 @@ std::string Wallet::genPaymentId()
}
+bool Wallet::paymentIdValid(const string &paiment_id)
+{
+ crypto::hash8 pid;
+ return tools::wallet2::parse_short_payment_id(paiment_id, pid);
+}
+
///////////////////////// WalletImpl implementation ////////////////////////
WalletImpl::WalletImpl(bool testnet)
@@ -153,13 +163,22 @@ WalletImpl::WalletImpl(bool testnet)
m_wallet = new tools::wallet2(testnet);
m_history = new TransactionHistoryImpl(this);
m_wallet2Callback = new Wallet2CallbackImpl;
+ m_wallet->callback(m_wallet2Callback);
+ m_refreshThreadDone = false;
+ m_refreshEnabled = false;
+ m_refreshIntervalSeconds = DEFAULT_REFRESH_INTERVAL_SECONDS;
+ m_refreshThread = std::thread([this] () {
+ this->refreshThreadFunc();
+ });
+
}
WalletImpl::~WalletImpl()
{
- delete m_wallet2Callback;
+ stopRefresh();
delete m_history;
delete m_wallet;
+ delete m_wallet2Callback;
}
bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
@@ -251,8 +270,12 @@ bool WalletImpl::close()
clearStatus();
bool result = false;
try {
+ // LOG_PRINT_L0("Calling wallet::store...");
m_wallet->store();
+ // LOG_PRINT_L0("wallet::store done");
+ // LOG_PRINT_L0("Calling wallet::stop...");
m_wallet->stop();
+ // LOG_PRINT_L0("wallet::stop done");
result = true;
} catch (const std::exception &e) {
m_status = Status_Error;
@@ -348,21 +371,30 @@ string WalletImpl::keysFilename() const
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);
- if (Utils::isAddressLocal(daemon_address)) {
- this->setTrustedDaemon(true);
- }
- } catch (const std::exception &e) {
- LOG_ERROR("Error initializing wallet: " << e.what());
- m_status = Status_Error;
- m_errorString = e.what();
+ m_wallet->init(daemon_address, upper_transaction_size_limit);
+ if (Utils::isAddressLocal(daemon_address)) {
+ this->setTrustedDaemon(true);
}
+ bool result = this->refresh();
+ // enabling background refresh thread
+ startRefresh();
+ return result;
- return m_status == Status_Ok;
}
+void WalletImpl::initAsync(const string &daemon_address, uint64_t upper_transaction_size_limit)
+{
+ clearStatus();
+ m_wallet->init(daemon_address, upper_transaction_size_limit);
+ if (Utils::isAddressLocal(daemon_address)) {
+ this->setTrustedDaemon(true);
+ }
+ startRefresh();
+}
+
+
+
uint64_t WalletImpl::balance() const
{
return m_wallet->balance();
@@ -377,15 +409,17 @@ uint64_t WalletImpl::unlockedBalance() const
bool WalletImpl::refresh()
{
clearStatus();
- try {
- m_wallet->refresh();
- } catch (const std::exception &e) {
- m_status = Status_Error;
- m_errorString = e.what();
- }
+ doRefresh();
return m_status == Status_Ok;
}
+void WalletImpl::refreshAsync()
+{
+ LOG_PRINT_L3(__FUNCTION__ << ": Refreshing asyncronously..");
+ clearStatus();
+ m_refreshCV.notify_one();
+}
+
// TODO:
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
// 2 - check / design how "Transaction" can be single interface
@@ -396,7 +430,9 @@ bool WalletImpl::refresh()
// - unconfirmed_transfer_details;
// - confirmed_transfer_details)
-PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count)
+PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, uint64_t amount, uint32_t mixin_count,
+ PendingTransaction::Priority priority)
+
{
clearStatus();
vector<cryptonote::tx_destination_entry> dsts;
@@ -458,8 +494,10 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
//std::vector<tools::wallet2::pending_tx> ptx_vector;
try {
+ // priority called "fee_multiplied in terms of underlying wallet interface
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
- 0 /* unused fee arg*/, extra, m_trustedDaemon);
+ static_cast<uint64_t>(priority),
+ extra, m_trustedDaemon);
} catch (const tools::error::daemon_busy&) {
// TODO: make it translatable with "tr"?
@@ -564,10 +602,17 @@ bool WalletImpl::connectToDaemon()
m_status = result ? Status_Ok : Status_Error;
if (!result) {
m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address();
+ } else {
+ // start refreshing here
}
return result;
}
+bool WalletImpl::connected() const
+{
+ return m_wallet->check_connection();
+}
+
void WalletImpl::setTrustedDaemon(bool arg)
{
m_trustedDaemon = arg;
@@ -584,5 +629,70 @@ void WalletImpl::clearStatus()
m_errorString.clear();
}
+void WalletImpl::refreshThreadFunc()
+{
+ LOG_PRINT_L3(__FUNCTION__ << ": starting refresh thread");
+
+ while (true) {
+ std::unique_lock<std::mutex> lock(m_refreshMutex);
+ if (m_refreshThreadDone) {
+ break;
+ }
+ LOG_PRINT_L3(__FUNCTION__ << ": waiting for refresh...");
+ m_refreshCV.wait_for(lock, std::chrono::seconds(m_refreshIntervalSeconds));
+ LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired...");
+ LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled);
+ LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << m_status);
+ if (m_refreshEnabled /*&& m_status == Status_Ok*/) {
+ LOG_PRINT_L3(__FUNCTION__ << ": refreshing...");
+ doRefresh();
+ }
+ }
+ LOG_PRINT_L3(__FUNCTION__ << ": refresh thread stopped");
+}
+
+void WalletImpl::doRefresh()
+{
+ // synchronizing async and sync refresh calls
+ std::lock_guard<std::mutex> guarg(m_refreshMutex2);
+ try {
+ m_wallet->refresh();
+ } catch (const std::exception &e) {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ }
+ if (m_wallet2Callback->getListener()) {
+ m_wallet2Callback->getListener()->refreshed();
+ }
+}
+
+
+void WalletImpl::startRefresh()
+{
+ if (!m_refreshEnabled) {
+ m_refreshEnabled = true;
+ m_refreshCV.notify_one();
+ }
+}
+
+
+
+void WalletImpl::stopRefresh()
+{
+ if (!m_refreshThreadDone) {
+ m_refreshEnabled = false;
+ m_refreshThreadDone = true;
+ m_refreshThread.join();
+ }
+}
+
+void WalletImpl::pauseRefresh()
+{
+ // TODO synchronize access
+ if (!m_refreshThreadDone) {
+ m_refreshEnabled = false;
+ }
+}
+
} // namespace
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 164aede1a..9a290e0bc 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -35,6 +35,9 @@
#include "wallet/wallet2.h"
#include <string>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
namespace Bitmonero {
@@ -65,14 +68,19 @@ public:
std::string filename() const;
std::string keysFilename() const;
bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
+ void initAsync(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
bool connectToDaemon();
+ bool connected() const;
void setTrustedDaemon(bool arg);
bool trustedDaemon() const;
uint64_t balance() const;
uint64_t unlockedBalance() const;
bool refresh();
+ void refreshAsync();
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
- uint64_t amount, uint32_t mixin_count);
+ uint64_t amount, uint32_t mixin_count,
+ PendingTransaction::Priority priority = PendingTransaction::Priority_Low);
+
virtual void disposeTransaction(PendingTransaction * t);
virtual TransactionHistory * history() const;
virtual void setListener(WalletListener * l);
@@ -81,19 +89,37 @@ public:
private:
void clearStatus();
+ void refreshThreadFunc();
+ void doRefresh();
+ void startRefresh();
+ void stopRefresh();
+ void pauseRefresh();
private:
friend class PendingTransactionImpl;
friend class TransactionHistoryImpl;
tools::wallet2 * m_wallet;
- int m_status;
+ std::atomic<int> m_status;
std::string m_errorString;
std::string m_password;
TransactionHistoryImpl * m_history;
bool m_trustedDaemon;
WalletListener * m_walletListener;
Wallet2CallbackImpl * m_wallet2Callback;
+
+ // multi-threaded refresh stuff
+ std::atomic<bool> m_refreshEnabled;
+ std::atomic<bool> m_refreshThreadDone;
+ std::atomic<int> m_refreshIntervalSeconds;
+ // synchronizing refresh loop;
+ std::mutex m_refreshMutex;
+
+ // synchronizing sync and async refresh
+ std::mutex m_refreshMutex2;
+ std::condition_variable m_refreshCV;
+ std::thread m_refreshThread;
+
};
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index bf072ccca..ca83806ff 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -137,6 +137,11 @@ WalletManager *WalletManagerFactory::getWalletManager()
return g_walletManager;
}
+void WalletManagerFactory::setLogLevel(int level)
+{
+ epee::log_space::log_singletone::get_set_log_detalisation_level(true, level);
+}
+
}
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 66987e4c5..2c5836573 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -50,6 +50,14 @@ struct PendingTransaction
Status_Ok,
Status_Error
};
+
+ enum Priority {
+ Priority_Low = 1,
+ Priority_Medium = 2,
+ Priority_High = 3,
+ Priority_Last
+ };
+
virtual ~PendingTransaction() = 0;
virtual int status() const = 0;
virtual std::string errorString() const = 0;
@@ -108,7 +116,10 @@ struct WalletListener
virtual ~WalletListener() = 0;
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;
+ // generic callback, called when any event (sent/received/block reveived/etc) happened with the wallet;
+ virtual void updated() = 0;
+ // called when wallet refreshed by background thread or explicitly called be calling "refresh" synchronously
+ virtual void refreshed() = 0;
};
@@ -163,9 +174,38 @@ struct Wallet
* \return
*/
virtual std::string keysFilename() const = 0;
-
+ /*!
+ * \brief init - initializes wallet with daemon connection params. implicitly connects to the daemon
+ * and refreshes the wallet. "refreshed" callback will be invoked. if daemon_address is
+ * local address, "trusted daemon" will be set to true forcibly
+ *
+ * \param daemon_address - daemon address in "hostname:port" format
+ * \param upper_transaction_size_limit
+ * \return - true if initialized and refreshed successfully
+ */
virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0;
+
+ /*!
+ * \brief init - initalizes wallet asynchronously. logic is the same as "init" but returns immediately.
+ * "refreshed" callback will be invoked.
+ *
+ * \param daemon_address - daemon address in "hostname:port" format
+ * \param upper_transaction_size_limit
+ * \return - true if initialized and refreshed successfully
+ */
+ virtual void initAsync(const std::string &daemon_address, uint64_t upper_transaction_size_limit) = 0;
+
+ /**
+ * @brief connectToDaemon - connects to the daemon. TODO: check if it can be removed
+ * @return
+ */
virtual bool connectToDaemon() = 0;
+
+ /**
+ * @brief connected - checks if the wallet connected to the daemon
+ * @return - true if connected
+ */
+ virtual bool connected() const = 0;
virtual void setTrustedDaemon(bool arg) = 0;
virtual bool trustedDaemon() const = 0;
virtual uint64_t balance() const = 0;
@@ -175,23 +215,36 @@ struct Wallet
static uint64_t amountFromString(const std::string &amount);
static uint64_t amountFromDouble(double amount);
static std::string genPaymentId();
+ static bool paymentIdValid(const std::string &paiment_id);
- // TODO?
- // virtual uint64_t unlockedDustBalance() const = 0;
+ /**
+ * @brief refresh - refreshes the wallet, updating transactions from daemon
+ * @return - true if refreshed successfully;
+ */
virtual bool refresh() = 0;
+ /**
+ * @brief refreshAsync - refreshes wallet asynchronously.
+ */
+ virtual void refreshAsync() = 0;
/*!
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
* \param dst_addr destination address as string
* \param payment_id optional payment_id, can be empty string
* \param amount amount
* \param mixin_count mixin count. if 0 passed, wallet will use default value
+ * \param priority
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
* after object returned
*/
virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
- uint64_t amount, uint32_t mixin_count) = 0;
+ uint64_t amount, uint32_t mixin_count,
+ PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
+ /*!
+ * \brief disposeTransaction - destroys transaction object
+ * \param t - pointer to the "PendingTransaction" object. Pointer is not valid after function returned;
+ */
virtual void disposeTransaction(PendingTransaction * t) = 0;
virtual TransactionHistory * history() const = 0;
virtual void setListener(WalletListener *) = 0;
@@ -271,8 +324,22 @@ struct WalletManager
struct WalletManagerFactory
{
+ // logging levels for underlying library
+ enum LogLevel {
+ LogLevel_Silent = -1,
+ LogLevel_0 = 0,
+ LogLevel_1 = 1,
+ LogLevel_2 = 2,
+ LogLevel_3 = 3,
+ LogLevel_4 = 4,
+ LogLevel_Min = LogLevel_Silent,
+ LogLevel_Max = LogLevel_4
+ };
+
static WalletManager * getWalletManager();
+ static void setLogLevel(int level);
};
+
}
diff --git a/tests/hash-target.cpp b/tests/hash-target.cpp
index c46f6722b..aeb6688bc 100644
--- a/tests/hash-target.cpp
+++ b/tests/hash-target.cpp
@@ -41,7 +41,7 @@ using cryptonote::check_hash;
int main(int argc, char *argv[]) {
crypto::hash h;
for (uint64_t diff = 1;; diff += 1 + (diff >> 8)) {
- for (int b = 0; b < 256; b++) {
+ for (uint16_t b = 0; b < 256; b++) {
memset(&h, b, sizeof(crypto::hash));
if (check_hash(h, diff) != (b == 0 || diff <= 255 / b)) {
return 1;
diff --git a/tests/libwallet_api_tests/main.cpp b/tests/libwallet_api_tests/main.cpp
index f6f1b0832..d642534b0 100644
--- a/tests/libwallet_api_tests/main.cpp
+++ b/tests/libwallet_api_tests/main.cpp
@@ -31,6 +31,7 @@
#include "gtest/gtest.h"
#include "wallet/wallet2_api.h"
+#include "include_base_utils.h"
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
@@ -39,6 +40,8 @@
#include <vector>
#include <mutex>
#include <thread>
+#include <atomic>
+#include <condition_variable>
using namespace std;
@@ -137,6 +140,7 @@ struct WalletManagerTest : public testing::Test
{
std::cout << __FUNCTION__ << std::endl;
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
+ // Bitmonero::WalletManagerFactory::setLogLevel(Bitmonero::WalletManagerFactory::LogLevel_4);
Utils::deleteWallet(WALLET_NAME);
Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
}
@@ -235,7 +239,7 @@ TEST_F(WalletManagerTest, WalletManagerMovesWallet)
}
-/*
+
TEST_F(WalletManagerTest, WalletManagerChangesPassword)
{
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
@@ -243,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);quint64
+ ASSERT_TRUE(wallet2->status() == Bitmonero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wmgr->closeWallet(wallet2));
Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
@@ -343,7 +347,9 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
ASSERT_TRUE(wallet1->address() == address1);
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
-*/
+
+
+
TEST_F(WalletManagerTest, WalletManagerFindsWallet)
{
@@ -415,7 +421,7 @@ TEST_F(WalletTest1, WalletConvertsToString)
}
-/*
+
TEST_F(WalletTest1, WalletTransaction)
{
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
@@ -429,8 +435,10 @@ TEST_F(WalletTest1, WalletTransaction)
wallet1->setDefaultMixin(1);
ASSERT_TRUE(wallet1->defaultMixin() == 1);
- Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
- recepient_address, AMOUNT_10XMR);
+ Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(recepient_address,
+ PAYMENT_ID_EMPTY,
+ AMOUNT_10XMR,
+ 1);
ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
wallet1->refresh();
@@ -440,7 +448,6 @@ TEST_F(WalletTest1, WalletTransaction)
ASSERT_FALSE(wallet1->balance() == balance);
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
-*/
TEST_F(WalletTest1, WalletTransactionWithMixin)
{
@@ -482,6 +489,48 @@ TEST_F(WalletTest1, WalletTransactionWithMixin)
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
+TEST_F(WalletTest1, WalletTransactionWithPriority)
+{
+
+ std::string payment_id = "";
+
+ 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);
+ uint32_t mixin = 2;
+ uint64_t fee = 0;
+
+ std::vector<Bitmonero::PendingTransaction::Priority> priorities = {
+ Bitmonero::PendingTransaction::Priority_Low,
+ Bitmonero::PendingTransaction::Priority_Medium,
+ Bitmonero::PendingTransaction::Priority_High
+ };
+
+ for (auto it = priorities.begin(); it != priorities.end(); ++it) {
+ std::cerr << "Transaction priority: " << *it << std::endl;
+ Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
+ recepient_address, payment_id, AMOUNT_5XMR, mixin, *it);
+ 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->fee() > fee);
+ ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
+ fee = transaction->fee();
+ 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);
@@ -522,7 +571,7 @@ TEST_F(WalletTest1, WalletTransactionAndHistory)
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
PAYMENT_ID_EMPTY,
- AMOUNT_10XMR * 5, 0);
+ AMOUNT_10XMR * 5, 1);
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
ASSERT_TRUE(tx->commit());
@@ -586,100 +635,193 @@ TEST_F(WalletTest1, WalletTransactionWithPaymentId)
ASSERT_TRUE(payment_id_in_history);
}
+
struct MyWalletListener : public Bitmonero::WalletListener
{
Bitmonero::Wallet * wallet;
uint64_t total_tx;
uint64_t total_rx;
- std::timed_mutex guard;
+ std::mutex mutex;
+ std::condition_variable cv_send;
+ std::condition_variable cv_receive;
+ std::condition_variable cv_update;
+ std::condition_variable cv_refresh;
+ bool send_triggered;
+ bool receive_triggered;
+ bool update_triggered;
+ bool refresh_triggered;
+
+
MyWalletListener(Bitmonero::Wallet * wallet)
: total_tx(0), total_rx(0)
{
+ reset();
+
this->wallet = wallet;
this->wallet->setListener(this);
}
+ void reset()
+ {
+ send_triggered = receive_triggered = update_triggered = refresh_triggered = false;
+ }
+
virtual void moneySpent(const string &txId, uint64_t amount)
{
- std::cout << "wallet: " << wallet->address() << " just spent money ("
+ std::cerr << "wallet: " << wallet->address() << "**** just spent money ("
<< txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
total_tx += amount;
- guard.unlock();
+ send_triggered = true;
+ cv_send.notify_one();
}
virtual void moneyReceived(const string &txId, uint64_t amount)
{
- std::cout << "wallet: " << wallet->address() << " just received money ("
+ std::cout << "wallet: " << wallet->address() << "**** just received money ("
<< txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
total_rx += amount;
- guard.unlock();
+ receive_triggered = true;
+ cv_receive.notify_one();
}
+
+ virtual void updated()
+ {
+ std::cout << __FUNCTION__ << "Wallet updated";
+ update_triggered = true;
+ cv_update.notify_one();
+ }
+
+ virtual void refreshed()
+ {
+ std::cout << __FUNCTION__ << "Wallet refreshed";
+ refresh_triggered = true;
+ cv_refresh.notify_one();
+ }
+
};
-/*
+
+TEST_F(WalletTest2, WalletCallBackRefreshedSync)
+{
+
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
+ ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
+ ASSERT_TRUE(wallet_src_listener->refresh_triggered);
+ ASSERT_TRUE(wallet_src->connected());
+// std::chrono::seconds wait_for = std::chrono::seconds(60*3);
+// std::unique_lock<std::mutex> lock (wallet_src_listener->mutex);
+// wallet_src_listener->cv_refresh.wait_for(lock, wait_for);
+ wmgr->closeWallet(wallet_src);
+}
+
+
+TEST_F(WalletTest2, WalletCallBackRefreshedAsync)
+{
+
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
+ MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
+
+ std::chrono::seconds wait_for = std::chrono::seconds(20);
+ std::unique_lock<std::mutex> lock (wallet_src_listener->mutex);
+ wallet_src->initAsync(TESTNET_DAEMON_ADDRESS, 0);
+ std::cerr << "TEST: waiting on refresh lock...\n";
+ wallet_src_listener->cv_refresh.wait_for(lock, wait_for);
+ std::cerr << "TEST: refresh lock acquired...\n";
+ ASSERT_TRUE(wallet_src_listener->refresh_triggered);
+ ASSERT_TRUE(wallet_src->connected());
+ std::cerr << "TEST: closing wallet...\n";
+ wmgr->closeWallet(wallet_src);
+}
+
+
+
TEST_F(WalletTest2, WalletCallbackSent)
{
- Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true);
+ 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());
MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
+ uint64_t balance = wallet_src->balance();
std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
+ Bitmonero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, true);
+ uint64_t amount = AMOUNT_1XMR * 5;
+ std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address();
+
+
+ Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet_dst->address(),
+ PAYMENT_ID_EMPTY,
+ amount, 1);
+ std::cout << "** Committing transaction: " << Bitmonero::Wallet::displayAmount(tx->amount())
+ << " with fee: " << Bitmonero::Wallet::displayAmount(tx->fee());
- 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_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_src_listener->guard.lock();
- wallet_src_listener->guard.try_lock_for(wait_for);
-
- ASSERT_TRUE(wallet_src_listener->total_tx != 0);
+ std::unique_lock<std::mutex> lock (wallet_src_listener->mutex);
+ std::cerr << "TEST: waiting on send lock...\n";
+ wallet_src_listener->cv_send.wait_for(lock, wait_for);
+ std::cerr << "TEST: send lock acquired...\n";
+ ASSERT_TRUE(wallet_src_listener->send_triggered);
+ ASSERT_TRUE(wallet_src_listener->update_triggered);
+ std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
+ ASSERT_TRUE(wallet_src->balance() < balance);
+ wmgr->closeWallet(wallet_src);
+ wmgr->closeWallet(wallet_dst);
}
-*/
-/*
+
TEST_F(WalletTest2, WalletCallbackReceived)
{
- Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET3_NAME, TESTNET_WALLET_PASS, true);
+ Bitmonero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET5_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);
+ Bitmonero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, true);
ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(wallet_dst->refresh());
+ uint64_t balance = wallet_dst->balance();
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);
+ std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address();
+ Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet_dst->address(),
+ PAYMENT_ID_EMPTY,
+ amount, 1);
+
+ std::cout << "** Committing transaction: " << Bitmonero::Wallet::displayAmount(tx->amount())
+ << " with fee: " << Bitmonero::Wallet::displayAmount(tx->fee());
+
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
ASSERT_TRUE(tx->commit());
std::chrono::seconds wait_for = std::chrono::seconds(60*4);
-
- wallet_dst_listener->guard.lock();
- wallet_dst_listener->guard.try_lock_for(wait_for);
-
- ASSERT_TRUE(wallet_dst_listener->total_tx != 0);
-
+ std::unique_lock<std::mutex> lock (wallet_dst_listener->mutex);
+ std::cerr << "TEST: waiting on receive lock...\n";
+ wallet_dst_listener->cv_receive.wait_for(lock, wait_for);
+ std::cerr << "TEST: receive lock acquired...\n";
+ ASSERT_TRUE(wallet_dst_listener->receive_triggered);
+ ASSERT_TRUE(wallet_dst_listener->update_triggered);
+ std::cout << "** Balance: " << wallet_dst->displayAmount(wallet_src->balance()) << std::endl;
+ ASSERT_TRUE(wallet_dst->balance() > balance);
+
+ wmgr->closeWallet(wallet_src);
+ wmgr->closeWallet(wallet_dst);
}
-*/
+
int main(int argc, char** argv)
{
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/libwallet_api_tests/scripts/send_funds.sh b/tests/libwallet_api_tests/scripts/send_funds.sh
index 306b06a40..437e4f240 100755
--- a/tests/libwallet_api_tests/scripts/send_funds.sh
+++ b/tests/libwallet_api_tests/scripts/send_funds.sh
@@ -12,11 +12,23 @@ function send_funds {
}
-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
-send_funds 100 wallet_06.bin
+function seed_wallets {
+ local amount=$1
+ send_funds $amount wallet_01.bin
+ send_funds $amount wallet_02.bin
+ send_funds $amount wallet_03.bin
+ send_funds $amount wallet_04.bin
+ send_funds $amount wallet_05.bin
+ send_funds $amount wallet_06.bin
+}
+
+seed_wallets 1
+seed_wallets 2
+seed_wallets 5
+seed_wallets 10
+seed_wallets 20
+seed_wallets 50
+seed_wallets 100
+