mirror of
https://github.com/monero-project/monero.git
synced 2025-01-26 12:15:55 -05:00
Merge pull request #915
d7597c5 refreshing wallet even if error happened (Ilya Kitaev) 6d32a3d wallet_api: async init, Wallet::connected status, log level (Ilya Kitaev) 193d251 libwallet_api cmake: conditionally creating libwallet_merged2 only for STATIC build (Ilya Kitaev) 10c06dd wallet_api: segfault on refresh fixed (Ilya Kitaev) 9d2cb4f WalletListener functionality (Ilya Kitaev) d27b883 hack to successfull linking for MSYS2 (Ilya Kitaev) 083380c Transaction fee multiplier aka priority integraged (Ilya Kitaev) 00ed12b Wallet::paymentIdValid (Ilya Kitaev)
This commit is contained in:
commit
b582764bd6
@ -75,13 +75,26 @@ target_link_libraries(wallet
|
|||||||
${Boost_REGEX_LIBRARY}
|
${Boost_REGEX_LIBRARY}
|
||||||
${EXTRA_LIBRARIES})
|
${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 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}
|
install(FILES ${wallet_api_headers}
|
||||||
DESTINATION include/wallet)
|
DESTINATION include/wallet)
|
||||||
|
@ -46,6 +46,7 @@ namespace Bitmonero {
|
|||||||
namespace {
|
namespace {
|
||||||
// copy-pasted from simplewallet
|
// copy-pasted from simplewallet
|
||||||
static const size_t DEFAULT_MIXIN = 4;
|
static const size_t DEFAULT_MIXIN = 4;
|
||||||
|
static const int DEFAULT_REFRESH_INTERVAL_SECONDS = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
||||||
@ -89,6 +90,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
|||||||
<< ", amount: " << print_money(amount));
|
<< ", amount: " << print_money(amount));
|
||||||
if (m_listener) {
|
if (m_listener) {
|
||||||
m_listener->moneyReceived(tx_hash, amount);
|
m_listener->moneyReceived(tx_hash, amount);
|
||||||
|
m_listener->updated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +105,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
|||||||
<< ", amount: " << print_money(amount));
|
<< ", amount: " << print_money(amount));
|
||||||
if (m_listener) {
|
if (m_listener) {
|
||||||
m_listener->moneySpent(tx_hash, amount);
|
m_listener->moneySpent(tx_hash, amount);
|
||||||
|
m_listener->updated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +121,7 @@ Wallet::~Wallet() {}
|
|||||||
|
|
||||||
WalletListener::~WalletListener() {}
|
WalletListener::~WalletListener() {}
|
||||||
|
|
||||||
|
|
||||||
string Wallet::displayAmount(uint64_t amount)
|
string Wallet::displayAmount(uint64_t amount)
|
||||||
{
|
{
|
||||||
return cryptonote::print_money(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 implementation ////////////////////////
|
||||||
WalletImpl::WalletImpl(bool testnet)
|
WalletImpl::WalletImpl(bool testnet)
|
||||||
@ -153,13 +163,22 @@ WalletImpl::WalletImpl(bool testnet)
|
|||||||
m_wallet = new tools::wallet2(testnet);
|
m_wallet = new tools::wallet2(testnet);
|
||||||
m_history = new TransactionHistoryImpl(this);
|
m_history = new TransactionHistoryImpl(this);
|
||||||
m_wallet2Callback = new Wallet2CallbackImpl;
|
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()
|
WalletImpl::~WalletImpl()
|
||||||
{
|
{
|
||||||
delete m_wallet2Callback;
|
stopRefresh();
|
||||||
delete m_history;
|
delete m_history;
|
||||||
delete m_wallet;
|
delete m_wallet;
|
||||||
|
delete m_wallet2Callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
|
bool WalletImpl::create(const std::string &path, const std::string &password, const std::string &language)
|
||||||
@ -251,8 +270,12 @@ bool WalletImpl::close()
|
|||||||
clearStatus();
|
clearStatus();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
try {
|
try {
|
||||||
|
// LOG_PRINT_L0("Calling wallet::store...");
|
||||||
m_wallet->store();
|
m_wallet->store();
|
||||||
|
// LOG_PRINT_L0("wallet::store done");
|
||||||
|
// LOG_PRINT_L0("Calling wallet::stop...");
|
||||||
m_wallet->stop();
|
m_wallet->stop();
|
||||||
|
// LOG_PRINT_L0("wallet::stop done");
|
||||||
result = true;
|
result = true;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
m_status = Status_Error;
|
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)
|
bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit)
|
||||||
{
|
{
|
||||||
clearStatus();
|
clearStatus();
|
||||||
try {
|
|
||||||
m_wallet->init(daemon_address, upper_transaction_size_limit);
|
|
||||||
if (Utils::isAddressLocal(daemon_address)) {
|
|
||||||
this->setTrustedDaemon(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (const std::exception &e) {
|
m_wallet->init(daemon_address, upper_transaction_size_limit);
|
||||||
LOG_ERROR("Error initializing wallet: " << e.what());
|
if (Utils::isAddressLocal(daemon_address)) {
|
||||||
m_status = Status_Error;
|
this->setTrustedDaemon(true);
|
||||||
m_errorString = e.what();
|
|
||||||
}
|
}
|
||||||
|
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
|
uint64_t WalletImpl::balance() const
|
||||||
{
|
{
|
||||||
return m_wallet->balance();
|
return m_wallet->balance();
|
||||||
@ -377,15 +409,17 @@ uint64_t WalletImpl::unlockedBalance() const
|
|||||||
bool WalletImpl::refresh()
|
bool WalletImpl::refresh()
|
||||||
{
|
{
|
||||||
clearStatus();
|
clearStatus();
|
||||||
try {
|
doRefresh();
|
||||||
m_wallet->refresh();
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
m_status = Status_Error;
|
|
||||||
m_errorString = e.what();
|
|
||||||
}
|
|
||||||
return m_status == Status_Ok;
|
return m_status == Status_Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WalletImpl::refreshAsync()
|
||||||
|
{
|
||||||
|
LOG_PRINT_L3(__FUNCTION__ << ": Refreshing asyncronously..");
|
||||||
|
clearStatus();
|
||||||
|
m_refreshCV.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
// 1 - properly handle payment id (add another menthod with explicit 'payment_id' param)
|
||||||
// 2 - check / design how "Transaction" can be single interface
|
// 2 - check / design how "Transaction" can be single interface
|
||||||
@ -396,7 +430,9 @@ bool WalletImpl::refresh()
|
|||||||
// - unconfirmed_transfer_details;
|
// - unconfirmed_transfer_details;
|
||||||
// - confirmed_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();
|
clearStatus();
|
||||||
vector<cryptonote::tx_destination_entry> dsts;
|
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;
|
//std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||||
|
|
||||||
try {
|
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 */,
|
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&) {
|
} catch (const tools::error::daemon_busy&) {
|
||||||
// TODO: make it translatable with "tr"?
|
// TODO: make it translatable with "tr"?
|
||||||
@ -564,10 +602,17 @@ bool WalletImpl::connectToDaemon()
|
|||||||
m_status = result ? Status_Ok : Status_Error;
|
m_status = result ? Status_Ok : Status_Error;
|
||||||
if (!result) {
|
if (!result) {
|
||||||
m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address();
|
m_errorString = "Error connecting to daemon at " + m_wallet->get_daemon_address();
|
||||||
|
} else {
|
||||||
|
// start refreshing here
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::connected() const
|
||||||
|
{
|
||||||
|
return m_wallet->check_connection();
|
||||||
|
}
|
||||||
|
|
||||||
void WalletImpl::setTrustedDaemon(bool arg)
|
void WalletImpl::setTrustedDaemon(bool arg)
|
||||||
{
|
{
|
||||||
m_trustedDaemon = arg;
|
m_trustedDaemon = arg;
|
||||||
@ -584,5 +629,70 @@ void WalletImpl::clearStatus()
|
|||||||
m_errorString.clear();
|
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
|
} // namespace
|
||||||
|
@ -35,6 +35,9 @@
|
|||||||
#include "wallet/wallet2.h"
|
#include "wallet/wallet2.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
|
||||||
namespace Bitmonero {
|
namespace Bitmonero {
|
||||||
@ -65,14 +68,19 @@ public:
|
|||||||
std::string filename() const;
|
std::string filename() const;
|
||||||
std::string keysFilename() const;
|
std::string keysFilename() const;
|
||||||
bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit);
|
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 connectToDaemon();
|
||||||
|
bool connected() const;
|
||||||
void setTrustedDaemon(bool arg);
|
void setTrustedDaemon(bool arg);
|
||||||
bool trustedDaemon() const;
|
bool trustedDaemon() const;
|
||||||
uint64_t balance() const;
|
uint64_t balance() const;
|
||||||
uint64_t unlockedBalance() const;
|
uint64_t unlockedBalance() const;
|
||||||
bool refresh();
|
bool refresh();
|
||||||
|
void refreshAsync();
|
||||||
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
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 void disposeTransaction(PendingTransaction * t);
|
||||||
virtual TransactionHistory * history() const;
|
virtual TransactionHistory * history() const;
|
||||||
virtual void setListener(WalletListener * l);
|
virtual void setListener(WalletListener * l);
|
||||||
@ -81,19 +89,37 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void clearStatus();
|
void clearStatus();
|
||||||
|
void refreshThreadFunc();
|
||||||
|
void doRefresh();
|
||||||
|
void startRefresh();
|
||||||
|
void stopRefresh();
|
||||||
|
void pauseRefresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class PendingTransactionImpl;
|
friend class PendingTransactionImpl;
|
||||||
friend class TransactionHistoryImpl;
|
friend class TransactionHistoryImpl;
|
||||||
|
|
||||||
tools::wallet2 * m_wallet;
|
tools::wallet2 * m_wallet;
|
||||||
int m_status;
|
std::atomic<int> m_status;
|
||||||
std::string m_errorString;
|
std::string m_errorString;
|
||||||
std::string m_password;
|
std::string m_password;
|
||||||
TransactionHistoryImpl * m_history;
|
TransactionHistoryImpl * m_history;
|
||||||
bool m_trustedDaemon;
|
bool m_trustedDaemon;
|
||||||
WalletListener * m_walletListener;
|
WalletListener * m_walletListener;
|
||||||
Wallet2CallbackImpl * m_wallet2Callback;
|
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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,6 +137,11 @@ WalletManager *WalletManagerFactory::getWalletManager()
|
|||||||
return g_walletManager;
|
return g_walletManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WalletManagerFactory::setLogLevel(int level)
|
||||||
|
{
|
||||||
|
epee::log_space::log_singletone::get_set_log_detalisation_level(true, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,14 @@ struct PendingTransaction
|
|||||||
Status_Ok,
|
Status_Ok,
|
||||||
Status_Error
|
Status_Error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Priority {
|
||||||
|
Priority_Low = 1,
|
||||||
|
Priority_Medium = 2,
|
||||||
|
Priority_High = 3,
|
||||||
|
Priority_Last
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~PendingTransaction() = 0;
|
virtual ~PendingTransaction() = 0;
|
||||||
virtual int status() const = 0;
|
virtual int status() const = 0;
|
||||||
virtual std::string errorString() const = 0;
|
virtual std::string errorString() const = 0;
|
||||||
@ -108,7 +116,10 @@ struct WalletListener
|
|||||||
virtual ~WalletListener() = 0;
|
virtual ~WalletListener() = 0;
|
||||||
virtual void moneySpent(const std::string &txId, uint64_t amount) = 0;
|
virtual void moneySpent(const std::string &txId, uint64_t amount) = 0;
|
||||||
virtual void moneyReceived(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
|
* \return
|
||||||
*/
|
*/
|
||||||
virtual std::string keysFilename() const = 0;
|
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;
|
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;
|
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 void setTrustedDaemon(bool arg) = 0;
|
||||||
virtual bool trustedDaemon() const = 0;
|
virtual bool trustedDaemon() const = 0;
|
||||||
virtual uint64_t balance() 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 amountFromString(const std::string &amount);
|
||||||
static uint64_t amountFromDouble(double amount);
|
static uint64_t amountFromDouble(double amount);
|
||||||
static std::string genPaymentId();
|
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;
|
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
|
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
|
||||||
* \param dst_addr destination address as string
|
* \param dst_addr destination address as string
|
||||||
* \param payment_id optional payment_id, can be empty string
|
* \param payment_id optional payment_id, can be empty string
|
||||||
* \param amount amount
|
* \param amount amount
|
||||||
* \param mixin_count mixin count. if 0 passed, wallet will use default value
|
* \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()
|
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||||
* after object returned
|
* after object returned
|
||||||
*/
|
*/
|
||||||
|
|
||||||
virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
|
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 void disposeTransaction(PendingTransaction * t) = 0;
|
||||||
virtual TransactionHistory * history() const = 0;
|
virtual TransactionHistory * history() const = 0;
|
||||||
virtual void setListener(WalletListener *) = 0;
|
virtual void setListener(WalletListener *) = 0;
|
||||||
@ -271,8 +324,22 @@ struct WalletManager
|
|||||||
|
|
||||||
struct WalletManagerFactory
|
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 WalletManager * getWalletManager();
|
||||||
|
static void setLogLevel(int level);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include "wallet/wallet2_api.h"
|
#include "wallet/wallet2_api.h"
|
||||||
|
#include "include_base_utils.h"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
@ -39,6 +40,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -137,6 +140,7 @@ struct WalletManagerTest : public testing::Test
|
|||||||
{
|
{
|
||||||
std::cout << __FUNCTION__ << std::endl;
|
std::cout << __FUNCTION__ << std::endl;
|
||||||
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
wmgr = Bitmonero::WalletManagerFactory::getWalletManager();
|
||||||
|
// Bitmonero::WalletManagerFactory::setLogLevel(Bitmonero::WalletManagerFactory::LogLevel_4);
|
||||||
Utils::deleteWallet(WALLET_NAME);
|
Utils::deleteWallet(WALLET_NAME);
|
||||||
Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
|
Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
|
||||||
}
|
}
|
||||||
@ -235,7 +239,7 @@ TEST_F(WalletManagerTest, WalletManagerMovesWallet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
TEST_F(WalletManagerTest, WalletManagerChangesPassword)
|
TEST_F(WalletManagerTest, WalletManagerChangesPassword)
|
||||||
{
|
{
|
||||||
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
|
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(wallet1->setPassword(WALLET_PASS2));
|
||||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
Bitmonero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2);
|
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(wallet2->seed() == seed1);
|
||||||
ASSERT_TRUE(wmgr->closeWallet(wallet2));
|
ASSERT_TRUE(wmgr->closeWallet(wallet2));
|
||||||
Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
|
Bitmonero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
|
||||||
@ -343,7 +347,9 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
|
|||||||
ASSERT_TRUE(wallet1->address() == address1);
|
ASSERT_TRUE(wallet1->address() == address1);
|
||||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TEST_F(WalletManagerTest, WalletManagerFindsWallet)
|
TEST_F(WalletManagerTest, WalletManagerFindsWallet)
|
||||||
{
|
{
|
||||||
@ -415,7 +421,7 @@ TEST_F(WalletTest1, WalletConvertsToString)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
TEST_F(WalletTest1, WalletTransaction)
|
TEST_F(WalletTest1, WalletTransaction)
|
||||||
{
|
{
|
||||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
||||||
@ -429,8 +435,10 @@ TEST_F(WalletTest1, WalletTransaction)
|
|||||||
wallet1->setDefaultMixin(1);
|
wallet1->setDefaultMixin(1);
|
||||||
ASSERT_TRUE(wallet1->defaultMixin() == 1);
|
ASSERT_TRUE(wallet1->defaultMixin() == 1);
|
||||||
|
|
||||||
Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(
|
Bitmonero::PendingTransaction * transaction = wallet1->createTransaction(recepient_address,
|
||||||
recepient_address, AMOUNT_10XMR);
|
PAYMENT_ID_EMPTY,
|
||||||
|
AMOUNT_10XMR,
|
||||||
|
1);
|
||||||
ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
|
ASSERT_TRUE(transaction->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||||
wallet1->refresh();
|
wallet1->refresh();
|
||||||
|
|
||||||
@ -440,7 +448,6 @@ TEST_F(WalletTest1, WalletTransaction)
|
|||||||
ASSERT_FALSE(wallet1->balance() == balance);
|
ASSERT_FALSE(wallet1->balance() == balance);
|
||||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
TEST_F(WalletTest1, WalletTransactionWithMixin)
|
TEST_F(WalletTest1, WalletTransactionWithMixin)
|
||||||
{
|
{
|
||||||
@ -482,6 +489,48 @@ TEST_F(WalletTest1, WalletTransactionWithMixin)
|
|||||||
ASSERT_TRUE(wmgr->closeWallet(wallet1));
|
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)
|
TEST_F(WalletTest1, WalletHistory)
|
||||||
{
|
{
|
||||||
Bitmonero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, true);
|
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,
|
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
|
||||||
PAYMENT_ID_EMPTY,
|
PAYMENT_ID_EMPTY,
|
||||||
AMOUNT_10XMR * 5, 0);
|
AMOUNT_10XMR * 5, 1);
|
||||||
|
|
||||||
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
|
ASSERT_TRUE(tx->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||||
ASSERT_TRUE(tx->commit());
|
ASSERT_TRUE(tx->commit());
|
||||||
@ -586,100 +635,193 @@ TEST_F(WalletTest1, WalletTransactionWithPaymentId)
|
|||||||
ASSERT_TRUE(payment_id_in_history);
|
ASSERT_TRUE(payment_id_in_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct MyWalletListener : public Bitmonero::WalletListener
|
struct MyWalletListener : public Bitmonero::WalletListener
|
||||||
{
|
{
|
||||||
|
|
||||||
Bitmonero::Wallet * wallet;
|
Bitmonero::Wallet * wallet;
|
||||||
uint64_t total_tx;
|
uint64_t total_tx;
|
||||||
uint64_t total_rx;
|
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)
|
MyWalletListener(Bitmonero::Wallet * wallet)
|
||||||
: total_tx(0), total_rx(0)
|
: total_tx(0), total_rx(0)
|
||||||
{
|
{
|
||||||
|
reset();
|
||||||
|
|
||||||
this->wallet = wallet;
|
this->wallet = wallet;
|
||||||
this->wallet->setListener(this);
|
this->wallet->setListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
send_triggered = receive_triggered = update_triggered = refresh_triggered = false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void moneySpent(const string &txId, uint64_t amount)
|
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;
|
<< txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
|
||||||
total_tx += amount;
|
total_tx += amount;
|
||||||
guard.unlock();
|
send_triggered = true;
|
||||||
|
cv_send.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void moneyReceived(const string &txId, uint64_t amount)
|
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;
|
<< txId << ", " << wallet->displayAmount(amount) << ")" << std::endl;
|
||||||
total_rx += amount;
|
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)
|
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
|
// make sure testnet daemon is running
|
||||||
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||||
ASSERT_TRUE(wallet_src->refresh());
|
ASSERT_TRUE(wallet_src->refresh());
|
||||||
MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
|
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;
|
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();
|
||||||
|
|
||||||
|
|
||||||
uint64_t amount = AMOUNT_10XMR * 5;
|
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(wallet_dst->address(),
|
||||||
std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS;
|
PAYMENT_ID_EMPTY,
|
||||||
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5);
|
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->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||||
ASSERT_TRUE(tx->commit());
|
ASSERT_TRUE(tx->commit());
|
||||||
|
|
||||||
std::chrono::seconds wait_for = std::chrono::seconds(60*3);
|
std::chrono::seconds wait_for = std::chrono::seconds(60*3);
|
||||||
|
std::unique_lock<std::mutex> lock (wallet_src_listener->mutex);
|
||||||
wallet_src_listener->guard.lock();
|
std::cerr << "TEST: waiting on send lock...\n";
|
||||||
wallet_src_listener->guard.try_lock_for(wait_for);
|
wallet_src_listener->cv_send.wait_for(lock, wait_for);
|
||||||
|
std::cerr << "TEST: send lock acquired...\n";
|
||||||
ASSERT_TRUE(wallet_src_listener->total_tx != 0);
|
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)
|
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
|
// make sure testnet daemon is running
|
||||||
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||||
ASSERT_TRUE(wallet_src->refresh());
|
ASSERT_TRUE(wallet_src->refresh());
|
||||||
std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance()) << std::endl;
|
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->init(TESTNET_DAEMON_ADDRESS, 0));
|
||||||
ASSERT_TRUE(wallet_dst->refresh());
|
ASSERT_TRUE(wallet_dst->refresh());
|
||||||
|
uint64_t balance = wallet_dst->balance();
|
||||||
MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst);
|
MyWalletListener * wallet_dst_listener = new MyWalletListener(wallet_dst);
|
||||||
|
|
||||||
|
|
||||||
uint64_t amount = AMOUNT_1XMR * 5;
|
uint64_t amount = AMOUNT_1XMR * 5;
|
||||||
std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << TESTNET_WALLET4_ADDRESS;
|
std::cout << "** Sending " << Bitmonero::Wallet::displayAmount(amount) << " to " << wallet_dst->address();
|
||||||
Bitmonero::PendingTransaction * tx = wallet_src->createTransaction(TESTNET_WALLET4_ADDRESS, AMOUNT_1XMR * 5);
|
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->status() == Bitmonero::PendingTransaction::Status_Ok);
|
||||||
ASSERT_TRUE(tx->commit());
|
ASSERT_TRUE(tx->commit());
|
||||||
|
|
||||||
std::chrono::seconds wait_for = std::chrono::seconds(60*4);
|
std::chrono::seconds wait_for = std::chrono::seconds(60*4);
|
||||||
|
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);
|
||||||
|
|
||||||
wallet_dst_listener->guard.lock();
|
wmgr->closeWallet(wallet_src);
|
||||||
wallet_dst_listener->guard.try_lock_for(wait_for);
|
wmgr->closeWallet(wallet_dst);
|
||||||
|
|
||||||
ASSERT_TRUE(wallet_dst_listener->total_tx != 0);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,23 @@ function send_funds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
send_funds 100 wallet_01.bin
|
function seed_wallets {
|
||||||
send_funds 100 wallet_02.bin
|
local amount=$1
|
||||||
send_funds 100 wallet_03.bin
|
send_funds $amount wallet_01.bin
|
||||||
send_funds 100 wallet_04.bin
|
send_funds $amount wallet_02.bin
|
||||||
send_funds 100 wallet_05.bin
|
send_funds $amount wallet_03.bin
|
||||||
send_funds 100 wallet_06.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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user