mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-12-23 21:57:46 +00:00
Update ZMQ fee estimate and add ZMQ output distribution
This commit is contained in:
parent
2287fb9fb4
commit
6097472a19
13 changed files with 260 additions and 88 deletions
|
@ -27,7 +27,8 @@
|
||||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
set(rpc_base_sources
|
set(rpc_base_sources
|
||||||
rpc_args.cpp)
|
rpc_args.cpp
|
||||||
|
rpc_handler.cpp)
|
||||||
|
|
||||||
set(rpc_sources
|
set(rpc_sources
|
||||||
core_rpc_server.cpp
|
core_rpc_server.cpp
|
||||||
|
@ -43,7 +44,8 @@ set(daemon_rpc_server_sources
|
||||||
|
|
||||||
|
|
||||||
set(rpc_base_headers
|
set(rpc_base_headers
|
||||||
rpc_args.h)
|
rpc_args.h
|
||||||
|
rpc_handler.h)
|
||||||
|
|
||||||
set(rpc_headers)
|
set(rpc_headers)
|
||||||
|
|
||||||
|
@ -63,7 +65,6 @@ set(daemon_rpc_server_private_headers
|
||||||
message.h
|
message.h
|
||||||
daemon_messages.h
|
daemon_messages.h
|
||||||
daemon_handler.h
|
daemon_handler.h
|
||||||
rpc_handler.h
|
|
||||||
zmq_server.h)
|
zmq_server.h)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ using namespace epee;
|
||||||
#include "storages/http_abstract_invoke.h"
|
#include "storages/http_abstract_invoke.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "rpc/rpc_args.h"
|
#include "rpc/rpc_args.h"
|
||||||
|
#include "rpc/rpc_handler.h"
|
||||||
#include "core_rpc_server_error_codes.h"
|
#include "core_rpc_server_error_codes.h"
|
||||||
#include "p2p/net_node.h"
|
#include "p2p/net_node.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -2124,62 +2125,15 @@ namespace cryptonote
|
||||||
const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
|
const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
|
||||||
for (uint64_t amount: req.amounts)
|
for (uint64_t amount: req.amounts)
|
||||||
{
|
{
|
||||||
static struct D
|
auto data = rpc::RpcHandler::get_output_distribution(m_core, amount, req.from_height, req_to_height, req.cumulative);
|
||||||
{
|
if (!data)
|
||||||
boost::mutex mutex;
|
|
||||||
std::vector<uint64_t> cached_distribution;
|
|
||||||
uint64_t cached_from, cached_to, cached_start_height, cached_base;
|
|
||||||
bool cached;
|
|
||||||
D(): cached_from(0), cached_to(0), cached_start_height(0), cached_base(0), cached(false) {}
|
|
||||||
} d;
|
|
||||||
boost::unique_lock<boost::mutex> lock(d.mutex);
|
|
||||||
|
|
||||||
if (d.cached && amount == 0 && d.cached_from == req.from_height && d.cached_to == req_to_height)
|
|
||||||
{
|
|
||||||
res.distributions.push_back({amount, d.cached_start_height, req.binary, d.cached_distribution, d.cached_base});
|
|
||||||
if (!req.cumulative)
|
|
||||||
{
|
|
||||||
auto &distribution = res.distributions.back().distribution;
|
|
||||||
for (size_t n = distribution.size() - 1; n > 0; --n)
|
|
||||||
distribution[n] -= distribution[n-1];
|
|
||||||
distribution[0] -= d.cached_base;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint64_t> distribution;
|
|
||||||
uint64_t start_height, base;
|
|
||||||
if (!m_core.get_output_distribution(amount, req.from_height, req_to_height, start_height, distribution, base))
|
|
||||||
{
|
{
|
||||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||||
error_resp.message = "Failed to get rct distribution";
|
error_resp.message = "Failed to get output distribution";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (req_to_height > 0 && req_to_height >= req.from_height)
|
|
||||||
{
|
|
||||||
uint64_t offset = std::max(req.from_height, start_height);
|
|
||||||
if (offset <= req_to_height && req_to_height - offset + 1 < distribution.size())
|
|
||||||
distribution.resize(req_to_height - offset + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount == 0)
|
res.distributions.push_back({std::move(*data), amount, req.binary});
|
||||||
{
|
|
||||||
d.cached_from = req.from_height;
|
|
||||||
d.cached_to = req_to_height;
|
|
||||||
d.cached_distribution = distribution;
|
|
||||||
d.cached_start_height = start_height;
|
|
||||||
d.cached_base = base;
|
|
||||||
d.cached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.cumulative)
|
|
||||||
{
|
|
||||||
for (size_t n = distribution.size() - 1; n > 0; --n)
|
|
||||||
distribution[n] -= distribution[n-1];
|
|
||||||
distribution[0] -= base;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.distributions.push_back({amount, start_height, req.binary, std::move(distribution), base});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const std::exception &e)
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "cryptonote_basic/cryptonote_basic.h"
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
#include "cryptonote_basic/difficulty.h"
|
#include "cryptonote_basic/difficulty.h"
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
|
#include "rpc/rpc_handler.h"
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
|
@ -2236,21 +2237,19 @@ namespace cryptonote
|
||||||
|
|
||||||
struct distribution
|
struct distribution
|
||||||
{
|
{
|
||||||
|
rpc::output_distribution_data data;
|
||||||
uint64_t amount;
|
uint64_t amount;
|
||||||
uint64_t start_height;
|
|
||||||
bool binary;
|
bool binary;
|
||||||
std::vector<uint64_t> distribution;
|
|
||||||
uint64_t base;
|
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(amount)
|
KV_SERIALIZE(amount)
|
||||||
KV_SERIALIZE(start_height)
|
KV_SERIALIZE_N(data.start_height, "start_height")
|
||||||
KV_SERIALIZE(binary)
|
KV_SERIALIZE(binary)
|
||||||
if (this_ref.binary)
|
if (this_ref.binary)
|
||||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(distribution)
|
KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(data.distribution, "distribution")
|
||||||
else
|
else
|
||||||
KV_SERIALIZE(distribution)
|
KV_SERIALIZE_N(data.distribution, "distribution")
|
||||||
KV_SERIALIZE(base)
|
KV_SERIALIZE_N(data.base, "base")
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -724,12 +724,53 @@ namespace rpc
|
||||||
res.status = Message::STATUS_OK;
|
res.status = Message::STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DaemonHandler::handle(const GetPerKBFeeEstimate::Request& req, GetPerKBFeeEstimate::Response& res)
|
void DaemonHandler::handle(const GetFeeEstimate::Request& req, GetFeeEstimate::Response& res)
|
||||||
{
|
{
|
||||||
res.estimated_fee_per_kb = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.num_grace_blocks);
|
res.hard_fork_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
|
||||||
|
res.estimated_base_fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.num_grace_blocks);
|
||||||
|
|
||||||
|
if (res.hard_fork_version < HF_VERSION_PER_BYTE_FEE)
|
||||||
|
{
|
||||||
|
res.size_scale = 1024; // per KiB fee
|
||||||
|
res.fee_mask = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res.size_scale = 1; // per byte fee
|
||||||
|
res.fee_mask = Blockchain::get_fee_quantization_mask();
|
||||||
|
}
|
||||||
res.status = Message::STATUS_OK;
|
res.status = Message::STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DaemonHandler::handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res.distributions.reserve(req.amounts.size());
|
||||||
|
|
||||||
|
const uint64_t req_to_height = req.to_height ? req.to_height : (m_core.get_current_blockchain_height() - 1);
|
||||||
|
for (std::uint64_t amount : req.amounts)
|
||||||
|
{
|
||||||
|
auto data = get_output_distribution(m_core, amount, req.from_height, req_to_height, req.cumulative);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
res.distributions.clear();
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = "Failed to get output distribution";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.distributions.push_back(output_distribution{std::move(*data), amount, req.cumulative});
|
||||||
|
}
|
||||||
|
res.status = Message::STATUS_OK;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
res.distributions.clear();
|
||||||
|
res.status = Message::STATUS_FAILED;
|
||||||
|
res.error_details = e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DaemonHandler::getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& header)
|
bool DaemonHandler::getBlockHeaderByHash(const crypto::hash& hash_in, cryptonote::rpc::BlockHeaderResponse& header)
|
||||||
{
|
{
|
||||||
block b;
|
block b;
|
||||||
|
@ -804,7 +845,8 @@ namespace rpc
|
||||||
REQ_RESP_TYPES_MACRO(request_type, GetOutputHistogram, req_json, resp_message, handle);
|
REQ_RESP_TYPES_MACRO(request_type, GetOutputHistogram, req_json, resp_message, handle);
|
||||||
REQ_RESP_TYPES_MACRO(request_type, GetOutputKeys, req_json, resp_message, handle);
|
REQ_RESP_TYPES_MACRO(request_type, GetOutputKeys, req_json, resp_message, handle);
|
||||||
REQ_RESP_TYPES_MACRO(request_type, GetRPCVersion, req_json, resp_message, handle);
|
REQ_RESP_TYPES_MACRO(request_type, GetRPCVersion, req_json, resp_message, handle);
|
||||||
REQ_RESP_TYPES_MACRO(request_type, GetPerKBFeeEstimate, req_json, resp_message, handle);
|
REQ_RESP_TYPES_MACRO(request_type, GetFeeEstimate, req_json, resp_message, handle);
|
||||||
|
REQ_RESP_TYPES_MACRO(request_type, GetOutputDistribution, req_json, resp_message, handle);
|
||||||
|
|
||||||
// if none of the request types matches
|
// if none of the request types matches
|
||||||
if (resp_message == NULL)
|
if (resp_message == NULL)
|
||||||
|
|
|
@ -126,7 +126,9 @@ class DaemonHandler : public RpcHandler
|
||||||
|
|
||||||
void handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res);
|
void handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res);
|
||||||
|
|
||||||
void handle(const GetPerKBFeeEstimate::Request& req, GetPerKBFeeEstimate::Response& res);
|
void handle(const GetFeeEstimate::Request& req, GetFeeEstimate::Response& res);
|
||||||
|
|
||||||
|
void handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res);
|
||||||
|
|
||||||
std::string handle(const std::string& request);
|
std::string handle(const std::string& request);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ const char* const HardForkInfo::name = "hard_fork_info";
|
||||||
const char* const GetOutputHistogram::name = "get_output_histogram";
|
const char* const GetOutputHistogram::name = "get_output_histogram";
|
||||||
const char* const GetOutputKeys::name = "get_output_keys";
|
const char* const GetOutputKeys::name = "get_output_keys";
|
||||||
const char* const GetRPCVersion::name = "get_rpc_version";
|
const char* const GetRPCVersion::name = "get_rpc_version";
|
||||||
const char* const GetPerKBFeeEstimate::name = "get_dynamic_per_kb_fee_estimate";
|
const char* const GetFeeEstimate::name = "get_dynamic_fee_estimate";
|
||||||
|
const char* const GetOutputDistribution::name = "get_output_distribution";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -825,7 +826,7 @@ void GetRPCVersion::Response::fromJson(rapidjson::Value& val)
|
||||||
GET_FROM_JSON_OBJECT(val, version, version);
|
GET_FROM_JSON_OBJECT(val, version, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
rapidjson::Value GetPerKBFeeEstimate::Request::toJson(rapidjson::Document& doc) const
|
rapidjson::Value GetFeeEstimate::Request::toJson(rapidjson::Document& doc) const
|
||||||
{
|
{
|
||||||
auto val = Message::toJson(doc);
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
|
@ -836,27 +837,70 @@ rapidjson::Value GetPerKBFeeEstimate::Request::toJson(rapidjson::Document& doc)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetPerKBFeeEstimate::Request::fromJson(rapidjson::Value& val)
|
void GetFeeEstimate::Request::fromJson(rapidjson::Value& val)
|
||||||
{
|
{
|
||||||
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
|
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
rapidjson::Value GetPerKBFeeEstimate::Response::toJson(rapidjson::Document& doc) const
|
rapidjson::Value GetFeeEstimate::Response::toJson(rapidjson::Document& doc) const
|
||||||
{
|
{
|
||||||
auto val = Message::toJson(doc);
|
auto val = Message::toJson(doc);
|
||||||
|
|
||||||
auto& al = doc.GetAllocator();
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
INSERT_INTO_JSON_OBJECT(val, doc, estimated_fee_per_kb, estimated_fee_per_kb);
|
INSERT_INTO_JSON_OBJECT(val, doc, estimated_base_fee, estimated_base_fee);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, fee_mask, fee_mask);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, size_scale, size_scale);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, hard_fork_version, hard_fork_version);
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetPerKBFeeEstimate::Response::fromJson(rapidjson::Value& val)
|
void GetFeeEstimate::Response::fromJson(rapidjson::Value& val)
|
||||||
{
|
{
|
||||||
GET_FROM_JSON_OBJECT(val, estimated_fee_per_kb, estimated_fee_per_kb);
|
GET_FROM_JSON_OBJECT(val, estimated_base_fee, estimated_base_fee);
|
||||||
|
GET_FROM_JSON_OBJECT(val, fee_mask, fee_mask);
|
||||||
|
GET_FROM_JSON_OBJECT(val, size_scale, size_scale);
|
||||||
|
GET_FROM_JSON_OBJECT(val, hard_fork_version, hard_fork_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetOutputDistribution::Request::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, from_height, from_height);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, to_height, to_height);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, cumulative, cumulative);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutputDistribution::Request::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, amounts, amounts);
|
||||||
|
GET_FROM_JSON_OBJECT(val, from_height, from_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, to_height, to_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, cumulative, cumulative);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value GetOutputDistribution::Response::toJson(rapidjson::Document& doc) const
|
||||||
|
{
|
||||||
|
auto val = Message::toJson(doc);
|
||||||
|
auto& al = doc.GetAllocator();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, status, status);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, distributions, distributions);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetOutputDistribution::Response::fromJson(rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
GET_FROM_JSON_OBJECT(val, status, status);
|
||||||
|
GET_FROM_JSON_OBJECT(val, distributions, distributions);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rpc
|
} // namespace rpc
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||||
#include "rpc/message_data_structs.h"
|
#include "rpc/message_data_structs.h"
|
||||||
|
@ -62,8 +65,6 @@ class classname \
|
||||||
#define END_RPC_MESSAGE_RESPONSE };
|
#define END_RPC_MESSAGE_RESPONSE };
|
||||||
#define END_RPC_MESSAGE_CLASS };
|
#define END_RPC_MESSAGE_CLASS };
|
||||||
|
|
||||||
#define COMMA() ,
|
|
||||||
|
|
||||||
// NOTE: when using a type with multiple template parameters,
|
// NOTE: when using a type with multiple template parameters,
|
||||||
// replace any comma in the template specifier with the macro
|
// replace any comma in the template specifier with the macro
|
||||||
// above, or the preprocessor will eat the comma in a bad way.
|
// above, or the preprocessor will eat the comma in a bad way.
|
||||||
|
@ -118,7 +119,8 @@ BEGIN_RPC_MESSAGE_CLASS(GetTransactions);
|
||||||
RPC_MESSAGE_MEMBER(std::vector<crypto::hash>, tx_hashes);
|
RPC_MESSAGE_MEMBER(std::vector<crypto::hash>, tx_hashes);
|
||||||
END_RPC_MESSAGE_REQUEST;
|
END_RPC_MESSAGE_REQUEST;
|
||||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
RPC_MESSAGE_MEMBER(std::unordered_map<crypto::hash COMMA() cryptonote::rpc::transaction_info>, txs);
|
using txes_map = std::unordered_map<crypto::hash, transaction_info>;
|
||||||
|
RPC_MESSAGE_MEMBER(txes_map, txs);
|
||||||
RPC_MESSAGE_MEMBER(std::vector<crypto::hash>, missed_hashes);
|
RPC_MESSAGE_MEMBER(std::vector<crypto::hash>, missed_hashes);
|
||||||
END_RPC_MESSAGE_RESPONSE;
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
END_RPC_MESSAGE_CLASS;
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
@ -407,12 +409,27 @@ BEGIN_RPC_MESSAGE_CLASS(GetRPCVersion);
|
||||||
END_RPC_MESSAGE_RESPONSE;
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
END_RPC_MESSAGE_CLASS;
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
BEGIN_RPC_MESSAGE_CLASS(GetPerKBFeeEstimate);
|
BEGIN_RPC_MESSAGE_CLASS(GetFeeEstimate);
|
||||||
BEGIN_RPC_MESSAGE_REQUEST;
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
RPC_MESSAGE_MEMBER(uint64_t, num_grace_blocks);
|
RPC_MESSAGE_MEMBER(uint64_t, num_grace_blocks);
|
||||||
END_RPC_MESSAGE_REQUEST;
|
END_RPC_MESSAGE_REQUEST;
|
||||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
RPC_MESSAGE_MEMBER(uint64_t, estimated_fee_per_kb);
|
RPC_MESSAGE_MEMBER(uint64_t, estimated_base_fee);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, fee_mask);
|
||||||
|
RPC_MESSAGE_MEMBER(uint32_t, size_scale);
|
||||||
|
RPC_MESSAGE_MEMBER(uint8_t, hard_fork_version);
|
||||||
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
BEGIN_RPC_MESSAGE_CLASS(GetOutputDistribution);
|
||||||
|
BEGIN_RPC_MESSAGE_REQUEST;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, amounts);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, from_height);
|
||||||
|
RPC_MESSAGE_MEMBER(uint64_t, to_height);
|
||||||
|
RPC_MESSAGE_MEMBER(bool, cumulative);
|
||||||
|
END_RPC_MESSAGE_REQUEST;
|
||||||
|
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||||
|
RPC_MESSAGE_MEMBER(std::vector<output_distribution>, distributions);
|
||||||
END_RPC_MESSAGE_RESPONSE;
|
END_RPC_MESSAGE_RESPONSE;
|
||||||
END_RPC_MESSAGE_CLASS;
|
END_RPC_MESSAGE_CLASS;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "crypto/hash.h"
|
#include "crypto/hash.h"
|
||||||
#include "cryptonote_basic/cryptonote_basic.h"
|
#include "cryptonote_basic/cryptonote_basic.h"
|
||||||
#include "ringct/rctSigs.h"
|
#include "ringct/rctSigs.h"
|
||||||
|
#include "rpc/rpc_handler.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -192,6 +193,12 @@ namespace rpc
|
||||||
uint64_t start_time;
|
uint64_t start_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct output_distribution
|
||||||
|
{
|
||||||
|
output_distribution_data data;
|
||||||
|
uint64_t amount;
|
||||||
|
bool cumulative;
|
||||||
|
};
|
||||||
} // namespace rpc
|
} // namespace rpc
|
||||||
|
|
||||||
} // namespace cryptonote
|
} // namespace cryptonote
|
||||||
|
|
69
src/rpc/rpc_handler.cpp
Normal file
69
src/rpc/rpc_handler.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/thread/locks.hpp>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
|
#include "cryptonote_core/cryptonote_core.h"
|
||||||
|
|
||||||
|
namespace cryptonote
|
||||||
|
{
|
||||||
|
namespace rpc
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
output_distribution_data
|
||||||
|
process_distribution(bool cumulative, std::uint64_t start_height, std::vector<std::uint64_t> distribution, std::uint64_t base)
|
||||||
|
{
|
||||||
|
if (!cumulative && !distribution.empty())
|
||||||
|
{
|
||||||
|
for (std::size_t n = distribution.size() - 1; 0 < n; --n)
|
||||||
|
distribution[n] -= distribution[n - 1];
|
||||||
|
distribution[0] -= base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {std::move(distribution), start_height, base};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<output_distribution_data>
|
||||||
|
RpcHandler::get_output_distribution(core& src, std::uint64_t amount, std::uint64_t from_height, std::uint64_t to_height, bool cumulative)
|
||||||
|
{
|
||||||
|
static struct D
|
||||||
|
{
|
||||||
|
boost::mutex mutex;
|
||||||
|
std::vector<std::uint64_t> cached_distribution;
|
||||||
|
std::uint64_t cached_from, cached_to, cached_start_height, cached_base;
|
||||||
|
bool cached;
|
||||||
|
D(): cached_from(0), cached_to(0), cached_start_height(0), cached_base(0), cached(false) {}
|
||||||
|
} d;
|
||||||
|
const boost::unique_lock<boost::mutex> lock(d.mutex);
|
||||||
|
|
||||||
|
if (d.cached && amount == 0 && d.cached_from == from_height && d.cached_to == to_height)
|
||||||
|
return process_distribution(cumulative, d.cached_start_height, d.cached_distribution, d.cached_base);
|
||||||
|
|
||||||
|
std::vector<std::uint64_t> distribution;
|
||||||
|
std::uint64_t start_height, base;
|
||||||
|
if (!src.get_output_distribution(amount, from_height, to_height, start_height, distribution, base))
|
||||||
|
return boost::none;
|
||||||
|
|
||||||
|
if (to_height > 0 && to_height >= from_height)
|
||||||
|
{
|
||||||
|
const std::uint64_t offset = std::max(from_height, start_height);
|
||||||
|
if (offset <= to_height && to_height - offset + 1 < distribution.size())
|
||||||
|
distribution.resize(to_height - offset + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (amount == 0)
|
||||||
|
{
|
||||||
|
d.cached_from = from_height;
|
||||||
|
d.cached_to = to_height;
|
||||||
|
d.cached_distribution = distribution;
|
||||||
|
d.cached_start_height = start_height;
|
||||||
|
d.cached_base = base;
|
||||||
|
d.cached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return process_distribution(cumulative, start_height, std::move(distribution), base);
|
||||||
|
}
|
||||||
|
} // rpc
|
||||||
|
} // cryptonote
|
|
@ -28,24 +28,35 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/optional/optional.hpp>
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace cryptonote
|
namespace cryptonote
|
||||||
{
|
{
|
||||||
|
class core;
|
||||||
|
|
||||||
namespace rpc
|
namespace rpc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct output_distribution_data
|
||||||
|
{
|
||||||
|
std::vector<std::uint64_t> distribution;
|
||||||
|
std::uint64_t start_height;
|
||||||
|
std::uint64_t base;
|
||||||
|
};
|
||||||
|
|
||||||
class RpcHandler
|
class RpcHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
RpcHandler() { }
|
||||||
|
virtual ~RpcHandler() { }
|
||||||
|
|
||||||
virtual std::string handle(const std::string& request) = 0;
|
virtual std::string handle(const std::string& request) = 0;
|
||||||
|
|
||||||
RpcHandler() { }
|
static boost::optional<output_distribution_data>
|
||||||
|
get_output_distribution(core& src, std::uint64_t amount, std::uint64_t from_height, std::uint64_t to_height, bool cumulative);
|
||||||
virtual ~RpcHandler() { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1232,6 +1232,29 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf
|
||||||
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
|
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_distribution& dist, rapidjson::Value& val)
|
||||||
|
{
|
||||||
|
val.SetObject();
|
||||||
|
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, distribution, dist.data.distribution);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, amount, dist.amount);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, start_height, dist.data.start_height);
|
||||||
|
INSERT_INTO_JSON_OBJECT(val, doc, base, dist.data.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_distribution& dist)
|
||||||
|
{
|
||||||
|
if (!val.IsObject())
|
||||||
|
{
|
||||||
|
throw WRONG_TYPE("json object");
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_FROM_JSON_OBJECT(val, dist.data.distribution, distribution);
|
||||||
|
GET_FROM_JSON_OBJECT(val, dist.amount, amount);
|
||||||
|
GET_FROM_JSON_OBJECT(val, dist.data.start_height, start_height);
|
||||||
|
GET_FROM_JSON_OBJECT(val, dist.data.base, base);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace json
|
} // namespace json
|
||||||
|
|
||||||
} // namespace cryptonote
|
} // namespace cryptonote
|
||||||
|
|
|
@ -281,6 +281,9 @@ void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig);
|
||||||
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& info, rapidjson::Value& val);
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& info, rapidjson::Value& val);
|
||||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
|
||||||
|
|
||||||
|
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_distribution& dist, rapidjson::Value& val);
|
||||||
|
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_distribution& dist);
|
||||||
|
|
||||||
template <typename Map>
|
template <typename Map>
|
||||||
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val);
|
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val);
|
||||||
|
|
||||||
|
|
|
@ -2865,8 +2865,8 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
|
||||||
MWARNING("Failed to request output distribution: results are not for amount 0");
|
MWARNING("Failed to request output distribution: results are not for amount 0");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
start_height = res.distributions[0].start_height;
|
start_height = res.distributions[0].data.start_height;
|
||||||
distribution = std::move(res.distributions[0].distribution);
|
distribution = std::move(res.distributions[0].data.distribution);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
@ -6747,13 +6747,13 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||||
{
|
{
|
||||||
if (d.amount == amount)
|
if (d.amount == amount)
|
||||||
{
|
{
|
||||||
THROW_WALLET_EXCEPTION_IF(d.start_height > segregation_fork_height, error::get_output_distribution, "Distribution start_height too high");
|
THROW_WALLET_EXCEPTION_IF(d.data.start_height > segregation_fork_height, error::get_output_distribution, "Distribution start_height too high");
|
||||||
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - d.start_height >= d.distribution.size(), error::get_output_distribution, "Distribution size too small");
|
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - d.data.start_height >= d.data.distribution.size(), error::get_output_distribution, "Distribution size too small");
|
||||||
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS - d.start_height >= d.distribution.size(), error::get_output_distribution, "Distribution size too small");
|
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS - d.data.start_height >= d.data.distribution.size(), error::get_output_distribution, "Distribution size too small");
|
||||||
THROW_WALLET_EXCEPTION_IF(segregation_fork_height <= RECENT_OUTPUT_BLOCKS, error::wallet_internal_error, "Fork height too low");
|
THROW_WALLET_EXCEPTION_IF(segregation_fork_height <= RECENT_OUTPUT_BLOCKS, error::wallet_internal_error, "Fork height too low");
|
||||||
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS < d.start_height, error::get_output_distribution, "Bad start height");
|
THROW_WALLET_EXCEPTION_IF(segregation_fork_height - RECENT_OUTPUT_BLOCKS < d.data.start_height, error::get_output_distribution, "Bad start height");
|
||||||
uint64_t till_fork = d.distribution[segregation_fork_height - d.start_height];
|
uint64_t till_fork = d.data.distribution[segregation_fork_height - d.data.start_height];
|
||||||
uint64_t recent = till_fork - d.distribution[segregation_fork_height - RECENT_OUTPUT_BLOCKS - d.start_height];
|
uint64_t recent = till_fork - d.data.distribution[segregation_fork_height - RECENT_OUTPUT_BLOCKS - d.data.start_height];
|
||||||
segregation_limit[amount] = std::make_pair(till_fork, recent);
|
segregation_limit[amount] = std::make_pair(till_fork, recent);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue