Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ wallet_full.start_syncing(5000)
wallet_full.add_listener(listener)

# connect to wallet RPC and open wallet
wallet_rpc: MoneroWallet = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123")
wallet_rpc: MoneroWallet = MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123")
wallet_rpc.open_wallet("sample_wallet_rpc", "supersecretpassword123")
primary_address: str = wallet_rpc.get_primary_address() # 555zgduFhmKd2o8rPUz...
balance: int = wallet_rpc.get_balance() # 533648366742
Expand Down
55 changes: 55 additions & 0 deletions src/cpp/common/py_monero_common.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
#include "py_monero_common.h"
#include "utils/monero_utils.h"

PyThreadPoller::~PyThreadPoller() {
set_is_polling(false);
}

void PyThreadPoller::init_common(const std::string& name) {
m_name = name;
m_is_polling = false;
m_poll_period_ms = 20000;
m_poll_loop_running = false;
}

void PyThreadPoller::set_is_polling(bool is_polling) {
if (is_polling == m_is_polling) return;
m_is_polling = is_polling;

if (m_is_polling) {
run_poll_loop();
} else {
if (m_poll_loop_running) {
m_poll_cv.notify_one();
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: in emscripten, m_sync_cv.notify_one() returns without waiting, so sleep; bug in emscripten upstream llvm?
m_thread.join();
}
}
}

void PyThreadPoller::set_period_in_ms(uint64_t period_ms) {
m_poll_period_ms = period_ms;
}

void PyThreadPoller::run_poll_loop() {
if (m_poll_loop_running) return; // only run one loop at a time
m_poll_loop_running = true;

// start pool loop thread
// TODO: use global threadpool, background sync wasm wallet in c++ thread
m_thread = boost::thread([this]() {

// poll while enabled
while (m_is_polling) {
try { poll(); }
catch (const std::exception& e) { std::cout << m_name << " failed to background poll: " << e.what() << std::endl; }
catch (...) { std::cout << m_name << " failed to background poll" << std::endl; }

// only wait if polling still enabled
if (m_is_polling) {
boost::mutex::scoped_lock lock(m_polling_mutex);
boost::posix_time::milliseconds wait_for_ms(m_poll_period_ms.load());
m_poll_cv.timed_wait(lock, wait_for_ms);
}
}

m_poll_loop_running = false;
});
}

py::object PyGenUtils::convert_value(const std::string& val) {
if (val == "true") return py::bool_(true);
Expand Down
24 changes: 24 additions & 0 deletions src/cpp/common/py_monero_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@ namespace pybind11 { namespace detail {

}}

class PyThreadPoller {
public:

~PyThreadPoller();

bool is_polling() const { return m_is_polling; }
void set_is_polling(bool is_polling);
void set_period_in_ms(uint64_t period_ms);
virtual void poll() = 0;

protected:
std::string m_name;
boost::recursive_mutex m_mutex;
boost::mutex m_polling_mutex;
boost::thread m_thread;
std::atomic<bool> m_is_polling;
std::atomic<bool> m_poll_loop_running;
std::atomic<uint64_t> m_poll_period_ms;
boost::condition_variable m_poll_cv;

void init_common(const std::string& name);
void run_poll_loop();
};

class PySerializableStruct : public monero::serializable_struct {
public:
using serializable_struct::serializable_struct;
Expand Down
3 changes: 1 addition & 2 deletions src/cpp/daemon/py_monero_daemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ class PyMoneroDaemon {
virtual void submit_blocks(const std::vector<std::string>& block_blobs) { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual std::shared_ptr<PyMoneroPruneResult> prune_blockchain(bool check) { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual std::shared_ptr<PyMoneroDaemonUpdateCheckResult> check_for_update() { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update() { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update(const std::string& path) { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update(const std::string& path = "") { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual void stop() { throw std::runtime_error("PyMoneroDaemon: not supported"); }
virtual std::shared_ptr<monero::monero_block_header> wait_for_next_block_header() { throw std::runtime_error("PyMoneroDaemon: not supported"); }
};
56 changes: 12 additions & 44 deletions src/cpp/daemon/py_monero_daemon_rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,10 @@
static const uint64_t MAX_REQ_SIZE = 3000000;
static const uint64_t NUM_HEADERS_PER_REQ = 750;

PyMoneroDaemonPoller::~PyMoneroDaemonPoller() {
set_is_polling(false);
}

PyMoneroDaemonPoller::PyMoneroDaemonPoller(PyMoneroDaemon* daemon, uint64_t poll_period_ms): m_poll_period_ms(poll_period_ms), m_is_polling(false) {
PyMoneroDaemonPoller::PyMoneroDaemonPoller(PyMoneroDaemon* daemon, uint64_t poll_period_ms) {
m_daemon = daemon;
}

void PyMoneroDaemonPoller::set_is_polling(bool is_polling) {
if (is_polling == m_is_polling) return;
m_is_polling = is_polling;

if (m_is_polling) {
m_thread = std::thread([this]() {
loop();
});
m_thread.detach();
} else {
if (m_thread.joinable()) m_thread.join();
}
}

void PyMoneroDaemonPoller::loop() {
while (m_is_polling) {
try {
poll();
} catch (const std::exception& e) {
std::cout << "ERROR " << e.what() << std::endl;
}

std::this_thread::sleep_for(std::chrono::milliseconds(m_poll_period_ms));
}
init_common("monero_daemon_rpc");
m_poll_period_ms = poll_period_ms;
}

void PyMoneroDaemonPoller::poll() {
Expand Down Expand Up @@ -73,6 +45,11 @@ PyMoneroDaemonRpc::PyMoneroDaemonRpc(const std::string& uri, const std::string&
if (!uri.empty()) m_rpc->check_connection();
}

std::vector<std::shared_ptr<PyMoneroDaemonListener>> PyMoneroDaemonRpc::get_listeners() {
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
return m_listeners;
}

void PyMoneroDaemonRpc::add_listener(const std::shared_ptr<PyMoneroDaemonListener> &listener) {
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
m_listeners.push_back(listener);
Expand Down Expand Up @@ -777,17 +754,6 @@ std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> PyMoneroDaemonRpc::download_
return result;
}

std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> PyMoneroDaemonRpc::download_update() {
auto params = std::make_shared<PyMoneroDownloadUpdateParams>();
PyMoneroPathRequest request("update", params);
auto response = m_rpc->send_path_request(request);
check_response_status(response);
auto result = std::make_shared<PyMoneroDaemonUpdateDownloadResult>();
auto res = response->m_response.get();
PyMoneroDaemonUpdateDownloadResult::from_property_tree(res, result);
return result;
}

void PyMoneroDaemonRpc::stop() {
PyMoneroPathRequest request("stop_daemon");
std::shared_ptr<PyMoneroPathResponse> response = m_rpc->send_path_request(request);
Expand Down Expand Up @@ -837,6 +803,7 @@ std::shared_ptr<PyMoneroBandwithLimits> PyMoneroDaemonRpc::set_bandwidth_limits(
}

void PyMoneroDaemonRpc::refresh_listening() {
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
if (!m_poller && m_listeners.size() > 0) {
m_poller = std::make_shared<PyMoneroDaemonPoller>(this);
}
Expand All @@ -847,9 +814,10 @@ void PyMoneroDaemonRpc::check_response_status(const boost::property_tree::ptree&
for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) {
std::string key = it->first;
if (key == std::string("status")) {
auto status = it->second.data();
std::string status = it->second.data();

if (status == std::string("OK")) {
// TODO monero-project empty string status is returned for download update response when an update is available
if (status == std::string("OK") || status == std::string("")) {
return;
}
else throw PyMoneroRpcError(status);
Expand Down
15 changes: 4 additions & 11 deletions src/cpp/daemon/py_monero_daemon_rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,17 @@

#include "py_monero_daemon.h"

class PyMoneroDaemonPoller {
class PyMoneroDaemonPoller: public PyThreadPoller {
public:

~PyMoneroDaemonPoller();
PyMoneroDaemonPoller(PyMoneroDaemon* daemon, uint64_t poll_period_ms = 5000);

void set_is_polling(bool is_polling);
void poll() override;

private:
PyMoneroDaemon* m_daemon;
std::shared_ptr<monero::monero_block_header> m_last_header;
uint64_t m_poll_period_ms;
std::atomic<bool> m_is_polling;
std::thread m_thread;

void loop();
void poll();
void announce_block_header(const std::shared_ptr<monero::monero_block_header>& header);
};

Expand All @@ -29,7 +23,7 @@ class PyMoneroDaemonRpc : public PyMoneroDaemon {
PyMoneroDaemonRpc(const std::shared_ptr<PyMoneroRpcConnection>& rpc);
PyMoneroDaemonRpc(const std::string& uri, const std::string& username = "", const std::string& password = "", const std::string& proxy_uri = "", const std::string& zmq_uri = "", uint64_t timeout = 20000);

std::vector<std::shared_ptr<PyMoneroDaemonListener>> get_listeners() override { return m_listeners; }
std::vector<std::shared_ptr<PyMoneroDaemonListener>> get_listeners() override;
void add_listener(const std::shared_ptr<PyMoneroDaemonListener> &listener) override;
void remove_listener(const std::shared_ptr<PyMoneroDaemonListener> &listener) override;
void remove_listeners() override;
Expand Down Expand Up @@ -90,8 +84,7 @@ class PyMoneroDaemonRpc : public PyMoneroDaemon {
void submit_blocks(const std::vector<std::string>& block_blobs) override;
std::shared_ptr<PyMoneroPruneResult> prune_blockchain(bool check) override;
std::shared_ptr<PyMoneroDaemonUpdateCheckResult> check_for_update() override;
std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update(const std::string& path) override;
std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update() override;
std::shared_ptr<PyMoneroDaemonUpdateDownloadResult> download_update(const std::string& path = "") override;
void stop() override;
std::shared_ptr<monero::monero_block_header> wait_for_next_block_header();
static void check_response_status(const std::shared_ptr<PyMoneroPathResponse>& response);
Expand Down
39 changes: 30 additions & 9 deletions src/cpp/py_monero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ PYBIND11_MODULE(monero, m) {
auto py_monero_subaddress = py::class_<monero::monero_subaddress, monero::serializable_struct, std::shared_ptr<monero::monero_subaddress>>(m, "MoneroSubaddress");
auto py_monero_sync_result = py::class_<monero::monero_sync_result, monero::serializable_struct, std::shared_ptr<monero::monero_sync_result>>(m, "MoneroSyncResult");
auto py_monero_account = py::class_<monero::monero_account, monero::serializable_struct, std::shared_ptr<monero::monero_account>>(m, "MoneroAccount");
auto py_monero_account_tag = py::class_<PyMoneroAccountTag, std::shared_ptr<PyMoneroAccountTag>>(m, "MoneroAccountTag");
auto py_monero_account_tag = py::class_<PyMoneroAccountTag, monero::serializable_struct, std::shared_ptr<PyMoneroAccountTag>>(m, "MoneroAccountTag");
auto py_monero_destination = py::class_<monero::monero_destination, std::shared_ptr<monero::monero_destination>>(m, "MoneroDestination");
auto py_monero_transfer = py::class_<monero::monero_transfer, monero::serializable_struct, PyMoneroTransfer, std::shared_ptr<monero::monero_transfer>>(m, "MoneroTransfer");
auto py_monero_incoming_transfer = py::class_<monero::monero_incoming_transfer, monero::monero_transfer, std::shared_ptr<monero::monero_incoming_transfer>>(m, "MoneroIncomingTransfer");
Expand Down Expand Up @@ -1546,12 +1546,9 @@ PYBIND11_MODULE(monero, m) {
.def("check_for_update", [](PyMoneroDaemon& self) {
MONERO_CATCH_AND_RETHROW(self.check_for_update());
})
.def("download_update", [](PyMoneroDaemon& self) {
MONERO_CATCH_AND_RETHROW(self.download_update());
})
.def("download_update", [](PyMoneroDaemon& self, const std::string& download_path) {
MONERO_CATCH_AND_RETHROW(self.download_update(download_path));
}, py::arg("download_path"))
.def("download_update", [](PyMoneroDaemon& self, const std::string& path) {
MONERO_CATCH_AND_RETHROW(self.download_update(path));
}, py::arg("path") = "")
.def("stop", [](PyMoneroDaemon& self) {
MONERO_CATCH_AND_RETHROW(self.stop());
})
Expand Down Expand Up @@ -2068,7 +2065,19 @@ PYBIND11_MODULE(monero, m) {
}, py::arg("config"))
.def_static("get_seed_languages", []() {
MONERO_CATCH_AND_RETHROW(monero::monero_wallet_keys::get_seed_languages());
});
})
.def("tag_accounts", [](monero::monero_wallet_keys& self, const std::string& tag, const std::vector<uint32_t>& account_indices) {
throw PyMoneroError("MoneroWalletKeys.tag_accounts(): not supported");
}, py::arg("tag"), py::arg("account_indices"))
.def("untag_accounts", [](monero::monero_wallet_keys& self, const std::vector<uint32_t>& account_indices) {
throw PyMoneroError("MoneroWalletKeys.untag_accounts(): not supported");
}, py::arg("account_indices"))
.def("get_account_tags", [](monero::monero_wallet_keys& self) {
throw PyMoneroError("MoneroWalletKeys.get_account_tags(): not supported");
})
.def("set_account_tag_label", [](monero::monero_wallet_keys& self, const std::string& tag, const std::string& label) {
throw PyMoneroError("MoneroWalletKeys.set_account_tag_label(): not supported");
}, py::arg("tag"), py::arg("label"));

// monero_wallet_full
py_monero_wallet_full
Expand Down Expand Up @@ -2102,7 +2111,19 @@ PYBIND11_MODULE(monero, m) {
}, py::arg("password"), py::arg("view_only"))
.def("get_cache_file_buffer", [](monero::monero_wallet_full& self) {
MONERO_CATCH_AND_RETHROW(self.get_cache_file_buffer());
});
})
.def("tag_accounts", [](monero::monero_wallet_full& self, const std::string& tag, const std::vector<uint32_t>& account_indices) {
throw PyMoneroError("MoneroWalletFull.tag_accounts(): not implemented");
}, py::arg("tag"), py::arg("account_indices"))
.def("untag_accounts", [](monero::monero_wallet_full& self, const std::vector<uint32_t>& account_indices) {
throw PyMoneroError("MoneroWalletFull.untag_accounts(): not implemented");
}, py::arg("account_indices"))
.def("get_account_tags", [](monero::monero_wallet_full& self) {
throw PyMoneroError("MoneroWalletFull.get_account_tags(): not implemented");
})
.def("set_account_tag_label", [](monero::monero_wallet_full& self, const std::string& tag, const std::string& label) {
throw PyMoneroError("MoneroWalletFull.set_account_tag_label(): not implemented");
}, py::arg("tag"), py::arg("label"));

// monero_wallet_rpc
py_monero_wallet_rpc
Expand Down
6 changes: 5 additions & 1 deletion src/cpp/wallet/py_monero_wallet_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ PyMoneroCreateOpenWalletParams::PyMoneroCreateOpenWalletParams(const boost::opti
m_autosave_current(autosave_current) {
}

PyMoneroGetAccountsParams::PyMoneroGetAccountsParams(const std::string& tag): m_tag(tag) {
if (tag.empty()) m_tag = boost::none;
}

PyMoneroReserveProofParams::PyMoneroReserveProofParams(const std::string &message, bool all):
m_all(all), m_message(message) {
}
Expand Down Expand Up @@ -1682,7 +1686,7 @@ rapidjson::Value PyMoneroAddressBookEntryParams::to_rapidjson_val(rapidjson::Doc
rapidjson::Value PyMoneroGetAccountsParams::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const {
rapidjson::Value root(rapidjson::kObjectType);
rapidjson::Value value_str(rapidjson::kStringType);
if (m_label != boost::none) monero_utils::add_json_member("label", m_label.get(), allocator, root, value_str);
if (m_tag != boost::none) monero_utils::add_json_member("tag", m_tag.get(), allocator, root, value_str);
return root;
}

Expand Down
4 changes: 2 additions & 2 deletions src/cpp/wallet/py_monero_wallet_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,9 @@ class PyMoneroWalletBalance {

class PyMoneroGetAccountsParams : public PyMoneroJsonRequestParams {
public:
boost::optional<std::string> m_label;
boost::optional<std::string> m_tag;

PyMoneroGetAccountsParams(const std::string& label): m_label(label) { }
PyMoneroGetAccountsParams(const std::string& tag);

rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
};
Expand Down
Loading
Loading