aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp52
-rw-r--r--src/cryptonote_core/blockchain.h14
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp139
-rw-r--r--src/cryptonote_core/cryptonote_core.h40
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp4
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h1
-rw-r--r--src/cryptonote_core/tx_pool.h1
7 files changed, 207 insertions, 44 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 2420adc53..d1f5f0dcd 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -118,6 +118,8 @@ static const struct {
{ 3, 800500, 0, 1472415034 },
{ 4, 801219, 0, 1472415035 },
{ 5, 802660, 0, 1472415036 + 86400*180 }, // add 5 months on testnet to shut the update warning up since there's a large gap to v6
+
+ { 6, 971400, 0, 1501709789 },
};
static const uint64_t testnet_hard_fork_version_1_till = 624633;
@@ -279,7 +281,8 @@ uint64_t Blockchain::get_current_blockchain_height() const
bool Blockchain::init(BlockchainDB* db, const bool testnet, const cryptonote::test_options *test_options)
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ CRITICAL_REGION_LOCAL(m_tx_pool);
+ CRITICAL_REGION_LOCAL1(m_blockchain_lock);
bool fakechain = test_options != NULL;
@@ -2254,8 +2257,8 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh
TIME_MEASURE_FINISH(a);
if(m_show_time_stats)
{
- size_t mixin = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() - 1 : 0;
- MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << mixin << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
+ size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
+ MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
}
return true;
}
@@ -2266,8 +2269,8 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh
TIME_MEASURE_FINISH(a);
if(m_show_time_stats)
{
- size_t mixin = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() - 1 : 0;
- MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << mixin << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx));
+ size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
+ MINFO("HASH: " << get_transaction_hash(tx) << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << max_used_block_height << " ms: " << a + m_fake_scan_time << " B: " << get_object_blobsize(tx));
}
if (!res)
return false;
@@ -2459,13 +2462,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
{
if (n_unmixable == 0)
{
- MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low mixin (" << mixin << "), and no unmixable inputs");
+ MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (mixin + 1) << "), and no unmixable inputs");
tvc.m_low_mixin = true;
return false;
}
if (n_mixable > 1)
{
- MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low mixin (" << mixin << "), and more than one mixable input with unmixable inputs");
+ MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (mixin + 1) << "), and more than one mixable input with unmixable inputs");
tvc.m_low_mixin = true;
return false;
}
@@ -3097,6 +3100,8 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
CRITICAL_REGION_LOCAL(m_blockchain_lock);
TIME_MEASURE_START(t1);
+ static bool seen_future_version = false;
+
m_db->block_txn_start(true);
if(bl.prev_id != get_tail_id())
{
@@ -3106,6 +3111,18 @@ leave:
return false;
}
+ // warn users if they're running an old version
+ if (!seen_future_version && bl.major_version > m_hardfork->get_ideal_version())
+ {
+ seen_future_version = true;
+ const el::Level level = el::Level::Warning;
+ MCLOG_RED(level, "global", "**********************************************************************");
+ MCLOG_RED(level, "global", "A block was seen on the network with a version higher than the last");
+ MCLOG_RED(level, "global", "known one. This may be an old version of the daemon, and a software");
+ MCLOG_RED(level, "global", "update may be required to sync further. Try running: update check");
+ MCLOG_RED(level, "global", "**********************************************************************");
+ }
+
// this is a cheap test
if (!m_hardfork->check(bl))
{
@@ -3541,19 +3558,17 @@ void Blockchain::set_enforce_dns_checkpoints(bool enforce_checkpoints)
}
//------------------------------------------------------------------
-void Blockchain::block_longhash_worker(const uint64_t height, const std::vector<block> &blocks, std::unordered_map<crypto::hash, crypto::hash> &map) const
+void Blockchain::block_longhash_worker(uint64_t height, const std::vector<block> &blocks, std::unordered_map<crypto::hash, crypto::hash> &map) const
{
TIME_MEASURE_START(t);
slow_hash_allocate_state();
- //FIXME: height should be changing here, as get_block_longhash expects
- // the height of the block passed to it
for (const auto & block : blocks)
{
if (m_cancel)
- return;
+ break;
crypto::hash id = get_block_hash(block);
- crypto::hash pow = get_block_longhash(block, height);
+ crypto::hash pow = get_block_longhash(block, height++);
map.emplace(id, pow);
}
@@ -3745,9 +3760,11 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
if (!blocks_exist)
{
m_blocks_longhash_table.clear();
+ uint64_t thread_height = height;
for (uint64_t i = 0; i < threads; i++)
{
- thread_list.push_back(new boost::thread(attrs, boost::bind(&Blockchain::block_longhash_worker, this, height + (i * batches), std::cref(blocks[i]), std::ref(maps[i]))));
+ thread_list.push_back(new boost::thread(attrs, boost::bind(&Blockchain::block_longhash_worker, this, thread_height, std::cref(blocks[i]), std::ref(maps[i]))));
+ thread_height += blocks[i].size();
}
for (size_t j = 0; j < thread_list.size(); j++)
@@ -4154,6 +4171,15 @@ void Blockchain::load_compiled_in_block_hashes()
}
#endif
+bool Blockchain::is_within_compiled_block_hash_area(uint64_t height) const
+{
+#if defined(PER_BLOCK_CHECKPOINT)
+ return height < m_blocks_hash_check.size();
+#else
+ return false;
+#endif
+}
+
void Blockchain::lock()
{
m_blockchain_lock.lock();
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 4f2e4f0d3..aa61dc034 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -746,6 +746,15 @@ namespace cryptonote
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return m_hardfork->get_ideal_version(height); }
/**
+ * @brief returns the actual hardfork version for a given block height
+ *
+ * @param height the height for which to check version info
+ *
+ * @return the version
+ */
+ uint8_t get_hard_fork_version(uint64_t height) const { return m_hardfork->get(height); }
+
+ /**
* @brief get information about hardfork voting for a version
*
* @param version the version in question
@@ -846,7 +855,7 @@ namespace cryptonote
* @param blocks the blocks to be hashed
* @param map return-by-reference the hashes for each block
*/
- void block_longhash_worker(const uint64_t height, const std::vector<block> &blocks,
+ void block_longhash_worker(uint64_t height, const std::vector<block> &blocks,
std::unordered_map<crypto::hash, crypto::hash> &map) const;
/**
@@ -865,6 +874,9 @@ namespace cryptonote
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false) const;
+ bool is_within_compiled_block_hash_area(uint64_t height) const;
+ bool is_within_compiled_block_hash_area() const { return is_within_compiled_block_hash_area(m_db->height()); }
+
void lock();
void unlock();
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 4cfa52441..13e5badd1 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -37,6 +37,7 @@ using namespace epee;
#include "common/util.h"
#include "common/updates.h"
#include "common/download.h"
+#include "common/task_region.h"
#include "warnings.h"
#include "crypto/crypto.h"
#include "cryptonote_config.h"
@@ -76,6 +77,8 @@ namespace cryptonote
m_checkpoints_path(""),
m_last_dns_checkpoints_update(0),
m_last_json_checkpoints_update(0),
+ m_disable_dns_checkpoints(false),
+ m_threadpool(tools::thread_group::optimal()),
m_update_download(0)
{
m_checkpoints_updating.clear();
@@ -106,7 +109,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::update_checkpoints()
{
- if (m_testnet || m_fakechain) return true;
+ if (m_testnet || m_fakechain || m_disable_dns_checkpoints) return true;
if (m_checkpoints_updating.test_and_set()) return true;
@@ -414,6 +417,8 @@ namespace cryptonote
if (block_sync_size == 0)
block_sync_size = BLOCKS_SYNCHRONIZING_DEFAULT_COUNT;
+ MGINFO("Loading checkpoints");
+
// load json & DNS checkpoints, and verify them
// with respect to what blocks we already have
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
@@ -483,11 +488,9 @@ namespace cryptonote
return false;
}
//-----------------------------------------------------------------------------------------------
- bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ bool core::handle_incoming_tx_pre(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
{
tvc = boost::value_initialized<tx_verification_context>();
- //want to process all transactions sequentially
- CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
if(tx_blob.size() > get_max_tx_size())
{
@@ -497,9 +500,8 @@ namespace cryptonote
return false;
}
- crypto::hash tx_hash = null_hash;
- crypto::hash tx_prefixt_hash = null_hash;
- transaction tx;
+ tx_hash = null_hash;
+ tx_prefixt_hash = null_hash;
if(!parse_tx_from_blob(tx, tx_hash, tx_prefixt_hash, tx_blob))
{
@@ -509,15 +511,18 @@ namespace cryptonote
}
//std::cout << "!"<< tx.vin.size() << std::endl;
+ bad_semantics_txes_lock.lock();
for (int idx = 0; idx < 2; ++idx)
{
if (bad_semantics_txes[idx].find(tx_hash) != bad_semantics_txes[idx].end())
{
+ bad_semantics_txes_lock.unlock();
LOG_PRINT_L1("Transaction already seen with bad semantics, rejected");
tvc.m_verifivation_failed = true;
return false;
}
}
+ bad_semantics_txes_lock.unlock();
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = version == 1 ? 1 : 2;
@@ -528,18 +533,11 @@ namespace cryptonote
return false;
}
- if(m_mempool.have_tx(tx_hash))
- {
- LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool");
- return true;
- }
-
- if(m_blockchain_storage.have_tx(tx_hash))
- {
- LOG_PRINT_L2("tx " << tx_hash << " already have transaction in blockchain");
- return true;
- }
-
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool core::handle_incoming_tx_post(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
+ {
if(!check_tx_syntax(tx))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
@@ -564,27 +562,92 @@ namespace cryptonote
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
}
- if(!check_tx_semantic(tx, keeped_by_block))
+ if (keeped_by_block && get_blockchain_storage().is_within_compiled_block_hash_area())
+ {
+ MTRACE("Skipping semantics check for tx kept by block in embedded hash area");
+ }
+ else if(!check_tx_semantic(tx, keeped_by_block))
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
tvc.m_verifivation_failed = true;
+ bad_semantics_txes_lock.lock();
bad_semantics_txes[0].insert(tx_hash);
if (bad_semantics_txes[0].size() >= BAD_SEMANTICS_TXES_MAX_SIZE)
{
std::swap(bad_semantics_txes[0], bad_semantics_txes[1]);
bad_semantics_txes[0].clear();
}
+ bad_semantics_txes_lock.unlock();
return false;
}
- bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block, relayed, do_not_relay);
- if(tvc.m_verifivation_failed)
- {MERROR_VER("Transaction verification failed: " << tx_hash);}
- else if(tvc.m_verifivation_impossible)
- {MERROR_VER("Transaction verification impossible: " << tx_hash);}
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool core::handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ {
+ struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; bool in_txpool; bool in_blockchain; };
+ std::vector<result> results(tx_blobs.size());
+
+ tvc.resize(tx_blobs.size());
+ tools::task_region(m_threadpool, [&] (tools::task_region_handle& region) {
+ std::list<blobdata>::const_iterator it = tx_blobs.begin();
+ for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
+ region.run([&, i, it] {
+ results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash, results[i].prefix_hash, keeped_by_block, relayed, do_not_relay);
+ });
+ }
+ });
+ tools::task_region(m_threadpool, [&] (tools::task_region_handle& region) {
+ std::list<blobdata>::const_iterator it = tx_blobs.begin();
+ for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
+ if (!results[i].res)
+ continue;
+ if(m_mempool.have_tx(results[i].hash))
+ {
+ LOG_PRINT_L2("tx " << results[i].hash << "already have transaction in tx_pool");
+ }
+ else if(m_blockchain_storage.have_tx(results[i].hash))
+ {
+ LOG_PRINT_L2("tx " << results[i].hash << " already have transaction in blockchain");
+ }
+ else
+ {
+ region.run([&, i, it] {
+ results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash, results[i].prefix_hash, keeped_by_block, relayed, do_not_relay);
+ });
+ }
+ }
+ });
+
+ bool ok = true;
+ std::list<blobdata>::const_iterator it = tx_blobs.begin();
+ for (size_t i = 0; i < tx_blobs.size(); i++, ++it) {
+ if (!results[i].res)
+ {
+ ok = false;
+ continue;
+ }
- if(tvc.m_added_to_pool)
- MDEBUG("tx added: " << tx_hash);
+ ok &= add_new_tx(results[i].tx, results[i].hash, results[i].prefix_hash, it->size(), tvc[i], keeped_by_block, relayed, do_not_relay);
+ if(tvc[i].m_verifivation_failed)
+ {MERROR_VER("Transaction verification failed: " << results[i].hash);}
+ else if(tvc[i].m_verifivation_impossible)
+ {MERROR_VER("Transaction verification impossible: " << results[i].hash);}
+
+ if(tvc[i].m_added_to_pool)
+ MDEBUG("tx added: " << results[i].hash);
+ }
+ return ok;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
+ {
+ std::list<cryptonote::blobdata> tx_blobs;
+ tx_blobs.push_back(tx_blob);
+ std::vector<tx_verification_context> tvcv(1);
+ bool r = handle_incoming_txs(tx_blobs, tvcv, keeped_by_block, relayed, do_not_relay);
+ tvc = tvcv[0];
return r;
}
//-----------------------------------------------------------------------------------------------
@@ -660,6 +723,12 @@ namespace cryptonote
return false;
}
+ if (!check_tx_inputs_ring_members_diff(tx))
+ {
+ MERROR_VER("tx uses duplicate ring members");
+ return false;
+ }
+
if (!check_tx_inputs_keyimages_domain(tx))
{
MERROR_VER("tx uses key image not in the valid domain");
@@ -752,6 +821,22 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
+ bool core::check_tx_inputs_ring_members_diff(const transaction& tx) const
+ {
+ const uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
+ if (version >= 6)
+ {
+ for(const auto& in: tx.vin)
+ {
+ CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
+ for (size_t n = 1; n < tokey_in.key_offsets.size(); ++n)
+ if (tokey_in.key_offsets[n] == 0)
+ return false;
+ }
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
bool core::check_tx_inputs_keyimages_domain(const transaction& tx) const
{
std::unordered_set<crypto::key_image> ki;
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index e5fbf7f91..171c3cb98 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -40,6 +40,7 @@
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
#include "storages/portable_storage_template_helper.h"
#include "common/download.h"
+#include "common/thread_group.h"
#include "tx_pool.h"
#include "blockchain.h"
#include "cryptonote_basic/miner.h"
@@ -115,6 +116,22 @@ namespace cryptonote
bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
/**
+ * @brief handles a list of incoming transactions
+ *
+ * Parses incoming transactions and, if nothing is obviously wrong,
+ * passes them along to the transaction pool
+ *
+ * @param tx_blobs the txs to handle
+ * @param tvc metadata about the transactions' validity
+ * @param keeped_by_block if the transactions have been in a block
+ * @param relayed whether or not the transactions were relayed to us
+ * @param do_not_relay whether to prevent the transactions from being relayed
+ *
+ * @return true if the transactions made it to the transaction pool, otherwise false
+ */
+ bool handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
+
+ /**
* @brief handles an incoming block
*
* periodic update to checkpoints is triggered here
@@ -390,6 +407,13 @@ namespace cryptonote
void set_enforce_dns_checkpoints(bool enforce_dns);
/**
+ * @brief set whether or not to enable or disable DNS checkpoints
+ *
+ * @param disble whether to disable DNS checkpoints
+ */
+ void disable_dns_checkpoints(bool disable = true) { m_disable_dns_checkpoints = disable; }
+
+ /**
* @copydoc tx_memory_pool::have_tx
*
* @note see tx_memory_pool::have_tx
@@ -753,6 +777,9 @@ namespace cryptonote
*/
bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const;
+ bool handle_incoming_tx_pre(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
+ bool handle_incoming_tx_post(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
+
/**
* @copydoc miner::on_block_chain_update
*
@@ -781,6 +808,15 @@ namespace cryptonote
bool check_tx_inputs_keyimages_diff(const transaction& tx) const;
/**
+ * @brief verify that each ring uses distinct members
+ *
+ * @param tx the transaction to check
+ *
+ * @return false if any ring uses duplicate members, true otherwise
+ */
+ bool check_tx_inputs_ring_members_diff(const transaction& tx) const;
+
+ /**
* @brief verify that each input key image in a transaction is in
* the valid domain
*
@@ -853,12 +889,16 @@ namespace cryptonote
time_t m_last_json_checkpoints_update; //!< time when json checkpoints were last updated
std::atomic_flag m_checkpoints_updating; //!< set if checkpoints are currently updating to avoid multiple threads attempting to update at once
+ bool m_disable_dns_checkpoints;
size_t block_sync_size;
time_t start_time;
std::unordered_set<crypto::hash> bad_semantics_txes[2];
+ boost::mutex bad_semantics_txes_lock;
+
+ tools::thread_group m_threadpool;
enum {
UPDATES_DISABLED,
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 26d5fb767..94f069827 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -265,7 +265,7 @@ namespace cryptonote
// "Shuffle" outs
std::vector<tx_destination_entry> shuffled_dsts(destinations);
- std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; } );
+ std::random_shuffle(shuffled_dsts.begin(), shuffled_dsts.end(), [](unsigned int i) { return crypto::rand<unsigned int>() % i; });
uint64_t summary_outs_money = 0;
//fill outputs
@@ -371,7 +371,7 @@ namespace cryptonote
// enforce same mixin for all outputs
for (size_t i = 1; i < sources.size(); ++i) {
if (n_total_outs != sources[i].outputs.size()) {
- LOG_ERROR("Non-simple ringct transaction has varying mixin");
+ LOG_ERROR("Non-simple ringct transaction has varying ring size");
return false;
}
}
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 933070e1e..7aa7c280d 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -32,6 +32,7 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
+#include "ringct/rctOps.h"
namespace cryptonote
{
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 1858ccdd8..47a41d070 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -493,7 +493,6 @@ private:
*/
std::unordered_set<crypto::hash> m_timed_out_transactions;
- std::string m_config_folder; //!< the folder to save state to
Blockchain& m_blockchain; //!< reference to the Blockchain object
};
}