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
7 changes: 7 additions & 0 deletions src/cpp/common/py_monero_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,13 @@ void PyMoneroUtils::binary_blocks_to_json(const std::string &bin, std::string &j
monero_utils::binary_blocks_to_json(bin, json);
}

void PyMoneroUtils::binary_blocks_to_property_tree(const std::string &bin, boost::property_tree::ptree &node) {
std::string response_json;
monero_utils::binary_blocks_to_json(bin, response_json);
std::istringstream iss = response_json.empty() ? std::istringstream() : std::istringstream(response_json);
boost::property_tree::read_json(iss, node);
}

bool PyMoneroUtils::is_valid_language(const std::string& language) {
return monero_utils::is_valid_language(language);
}
Expand Down
1 change: 1 addition & 0 deletions src/cpp/common/py_monero_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class PyMoneroUtils {
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 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);
static std::vector<std::shared_ptr<monero_block>> get_blocks_from_transfers(std::vector<std::shared_ptr<monero_transfer>> transfers);
Expand Down
118 changes: 108 additions & 10 deletions src/cpp/daemon/py_monero_daemon.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "py_monero_daemon.h"

static const uint64_t MAX_REQ_SIZE = 3000000;
static const uint64_t NUM_HEADERS_PER_REQ = 750;

void PyMoneroDaemonDefault::add_listener(const std::shared_ptr<PyMoneroDaemonListener> &listener) {
boost::lock_guard<boost::recursive_mutex> lock(m_listeners_mutex);
Expand Down Expand Up @@ -64,6 +66,13 @@ void PyMoneroDaemonDefault::submit_block(const std::string& block_blob) {
return submit_blocks(block_blobs);
}

void PyMoneroDaemonDefault::set_peer_ban(const std::shared_ptr<PyMoneroBan>& ban) {
if (ban == nullptr) throw std::runtime_error("Ban is none");
std::vector<std::shared_ptr<PyMoneroBan>> bans;
bans.push_back(ban);
set_peer_bans(bans);
}

PyMoneroDaemonPoller::~PyMoneroDaemonPoller() {
set_is_polling(false);
}
Expand Down Expand Up @@ -275,6 +284,23 @@ std::shared_ptr<monero::monero_block> PyMoneroDaemonRpc::get_block_by_hash(const
return block;
}

std::shared_ptr<monero::monero_block_header> PyMoneroDaemonRpc::get_block_header_by_height_cached(uint64_t height, uint64_t max_height) {
// get header from cache
auto found = m_cached_headers.find(height);
if (found != m_cached_headers.end()) return found->second;

// fetch and cache headers if not in cache
uint64_t end_height = std::min(max_height, height + NUM_HEADERS_PER_REQ - 1);
auto headers = get_block_headers_by_range(height, end_height);

for(const auto& header : headers) {
m_cached_headers[header->m_height.get()] = header;
}

return m_cached_headers[height];
}


std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) {
throw std::runtime_error("PyMoneroDaemonRpc::get_blocks_by_hash(): not implemented");
}
Expand All @@ -292,25 +318,91 @@ std::shared_ptr<monero::monero_block> PyMoneroDaemonRpc::get_block_by_height(uin
return block;
}

std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_blocks_by_height(std::vector<uint64_t> heights) {
// TODO Binary Request
throw std::runtime_error("PyMoneroDaemonRpc::get_blocks_by_height(): not implemented");
std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_blocks_by_height(const std::vector<uint64_t>& heights) {
// fetch blocks in binary
PyMoneroGetBlocksByHeightRequest request(heights);
auto response = m_rpc->send_binary_request(request);
if (response->m_binary == boost::none) throw std::runtime_error("Invalid Monero Binary response");
boost::property_tree::ptree node;
PyMoneroUtils::binary_blocks_to_property_tree(response->m_binary.get(), node);
check_response_status(node);
std::vector<std::shared_ptr<monero::monero_block>> blocks;
PyMoneroBlock::from_property_tree(node, heights, blocks);
return blocks;
}

std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_blocks_by_range(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height) {
if (!start_height.has_value()) {
std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_blocks_by_range(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height) {
if (start_height == boost::none) {
start_height = 0;
}
if (!end_height.has_value()) {
if (end_height == boost::none) {
end_height = get_height() - 1;
}

std::vector<uint64_t> heights;
for (uint64_t height = start_height.value(); height <= end_height.value(); height++) heights.push_back(height);
for (uint64_t height = start_height.get(); height <= end_height.get(); height++) heights.push_back(height);

return get_blocks_by_height(heights);
}

std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_blocks_by_range_chunked(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height, boost::optional<uint64_t> max_chunk_size) {
if (start_height == boost::none) start_height = 0;
if (end_height == boost::none) end_height = get_height() - 1;
uint64_t from_height = start_height.get();
bool from_zero = from_height == 0;
uint64_t last_height = (!from_zero) ? from_height - 1 : from_height;
std::vector<std::shared_ptr<monero::monero_block>> blocks;
while (last_height < end_height) {
uint64_t height_to_get = last_height + 1;
if (from_zero) {
height_to_get = 0;
from_zero = false;
}
auto max_blocks = get_max_blocks(height_to_get, end_height, max_chunk_size);
blocks.insert(blocks.end(), max_blocks.begin(), max_blocks.end());
last_height = blocks[blocks.size() - 1]->m_height.get();
}
return blocks;
}

std::vector<std::shared_ptr<monero::monero_block>> PyMoneroDaemonRpc::get_max_blocks(boost::optional<uint64_t> start_height, boost::optional<uint64_t> max_height, boost::optional<uint64_t> chunk_size) {
if (start_height == boost::none) start_height = 0;
if (max_height == boost::none) max_height = get_height() - 1;
if (chunk_size == boost::none) chunk_size = MAX_REQ_SIZE;

// determine end height to fetch
uint64_t req_size = 0;
uint64_t from_height = start_height.get();
bool from_zero = from_height == 0;
uint64_t end_height = (!from_zero) ? from_height - 1 : 0;

while (req_size < chunk_size && end_height < max_height) {
// get header of next block
uint64_t height_to_get = end_height + 1;
if (from_zero) {
height_to_get = 0;
from_zero = false;
}
auto header = get_block_header_by_height_cached(height_to_get, max_height.get());
uint64_t header_size = header->m_size.get();
// block cannot be bigger than max request size
if (header_size > chunk_size) throw std::runtime_error("Block exceeds maximum request size: " + std::to_string(header_size));

// done iterating if fetching block would exceed max request size
if (req_size + header_size > chunk_size) break;

// otherwise block is included
req_size += header_size;
end_height++;
}

if (end_height >= start_height) {
return get_blocks_by_range(start_height, end_height);
}

return std::vector<std::shared_ptr<monero::monero_block>>();
}

std::vector<std::string> PyMoneroDaemonRpc::get_block_hashes(std::vector<std::string> block_hashes, uint64_t start_height) {
throw std::runtime_error("PyMoneroDaemonRpc::get_block_hashes(): not implemented");
}
Expand All @@ -320,7 +412,13 @@ std::vector<std::shared_ptr<monero::monero_tx>> PyMoneroDaemonRpc::get_txs(const
auto params = std::make_shared<PyMoneroGetTxsParams>(tx_hashes, prune);
PyMoneroPathRequest request("get_transactions", params);
std::shared_ptr<PyMoneroPathResponse> response = m_rpc->send_path_request(request);
check_response_status(response);
try { check_response_status(response); }
catch (const std::exception& ex) {
if (std::string(ex.what()).find("Failed to parse hex representation of transaction hash") != std::string::npos) {
throw std::runtime_error("Invalid transaction hash");
}
throw;
}
auto res = response->m_response.get();
std::vector<std::shared_ptr<monero::monero_tx>> txs;
PyMoneroTx::from_property_tree(res, txs);
Expand Down Expand Up @@ -624,7 +722,7 @@ std::vector<std::shared_ptr<PyMoneroBan>> PyMoneroDaemonRpc::get_peer_bans() {
return bans;
}

void PyMoneroDaemonRpc::set_peer_bans(std::vector<std::shared_ptr<PyMoneroBan>> bans) {
void PyMoneroDaemonRpc::set_peer_bans(const std::vector<std::shared_ptr<PyMoneroBan>>& bans) {
auto params = std::make_shared<PyMoneroSetBansParams>(bans);
PyMoneroJsonRequest request("set_bans", params);
std::shared_ptr<PyMoneroJsonResponse> response = m_rpc->send_json_request(request);
Expand Down
20 changes: 12 additions & 8 deletions src/cpp/daemon/py_monero_daemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ class PyMoneroDaemon {
virtual std::shared_ptr<monero::monero_block> get_block_by_hash(const std::string& hash) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::shared_ptr<monero::monero_block> get_block_by_height(uint64_t height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_height(std::vector<uint64_t> heights) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range_chunked(uint64_t start_height, uint64_t end_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range_chunked(uint64_t start_height, uint64_t end_height, uint64_t max_chunk_size) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_height(const std::vector<uint64_t>& heights) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range_chunked(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height, boost::optional<uint64_t> max_chunk_size) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::string> get_block_hashes(std::vector<std::string> block_hashes, uint64_t start_height) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::optional<std::shared_ptr<monero::monero_tx>> get_tx(const std::string& tx_hash, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<monero::monero_tx>> get_txs(const std::vector<std::string>& tx_hashes, bool prune = false) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
Expand Down Expand Up @@ -98,7 +97,7 @@ class PyMoneroDaemon {
virtual void set_outgoing_peer_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual void set_incoming_peer_limit(int limit) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual std::vector<std::shared_ptr<PyMoneroBan>> get_peer_bans() { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual void set_peer_bans(std::vector<std::shared_ptr<PyMoneroBan>> bans) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual void set_peer_bans(const std::vector<std::shared_ptr<PyMoneroBan>>& bans) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual void set_peer_ban(const std::shared_ptr<PyMoneroBan>& ban) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual void start_mining(const std::string &address, int num_threads, bool is_background, bool ignore_battery) { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
virtual void stop_mining() { throw std::runtime_error("PyMoneroDaemon: not implemented"); }
Expand All @@ -125,6 +124,7 @@ class PyMoneroDaemonDefault : public PyMoneroDaemon {
PyMoneroKeyImageSpentStatus get_key_image_spent_status(std::string& key_image) override;
std::optional<std::string> get_tx_hex(const std::string& tx_hash, bool prune = false);
void submit_block(const std::string& block_blob) override;
void set_peer_ban(const std::shared_ptr<PyMoneroBan>& ban) override;

protected:
mutable boost::recursive_mutex m_listeners_mutex;
Expand Down Expand Up @@ -190,8 +190,9 @@ class PyMoneroDaemonRpc : public PyMoneroDaemonDefault {
std::shared_ptr<monero::monero_block> get_block_by_hash(const std::string& hash) override;
std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) override;
std::shared_ptr<monero::monero_block> get_block_by_height(uint64_t height) override;
std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_height(std::vector<uint64_t> heights) override;
std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height) override;
std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_height(const std::vector<uint64_t>& heights) override;
std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height) override;
std::vector<std::shared_ptr<monero::monero_block>> get_blocks_by_range_chunked(boost::optional<uint64_t> start_height, boost::optional<uint64_t> end_height, boost::optional<uint64_t> max_chunk_size) override;
std::vector<std::string> get_block_hashes(std::vector<std::string> block_hashes, uint64_t start_height) override;
std::vector<std::shared_ptr<monero::monero_tx>> get_txs(const std::vector<std::string>& tx_hashes, bool prune = false) override;
std::vector<std::string> get_tx_hexes(const std::vector<std::string>& tx_hashes, bool prune = false) override;
Expand Down Expand Up @@ -224,7 +225,7 @@ class PyMoneroDaemonRpc : public PyMoneroDaemonDefault {
void set_outgoing_peer_limit(int limit) override;
void set_incoming_peer_limit(int limit) override;
std::vector<std::shared_ptr<PyMoneroBan>> get_peer_bans() override;
void set_peer_bans(std::vector<std::shared_ptr<PyMoneroBan>> bans) override;
void set_peer_bans(const std::vector<std::shared_ptr<PyMoneroBan>>& bans) override;
void start_mining(const std::string &address, int num_threads, bool is_background, bool ignore_battery) override;
void stop_mining() override;
std::shared_ptr<PyMoneroMiningStatus> get_mining_status() override;
Expand All @@ -241,7 +242,10 @@ class PyMoneroDaemonRpc : public PyMoneroDaemonDefault {
protected:
std::shared_ptr<PyMoneroRpcConnection> m_rpc;
std::shared_ptr<PyMoneroDaemonPoller> m_poller;
std::unordered_map<uint64_t, std::shared_ptr<monero::monero_block_header>> m_cached_headers;

std::vector<std::shared_ptr<monero::monero_block>> get_max_blocks(boost::optional<uint64_t> start_height, boost::optional<uint64_t> max_height, boost::optional<uint64_t> chunk_size);
std::shared_ptr<monero::monero_block_header> get_block_header_by_height_cached(uint64_t height, uint64_t max_height);
std::shared_ptr<PyMoneroBandwithLimits> get_bandwidth_limits();
std::shared_ptr<PyMoneroBandwithLimits> set_bandwidth_limits(int up, int down);
void refresh_listening() override;
Expand Down
Loading