aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp3
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h2
-rw-r--r--src/blockchain_db/blockchain_db.h9
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp56
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h3
-rw-r--r--src/blockchain_utilities/fake_core.h4
-rw-r--r--src/cryptonote_core/account.cpp8
-rw-r--r--src/cryptonote_core/blockchain.cpp14
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp11
-rw-r--r--src/cryptonote_core/tx_pool.cpp32
-rw-r--r--src/cryptonote_core/tx_pool.h15
-rw-r--r--src/wallet/api/address_book.cpp54
-rw-r--r--src/wallet/api/wallet.cpp18
-rw-r--r--src/wallet/api/wallet.h2
-rw-r--r--src/wallet/wallet2_api.h5
-rw-r--r--tests/unit_tests/hardfork.cpp2
16 files changed, 169 insertions, 69 deletions
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index 137ed9dc6..57d8371bd 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -1813,9 +1813,10 @@ bool BlockchainBDB::has_key_image(const crypto::key_image& img) const
// Ostensibly BerkeleyDB has batch transaction support built-in,
// so the following few functions will be NOP.
-void BlockchainBDB::batch_start(uint64_t batch_num_blocks)
+bool BlockchainBDB::batch_start(uint64_t batch_num_blocks)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
+ return false;
}
void BlockchainBDB::batch_commit()
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index f320ab0e3..266e780c6 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -324,7 +324,7 @@ public:
);
virtual void set_batch_transactions(bool batch_transactions);
- virtual void batch_start(uint64_t batch_num_blocks=0);
+ virtual bool batch_start(uint64_t batch_num_blocks=0);
virtual void batch_commit();
virtual void batch_stop();
virtual void batch_abort();
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index b39cb1801..455e0c811 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -655,16 +655,17 @@ public:
* been called. In either case, it should end the batch and write to its
* backing store.
*
- * If a batch is already in-progress, this function should throw a DB_ERROR.
- * This exception may change in the future if it is deemed necessary to
- * have a more granular exception type for this scenario.
+ * If a batch is already in-progress, this function must return false.
+ * If a batch was started by this call, it must return true.
*
* If any of this cannot be done, the subclass should throw the corresponding
* subclass of DB_EXCEPTION
*
* @param batch_num_blocks number of blocks to batch together
+ *
+ * @return true if we started the batch, false if already started
*/
- virtual void batch_start(uint64_t batch_num_blocks=0) = 0;
+ virtual bool batch_start(uint64_t batch_num_blocks=0) = 0;
/**
* @brief ends a batch transaction
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index ba2cb60bd..ca79ab4f8 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -543,6 +543,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
uint64_t min_block_size = 4 * 1024;
uint64_t block_stop = 0;
+ uint64_t m_height = height();
if (m_height > 1)
block_stop = m_height - 1;
uint64_t block_start = 0;
@@ -593,6 +594,7 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
+ uint64_t m_height = height();
CURSOR(block_heights)
blk_height bh = {blk_hash, m_height};
@@ -654,6 +656,7 @@ void BlockchainLMDB::remove_block()
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height == 0)
throw0(BLOCK_DNE ("Attempting to remove block from an empty blockchain"));
@@ -691,6 +694,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
+ uint64_t m_height = height();
int result;
uint64_t tx_id = m_num_txs;
@@ -787,6 +791,7 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
+ uint64_t m_height = height();
int result = 0;
@@ -1018,7 +1023,6 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions)
m_write_txn = nullptr;
m_write_batch_txn = nullptr;
m_batch_active = false;
- m_height = 0;
m_cum_size = 0;
m_cum_count = 0;
@@ -1143,7 +1147,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
if ((result = mdb_stat(txn, m_blocks, &db_stats)))
throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
LOG_PRINT_L2("Setting m_height to: " << db_stats.ms_entries);
- m_height = db_stats.ms_entries;
+ uint64_t m_height = db_stats.ms_entries;
// get and keep current number of txs
if ((result = mdb_stat(txn, m_txs, &db_stats)))
@@ -1294,7 +1298,6 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to write version to database: ", result).c_str()));
txn.commit();
- m_height = 0;
m_num_outputs = 0;
m_cum_size = 0;
m_cum_count = 0;
@@ -1515,6 +1518,7 @@ uint64_t BlockchainLMDB::get_top_block_timestamp() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
// if no blocks, return 0
if (m_height == 0)
@@ -1666,6 +1670,7 @@ crypto::hash BlockchainLMDB::top_block_hash() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height != 0)
{
return get_block_hash_from_height(m_height - 1);
@@ -1678,6 +1683,7 @@ block BlockchainLMDB::get_top_block() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height != 0)
{
@@ -1692,8 +1698,14 @@ uint64_t BlockchainLMDB::height() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ TXN_PREFIX_RDONLY();
+ int result;
- return m_height;
+ // get current height
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_blocks, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
+ return db_stats.ms_entries;
}
bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
@@ -2242,15 +2254,15 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
}
// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts.
-void BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
+bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (! m_batch_transactions)
throw0(DB_ERROR("batch transactions not enabled"));
if (m_batch_active)
- throw0(DB_ERROR("batch transaction already in progress"));
+ return false;
if (m_write_batch_txn != nullptr)
- throw0(DB_ERROR("batch transaction already in progress"));
+ return false;
if (m_write_txn)
throw0(DB_ERROR("batch transaction attempted, but m_write_txn already in use"));
check_open();
@@ -2276,6 +2288,7 @@ void BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
memset(&m_wcursors, 0, sizeof(m_wcursors));
LOG_PRINT_L3("batch transaction: begin");
+ return true;
}
void BlockchainLMDB::batch_commit()
@@ -2287,6 +2300,9 @@ void BlockchainLMDB::batch_commit()
throw0(DB_ERROR("batch transaction not in progress"));
if (m_write_batch_txn == nullptr)
throw0(DB_ERROR("batch transaction not in progress"));
+ if (m_writer != boost::this_thread::get_id())
+ return; // batch txn owned by other thread
+
check_open();
LOG_PRINT_L3("batch transaction: committing...");
@@ -2311,6 +2327,8 @@ void BlockchainLMDB::batch_stop()
throw0(DB_ERROR("batch transaction not in progress"));
if (m_write_batch_txn == nullptr)
throw0(DB_ERROR("batch transaction not in progress"));
+ if (m_writer != boost::this_thread::get_id())
+ return; // batch txn owned by other thread
check_open();
LOG_PRINT_L3("batch transaction: committing...");
TIME_MEASURE_START(time1);
@@ -2333,6 +2351,8 @@ void BlockchainLMDB::batch_abort()
throw0(DB_ERROR("batch transactions not enabled"));
if (! m_batch_active)
throw0(DB_ERROR("batch transaction not in progress"));
+ if (m_writer != boost::this_thread::get_id())
+ return; // batch txn owned by other thread
check_open();
// for destruction of batch transaction
m_write_txn = nullptr;
@@ -2505,6 +2525,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ uint64_t m_height = height();
if (m_height % 1000 == 0)
{
@@ -2558,8 +2579,6 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
block_txn_abort();
throw;
}
-
- --m_height;
}
void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -2850,7 +2869,7 @@ void BlockchainLMDB::fixup()
void BlockchainLMDB::migrate_0_1()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- uint64_t i, z;
+ uint64_t i, z, m_height;
int result;
mdb_txn_safe txn(false);
MDB_val k, v;
@@ -2859,17 +2878,22 @@ void BlockchainLMDB::migrate_0_1()
LOG_PRINT_YELLOW("Migrating blockchain from DB version 0 to 1 - this may take a while:", LOG_LEVEL_0);
LOG_PRINT_L0("updating blocks, hf_versions, outputs, txs, and spent_keys tables...");
- LOG_PRINT_L0("Total number of blocks: " << m_height);
- LOG_PRINT_L1("block migration will update block_heights, block_info, and hf_versions...");
-
do {
+ result = mdb_txn_begin(m_env, NULL, 0, txn);
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
+
+ MDB_stat db_stats;
+ if ((result = mdb_stat(txn, m_blocks, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
+ m_height = db_stats.ms_entries;
+ LOG_PRINT_L0("Total number of blocks: " << m_height);
+ LOG_PRINT_L1("block migration will update block_heights, block_info, and hf_versions...");
+
LOG_PRINT_L1("migrating block_heights:");
MDB_dbi o_heights;
unsigned int flags;
- result = mdb_txn_begin(m_env, NULL, 0, txn);
- if (result)
- throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
result = mdb_dbi_flags(txn, m_block_heights, &flags);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to retrieve block_heights flags: ", result).c_str()));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index b0d8d9d0a..e7faf8cdc 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -247,7 +247,7 @@ public:
);
virtual void set_batch_transactions(bool batch_transactions);
- virtual void batch_start(uint64_t batch_num_blocks=0);
+ virtual bool batch_start(uint64_t batch_num_blocks=0);
virtual void batch_commit();
virtual void batch_stop();
virtual void batch_abort();
@@ -369,7 +369,6 @@ private:
MDB_dbi m_properties;
- uint64_t m_height;
uint64_t m_num_txs;
uint64_t m_num_outputs;
mutable uint64_t m_cum_size; // used in batch size estimation
diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h
index ba1c2ed72..814139602 100644
--- a/src/blockchain_utilities/fake_core.h
+++ b/src/blockchain_utilities/fake_core.h
@@ -119,9 +119,9 @@ struct fake_core_db
return m_storage.get_db().add_block(blk, block_size, cumulative_difficulty, coins_generated, txs);
}
- void batch_start(uint64_t batch_num_blocks = 0)
+ bool batch_start(uint64_t batch_num_blocks = 0)
{
- m_storage.get_db().batch_start(batch_num_blocks);
+ return m_storage.get_db().batch_start(batch_num_blocks);
}
void batch_stop()
diff --git a/src/cryptonote_core/account.cpp b/src/cryptonote_core/account.cpp
index 602561489..bd703eee2 100644
--- a/src/cryptonote_core/account.cpp
+++ b/src/cryptonote_core/account.cpp
@@ -82,7 +82,9 @@ DISABLE_VS_WARNINGS(4244 4345)
if (recover)
{
- m_creation_timestamp = std::max(mktime(&timestamp), (long)0);
+ m_creation_timestamp = mktime(&timestamp);
+ if (m_creation_timestamp == (uint64_t)-1) // failure
+ m_creation_timestamp = 0; // lowest value
}
else
{
@@ -105,7 +107,9 @@ DISABLE_VS_WARNINGS(4244 4345)
timestamp.tm_min = 0;
timestamp.tm_sec = 0;
- m_creation_timestamp = std::max(mktime(&timestamp), (long)0);
+ m_creation_timestamp = mktime(&timestamp);
+ if (m_creation_timestamp == (uint64_t)-1) // failure
+ m_creation_timestamp = 0; // lowest value
}
//-----------------------------------------------------------------
void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index de3af8e02..f0779dad0 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -3381,9 +3381,10 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc
void Blockchain::check_against_checkpoints(const checkpoints& points, bool enforce)
{
const auto& pts = points.get_points();
+ bool stop_batch;
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- m_db->batch_start();
+ stop_batch = m_db->batch_start();
for (const auto& pt : pts)
{
// if the checkpoint is for a block we don't have yet, move on
@@ -3407,7 +3408,8 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor
}
}
}
- m_db->batch_stop();
+ if (stop_batch)
+ m_db->batch_stop();
}
//------------------------------------------------------------------
// returns false if any of the checkpoints loading returns false.
@@ -3481,6 +3483,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
CRITICAL_REGION_LOCAL(m_blockchain_lock);
TIME_MEASURE_START(t1);
+ m_db->batch_stop();
if (m_sync_counter > 0)
{
if (force_sync)
@@ -3545,11 +3548,18 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
{
LOG_PRINT_YELLOW("Blockchain::" << __func__, LOG_LEVEL_3);
TIME_MEASURE_START(prepare);
+ bool stop_batch;
CRITICAL_REGION_LOCAL(m_blockchain_lock);
if(blocks_entry.size() == 0)
return false;
+ while (!(stop_batch = m_db->batch_start(blocks_entry.size()))) {
+ m_blockchain_lock.unlock();
+ epee::misc_utils::sleep_no_w(1000);
+ m_blockchain_lock.lock();
+ }
+
if ((m_db->height() + blocks_entry.size()) < m_blocks_hash_check.size())
return true;
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index c63a08ee4..c2da7aaea 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -312,9 +312,9 @@ namespace cryptonote
LOG_PRINT_L0("Loading blockchain from folder " << folder.string() << " ...");
const std::string filename = folder.string();
- // temporarily default to fastest:async:1000
+ // default to fast:async:1
blockchain_db_sync_mode sync_mode = db_async;
- uint64_t blocks_per_sync = 1000;
+ uint64_t blocks_per_sync = 1;
try
{
@@ -327,12 +327,12 @@ namespace cryptonote
for(const auto &option : options)
LOG_PRINT_L0("option: " << option);
- // default to fast:async:1000
+ // default to fast:async:1
uint64_t DEFAULT_FLAGS = DBS_FAST_MODE;
if(options.size() == 0)
{
- // temporarily default to fastest:async:1000
+ // default to fast:async:1
db_flags = DEFAULT_FLAGS;
}
@@ -348,7 +348,10 @@ namespace cryptonote
else if(options[0] == "fast")
db_flags = DBS_FAST_MODE;
else if(options[0] == "fastest")
+ {
db_flags = DBS_FASTEST_MODE;
+ blocks_per_sync = 1000; // default to fastest:async:1000
+ }
else
db_flags = DEFAULT_FLAGS;
}
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 59ac534fe..028585741 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -177,6 +177,8 @@ namespace cryptonote
return false;
}
+ time_t receive_time = time(nullptr);
+
crypto::hash max_used_block_id = null_hash;
uint64_t max_used_block_height = 0;
tx_details txd;
@@ -198,7 +200,7 @@ namespace cryptonote
txd_p.first->second.last_failed_height = 0;
txd_p.first->second.last_failed_id = null_hash;
txd_p.first->second.kept_by_block = kept_by_block;
- txd_p.first->second.receive_time = time(nullptr);
+ txd_p.first->second.receive_time = receive_time;
txd_p.first->second.last_relayed_time = time(NULL);
txd_p.first->second.relayed = relayed;
tvc.m_verifivation_impossible = true;
@@ -221,7 +223,7 @@ namespace cryptonote
txd_p.first->second.max_used_block_height = max_used_block_height;
txd_p.first->second.last_failed_height = 0;
txd_p.first->second.last_failed_id = null_hash;
- txd_p.first->second.receive_time = time(nullptr);
+ txd_p.first->second.receive_time = receive_time;
txd_p.first->second.last_relayed_time = time(NULL);
txd_p.first->second.relayed = relayed;
tvc.m_added_to_pool = true;
@@ -246,7 +248,7 @@ namespace cryptonote
tvc.m_verifivation_failed = false;
- m_txs_by_fee.emplace((double)blob_size / fee, id);
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>((double)blob_size / fee, receive_time), id);
return true;
}
@@ -301,7 +303,7 @@ namespace cryptonote
auto sorted_it = find_tx_in_sorted_container(id);
- if (sorted_it == m_txs_by_fee.end())
+ if (sorted_it == m_txs_by_fee_and_receive_time.end())
return false;
tx = it->second.tx;
@@ -310,7 +312,7 @@ namespace cryptonote
relayed = it->second.relayed;
remove_transaction_keyimages(it->second.tx);
m_transactions.erase(it);
- m_txs_by_fee.erase(sorted_it);
+ m_txs_by_fee_and_receive_time.erase(sorted_it);
return true;
}
//---------------------------------------------------------------------------------
@@ -321,7 +323,7 @@ namespace cryptonote
//---------------------------------------------------------------------------------
sorted_tx_container::iterator tx_memory_pool::find_tx_in_sorted_container(const crypto::hash& id) const
{
- return std::find_if( m_txs_by_fee.begin(), m_txs_by_fee.end()
+ return std::find_if( m_txs_by_fee_and_receive_time.begin(), m_txs_by_fee_and_receive_time.end()
, [&](const sorted_tx_container::value_type& a){
return a.second == id;
}
@@ -342,13 +344,13 @@ namespace cryptonote
LOG_PRINT_L1("Tx " << it->first << " removed from tx pool due to outdated, age: " << tx_age );
remove_transaction_keyimages(it->second.tx);
auto sorted_it = find_tx_in_sorted_container(it->first);
- if (sorted_it == m_txs_by_fee.end())
+ if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
LOG_PRINT_L1("Removing tx " << it->first << " from tx pool, but it was not found in the sorted txs container!");
}
else
{
- m_txs_by_fee.erase(sorted_it);
+ m_txs_by_fee_and_receive_time.erase(sorted_it);
}
m_timed_out_transactions.insert(it->first);
auto pit = it++;
@@ -608,9 +610,9 @@ namespace cryptonote
size_t max_total_size = 2 * median_size - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
std::unordered_set<crypto::key_image> k_images;
- LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee.size() << " txes in the pool");
- auto sorted_it = m_txs_by_fee.begin();
- while (sorted_it != m_txs_by_fee.end())
+ LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
+ auto sorted_it = m_txs_by_fee_and_receive_time.begin();
+ while (sorted_it != m_txs_by_fee_and_receive_time.end())
{
auto tx_it = m_transactions.find(sorted_it->second);
LOG_PRINT_L2("Considering " << tx_it->first << ", size " << tx_it->second.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase));
@@ -675,13 +677,13 @@ namespace cryptonote
LOG_PRINT_L1("Transaction " << get_transaction_hash(it->second.tx) << " is too big (" << it->second.blob_size << " bytes), removing it from pool");
remove_transaction_keyimages(it->second.tx);
auto sorted_it = find_tx_in_sorted_container(it->first);
- if (sorted_it == m_txs_by_fee.end())
+ if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
LOG_PRINT_L1("Removing tx " << it->first << " from tx pool, but it was not found in the sorted txs container!");
}
else
{
- m_txs_by_fee.erase(sorted_it);
+ m_txs_by_fee_and_receive_time.erase(sorted_it);
}
auto pit = it++;
m_transactions.erase(pit);
@@ -712,14 +714,14 @@ namespace cryptonote
LOG_ERROR("Failed to load memory pool from file " << state_file_path);
m_transactions.clear();
- m_txs_by_fee.clear();
+ m_txs_by_fee_and_receive_time.clear();
m_spent_key_images.clear();
}
// no need to store queue of sorted transactions, as it's easy to generate.
for (const auto& tx : m_transactions)
{
- m_txs_by_fee.emplace((double)tx.second.blob_size / tx.second.fee, tx.first);
+ m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>((double)tx.second.blob_size / tx.second.fee, tx.second.receive_time), tx.first);
}
// Ignore deserialization error
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 32a05b0f4..9258a0c38 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -54,23 +54,25 @@ namespace cryptonote
/************************************************************************/
//! pair of <transaction fee, transaction hash> for organization
- typedef std::pair<double, crypto::hash> tx_by_fee_entry;
+ typedef std::pair<std::pair<double, std::time_t>, crypto::hash> tx_by_fee_and_receive_time_entry;
class txCompare
{
public:
- bool operator()(const tx_by_fee_entry& a, const tx_by_fee_entry& b)
+ bool operator()(const tx_by_fee_and_receive_time_entry& a, const tx_by_fee_and_receive_time_entry& b)
{
// sort by greatest first, not least
- if (a.first > b.first) return true;
- else if (a.first < b.first) return false;
+ if (a.first.first > b.first.first) return true;
+ else if (a.first.first < b.first.first) return false;
+ else if (a.first.second < b.first.second) return true;
+ else if (a.first.second > b.first.second) return false;
else if (a.second != b.second) return true;
else return false;
}
};
//! container for sorting transactions by fee per unit size
- typedef std::set<tx_by_fee_entry, txCompare> sorted_tx_container;
+ typedef std::set<tx_by_fee_and_receive_time_entry, txCompare> sorted_tx_container;
/**
* @brief Transaction pool, handles transactions which are not part of a block
@@ -473,7 +475,8 @@ private:
epee::math_helper::once_a_time_seconds<30> m_remove_stuck_tx_interval;
//TODO: look into doing this better
- sorted_tx_container m_txs_by_fee; //!< container for transactions organized by fee per size
+ //!< container for transactions organized by fee per size and receive time
+ sorted_tx_container m_txs_by_fee_and_receive_time;
/**
* @brief get an iterator to a transaction in the sorted container
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index b878491ce..e397dac04 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -33,6 +33,7 @@
#include "wallet.h"
#include "crypto/hash.h"
#include "wallet/wallet2.h"
+#include "common_defines.h"
#include <vector>
@@ -43,30 +44,50 @@ AddressBook::~AddressBook() {}
AddressBookImpl::AddressBookImpl(WalletImpl *wallet)
: m_wallet(wallet) {}
-bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description)
+bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id_str, const std::string &description)
{
- LOG_PRINT_L2("Adding row");
-
clearStatus();
cryptonote::account_public_address addr;
- bool has_payment_id;
+ bool has_short_pid;
crypto::hash8 payment_id_short;
- if(!cryptonote::get_account_integrated_address_from_str(addr, has_payment_id, payment_id_short, m_wallet->m_wallet->testnet(), dst_addr)) {
- m_errorString = "Invalid destination address";
+ if(!cryptonote::get_account_integrated_address_from_str(addr, has_short_pid, payment_id_short, m_wallet->m_wallet->testnet(), dst_addr)) {
+ m_errorString = tr("Invalid destination address");
m_errorCode = Invalid_Address;
return false;
}
- crypto::hash pid32 = cryptonote::null_hash;
- bool long_pid = (payment_id.empty())? false : tools::wallet2::parse_long_payment_id(payment_id, pid32);
- if(!payment_id.empty() && !long_pid) {
- m_errorString = "Invalid payment ID";
+ crypto::hash payment_id = cryptonote::null_hash;
+ bool has_long_pid = (payment_id_str.empty())? false : tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
+
+ // Short payment id provided
+ if(payment_id_str.length() == 16) {
+ m_errorString = tr("Invalid payment ID. Short payment ID should only be used in an integrated address");
+ m_errorCode = Invalid_Payment_Id;
+ return false;
+ }
+
+ // long payment id provided but not valid
+ if(!payment_id_str.empty() && !has_long_pid) {
+ m_errorString = tr("Invalid payment ID");
+ m_errorCode = Invalid_Payment_Id;
+ return false;
+ }
+
+ // integrated + long payment id provided
+ if(has_long_pid && has_short_pid) {
+ m_errorString = tr("Integrated address and long payment id can't be used at the same time");
m_errorCode = Invalid_Payment_Id;
return false;
}
- bool r = m_wallet->m_wallet->add_address_book_row(addr,pid32,description);
+ // Pad short pid with zeros
+ if (has_short_pid)
+ {
+ memcpy(payment_id.data, payment_id_short.data, 8);
+ }
+
+ bool r = m_wallet->m_wallet->add_address_book_row(addr,payment_id,description);
if (r)
refresh();
else
@@ -87,7 +108,16 @@ void AddressBookImpl::refresh()
std::string payment_id = (row->m_payment_id == cryptonote::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id);
std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(),row->m_address);
-
+ // convert the zero padded short payment id to integrated address
+ if (payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) {
+ payment_id = payment_id.substr(0,16);
+ crypto::hash8 payment_id_short;
+ if(tools::wallet2::parse_short_payment_id(payment_id, payment_id_short)) {
+ address = cryptonote::get_account_integrated_address_as_str(m_wallet->m_wallet->testnet(), row->m_address, payment_id_short);
+ // Don't show payment id when integrated address is used
+ payment_id = "";
+ }
+ }
AddressBookRow * abr = new AddressBookRow(i, address, payment_id, row->m_description);
m_rows.push_back(abr);
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 849ecf651..353737d6b 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1260,6 +1260,24 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st
return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
}
+bool WalletImpl::rescanSpent()
+{
+ clearStatus();
+ if (!trustedDaemon()) {
+ m_status = Status_Error;
+ m_errorString = tr("Rescan spent can only be used with a trusted daemon");
+ return false;
+ }
+ try {
+ m_wallet->rescan_spent();
+ } catch (const std::exception &e) {
+ LOG_ERROR(__FUNCTION__ << " error: " << e.what());
+ m_status = Status_Error;
+ m_errorString = e.what();
+ return false;
+ }
+ return true;
+}
} // namespace
namespace Bitmonero = Monero;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index ea8c864ac..e26f30d70 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -93,7 +93,7 @@ public:
void setRefreshFromBlockHeight(uint64_t refresh_from_block_height);
void setRecoveringFromSeed(bool recoveringFromSeed);
bool watchOnly() const;
-
+ bool rescanSpent();
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 7ae8eb9c3..5a13205c5 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -573,6 +573,11 @@ struct Wallet
virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
+ /*
+ * \brief rescanSpent - Rescan spent outputs - Can only be used with trusted daemon
+ * \return true on success
+ */
+ virtual bool rescanSpent() = 0;
};
/**
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index ca72f5e0e..be17f01ad 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -51,7 +51,7 @@ public:
virtual std::string get_db_name() const { return std::string(); }
virtual bool lock() { return true; }
virtual void unlock() { }
- virtual void batch_start(uint64_t batch_num_blocks=0) {}
+ virtual bool batch_start(uint64_t batch_num_blocks=0) {}
virtual void batch_stop() {}
virtual void set_batch_transactions(bool) {}
virtual void block_txn_start(bool readonly=false) {}