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
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 @@ -150,8 +150,7 @@ class monero_daemon {
virtual std::vector<monero_key_image_spent_status> get_key_image_spent_statuses(const std::vector<std::string>& key_images) { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::vector<std::shared_ptr<monero::monero_output>> get_outputs(const std::vector<monero::monero_output>& outputs) { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::vector<std::shared_ptr<monero_output_histogram_entry>> get_output_histogram(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::vector<std::shared_ptr<monero_output_distribution_entry>> get_output_distribution(const std::vector<uint64_t>& amounts) { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::vector<std::shared_ptr<monero_output_distribution_entry>> get_output_distribution(const std::vector<uint64_t>& amounts, bool is_cumulative, uint64_t start_height, uint64_t end_height) { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::vector<std::shared_ptr<monero_output_distribution_entry>> get_output_distribution(const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative = boost::none, const boost::optional<uint64_t>& start_height = boost::none, const boost::optional<uint64_t>& end_height = boost::none) { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::shared_ptr<monero_daemon_info> get_info() { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::shared_ptr<monero_daemon_sync_info> get_sync_info() { throw std::runtime_error("monero_daemon: not supported"); }
virtual std::shared_ptr<monero_hard_fork_info> get_hard_fork_info() { throw std::runtime_error("monero_daemon: not supported"); }
Expand Down
15 changes: 15 additions & 0 deletions src/cpp/daemon/py_monero_daemon_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,21 @@ void monero_output_distribution_entry::from_property_tree(const boost::property_
}
}

void monero_output_distribution_entry::from_property_tree(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_output_distribution_entry>>& entries) {
for (boost::property_tree::ptree::const_iterator it = node.begin(); it != node.end(); ++it) {
std::string key = it->first;

if (key == std::string("distributions")) {
auto node2 = it->second;
for(boost::property_tree::ptree::const_iterator it2 = node2.begin(); it2 != node2.end(); ++it2) {
auto entry = std::make_shared<monero_output_distribution_entry>();
from_property_tree(it2->second, entry);
entries.push_back(entry);
}
}
}
}

rapidjson::Value monero_output_distribution_entry::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const {
// create root
rapidjson::Value root(rapidjson::kObjectType);
Expand Down
1 change: 1 addition & 0 deletions src/cpp/daemon/py_monero_daemon_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ struct monero_output_distribution_entry : public monero::serializable_struct {
boost::optional<uint64_t> m_start_height;

static void from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_output_distribution_entry>& entry);
static void from_property_tree(const boost::property_tree::ptree& node, std::vector<std::shared_ptr<monero_output_distribution_entry>>& entries);
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
};

Expand Down
11 changes: 10 additions & 1 deletion src/cpp/daemon/py_monero_daemon_rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,6 @@ std::vector<std::shared_ptr<monero::monero_output>> monero_daemon_rpc::get_outpu

std::vector<std::shared_ptr<monero_output_histogram_entry>> monero_daemon_rpc::get_output_histogram(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) {
MTRACE("monero_daemon_rpc::get_output_histogram()");

auto params = std::make_shared<monero_get_output_histogram_params>(amounts, min_count, max_count, is_unlocked, recent_cutoff);
auto res = m_rpc->send_json_request("get_output_histogram", params);
check_response_status(res);
Expand All @@ -526,6 +525,16 @@ std::vector<std::shared_ptr<monero_output_histogram_entry>> monero_daemon_rpc::g
return entries;
}

std::vector<std::shared_ptr<monero_output_distribution_entry>> monero_daemon_rpc::get_output_distribution(const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative, const boost::optional<uint64_t>& start_height, const boost::optional<uint64_t>& end_height) {
MTRACE("monero_daemon_rpc::get_output_distribution()");
auto params = std::make_shared<monero_get_output_distribution_params>(amounts, is_cumulative, start_height, end_height);
auto res = m_rpc->send_json_request("get_output_distribution", params);
check_response_status(res);
std::vector<std::shared_ptr<monero_output_distribution_entry>> entries;
monero_output_distribution_entry::from_property_tree(res, entries);
return entries;
}

std::shared_ptr<monero_daemon_info> monero_daemon_rpc::get_info() {
auto res = m_rpc->send_json_request("get_info");
check_response_status(res);
Expand Down
1 change: 1 addition & 0 deletions src/cpp/daemon/py_monero_daemon_rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class monero_daemon_rpc : public monero_daemon {
std::vector<monero_key_image_spent_status> get_key_image_spent_statuses(const std::vector<std::string>& key_images) override;
std::vector<std::shared_ptr<monero::monero_output>> get_outputs(const std::vector<monero::monero_output>& outputs) override;
std::vector<std::shared_ptr<monero_output_histogram_entry>> get_output_histogram(const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) override;
std::vector<std::shared_ptr<monero_output_distribution_entry>> get_output_distribution(const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative = boost::none, const boost::optional<uint64_t>& start_height = boost::none, const boost::optional<uint64_t>& end_height = boost::none) override;
std::shared_ptr<monero_daemon_info> get_info() override;
std::shared_ptr<monero_daemon_sync_info> get_sync_info() override;
std::shared_ptr<monero_hard_fork_info> get_hard_fork_info() override;
Expand Down
23 changes: 23 additions & 0 deletions src/cpp/daemon/py_monero_daemon_rpc_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,29 @@ rapidjson::Value monero_get_output_histogram_params::to_rapidjson_val(rapidjson:
return root;
}

// --------------------------- MONERO GET OUTPUT DISTRIBUTION PARAMS ---------------------------

rapidjson::Value monero_get_output_distribution_params::to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const {
// create root
rapidjson::Value root(rapidjson::kObjectType);

// set num values
rapidjson::Value value_num(rapidjson::kNumberType);
if (m_from_height != boost::none) monero_utils::add_json_member("from_height", m_from_height.get(), allocator, root, value_num);
if (m_to_height != boost::none) monero_utils::add_json_member("to_height", m_to_height.get(), allocator, root, value_num);

// set bool values
if (m_cumulative != boost::none) monero_utils::add_json_member("cumulative", m_cumulative.get(), allocator, root);
if (m_binary != boost::none) monero_utils::add_json_member("binary", m_binary.get(), allocator, root);

// set sub-array values
if (!m_amounts.empty()) root.AddMember("amounts", monero_utils::to_rapidjson_val(allocator, m_amounts), allocator);

// return root
return root;
}


// --------------------------- MONERO GET BLOCK RESULT ---------------------------

void monero_get_block_result::from_property_tree(const boost::property_tree::ptree& node, const std::shared_ptr<monero_get_block_result>& result) {
Expand Down
13 changes: 13 additions & 0 deletions src/cpp/daemon/py_monero_daemon_rpc_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ struct monero_get_output_histogram_params : public monero::serializable_struct {
rapidjson::Value to_rapidjson_val(rapidjson::Document::AllocatorType& allocator) const override;
};

struct monero_get_output_distribution_params : public monero::serializable_struct {
public:
std::vector<uint64_t> m_amounts;
boost::optional<bool> m_cumulative;
boost::optional<bool> m_binary;
boost::optional<uint64_t> m_from_height;
boost::optional<uint64_t> m_to_height;

monero_get_output_distribution_params(const std::vector<uint64_t>& amounts, const boost::optional<bool>& cumulative, const boost::optional<uint64_t>& from_height, const boost::optional<uint64_t>& to_height) : m_amounts(amounts), m_cumulative(cumulative), m_from_height(from_height), m_to_height(to_height), m_binary(false) { }

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

// ------------------------------ JSON-RPC Response ---------------------------------

struct monero_get_block_result {
Expand Down
17 changes: 6 additions & 11 deletions src/cpp/py_monero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1379,12 +1379,9 @@ PYBIND11_MODULE(monero, m) {
.def("get_output_histogram", [](monero_daemon& self, const std::vector<uint64_t>& amounts, const boost::optional<int>& min_count, const boost::optional<int>& max_count, const boost::optional<bool>& is_unlocked, const boost::optional<int>& recent_cutoff) {
MONERO_CATCH_AND_RETHROW(self.get_output_histogram(amounts, min_count, max_count, is_unlocked, recent_cutoff));
}, py::arg("amounts"), py::arg("min_count"), py::arg("max_count"), py::arg("is_unlocked"), py::arg("recent_cutoff"), py::call_guard<py::gil_scoped_release>())
.def("get_output_distribution", [](monero_daemon& self, const std::vector<uint64_t>& amounts) {
MONERO_CATCH_AND_RETHROW(self.get_output_distribution(amounts));
}, py::arg("amounts"), py::call_guard<py::gil_scoped_release>())
.def("get_output_distribution", [](monero_daemon& self, const std::vector<uint64_t>& amounts, bool is_cumulative, uint64_t start_height, uint64_t end_height) {
.def("get_output_distribution", [](monero_daemon& self, const std::vector<uint64_t>& amounts, const boost::optional<bool>& is_cumulative, const boost::optional<uint64_t>& start_height, const boost::optional<uint64_t>& end_height) {
MONERO_CATCH_AND_RETHROW(self.get_output_distribution(amounts, is_cumulative, start_height, end_height));
}, py::arg("amounts"), py::arg("is_cumulative"), py::arg("start_height"), py::arg("end_height"), py::call_guard<py::gil_scoped_release>())
}, py::arg("amounts"), py::arg("is_cumulative") = py::none(), py::arg("start_height") = py::none(), py::arg("end_height") = py::none(), py::call_guard<py::gil_scoped_release>())
.def("get_info", [](monero_daemon& self) {
MONERO_CATCH_AND_RETHROW(self.get_info());
}, py::call_guard<py::gil_scoped_release>())
Expand Down Expand Up @@ -2144,18 +2141,16 @@ PYBIND11_MODULE(monero, m) {
std::string b{bin};
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_json(b));
}, py::arg("bin"))
.def_static("binary_to_json", [](const std::string &bin) {
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_json(bin));
}, py::arg("bin"))
.def_static("dict_to_binary", [](const py::dict &dictionary) {
MONERO_CATCH_AND_RETHROW(py::bytes(PyMoneroUtils::dict_to_binary(dictionary)));
}, py::arg("dictionary"))
.def_static("binary_to_dict", [](const std::string &bin) {
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_dict(bin));
}, py::arg("bin"))
.def_static("binary_to_dict", [](const py::bytes &bin) {
std::string b{bin};
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_to_dict(b));
}, py::arg("bin"))
.def_static("binary_blocks_to_json", [](const py::bytes &bin) {
std::string b{bin};
MONERO_CATCH_AND_RETHROW(PyMoneroUtils::binary_blocks_to_json(b));
}, py::arg("bin"));

py_tx_height_comparator
Expand Down
4 changes: 3 additions & 1 deletion src/cpp/utils/py_monero_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,10 @@ std::string PyMoneroUtils::binary_to_json(const std::string &bin) {
return json;
}

void PyMoneroUtils::binary_blocks_to_json(const std::string &bin, std::string &json) {
std::string PyMoneroUtils::binary_blocks_to_json(const std::string &bin) {
std::string json;
monero_utils::binary_blocks_to_json(bin, json);
return json;
}

void PyMoneroUtils::binary_blocks_to_property_tree(const std::string &bin, boost::property_tree::ptree &node) {
Expand Down
2 changes: 1 addition & 1 deletion src/cpp/utils/py_monero_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class PyMoneroUtils {
static std::string dict_to_binary(const py::dict &dictionary);
static py::dict binary_to_dict(const std::string& bin);
static std::string binary_to_json(const std::string &bin);
static void binary_blocks_to_json(const std::string &bin, std::string &json);
static std::string binary_blocks_to_json(const std::string &bin);
static void binary_blocks_to_property_tree(const std::string &bin, boost::property_tree::ptree &node);
static bool is_valid_language(const std::string& language);
static std::vector<std::shared_ptr<monero_block>> get_blocks_from_txs(std::vector<std::shared_ptr<monero_tx_wallet>> txs);
Expand Down
10 changes: 0 additions & 10 deletions src/cpp/wallet/py_monero_wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,6 @@ void PyMoneroWallet::announce_new_block(uint64_t height) {
}
}

void PyMoneroWallet::announce_sync_progress(uint64_t height, uint64_t start_height, uint64_t end_height, float percent_done, const std::string &message) {
for (const auto &listener : m_listeners) {
try {
listener->on_sync_progress(height, start_height, end_height, percent_done, message);
} catch (const std::exception &e) {
MERROR(e.what());
}
}
}

void PyMoneroWallet::announce_balances_changed(uint64_t balance, uint64_t unlocked_balance) {
for (const auto &listener : m_listeners) {
try {
Expand Down
1 change: 0 additions & 1 deletion src/cpp/wallet/py_monero_wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,6 @@ class PyMoneroWallet : public monero::monero_wallet {
}

virtual void announce_new_block(uint64_t height);
virtual void announce_sync_progress(uint64_t height, uint64_t start_height, uint64_t end_height, float percent_done, const std::string &message);
virtual void announce_balances_changed(uint64_t balance, uint64_t unlocked_balance);
virtual void announce_output_spent(const std::shared_ptr<monero::monero_output_wallet> &output);
virtual void announce_output_received(const std::shared_ptr<monero::monero_output_wallet> &output);
Expand Down
19 changes: 4 additions & 15 deletions src/python/monero_daemon.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -318,25 +318,14 @@ class MoneroDaemon:
"""
...

@typing.overload
def get_output_distribution(self, amounts: list[int]) -> list[MoneroOutputDistributionEntry]:
"""
Creates an output distribution.

:param list[int] amounts: are amounts of outputs to make the distribution with.
:returns list[MoneroOutputDistributionEntry]: output distribution entries meeting the parameters.
"""
...

@typing.overload
def get_output_distribution(self, amounts: list[int], is_cumulative: bool, start_height: int, end_height: int) -> list[MoneroOutputDistributionEntry]:
def get_output_distribution(self, amounts: list[int], is_cumulative: bool | None = None, start_height: int | None = None, end_height: int | None = None) -> list[MoneroOutputDistributionEntry]:
"""
Creates an output distribution.

:param list[int] amounts: are amounts of outputs to make the distribution with.
:param bool is_cumulative: specifies if the results should be cumulative.
:param int start_height: is the start height lower bound inclusive (optional).
:param int end_height: is the end height upper bound inclusive (optional).
:param bool | None is_cumulative: specifies if the results should be cumulative (optional).
:param int | None start_height: is the start height lower bound inclusive (optional).
:param int | None end_height: is the end height upper bound inclusive (optional).
:returns list[MoneroOutputDistributionEntry]: output distribution entries meeting the parameters.
"""
...
Expand Down
24 changes: 5 additions & 19 deletions src/python/monero_utils.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, overload
from typing import Any
from .monero_output_wallet import MoneroOutputWallet
from .monero_block import MoneroBlock
from .monero_transfer import MoneroTransfer
Expand All @@ -22,7 +22,6 @@ class MoneroUtils:
...

@staticmethod
@overload
def binary_to_dict(bin: bytes) -> dict[Any, Any]:
"""
Deserialize a dictionary from binary format.
Expand All @@ -33,18 +32,6 @@ class MoneroUtils:
...

@staticmethod
@overload
def binary_to_dict(bin: str) -> dict[Any, Any]:
"""
Deserialize a dictionary from binary format.

:param str bin: Dictionary in binary format.
:returns dict: Deserialized dictionary.
"""
...

@staticmethod
@overload
def binary_to_json(bin: bytes) -> str:
"""
Deserialize a JSON string from binary format.
Expand All @@ -55,13 +42,12 @@ class MoneroUtils:
...

@staticmethod
@overload
def binary_to_json(bin: str) -> str:
def binary_blocks_to_json(bin: bytes) -> str:
"""
Deserialize a JSON string from binary format.
Deserialize blocks JSON string from binary format.

:param str bin: JSON string in binary format.
:returns str: The deserialized JSON string.
:param bytes bin: blocks JSON string in binary format.
:returns str: The deserialized blocks in JSON string format.
"""
...

Expand Down
7 changes: 3 additions & 4 deletions tests/test_monero_daemon_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,11 +732,10 @@ def test_get_output_histogram_binary(self, daemon: MoneroDaemonRpc) -> None:
for entry in entries:
OutputUtils.test_output_histogram_entry(entry)

# Can get an output distribution (binary)
# Can get an output distribution
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
@pytest.mark.xfail(reason="TODO not implemented")
def test_get_output_distribution_binary(self, daemon: MoneroDaemonRpc) -> None:
amounts: list[int] = [0, 1, 10, 100, 1000, 10000, 100000, 1000000]
def test_get_output_distribution(self, daemon: MoneroDaemonRpc) -> None:
amounts: list[int] = [0]
entries: list[MoneroOutputDistributionEntry] = daemon.get_output_distribution(amounts)
for entry in entries:
OutputUtils.test_output_distribution_entry(entry)
Expand Down
9 changes: 7 additions & 2 deletions tests/test_monero_rpc_connection.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import pytest
import logging

from monero import MoneroRpcConnection, MoneroConnectionType, MoneroRpcError
from utils import TestUtils as Utils, RpcConnectionUtils, StringUtils, BaseTestClass
from monero import MoneroRpcConnection, MoneroConnectionType, MoneroRpcError, MoneroUtils
from utils import (
TestUtils as Utils, RpcConnectionUtils,
StringUtils, BaseTestClass
)

logger: logging.Logger = logging.getLogger("TestMoneroRpcConnection")

Expand Down Expand Up @@ -218,6 +221,8 @@ def test_send_binary_request(self, node_connection: MoneroRpcConnection) -> None
bin_result: bytes | None = node_connection.send_binary_request("get_blocks_by_height.bin", parameters)
assert bin_result is not None
logger.debug(f"Binary response: {bin_result}")
json_result: str = MoneroUtils.binary_blocks_to_json(bin_result)
logger.debug(f"Deserialized binary response: {StringUtils.prettify(json_result)}")

# test invalid binary method
try:
Expand Down
1 change: 1 addition & 0 deletions tests/test_monero_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ def test_key_validation(self, config: TestMoneroUtils.Config) -> None:

# test public view key validation
assert MoneroUtils.is_valid_public_view_key(config.keys.public_view_key)
MoneroUtils.validate_public_view_key(config.keys.public_view_key)
WalletUtils.test_invalid_public_view_key("")
WalletUtils.test_invalid_public_view_key(None)
WalletUtils.test_invalid_public_view_key(config.keys.invalid_public_view_key)
Expand Down
7 changes: 7 additions & 0 deletions tests/utils/string_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from abc import ABC
from typing import Any
from json import loads, dumps
from secrets import token_hex


Expand Down Expand Up @@ -38,3 +40,8 @@ def get_random_string(cls, n: int = 25) -> str:
"""
# generate random string
return token_hex(n)

@classmethod
def prettify(cls, json_str: str) -> str:
parsed_obj: Any = loads(json_str)
return dumps(parsed_obj, indent=1)
Loading