|
|
|
@ -1597,6 +1597,104 @@ bool Blockchain::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUT
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
|
// This function adds the ringct output at index i to the list
|
|
|
|
|
// unlocked and other such checks should be done by here.
|
|
|
|
|
void Blockchain::add_out_to_get_rct_random_outs(std::list<COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::out_entry>& outs, size_t i) const
|
|
|
|
|
{
|
|
|
|
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
|
|
|
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
|
|
|
|
|
|
|
|
|
COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::out_entry& oen = *outs.insert(outs.end(), COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::out_entry());
|
|
|
|
|
oen.global_amount_index = i;
|
|
|
|
|
output_data_t data = m_db->get_output_key(0, i);
|
|
|
|
|
oen.out_key = data.pubkey;
|
|
|
|
|
oen.commitment = m_db->get_rct_commitment(i);
|
|
|
|
|
}
|
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
|
// This function takes an RPC request for mixins and creates an RPC response
|
|
|
|
|
// with the requested mixins.
|
|
|
|
|
// TODO: figure out why this returns boolean / if we should be returning false
|
|
|
|
|
// in some cases
|
|
|
|
|
bool Blockchain::get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res) const
|
|
|
|
|
{
|
|
|
|
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
|
|
|
|
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
|
|
|
|
|
|
|
|
|
// for each amount that we need to get mixins for, get <n> random outputs
|
|
|
|
|
// from BlockchainDB where <n> is req.outs_count (number of mixins).
|
|
|
|
|
auto num_outs = m_db->get_num_outputs(0);
|
|
|
|
|
// ensure we don't include outputs that aren't yet eligible to be used
|
|
|
|
|
// outpouts are sorted by height
|
|
|
|
|
while (num_outs > 0)
|
|
|
|
|
{
|
|
|
|
|
const tx_out_index toi = m_db->get_output_tx_and_index(0, num_outs - 1);
|
|
|
|
|
const uint64_t height = m_db->get_tx_block_height(toi.first);
|
|
|
|
|
if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_db->height())
|
|
|
|
|
break;
|
|
|
|
|
--num_outs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unordered_set<uint64_t> seen_indices;
|
|
|
|
|
|
|
|
|
|
// if there aren't enough outputs to mix with (or just enough),
|
|
|
|
|
// use all of them. Eventually this should become impossible.
|
|
|
|
|
if (num_outs <= req.outs_count)
|
|
|
|
|
{
|
|
|
|
|
for (uint64_t i = 0; i < num_outs; i++)
|
|
|
|
|
{
|
|
|
|
|
// get tx_hash, tx_out_index from DB
|
|
|
|
|
tx_out_index toi = m_db->get_output_tx_and_index(0, i);
|
|
|
|
|
|
|
|
|
|
// if tx is unlocked, add output to result_outs
|
|
|
|
|
if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)))
|
|
|
|
|
{
|
|
|
|
|
add_out_to_get_rct_random_outs(res.outs, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// while we still need more mixins
|
|
|
|
|
while (res.outs.size() < req.outs_count)
|
|
|
|
|
{
|
|
|
|
|
// if we've gone through every possible output, we've gotten all we can
|
|
|
|
|
if (seen_indices.size() == num_outs)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get a random output index from the DB. If we've already seen it,
|
|
|
|
|
// return to the top of the loop and try again, otherwise add it to the
|
|
|
|
|
// list of output indices we've seen.
|
|
|
|
|
|
|
|
|
|
// triangular distribution over [a,b) with a=0, mode c=b=up_index_limit
|
|
|
|
|
uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53);
|
|
|
|
|
double frac = std::sqrt((double)r / ((uint64_t)1 << 53));
|
|
|
|
|
uint64_t i = (uint64_t)(frac*num_outs);
|
|
|
|
|
// just in case rounding up to 1 occurs after sqrt
|
|
|
|
|
if (i == num_outs)
|
|
|
|
|
--i;
|
|
|
|
|
|
|
|
|
|
if (seen_indices.count(i))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
seen_indices.emplace(i);
|
|
|
|
|
|
|
|
|
|
// get tx_hash, tx_out_index from DB
|
|
|
|
|
tx_out_index toi = m_db->get_output_tx_and_index(0, i);
|
|
|
|
|
|
|
|
|
|
// if the output's transaction is unlocked, add the output's index to
|
|
|
|
|
// our list.
|
|
|
|
|
if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)))
|
|
|
|
|
{
|
|
|
|
|
add_out_to_get_rct_random_outs(res.outs, i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
|
bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const
|
|
|
|
|
{
|
|
|
|
|
LOG_PRINT_L3("Blockchain::" << __func__);
|
|
|
|
|