Skip to content
Open
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
80 changes: 78 additions & 2 deletions src/rpc/daemon_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ namespace rpc
{u8"get_rpc_version", handle_message<GetRPCVersion>},
{u8"get_transaction_pool", handle_message<GetTransactionPool>},
{u8"get_transactions", handle_message<GetTransactions>},
{u8"get_tree_paths", handle_message<GetTreePaths>},
{u8"get_tx_global_output_indices", handle_message<GetTxGlobalOutputIndices>},
{u8"get_unified_ids", handle_message<GetUnifiedId>},
{u8"hard_fork_info", handle_message<HardForkInfo>},
{u8"key_images_spent", handle_message<KeyImagesSpent>},
{u8"mining_status", handle_message<MiningStatus>},
Expand Down Expand Up @@ -136,10 +138,11 @@ namespace rpc
}

res.blocks.resize(blocks.size());
res.output_indices.resize(blocks.size());

auto it = blocks.begin();

bool use_unified = false;
std::optional<std::uint64_t> unified;
uint64_t block_count = 0;
while (it != blocks.end())
{
Expand All @@ -154,6 +157,12 @@ namespace rpc
return;
}

if (!block_count)
use_unified = (HF_VERSION_FCMP_PLUS_PLUS <= bwt.block.major_version);

auto& block_indices = use_unified ? res.unified_indices : res.output_indices;
block_indices.resize(blocks.size());

if (it->second.size() != bwt.block.tx_hashes.size())
{
res.blocks.clear();
Expand All @@ -163,7 +172,7 @@ namespace rpc
return;
}

cryptonote::rpc::block_output_indices& indices = res.output_indices[block_count];
cryptonote::rpc::block_output_indices& indices = block_indices[block_count];

// miner tx output indices
{
Expand All @@ -174,6 +183,15 @@ namespace rpc
res.error_details = "core::get_tx_outputs_gindexs() returned false";
return;
}

if (use_unified && !unified && !tx_indices.empty())
unified = m_core.get_blockchain_storage().get_db().get_output_key(0, tx_indices[0], false).output_id - tx_indices[0];

if (unified)
{
for (std::uint64_t& indice : tx_indices)
indice += *unified;
}
indices.push_back(std::move(tx_indices));
}

Expand Down Expand Up @@ -204,6 +222,15 @@ namespace rpc
return;
}

if (use_unified && !unified && !tx_indices.empty())
unified = m_core.get_blockchain_storage().get_db().get_output_key(0, tx_indices[0], false).output_id - tx_indices[0];

if (unified)
{
for (std::uint64_t& indice : tx_indices)
indice += *unified;
}

indices.push_back(std::move(tx_indices));
++hash_it;
}
Expand Down Expand Up @@ -883,6 +910,55 @@ namespace rpc
}
}

void DaemonHandler::handle(const GetUnifiedId::Request& req, GetUnifiedId::Response& res)
{
try
{
res.output_ids.clear();
res.output_ids.reserve(req.legacy_ids.size());
for (const auto& legacy : req.legacy_ids)
{
const auto info = m_core.get_blockchain_storage().get_db().get_output_key(legacy.amount, legacy.index, false);
res.output_ids.push_back({.legacy = legacy, .unified_id = info.output_id});
}
}
catch (const std::exception& e)
{
MERROR("Failed to get output ids: " << e.what());
res.status = Message::STATUS_FAILED;
res.error_details = e.what();
}
}

void DaemonHandler::handle(const GetTreePaths::Request& req, GetTreePaths::Response& res)
{
try
{
res.top_block_hash = m_core.get_blockchain_storage().get_db().top_block_hash(&res.top_block_height);
auto last = m_core.get_blockchain_storage().get_db().get_last_path(res.top_block_height);
res.n_leaf_tuples = last.first;
res.last_path = std::move(last.second);

std::vector<std::uint64_t> leaf_idxs;
std::vector<fcmp_pp::curve_trees::PathBytes> paths;
res.paths.resize(req.output_ids.size());
m_core.get_blockchain_storage().get_db().get_path_by_global_output_id(req.output_ids, res.top_block_height, leaf_idxs, paths);
for (std::size_t i = 0; i < paths.size(); ++i)
{
auto& elem = res.paths.at(i);
elem.output_id = req.output_ids.at(i);
elem.leaf_idx = leaf_idxs.at(i);
elem.path = std::move(paths.at(i));
}
}
catch (const std::exception& e)
{
MERROR("Failed to get output path data: " << e.what());
res.status = Message::STATUS_FAILED;
res.error_details = e.what();
}
}

bool DaemonHandler::getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& header)
{
block b;
Expand Down
4 changes: 4 additions & 0 deletions src/rpc/daemon_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ class DaemonHandler : public RpcHandler

void handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res);

void handle(const GetTreePaths::Request& req, GetTreePaths::Response& res);

void handle(const GetUnifiedId::Request& req, GetUnifiedId::Response& res);

epee::byte_slice handle(std::string&& request) override final;

private:
Expand Down
71 changes: 71 additions & 0 deletions src/rpc/daemon_messages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ void GetBlocksFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
INSERT_INTO_JSON_OBJECT(dest, current_height, current_height);
INSERT_INTO_JSON_OBJECT(dest, output_indices, output_indices);
INSERT_INTO_JSON_OBJECT(dest, unified_indices, unified_indices);
}

void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
Expand All @@ -95,6 +96,8 @@ void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
if (val.HasMember("unified_indices"))
GET_FROM_JSON_OBJECT(val, unified_indices, unified_indices);
}


Expand Down Expand Up @@ -812,6 +815,74 @@ void GetOutputDistribution::Response::fromJson(const rapidjson::Value& val)
GET_FROM_JSON_OBJECT(val, distributions, distributions);
}

void GetUnifiedId::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, legacy_ids, legacy_ids);
}

void GetUnifiedId::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}

GET_FROM_JSON_OBJECT(val, legacy_ids, legacy_ids);
}

void GetUnifiedId::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, output_ids, output_ids);
}

void GetUnifiedId::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}

GET_FROM_JSON_OBJECT(val, output_ids, output_ids);
}

void GetTreePaths::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, output_ids, output_ids);
}

void GetTreePaths::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}

GET_FROM_JSON_OBJECT(val, output_ids, output_ids);
}

void GetTreePaths::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) const
{
INSERT_INTO_JSON_OBJECT(dest, paths, paths);
INSERT_INTO_JSON_OBJECT(dest, top_block_height, top_block_height);
INSERT_INTO_JSON_OBJECT(dest, n_leaf_tuples, n_leaf_tuples);
INSERT_INTO_JSON_OBJECT(dest, last_path, last_path);
INSERT_INTO_JSON_OBJECT(dest, top_block_hash, top_block_hash);
}

void GetTreePaths::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}

GET_FROM_JSON_OBJECT(val, paths, paths);
GET_FROM_JSON_OBJECT(val, top_block_height, top_block_height);
GET_FROM_JSON_OBJECT(val, n_leaf_tuples, n_leaf_tuples);
GET_FROM_JSON_OBJECT(val, last_path, last_path);
GET_FROM_JSON_OBJECT(val, top_block_hash, top_block_hash);
}

} // namespace rpc

} // namespace cryptonote
23 changes: 23 additions & 0 deletions src/rpc/daemon_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ BEGIN_RPC_MESSAGE_CLASS(GetBlocksFast);
RPC_MESSAGE_MEMBER(uint64_t, current_height);
RPC_MESSAGE_MEMBER(crypto::hash, top_block_hash);
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::block_output_indices>, output_indices);
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::block_output_indices>, unified_indices);
RPC_MESSAGE_MEMBER(uint64_t, max_block_count);
END_RPC_MESSAGE_RESPONSE;
END_RPC_MESSAGE_CLASS;
Expand Down Expand Up @@ -445,6 +446,28 @@ BEGIN_RPC_MESSAGE_CLASS(GetOutputDistribution);
END_RPC_MESSAGE_RESPONSE;
END_RPC_MESSAGE_CLASS;

BEGIN_RPC_MESSAGE_CLASS(GetUnifiedId);
BEGIN_RPC_MESSAGE_REQUEST;
RPC_MESSAGE_MEMBER(std::vector<output_amount_and_index>, legacy_ids);
END_RPC_MESSAGE_REQUEST;
BEGIN_RPC_MESSAGE_RESPONSE;
RPC_MESSAGE_MEMBER(std::vector<output_map>, output_ids);
END_RPC_MESSAGE_RESPONSE;
END_RPC_MESSAGE_CLASS;

BEGIN_RPC_MESSAGE_CLASS(GetTreePaths);
BEGIN_RPC_MESSAGE_REQUEST;
RPC_MESSAGE_MEMBER(std::vector<std::uint64_t>, output_ids);
END_RPC_MESSAGE_RESPONSE;
BEGIN_RPC_MESSAGE_RESPONSE;
RPC_MESSAGE_MEMBER(std::vector<rpc::path_response>, paths);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be interested in #89 which allows for a much more compact response when dealing with multiple paths at once.

Copy link
Author

@vtnerd vtnerd Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll wait until that finalizes before incorporating it into this patch. Although its been sitting a while ...

RPC_MESSAGE_MEMBER(std::uint64_t, top_block_height);
RPC_MESSAGE_MEMBER(std::uint64_t, n_leaf_tuples);
RPC_MESSAGE_MEMBER(fcmp_pp::curve_trees::PathBytes, last_path);
RPC_MESSAGE_MEMBER(crypto::hash, top_block_hash);
END_RPC_MESSAGE_RESPONSE;
END_RPC_MESSAGE_CLASS;

} // namespace rpc

} // namespace cryptonote
15 changes: 15 additions & 0 deletions src/rpc/message_data_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "crypto/hash.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/difficulty.h"
#include "fcmp_pp/curve_trees.h"
#include "ringct/rctSigs.h"
#include "rpc/rpc_handler.h"

Expand Down Expand Up @@ -184,6 +185,7 @@ namespace rpc
uint64_t tx_pool_size;
uint64_t alt_blocks_count;
uint64_t outgoing_connections_count;

uint64_t incoming_connections_count;
uint64_t white_peerlist_size;
uint64_t grey_peerlist_size;
Expand All @@ -209,6 +211,19 @@ namespace rpc
uint64_t amount;
bool cumulative;
};

struct output_map
{
output_amount_and_index legacy;
std::uint64_t unified_id;
};

struct path_response
{
std::uint64_t output_id;
std::uint64_t leaf_idx;
fcmp_pp::curve_trees::PathBytes path;
};
} // namespace rpc

} // namespace cryptonote
3 changes: 3 additions & 0 deletions src/serialization/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ target_link_libraries(serialization
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${EXTRA_LIBRARIES})
target_include_directories(serialization
PUBLIC
${MX25519_INCLUDE})
add_dependencies(serialization
version)

Loading