aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp122
-rw-r--r--src/cryptonote_core/blockchain.h36
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp52
-rw-r--r--src/cryptonote_core/cryptonote_core.h13
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp15
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h4
-rw-r--r--src/cryptonote_core/tx_pool.cpp47
7 files changed, 185 insertions, 104 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index d2d43490e..6a75c52dd 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -107,8 +107,8 @@ static const struct {
// version 6 starts from block 1400000, which is on or around the 16th of September, 2017. Fork time finalised on 2017-08-18.
{ 6, 1400000, 0, 1503046577 },
- // version 7 starts from block 1539500, which is on or around the 28th of March, 2018. Fork time finalised on 2018-03-07.
- { 7, 1539500, 0, 1520436050 },
+ // version 7 starts from block 1546000, which is on or around the 6th of April, 2018. Fork time finalised on 2018-03-17.
+ { 7, 1546000, 0, 1521303150 },
};
static const uint64_t mainnet_hard_fork_version_1_till = 1009826;
@@ -441,6 +441,53 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block());
m_db->block_txn_stop();
+ uint64_t num_popped_blocks = 0;
+ while (true)
+ {
+ const uint64_t top_height = m_db->height() - 1;
+ const crypto::hash top_id = m_db->top_block_hash();
+ const block top_block = m_db->get_top_block();
+ const uint8_t ideal_hf_version = get_ideal_hard_fork_version(top_height);
+ if (ideal_hf_version <= 1 || ideal_hf_version == top_block.major_version)
+ {
+ if (num_popped_blocks > 0)
+ MGINFO("Initial popping done, top block: " << top_id << ", top height: " << top_height << ", block version: " << (uint64_t)top_block.major_version);
+ break;
+ }
+ else
+ {
+ if (num_popped_blocks == 0)
+ MGINFO("Current top block " << top_id << " at height " << top_height << " has version " << (uint64_t)top_block.major_version << " which disagrees with the ideal version " << (uint64_t)ideal_hf_version);
+ if (num_popped_blocks % 100 == 0)
+ MGINFO("Popping blocks... " << top_height);
+ ++num_popped_blocks;
+ block popped_block;
+ std::vector<transaction> popped_txs;
+ try
+ {
+ m_db->pop_block(popped_block, popped_txs);
+ }
+ // anything that could cause this to throw is likely catastrophic,
+ // so we re-throw
+ catch (const std::exception& e)
+ {
+ MERROR("Error popping block from blockchain: " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ MERROR("Error popping block from blockchain, throwing!");
+ throw;
+ }
+ }
+ }
+ if (num_popped_blocks > 0)
+ {
+ m_timestamps_and_difficulties_height = 0;
+ m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
+ m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id());
+ }
+
update_next_cumulative_size_limit();
return true;
}
@@ -584,6 +631,12 @@ block Blockchain::pop_block_from_blockchain()
}
}
}
+
+ m_blocks_longhash_table.clear();
+ m_scan_table.clear();
+ m_blocks_txs_check.clear();
+ m_check_txin_table.clear();
+
update_next_cumulative_size_limit();
m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id());
@@ -744,25 +797,6 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
return false;
}
//------------------------------------------------------------------
-//FIXME: this function does not seem to be called from anywhere, but
-// if it ever is, should probably change std::list for std::vector
-void Blockchain::get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid) const
-{
- LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
-
- for (auto& a : m_db->get_hashes_range(0, m_db->height() - 1))
- {
- main.push_back(a);
- }
-
- for (const blocks_ext_by_hash::value_type &v: m_alternative_chains)
- alt.push_back(v.first);
-
- for (const blocks_ext_by_hash::value_type &v: m_invalid_blocks)
- invalid.push_back(v.first);
-}
-//------------------------------------------------------------------
// This function aggregates the cumulative difficulties and timestamps of the
// last DIFFICULTY_BLOCKS_COUNT blocks and passes them to next_difficulty,
// returning the result of that call. Ignores the genesis block, and can use
@@ -1255,7 +1289,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
cumulative_size = txs_size + coinbase_blob_size;
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
MDEBUG("Creating block template: miner tx size " << coinbase_blob_size <<
- ", cumulative size " << cumulative_size << " is greater then before");
+ ", cumulative size " << cumulative_size << " is greater than before");
#endif
continue;
}
@@ -1266,7 +1300,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
MDEBUG("Creating block template: miner tx size " << coinbase_blob_size <<
", cumulative size " << txs_size + coinbase_blob_size <<
- " is less then before, adding " << delta << " zero bytes");
+ " is less than before, adding " << delta << " zero bytes");
#endif
b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
//here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
@@ -1922,6 +1956,30 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint
unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
}
//------------------------------------------------------------------
+bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
+{
+ // rct outputs don't exist before v3
+ if (amount == 0)
+ {
+ switch (m_nettype)
+ {
+ case STAGENET: start_height = stagenet_hard_forks[2].height; break;
+ case TESTNET: start_height = testnet_hard_forks[2].height; break;
+ case MAINNET: start_height = mainnet_hard_forks[2].height; break;
+ default: return false;
+ }
+ }
+ else
+ start_height = 0;
+ base = 0;
+
+ const uint64_t real_start_height = start_height;
+ if (from_height > start_height)
+ start_height = from_height;
+
+ return m_db->get_output_distribution(amount, start_height, to_height, distribution, base);
+}
+//------------------------------------------------------------------
// This function takes a list of block hashes from another node
// on the network to find where the split point is between us and them.
// This is used to see what to send another node that needs to sync.
@@ -2426,7 +2484,8 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
// from v8, allow bulletproofs
if (hf_version < 8) {
- if (!tx.rct_signatures.p.bulletproofs.empty())
+ const bool bulletproof = tx.rct_signatures.type == rct::RCTTypeFullBulletproof || tx.rct_signatures.type == rct::RCTTypeSimpleBulletproof;
+ if (bulletproof || !tx.rct_signatures.p.bulletproofs.empty())
{
MERROR("Bulletproofs are not allowed before v8");
tvc.m_invalid_output = true;
@@ -2962,7 +3021,7 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const
return false;
fee_per_kb = get_dynamic_per_kb_fee(base_reward, median, version);
}
- MDEBUG("Using " << print_money(fee) << "/kB fee");
+ MDEBUG("Using " << print_money(fee_per_kb) << "/kB fee");
uint64_t needed_fee = blob_size / 1024;
needed_fee += (blob_size % 1024) ? 1 : 0;
@@ -4301,9 +4360,9 @@ uint64_t Blockchain::get_difficulty_target() const
return get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
}
-std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const
+std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count) const
{
- return m_db->get_output_histogram(amounts, unlocked, recent_cutoff);
+ return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
}
std::list<std::pair<Blockchain::block_extended_info,uint64_t>> Blockchain::get_alternative_chains() const
@@ -4344,7 +4403,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
-static const char expected_block_hashes_hash[] = "4b553162ee4e7af3c53666506591489c68560b9175e6e941dc96c89f96f0e35c";
+static const char expected_block_hashes_hash[] = "59261c03b54bcb21bd463f9fe40a94f40840a12642e9a3b3bfb11b35839a5fe3";
void Blockchain::load_compiled_in_block_hashes()
{
const bool testnet = m_nettype == TESTNET;
@@ -4460,11 +4519,16 @@ bool Blockchain::for_all_transactions(std::function<bool(const crypto::hash&, co
return m_db->for_all_transactions(f);
}
-bool Blockchain::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, size_t tx_idx)> f) const
+bool Blockchain::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const
{
return m_db->for_all_outputs(f);;
}
+bool Blockchain::for_all_outputs(uint64_t amount, std::function<bool(uint64_t height)> f) const
+{
+ return m_db->for_all_outputs(amount, f);;
+}
+
namespace cryptonote {
template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::list<transaction>&, std::list<crypto::hash>&) const;
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index dd490cdd5..f58885812 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -207,15 +207,6 @@ namespace cryptonote
bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan = NULL) const;
/**
- * @brief get all block hashes (main chain, alt chains, and invalid blocks)
- *
- * @param main return-by-reference container to put result main chain blocks' hashes in
- * @param alt return-by-reference container to put result alt chain blocks' hashes in
- * @param invalid return-by-reference container to put result invalid blocks' hashes in
- */
- void get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid) const;
-
- /**
* @brief performs some preprocessing on a group of incoming blocks to speed up verification
*
* @param blocks a list of incoming blocks
@@ -533,6 +524,18 @@ namespace cryptonote
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 per block distribution of outputs of a given amount
+ *
+ * @param amount the amount to get a ditribution for
+ * @param from_height the height before which we do not care about the data
+ * @param to_height the height after which we do not care about the data
+ * @param return-by-reference start_height the height of the first rct output
+ * @param return-by-reference distribution the start offset of the first rct output in this block (same as previous if none)
+ * @param return-by-reference base how many outputs of that amount are before the stated distribution
+ */
+ bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const;
+
+ /**
* @brief gets the global indices for outputs from a given transaction
*
* This function gets the global indices for all outputs belonging
@@ -825,10 +828,11 @@ namespace cryptonote
* @param amounts optional set of amounts to lookup
* @param unlocked whether to restrict instances to unlocked ones
* @param recent_cutoff timestamp to consider outputs as recent
+ * @param min_count return only amounts with at least that many instances
*
* @return a set of amount/instances
*/
- std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff) const;
+ std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count = 0) const;
/**
* @brief perform a check on all key images in the blockchain
@@ -866,7 +870,17 @@ namespace cryptonote
*
* @return false if any output fails the check, otherwise true
*/
- bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, size_t tx_idx)>) const;
+ bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)>) const;
+
+ /**
+ * @brief perform a check on all outputs of a given amount in the blockchain
+ *
+ * @param amount the amount to iterate through
+ * @param std::function the check to perform, pass/fail
+ *
+ * @return false if any output fails the check, otherwise true
+ */
+ bool for_all_outputs(uint64_t amount, std::function<bool(uint64_t height)>) const;
/**
* @brief get a reference to the BlockchainDB in use by Blockchain
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 8c0118803..01cd56a11 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -81,7 +81,7 @@ namespace cryptonote
, "Specify data directory"
, tools::get_default_data_dir()
, {{ &arg_testnet_on, &arg_stagenet_on }}
- , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val) {
+ , [](std::array<bool, 2> testnet_stagenet, bool defaulted, std::string val)->std::string {
if (testnet_stagenet[0])
return (boost::filesystem::path(val) / "testnet").string();
else if (testnet_stagenet[1])
@@ -104,7 +104,7 @@ namespace cryptonote
};
static const command_line::arg_descriptor<uint64_t> arg_test_drop_download_height = {
"test-drop-download-height"
- , "Like test-drop-download but disards only after around certain height"
+ , "Like test-drop-download but discards only after around certain height"
, 0
};
static const command_line::arg_descriptor<int> arg_test_dbg_lock_sleep = {
@@ -171,7 +171,8 @@ namespace cryptonote
m_last_json_checkpoints_update(0),
m_disable_dns_checkpoints(false),
m_threadpool(tools::threadpool::getInstance()),
- m_update_download(0)
+ m_update_download(0),
+ m_nettype(UNDEFINED)
{
m_checkpoints_updating.clear();
set_cryptonote_protocol(pprotocol);
@@ -649,39 +650,6 @@ namespace cryptonote
return false;
}
- // resolve outPk references in rct txes
- // outPk aren't the only thing that need resolving for a fully resolved tx,
- // but outPk (1) are needed now to check range proof semantics, and
- // (2) do not need access to the blockchain to find data
- if (tx.version >= 2)
- {
- rct::rctSig &rv = tx.rct_signatures;
- if (rv.outPk.size() != tx.vout.size())
- {
- LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad outPk size in tx " << tx_hash << ", rejected");
- tvc.m_verifivation_failed = true;
- return false;
- }
- for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
- rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
-
- const bool bulletproof = rv.type == rct::RCTTypeFullBulletproof || rv.type == rct::RCTTypeSimpleBulletproof;
- if (bulletproof)
- {
- if (rv.p.bulletproofs.size() != tx.vout.size())
- {
- LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad bulletproofs size in tx " << tx_hash << ", rejected");
- tvc.m_verifivation_failed = true;
- return false;
- }
- for (size_t n = 0; n < rv.outPk.size(); ++n)
- {
- rv.p.bulletproofs[n].V.resize(1);
- rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask;
- }
- }
- }
-
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");
@@ -1105,6 +1073,11 @@ namespace cryptonote
return m_blockchain_storage.get_random_rct_outs(req, res);
}
//-----------------------------------------------------------------------------------------------
+ bool core::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
+ {
+ return m_blockchain_storage.get_output_distribution(amount, from_height, to_height, start_height, distribution, base);
+ }
+ //-----------------------------------------------------------------------------------------------
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);
@@ -1169,7 +1142,7 @@ namespace cryptonote
LOG_PRINT_L1("Block found but, seems that reorganize just happened after that, do not relay this block");
return true;
}
- CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size() && !missed_txs.size(), false, "cant find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size()
+ CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size() && !missed_txs.size(), false, "can't find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size()
<< ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
block_to_blob(b, arg.b.block);
@@ -1412,6 +1385,11 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
+ uint8_t core::get_ideal_hard_fork_version() const
+ {
+ return get_blockchain_storage().get_ideal_hard_fork_version();
+ }
+ //-----------------------------------------------------------------------------------------------
uint8_t core::get_ideal_hard_fork_version(uint64_t height) const
{
return get_blockchain_storage().get_ideal_hard_fork_version(height);
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index e1e430516..f3b9dddc0 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -571,6 +571,12 @@ namespace cryptonote
*/
bool get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res) const;
+ /**
+ * @copydoc Blockchain::get_output_distribution
+ *
+ * @brief get per block distribution of outputs of a given amount
+ */
+ bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const;
/**
* @copydoc miner::pause
@@ -636,6 +642,13 @@ namespace cryptonote
uint64_t get_target_blockchain_height() const;
/**
+ * @brief returns the newest hardfork version known to the blockchain
+ *
+ * @return the version
+ */
+ uint8_t get_ideal_hard_fork_version() const;
+
+ /**
* @brief return the ideal hard fork version for a given block height
*
* @return what it says above
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index db4ab9e11..071ce591e 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <unordered_set>
+#include <random>
#include "include_base_utils.h"
#include "string_tools.h"
using namespace epee;
@@ -194,7 +195,7 @@ namespace cryptonote
return addr.m_view_public_key;
}
//---------------------------------------------------------------
- bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
+ bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout, bool shuffle_outs)
{
hw::device &hwdev = sender_account_keys.get_device();
@@ -314,9 +315,10 @@ namespace cryptonote
tx.vin.push_back(input_to_key);
}
- // "Shuffle" outs
- std::vector<tx_destination_entry> shuffled_dsts(destinations);
- std::random_shuffle(shuffled_dsts.begin(), shuffled_dsts.end(), [](unsigned int i) { return crypto::rand<unsigned int>() % i; });
+ if (shuffle_outs)
+ {
+ std::shuffle(destinations.begin(), destinations.end(), std::default_random_engine(crypto::rand<unsigned int>()));
+ }
// sort ins by their key image
std::vector<size_t> ins_order(sources.size());
@@ -599,7 +601,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
+ bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
{
hw::device &hwdev = sender_account_keys.get_device();
hwdev.open_tx(tx_key);
@@ -628,7 +630,8 @@ namespace cryptonote
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
- return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, false, NULL);
+ std::vector<tx_destination_entry> destinations_copy = destinations;
+ return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, false, NULL);
}
//---------------------------------------------------------------
bool generate_genesis_block(
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 1c390078d..a5d149fca 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -90,8 +90,8 @@ namespace cryptonote
//---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
- bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
+ bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL, bool shuffle_outs = true);
+ bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
bool generate_genesis_block(
block& bl
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 762feb5ee..5dfbc1dd4 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -153,7 +153,7 @@ namespace cryptonote
uint64_t outputs_amount = get_outs_money_amount(tx);
if(outputs_amount > inputs_amount)
{
- LOG_PRINT_L1("transaction use more money then it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount));
+ LOG_PRINT_L1("transaction use more money than it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount));
tvc.m_verifivation_failed = true;
tvc.m_overspend = true;
return false;
@@ -292,7 +292,7 @@ namespace cryptonote
}
catch (const std::exception &e)
{
- MERROR("internal error: transaction already exists at inserting in memorypool: " << e.what());
+ MERROR("internal error: transaction already exists at inserting in memory pool: " << e.what());
return false;
}
tvc.m_added_to_pool = true;
@@ -1268,24 +1268,33 @@ namespace cryptonote
m_spent_key_images.clear();
m_txpool_size = 0;
std::vector<crypto::hash> remove;
- bool r = m_blockchain.for_all_txpool_txes([this, &remove](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) {
- cryptonote::transaction tx;
- if (!parse_and_validate_tx_from_blob(*bd, tx))
- {
- MWARNING("Failed to parse tx from txpool, removing");
- remove.push_back(txid);
- }
- if (!insert_key_images(tx, meta.kept_by_block))
- {
- MFATAL("Failed to insert key images from txpool tx");
+
+ // first add the not kept by block, then the kept by block,
+ // to avoid rejection due to key image collision
+ for (int pass = 0; pass < 2; ++pass)
+ {
+ const bool kept = pass == 1;
+ bool r = m_blockchain.for_all_txpool_txes([this, &remove, kept](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) {
+ if (!!kept != !!meta.kept_by_block)
+ return true;
+ cryptonote::transaction tx;
+ if (!parse_and_validate_tx_from_blob(*bd, tx))
+ {
+ MWARNING("Failed to parse tx from txpool, removing");
+ remove.push_back(txid);
+ }
+ if (!insert_key_images(tx, meta.kept_by_block))
+ {
+ MFATAL("Failed to insert key images from txpool tx");
+ return false;
+ }
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid);
+ m_txpool_size += meta.blob_size;
+ return true;
+ }, true);
+ if (!r)
return false;
- }
- m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid);
- m_txpool_size += meta.blob_size;
- return true;
- }, true);
- if (!r)
- return false;
+ }
if (!remove.empty())
{
LockedTXN lock(m_blockchain);