class RandomOutputs added

pull/85/head
moneroexamples 6 years ago
parent 4e0f2f2a26
commit 960b593ea2

@ -18,7 +18,8 @@ set(SOURCE_FILES
BlockchainSetup.cpp
ThreadRAII.cpp
MysqlPing.cpp
TxUnlockChecker.cpp)
TxUnlockChecker.cpp
RandomOutputs.cpp)
# make static library called libmyxrm
# that we are going to link to

@ -5,8 +5,6 @@
#include "CurrentBlockchainStatus.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "openmonero"
@ -291,51 +289,19 @@ CurrentBlockchainStatus::get_amount_specific_indices(
bool
CurrentBlockchainStatus::get_random_outputs(
const vector<uint64_t>& amounts,
const uint64_t& outs_count,
vector<COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry>& found_outputs)
vector<uint64_t> const& amounts,
uint64_t outs_count,
RandomOutputs::outs_for_amount_v& found_outputs)
{
RandomOutputs ro = RandomOutputs(*mcore, amounts, outs_count);
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req;
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response res;
req.amounts = amounts;
req.unlocked = true;
req.recent_cutoff = 0;
req.min_count = outs_count;
req.max_count = 0;
//req.outs_count = outs_count;
// req.amounts = amounts;
if (!mcore->get_random_outs_for_amounts(req, res))
if (!ro.find_random_outputs())
{
OMERROR << "mcore->get_random_outs_for_amounts(req, res) failed";
OMERROR << "!ro.find_random_outputs()";
return false;
}
found_outputs = res.histogram;
struct gamma_engine
{
typedef uint64_t result_type;
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return std::numeric_limits<result_type>::max(); }
result_type operator()() { return crypto::rand<result_type>(); }
} engine;
static const double shape = 19.28/*16.94*/;
//static const double shape = m_testnet ? 17.02 : 17.28;
static const double scale = 1/1.61;
std::gamma_distribution<double> gamma(shape, scale);
uint64_t num_outs_found {0};
while (num_outs_found < outs_count)
{
}
found_outputs = ro.get_found_outputs();
return true;
}

@ -12,6 +12,7 @@
#include "ThreadRAII.h"
#include "RPCCalls.h"
#include "MySqlAccounts.h"
#include "RandomOutputs.h"
#include <iostream>
#include <memory>
@ -40,6 +41,8 @@ class CurrentBlockchainStatus
: public std::enable_shared_from_this<CurrentBlockchainStatus>
{
public:
// vector of mempool transactions that all threads
// can refer to
// recieved_time, tx
@ -133,10 +136,10 @@ public:
vector<uint64_t>& out_indices);
virtual bool
get_random_outputs(const vector<uint64_t>& amounts,
const uint64_t& outs_count,
vector<COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry>&
found_outputs);
get_random_outputs(vector<uint64_t> const& amounts,
uint64_t outs_count,
RandomOutputs::outs_for_amount_v&
found_outputs);
virtual uint64_t
get_dynamic_per_kb_fee_estimate() const;

@ -145,6 +145,73 @@ MicroCore::get_tx(crypto::hash const& tx_hash, transaction& tx) const
return true;
}
bool
MicroCore::get_output_histogram(
vector<uint64_t> const& amounts,
uint64_t min_count,
histogram_map& histogram,
bool unlocked,
uint64_t recent_cutoff) const
{
try
{
histogram = core_storage.get_output_histogram(
amounts,
unlocked,
recent_cutoff,
min_count);
}
catch (std::exception const& e)
{
cerr << e.what() << endl;
return false;
}
return true;
}
bool
MicroCore::get_output_histogram(
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request const& req,
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res) const
{
// based on bool core_rpc_server::on_get_output_histogram(const ...
MicroCore::histogram_map histogram;
if (!get_output_histogram(req.amounts,
req.min_count,
histogram,
req.unlocked,
req.recent_cutoff))
{
return false;
}
res.histogram.clear();
res.histogram.reserve(histogram.size());
for (auto const& i: histogram)
{
if (std::get<0>(i.second)
>= req.min_count
&& (std::get<0>(i.second) <= req.max_count
|| req.max_count == 0))
res.histogram.push_back(
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry(
i.first,
std::get<0>(i.second),
std::get<1>(i.second),
std::get<2>(i.second)));
}
res.status = CORE_RPC_STATUS_OK;
return true;
}
hw::device* const
MicroCore::get_device() const
{

@ -39,6 +39,12 @@ class MicroCore {
bool initialization_succeded {false};
public:
// <amoumt,
// tuple<total_instances, unlocked_instances, recent_instances>
using histogram_map = std::map<uint64_t,
std::tuple<uint64_t, uint64_t, uint64_t>>;
MicroCore();
/**
@ -137,55 +143,22 @@ public:
return core_storage.get_current_blockchain_height();
}
virtual bool
get_random_outs_for_amounts(
get_output_histogram(
vector<uint64_t> const& amounts,
uint64_t min_count,
histogram_map& histogram,
bool unlocked = true,
uint64_t recent_cutoff = 0) const;
// mimicks core_rpc_server::on_get_output_histogram(..)
virtual bool
get_output_histogram(
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request const& req,
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res) const
{
// based on bool core_rpc_server::on_get_output_histogram(const ...
// <amoumt,
// tuple<total_instances, unlocked_instances, recent_instances>
std::map<uint64_t,
std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
try
{
core_storage.get_output_histogram(
req.amounts,
req.unlocked,
req.recent_cutoff,
req.min_count);
}
catch (std::exception const& e)
{
res.status = "Failed to get output histogram";
return false;
}
res.histogram.clear();
res.histogram.reserve(histogram.size());
for (auto const& i: histogram)
{
if (std::get<0>(i.second)
>= req.min_count
&& (std::get<0>(i.second) <= req.max_count
|| req.max_count == 0))
res.histogram.push_back(
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry(
i.first,
std::get<0>(i.second),
std::get<1>(i.second),
std::get<2>(i.second)));
}
res.status = CORE_RPC_STATUS_OK;
return true;
}
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res) const;
virtual bool
get_outs(COMMAND_RPC_GET_OUTPUTS_BIN::request const& req,

@ -0,0 +1,142 @@
#include "RandomOutputs.h"
namespace xmreg
{
RandomOutputs::RandomOutputs(
MicroCore const& _mcore,
vector<uint64_t> const& _amounts,
uint64_t _outs_count)
: mcore {_mcore},
amounts {_amounts},
outs_count {_outs_count}
{
}
uint64_t
RandomOutputs::get_random_output_index(uint64_t num_outs) const
{
// type = "triangular"; from wallet2.cpp
uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53);
double frac = std::sqrt((double)r / ((uint64_t)1 << 53));
uint64_t i = static_cast<uint64_t>(frac * num_outs);
i = (i == num_outs ? --i : i);
return i;
}
bool
RandomOutputs::get_output_pub_key(
uint64_t amount,
uint64_t global_output_index,
crypto::public_key& out_pk) const
{
COMMAND_RPC_GET_OUTPUTS_BIN::request req;
COMMAND_RPC_GET_OUTPUTS_BIN::response res;
req.outputs.push_back(get_outputs_out {amount, global_output_index});
if (!mcore.get_outs(req, res))
{
OMERROR << "mcore->get_outs(req, res) failed";
return false;
}
if (res.outs.empty())
return false;
out_pk = res.outs[0].key;
return true;
}
bool
RandomOutputs::find_random_outputs()
{
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req;
COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response res;
req.amounts = amounts;
req.unlocked = true;
req.recent_cutoff = 0;
req.min_count = outs_count;
req.max_count = 0;
if (!mcore.get_output_histogram(req, res))
{
//OMERROR << "mcore->get_output_histogram(req, res)";
return false;
}
found_outputs.clear();
using histogram_entry = COMMAND_RPC_GET_OUTPUT_HISTOGRAM::entry;
for (uint64_t amount: amounts)
{
// find histogram_entry for amount that we look
// random outputs for
auto const hist_entry_it = std::find_if(
begin(res.histogram), end(res.histogram),
[&amount](histogram_entry const& he)
{
return amount == he.amount;
});
if (hist_entry_it == res.histogram.end())
{
OMERROR << "Could not find amount: it == res.histogram.end()\n";
return false;
}
RandomOutputs::outs_for_amount outs_info;
outs_info.amount = amount;
uint64_t num_outs = hist_entry_it->unlocked_instances;
// keep track of seen random_global_amount_idx
// so that we don't use same idx twice
std::unordered_set<uint64_t> seen_indices;
// use it as a failself, as we don't want infinit loop here
size_t trial_i {0};
while (seen_indices.size() < outs_count)
{
if (trial_i++ > max_no_of_trials)
{
OMERROR << "Can't find random output: maximum number "
"of trials reached";
return false;
}
uint64_t random_global_amount_idx
= get_random_output_index(num_outs);
if (seen_indices.count(random_global_amount_idx) > 0)
continue;
seen_indices.emplace(random_global_amount_idx);
crypto::public_key found_output_public_key;
if (!get_output_pub_key(amount,
random_global_amount_idx,
found_output_public_key))
{
OMERROR << "Cant find outputs public key for amount "
<< amount << " and global_index of "
<< random_global_amount_idx;
}
outs_info.outs.push_back({random_global_amount_idx,
found_output_public_key});
}
found_outputs.push_back(outs_info);
}
return true;
}
}

@ -0,0 +1,71 @@
#ifndef RANDOMOUTPUTS_H
#define RANDOMOUTPUTS_H
#include "om_log.h"
#include "MicroCore.h"
namespace xmreg
{
class RandomOutputs
{
public:
// how many times wy tray to get uinique random output
// before we give up
size_t const max_no_of_trials {100};
// the two structures are here to make get_random_outs
// method work as before. Normally, the used to be defined
// in monero, but due to recent changes in 2018 09,
// they were removed. However, parts of openmonero
// require them.
struct out_entry
{
uint64_t global_amount_index;
crypto::public_key out_key;
};
struct outs_for_amount
{
uint64_t amount;
std::list<out_entry> outs;
};
using outs_for_amount_v = vector<outs_for_amount>;
RandomOutputs(MicroCore const& _mcore,
vector<uint64_t> const& _amounts,
uint64_t _outs_count);
virtual bool
find_random_outputs();
outs_for_amount_v
get_found_outputs() const { return found_outputs; }
virtual ~RandomOutputs() = default;
protected:
MicroCore const& mcore;
vector<uint64_t> amounts;
uint64_t outs_count;
outs_for_amount_v found_outputs;
virtual uint64_t
get_random_output_index(uint64_t num_outs) const;
virtual bool
get_output_pub_key(uint64_t amount,
uint64_t global_output_index,
crypto::public_key& out_pk) const;
};
}
#endif // RANDOMOUTPUTS_H

@ -815,9 +815,7 @@ YourMoneroRequests::get_random_outs(
return;
}
using rpc_outs = COMMAND_RPC_GET_OUTPUT_HISTOGRAM;
vector<rpc_outs::entry> found_outputs;
vector<RandomOutputs::outs_for_amount> found_outputs;
if (current_bc_status->get_random_outputs(amounts, count, found_outputs))
{
@ -831,26 +829,26 @@ YourMoneroRequests::get_random_outs(
json& j_outputs = j_outs["outputs"];
// for (auto const& out: outs.outs)
// {
// tuple<string, string, string>
// rct_field = current_bc_status
// ->construct_output_rct_field(
// out.global_amount_index, outs.amount);
// string rct = std::get<0>(rct_field) // rct_pk
// + std::get<1>(rct_field) // rct_mask
// + std::get<2>(rct_field); // rct_amount
// json out_details {
// {"global_index", out.global_amount_index},
// {"public_key" , pod_to_hex(out.out_key)},
// {"rct" , rct}
// };
for (auto const& out: outs.outs)
{
tuple<string, string, string>
rct_field = current_bc_status
->construct_output_rct_field(
out.global_amount_index, outs.amount);
string rct = std::get<0>(rct_field) // rct_pk
+ std::get<1>(rct_field) // rct_mask
+ std::get<2>(rct_field); // rct_amount
json out_details {
{"global_index", out.global_amount_index},
{"public_key" , pod_to_hex(out.out_key)},
{"rct" , rct}
};
// j_outputs.push_back(out_details);
j_outputs.push_back(out_details);
// } // for (const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AM
} // for (const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AM
j_amount_outs.push_back(j_outs);
@ -1688,6 +1686,8 @@ YourMoneroRequests::get_version(
const Bytes & body)
{
(void) body;
json j_response {
{"last_git_commit_hash", string {GIT_COMMIT_HASH}},
{"last_git_commit_date", string {GIT_COMMIT_DATETIME}},

Loading…
Cancel
Save