aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-06-05 10:46:18 +0100
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-08-28 21:28:16 +0100
commit4258dab4d6dcbf563daa054c7e05e8a0027290b8 (patch)
treec992aabb714180d490970957e62b1f54ab65cf59 /src/cryptonote_core
parentringct: add convenience functions to bridge ringct and cryptonote (diff)
downloadmonero-4258dab4d6dcbf563daa054c7e05e8a0027290b8.tar.xz
core: new /getrandom_rctouts.bin binary RPC call
to get random ringct outputs to mix with
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp98
-rw-r--r--src/cryptonote_core/blockchain.h25
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp5
-rw-r--r--src/cryptonote_core/cryptonote_core.h8
4 files changed, 136 insertions, 0 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index cc6b48b6b..46ff7efbb 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -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__);
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 1524693b8..701c17d9e 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -455,6 +455,23 @@ namespace cryptonote
bool get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const;
/**
+ * @brief gets random ringct outputs to mix with
+ *
+ * This function takes an RPC request for outputs to mix with
+ * and creates an RPC response with the resultant output indices
+ * and the matching keys.
+ *
+ * Outputs to mix with are randomly selected from the utxo set
+ * for each output amount in the request.
+ *
+ * @param req the output amounts and number of mixins to select
+ * @param res return-by-reference the resultant output indices
+ *
+ * @return true
+ */
+ bool get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res) const;
+
+ /**
* @brief gets the global indices for outputs from a given transaction
*
* This function gets the global indices for all outputs belonging
@@ -1054,6 +1071,14 @@ namespace cryptonote
void add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i) const;
/**
+ * @brief adds the given output to the requested set of random ringct outputs
+ *
+ * @param outs return-by-reference the set the output is to be added to
+ * @param i the rct output index
+ */
+ void add_out_to_get_rct_random_outs(std::list<COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::out_entry>& outs, size_t i) const;
+
+ /**
* @brief checks if a transaction is unlocked (its outputs spendable)
*
* This function checks to see if a transaction is unlocked.
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 550c55759..b3a7cb98d 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -706,6 +706,11 @@ namespace cryptonote
return m_blockchain_storage.get_outs(req, res);
}
//-----------------------------------------------------------------------------------------------
+ bool core::get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res) const
+ {
+ return m_blockchain_storage.get_random_rct_outs(req, res);
+ }
+ //-----------------------------------------------------------------------------------------------
bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
{
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 84b1f27a8..d16bd6553 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -479,6 +479,14 @@ namespace cryptonote
*/
bool get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res) const;
+ /**
+ *
+ * @copydoc Blockchain::get_random_rct_outs
+ *
+ * @note see Blockchain::get_random_rct_outs
+ */
+ bool get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res) const;
+
/**
* @copydoc miner::pause