aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/syncobj.h17
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp2
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.h2
-rw-r--r--src/blockchain_db/blockchain_db.cpp11
-rw-r--r--src/blockchain_db/blockchain_db.h2
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp430
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h78
-rw-r--r--src/blockchain_utilities/blockchain_converter.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_dump.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_export.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp2
-rw-r--r--src/blockchain_utilities/cn_deserialize.cpp2
-rw-r--r--src/common/dns_utils.cpp38
-rw-r--r--src/connectivity_tool/conn_tool.cpp2
-rw-r--r--src/cryptonote_core/account.cpp10
-rw-r--r--src/cryptonote_core/account.h1
-rw-r--r--src/cryptonote_core/blockchain.cpp45
-rw-r--r--src/cryptonote_core/hardfork.cpp6
-rw-r--r--src/daemon/daemon.cpp2
-rw-r--r--src/daemon/main.cpp2
-rw-r--r--src/miner/simpleminer.cpp1
-rw-r--r--src/simplewallet/simplewallet.cpp135
-rw-r--r--src/simplewallet/simplewallet.h3
-rw-r--r--src/wallet/wallet2.cpp35
-rw-r--r--src/wallet/wallet2.h10
-rw-r--r--tests/core_proxy/core_proxy.cpp2
-rw-r--r--tests/core_tests/chaingen_main.cpp2
-rw-r--r--tests/functional_tests/main.cpp2
-rw-r--r--tests/net_load_tests/clt.cpp2
-rw-r--r--tests/net_load_tests/srv.cpp2
-rw-r--r--tests/performance_tests/main.cpp2
-rw-r--r--tests/unit_tests/main.cpp2
32 files changed, 580 insertions, 276 deletions
diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h
index 275324436..0833b4114 100644
--- a/contrib/epee/include/syncobj.h
+++ b/contrib/epee/include/syncobj.h
@@ -39,7 +39,14 @@
namespace epee
{
- extern unsigned int g_test_dbg_lock_sleep;
+ namespace debug
+ {
+ inline unsigned int &g_test_dbg_lock_sleep()
+ {
+ static unsigned int value = 0;
+ return value;
+ }
+ }
struct simple_event
{
@@ -217,10 +224,10 @@ namespace epee
#define SHARED_CRITICAL_REGION_BEGIN(x) { shared_guard critical_region_var(x)
#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { exclusive_guard critical_region_var(x)
-#define CRITICAL_REGION_LOCAL(x) {std::this_thread::sleep_for(std::chrono::milliseconds(epee::g_test_dbg_lock_sleep));} epee::critical_region_t<decltype(x)> critical_region_var(x)
-#define CRITICAL_REGION_BEGIN(x) { std::this_thread::sleep_for(std::chrono::milliseconds(epee::g_test_dbg_lock_sleep)); epee::critical_region_t<decltype(x)> critical_region_var(x)
-#define CRITICAL_REGION_LOCAL1(x) {std::this_thread::sleep_for(std::chrono::milliseconds(epee::g_test_dbg_lock_sleep));} epee::critical_region_t<decltype(x)> critical_region_var1(x)
-#define CRITICAL_REGION_BEGIN1(x) { std::this_thread::sleep_for(std::chrono::milliseconds(epee::g_test_dbg_lock_sleep)); epee::critical_region_t<decltype(x)> critical_region_var1(x)
+#define CRITICAL_REGION_LOCAL(x) {std::this_thread::sleep_for(std::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep()));} epee::critical_region_t<decltype(x)> critical_region_var(x)
+#define CRITICAL_REGION_BEGIN(x) { std::this_thread::sleep_for(std::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep())); epee::critical_region_t<decltype(x)> critical_region_var(x)
+#define CRITICAL_REGION_LOCAL1(x) {std::this_thread::sleep_for(std::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep()));} epee::critical_region_t<decltype(x)> critical_region_var1(x)
+#define CRITICAL_REGION_BEGIN1(x) { std::this_thread::sleep_for(std::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep())); epee::critical_region_t<decltype(x)> critical_region_var1(x)
#define CRITICAL_REGION_END() }
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index d44e14f5b..bfdb22a10 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -1837,7 +1837,7 @@ void BlockchainBDB::set_batch_transactions(bool batch_transactions)
LOG_PRINT_L3("batch transactions " << (m_batch_transactions ? "enabled" : "disabled"));
}
-void BlockchainBDB::block_txn_start()
+void BlockchainBDB::block_txn_start(bool readonly)
{
// TODO
}
diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h
index aee160fa6..bf9665cae 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.h
+++ b/src/blockchain_db/berkeleydb/db_bdb.h
@@ -329,7 +329,7 @@ public:
virtual void batch_stop();
virtual void batch_abort();
- virtual void block_txn_start();
+ virtual void block_txn_start(bool readonly);
virtual void block_txn_stop();
virtual void block_txn_abort();
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 68bef3892..a66f4a403 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -99,7 +99,7 @@ uint64_t BlockchainDB::add_block( const block& blk
, const std::vector<transaction>& txs
)
{
- block_txn_start();
+ block_txn_start(false);
TIME_MEASURE_START(time1);
crypto::hash blk_hash = get_block_hash(blk);
@@ -227,6 +227,9 @@ void BlockchainDB::fixup()
static const char * const mainnet_genesis_hex = "418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e3";
crypto::hash mainnet_genesis_hash;
epee::string_tools::hex_to_pod(mainnet_genesis_hex, mainnet_genesis_hash );
+ set_batch_transactions(true);
+ batch_start();
+
if (get_block_hash_from_height(0) == mainnet_genesis_hash)
{
// block 202612 (511 key images in 511 transactions)
@@ -762,9 +765,6 @@ void BlockchainDB::fixup()
"633cdedeb3b96ec4f234c670254c6f721e0b368d00b48c6b26759db7d62cf52d",
};
- set_batch_transactions(true);
- batch_start();
-
if (height() > 202612)
{
for (const auto &kis: key_images_202612)
@@ -791,9 +791,8 @@ void BlockchainDB::fixup()
}
}
}
-
- batch_stop();
}
+ batch_stop();
}
} // namespace cryptonote
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 2aa4506e6..3396b8c20 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -381,7 +381,7 @@ public:
virtual void batch_stop() = 0;
virtual void set_batch_transactions(bool) = 0;
- virtual void block_txn_start() = 0;
+ virtual void block_txn_start(bool readonly=false) = 0;
virtual void block_txn_stop() = 0;
virtual void block_txn_abort() = 0;
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index b43d5742f..e6d20a9e0 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -38,6 +38,10 @@
#include "crypto/crypto.h"
#include "profile_tools.h"
+#if defined(__i386) || defined(__x86_64)
+#define MISALIGNED_OK 1
+#endif
+
using epee::string_tools::pod_to_hex;
// Increase when the DB changes in a non backward compatible way, and there
@@ -143,22 +147,11 @@ private:
std::unique_ptr<char[]> data;
};
-auto compare_uint64 = [](const MDB_val *a, const MDB_val *b)
-{
- const uint64_t va = *(const uint64_t*)a->mv_data;
- const uint64_t vb = *(const uint64_t*)b->mv_data;
- if (va < vb) return -1;
- else if (va == vb) return 0;
- else return 1;
-};
-
-auto compare_uint8 = [](const MDB_val *a, const MDB_val *b)
+int compare_uint8(const MDB_val *a, const MDB_val *b)
{
const uint8_t va = *(const uint8_t*)a->mv_data;
const uint8_t vb = *(const uint8_t*)b->mv_data;
- if (va < vb) return -1;
- else if (va == vb) return 0;
- else return 1;
+ return va - vb;
};
int compare_hash32(const MDB_val *a, const MDB_val *b)
@@ -227,11 +220,34 @@ const std::string lmdb_error(const std::string& error_string, int mdb_res)
throw0(DB_ERROR(std::string("Failed to open cursor: ").append(mdb_strerror(result)).c_str())); \
}
+#define RCURSOR(name) \
+ if (!m_cur_ ## name) { \
+ int result = mdb_cursor_open(m_txn, m_ ## name, (MDB_cursor **)&m_cur_ ## name); \
+ if (result) \
+ throw0(DB_ERROR(std::string("Failed to open cursor: ").append(mdb_strerror(result)).c_str())); \
+ if (!m_write_txn) \
+ m_tinfo->m_ti_rflags.m_rf_ ## name = true; \
+ } else if (!m_write_txn && !m_tinfo->m_ti_rflags.m_rf_ ## name) { \
+ mdb_cursor_renew(m_txn, m_cur_ ## name); \
+ m_tinfo->m_ti_rflags.m_rf_ ## name = true; \
+ }
+
namespace cryptonote
{
std::atomic<uint64_t> mdb_txn_safe::num_active_txns{0};
std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT;
+mdb_threadinfo::~mdb_threadinfo()
+{
+ MDB_cursor **cur = &m_ti_rcursors.m_txc_blocks;
+ unsigned i;
+ for (i=0; i<sizeof(mdb_txn_cursors)/sizeof(MDB_cursor *); i++)
+ if (cur[i])
+ mdb_cursor_close(cur[i]);
+ if (m_ti_rtxn)
+ mdb_txn_abort(m_ti_rtxn);
+}
+
mdb_txn_safe::mdb_txn_safe() : m_txn(NULL)
{
while (creation_gate.test_and_set());
@@ -529,6 +545,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;
CURSOR(block_heights)
MDB_val_copy<crypto::hash> val_h(blk_hash);
@@ -637,6 +654,7 @@ void BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const tr
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
int result = 0;
@@ -695,6 +713,7 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_ou
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
int result = 0;
@@ -890,6 +909,7 @@ void BlockchainLMDB::add_spent_key(const crypto::key_image& k_image)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(spent_keys)
@@ -1072,29 +1092,26 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
lmdb_db_open(txn, LMDB_TXS, MDB_CREATE, m_txs, "Failed to open db handle for m_txs");
lmdb_db_open(txn, LMDB_TX_UNLOCKS, MDB_CREATE, m_tx_unlocks, "Failed to open db handle for m_tx_unlocks");
lmdb_db_open(txn, LMDB_TX_HEIGHTS, MDB_CREATE, m_tx_heights, "Failed to open db handle for m_tx_heights");
- lmdb_db_open(txn, LMDB_TX_OUTPUTS, MDB_DUPSORT | MDB_CREATE, m_tx_outputs, "Failed to open db handle for m_tx_outputs");
+ lmdb_db_open(txn, LMDB_TX_OUTPUTS, MDB_DUPSORT | MDB_INTEGERDUP | MDB_CREATE, m_tx_outputs, "Failed to open db handle for m_tx_outputs");
lmdb_db_open(txn, LMDB_OUTPUT_TXS, MDB_INTEGERKEY | MDB_CREATE, m_output_txs, "Failed to open db handle for m_output_txs");
lmdb_db_open(txn, LMDB_OUTPUT_INDICES, MDB_INTEGERKEY | MDB_CREATE, m_output_indices, "Failed to open db handle for m_output_indices");
- lmdb_db_open(txn, LMDB_OUTPUT_AMOUNTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_output_amounts, "Failed to open db handle for m_output_amounts");
+ lmdb_db_open(txn, LMDB_OUTPUT_AMOUNTS, MDB_INTEGERKEY | MDB_INTEGERDUP| MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_output_amounts, "Failed to open db handle for m_output_amounts");
lmdb_db_open(txn, LMDB_OUTPUT_KEYS, MDB_INTEGERKEY | MDB_CREATE, m_output_keys, "Failed to open db handle for m_output_keys");
lmdb_db_open(txn, LMDB_SPENT_KEYS, MDB_CREATE, m_spent_keys, "Failed to open db handle for m_spent_keys");
lmdb_db_open(txn, LMDB_HF_STARTING_HEIGHTS, MDB_CREATE, m_hf_starting_heights, "Failed to open db handle for m_hf_starting_heights");
- lmdb_db_open(txn, LMDB_HF_VERSIONS, MDB_CREATE, m_hf_versions, "Failed to open db handle for m_hf_versions");
+ lmdb_db_open(txn, LMDB_HF_VERSIONS, MDB_INTEGERKEY| MDB_CREATE, m_hf_versions, "Failed to open db handle for m_hf_versions");
lmdb_db_open(txn, LMDB_PROPERTIES, MDB_CREATE, m_properties, "Failed to open db handle for m_properties");
- mdb_set_dupsort(txn, m_output_amounts, compare_uint64);
- mdb_set_dupsort(txn, m_tx_outputs, compare_uint64);
mdb_set_compare(txn, m_spent_keys, compare_hash32);
mdb_set_compare(txn, m_block_heights, compare_hash32);
mdb_set_compare(txn, m_txs, compare_hash32);
mdb_set_compare(txn, m_tx_unlocks, compare_hash32);
mdb_set_compare(txn, m_tx_heights, compare_hash32);
mdb_set_compare(txn, m_hf_starting_heights, compare_uint8);
- mdb_set_compare(txn, m_hf_versions, compare_uint64);
mdb_set_compare(txn, m_properties, compare_string);
// get and keep current height
@@ -1201,6 +1218,7 @@ void BlockchainLMDB::close()
batch_abort();
}
this->sync();
+ m_tinfo.reset();
// FIXME: not yet thread safe!!! Use with care.
mdb_env_close(m_env);
@@ -1303,7 +1321,11 @@ void BlockchainLMDB::unlock()
throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \
} \
-#define TXN_PREFIX_RDONLY(); TXN_PREFIX(MDB_RDONLY);
+#define TXN_PREFIX_RDONLY() \
+ bool my_rtxn = block_rtxn_start(); \
+ MDB_txn *m_txn = m_write_txn ? m_write_txn->m_txn : m_tinfo->m_ti_rtxn
+#define TXN_POSTFIX_RDONLY() \
+ if (my_rtxn) block_rtxn_stop()
#define TXN_POSTFIX_SUCCESS() \
do { \
@@ -1343,20 +1365,21 @@ bool BlockchainLMDB::block_exists(const crypto::hash& h) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_heights);
MDB_val_copy<crypto::hash> key(h);
- MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_heights, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_heights, &key, NULL, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
LOG_PRINT_L3("Block with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
return false;
}
else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch block index from hash"));
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return true;
}
@@ -1374,17 +1397,19 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_heights);
MDB_val_copy<crypto::hash> key(h);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_heights, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_heights, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(BLOCK_DNE("Attempted to retrieve non-existent block height"));
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a block height from the db"));
uint64_t ret = *(const uint64_t *)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1403,10 +1428,12 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(blocks);
MDB_val_copy<uint64_t> key(height);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_blocks, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_blocks, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw0(BLOCK_DNE(std::string("Attempt to get block from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block not in db").c_str()));
@@ -1421,7 +1448,7 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
if (!parse_and_validate_block_from_blob(bd, b))
throw0(DB_ERROR("Failed to parse block from blob retrieved from the db"));
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return b;
}
@@ -1432,10 +1459,12 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_timestamps);
MDB_val_copy<uint64_t> key(height);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_timestamps, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_timestamps, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw0(BLOCK_DNE(std::string("Attempt to get timestamp from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- timestamp not in db").c_str()));
@@ -1444,7 +1473,7 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
throw0(DB_ERROR("Error attempting to retrieve a timestamp from the db"));
uint64_t ret = *(const uint64_t *)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1468,10 +1497,12 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_sizes);
MDB_val_copy<uint64_t> key(height);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_sizes, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_sizes, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw0(BLOCK_DNE(std::string("Attempt to get block size from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block size not in db").c_str()));
@@ -1480,7 +1511,7 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
throw0(DB_ERROR("Error attempting to retrieve a block size from the db"));
size_t ret = *(const size_t *)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1490,10 +1521,12 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_diffs);
MDB_val_copy<uint64_t> key(height);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_diffs, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_diffs, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw0(BLOCK_DNE(std::string("Attempt to get cumulative difficulty from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- difficulty not in db").c_str()));
@@ -1502,7 +1535,7 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
throw0(DB_ERROR("Error attempting to retrieve a cumulative difficulty from the db"));
difficulty_type ret = *(const difficulty_type*)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1529,10 +1562,12 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_coins);
MDB_val_copy<uint64_t> key(height);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_coins, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_coins, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw0(BLOCK_DNE(std::string("Attempt to get generated coins from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block size not in db").c_str()));
@@ -1541,7 +1576,7 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
throw0(DB_ERROR("Error attempting to retrieve a total generated coins from the db"));
uint64_t ret = *(const uint64_t*)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1551,10 +1586,12 @@ crypto::hash BlockchainLMDB::get_block_hash_from_height(const uint64_t& height)
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(block_hashes);
MDB_val_copy<uint64_t> key(height);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_block_hashes, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_block_hashes, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw0(BLOCK_DNE(std::string("Attempt to get hash from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- hash not in db").c_str()));
@@ -1564,7 +1601,7 @@ crypto::hash BlockchainLMDB::get_block_hash_from_height(const uint64_t& height)
append(mdb_strerror(get_result)).c_str()));
crypto::hash ret = *(const crypto::hash*)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1636,16 +1673,18 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(txs);
MDB_val_copy<crypto::hash> key(h);
MDB_val result;
TIME_MEASURE_START(time1);
- auto get_result = mdb_get(*txn_ptr, m_txs, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_txs, &key, &result, MDB_SET);
TIME_MEASURE_FINISH(time1);
time_tx_exists += time1;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
if (get_result == MDB_NOTFOUND)
{
@@ -1664,17 +1703,19 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(tx_unlocks);
MDB_val_copy<crypto::hash> key(h);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_tx_unlocks, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_tx_unlocks, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(std::string("tx unlock time with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch tx unlock time from hash"));
uint64_t ret = *(const uint64_t*)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1684,10 +1725,12 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(txs);
MDB_val_copy<crypto::hash> key(h);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_txs, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_txs, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(std::string("tx with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
else if (get_result)
@@ -1700,7 +1743,7 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
if (!parse_and_validate_tx_from_blob(bd, tx))
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return tx;
}
@@ -1713,10 +1756,10 @@ uint64_t BlockchainLMDB::get_tx_count() const
TXN_PREFIX_RDONLY();
MDB_stat db_stats;
- if (mdb_stat(*txn_ptr, m_txs, &db_stats))
+ if (mdb_stat(m_txn, m_txs, &db_stats))
throw0(DB_ERROR("Failed to query m_txs"));
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return db_stats.ms_entries;
}
@@ -1741,10 +1784,12 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(tx_heights);
MDB_val_copy<crypto::hash> key(h);
MDB_val result;
- auto get_result = mdb_get(*txn_ptr, m_tx_heights, &key, &result);
+ auto get_result = mdb_cursor_get(m_cur_tx_heights, &key, &result, MDB_SET);
if (get_result == MDB_NOTFOUND)
{
throw1(TX_DNE(std::string("tx height with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
@@ -1753,7 +1798,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
throw0(DB_ERROR("DB error attempting to fetch tx height from hash"));
uint64_t ret = *(const uint64_t*)result.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1763,24 +1808,24 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
check_open();
TXN_PREFIX_RDONLY();
-
- lmdb_cur cur(*txn_ptr, m_output_amounts);
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_amounts);
MDB_val_copy<uint64_t> k(amount);
MDB_val v;
- auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
+ auto result = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
{
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return 0;
}
else if (result)
throw0(DB_ERROR("DB error attempting to get number of outputs of an amount"));
mdb_size_t num_elems = 0;
- mdb_cursor_count(cur, &num_elems);
+ mdb_cursor_count(m_cur_output_amounts, &num_elems);
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return num_elems;
}
@@ -1791,16 +1836,18 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_keys);
MDB_val_copy<uint64_t> k(global_index);
MDB_val v;
- auto get_result = mdb_get(*txn_ptr, m_output_keys, &k, &v);
+ auto get_result = mdb_cursor_get(m_cur_output_keys, &k, &v, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist"));
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db"));
output_data_t ret = *(const output_data_t *) v.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1819,11 +1866,14 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_txs);
+ RCURSOR(output_indices);
MDB_val_copy<uint64_t> k(index);
MDB_val v;
- auto get_result = mdb_get(*txn_ptr, m_output_txs, &k, &v);
+ auto get_result = mdb_cursor_get(m_cur_output_txs, &k, &v, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("output with given index not in db"));
else if (get_result)
@@ -1831,14 +1881,14 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
crypto::hash tx_hash = *(const crypto::hash*)v.mv_data;
- get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v);
+ get_result = mdb_cursor_get(m_cur_output_indices, &k, &v, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("output with given index not in db"));
else if (get_result)
throw0(DB_ERROR("DB error attempting to fetch output tx index"));
tx_out_index ret = tx_out_index(tx_hash, *(const uint64_t *)v.mv_data);
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -1862,31 +1912,30 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_output_indices(const crypto::hash&
std::vector<uint64_t> index_vec;
TXN_PREFIX_RDONLY();
-
- lmdb_cur cur(*txn_ptr, m_tx_outputs);
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(tx_outputs);
MDB_val_copy<crypto::hash> k(h);
MDB_val v;
- auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
+ auto result = mdb_cursor_get(m_cur_tx_outputs, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("Attempting to get an output by tx hash and tx index, but output not found"));
else if (result)
throw0(DB_ERROR("DB error attempting to get an output"));
mdb_size_t num_elems = 0;
- mdb_cursor_count(cur, &num_elems);
+ mdb_cursor_count(m_cur_tx_outputs, &num_elems);
- mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP);
+ mdb_cursor_get(m_cur_tx_outputs, &k, &v, MDB_FIRST_DUP);
for (uint64_t i = 0; i < num_elems; ++i)
{
- mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT);
+ mdb_cursor_get(m_cur_tx_outputs, &k, &v, MDB_GET_CURRENT);
index_vec.push_back(*(const uint64_t *)v.mv_data);
- mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP);
+ mdb_cursor_get(m_cur_tx_outputs, &k, &v, MDB_NEXT_DUP);
}
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return index_vec;
}
@@ -1905,6 +1954,8 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
transaction tx = get_tx(h);
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_amounts);
uint64_t i = 0;
uint64_t global_index;
@@ -1914,28 +1965,26 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
global_index = index_vec[i];
- lmdb_cur cur(*txn_ptr, m_output_amounts);
-
MDB_val_copy<uint64_t> k(amount);
MDB_val v;
- auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
+ auto result = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found"));
else if (result)
throw0(DB_ERROR("DB error attempting to get an output"));
mdb_size_t num_elems = 0;
- mdb_cursor_count(cur, &num_elems);
+ mdb_cursor_count(m_cur_output_amounts, &num_elems);
- mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_FIRST_DUP);
uint64_t amount_output_index = 0;
uint64_t output_index = 0;
bool found_index = false;
for (uint64_t j = 0; j < num_elems; ++j)
{
- mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_GET_CURRENT);
output_index = *(const uint64_t *)v.mv_data;
if (output_index == global_index)
{
@@ -1943,7 +1992,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
found_index = true;
break;
}
- mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_NEXT_DUP);
}
if (found_index)
{
@@ -1952,16 +2001,14 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
else
{
// not found
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
throw1(OUTPUT_DNE("specified output not found in db"));
}
- cur.close();
++i;
}
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return index_vec2;
}
@@ -1974,16 +2021,17 @@ bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(spent_keys);
MDB_val_copy<crypto::key_image> val_key(img);
- MDB_val unused;
- if (mdb_get(*txn_ptr, m_spent_keys, &val_key, &unused) == 0)
+ if (mdb_cursor_get(m_cur_spent_keys, &val_key, NULL, MDB_SET) == 0)
{
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return true;
}
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return false;
}
@@ -1993,16 +2041,17 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(spent_keys);
MDB_val k;
MDB_val v;
bool ret = true;
- lmdb_cur cur(*txn_ptr, m_spent_keys);
MDB_cursor_op op = MDB_FIRST;
while (1)
{
- int ret = mdb_cursor_get(cur, &k, &v, op);
+ int ret = mdb_cursor_get(m_cur_spent_keys, &k, &v, op);
op = MDB_NEXT;
if (ret == MDB_NOTFOUND)
break;
@@ -2015,8 +2064,7 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
}
}
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -2027,16 +2075,17 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(blocks);
MDB_val k;
MDB_val v;
bool ret = true;
- lmdb_cur cur(*txn_ptr, m_blocks);
MDB_cursor_op op = MDB_FIRST;
while (1)
{
- int ret = mdb_cursor_get(cur, &k, &v, op);
+ int ret = mdb_cursor_get(m_cur_blocks, &k, &v, op);
op = MDB_NEXT;
if (ret == MDB_NOTFOUND)
break;
@@ -2057,8 +2106,7 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
}
}
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -2069,16 +2117,17 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(txs);
MDB_val k;
MDB_val v;
bool ret = true;
- lmdb_cur cur(*txn_ptr, m_txs);
MDB_cursor_op op = MDB_FIRST;
while (1)
{
- int ret = mdb_cursor_get(cur, &k, &v, op);
+ int ret = mdb_cursor_get(m_cur_txs, &k, &v, op);
op = MDB_NEXT;
if (ret == MDB_NOTFOUND)
break;
@@ -2096,8 +2145,7 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
}
}
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -2108,16 +2156,17 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_amounts);
MDB_val k;
MDB_val v;
bool ret = true;
- lmdb_cur cur(*txn_ptr, m_output_amounts);
MDB_cursor_op op = MDB_FIRST;
while (1)
{
- int ret = mdb_cursor_get(cur, &k, &v, op);
+ int ret = mdb_cursor_get(m_cur_output_amounts, &k, &v, op);
op = MDB_NEXT;
if (ret == MDB_NOTFOUND)
break;
@@ -2132,8 +2181,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
}
}
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -2167,8 +2215,9 @@ void BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
// active
m_write_batch_txn->m_batch_txn = true;
m_write_txn = m_write_batch_txn;
+
m_batch_active = true;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
LOG_PRINT_L3("batch transaction: begin");
}
@@ -2193,7 +2242,7 @@ void BlockchainLMDB::batch_commit()
m_write_txn = nullptr;
delete m_write_batch_txn;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
}
void BlockchainLMDB::batch_stop()
@@ -2216,7 +2265,7 @@ void BlockchainLMDB::batch_stop()
delete m_write_batch_txn;
m_write_batch_txn = nullptr;
m_batch_active = false;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
LOG_PRINT_L3("batch transaction: end");
}
@@ -2234,7 +2283,7 @@ void BlockchainLMDB::batch_abort()
m_write_batch_txn->abort();
m_batch_active = false;
m_write_batch_txn = nullptr;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
LOG_PRINT_L3("batch transaction: aborted");
}
@@ -2245,9 +2294,68 @@ void BlockchainLMDB::set_batch_transactions(bool batch_transactions)
LOG_PRINT_L3("batch transactions " << (m_batch_transactions ? "enabled" : "disabled"));
}
-void BlockchainLMDB::block_txn_start()
+// return true if we started the txn, false if already started
+bool BlockchainLMDB::block_rtxn_start() const
+{
+ if (m_write_txn)
+ return false;
+ if (!m_tinfo.get())
+ {
+ m_tinfo.reset(new mdb_threadinfo);
+ memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+ if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
+ } else if (!m_tinfo->m_ti_rflags.m_rf_txn)
+ {
+ if (auto mdb_res = mdb_txn_renew(m_tinfo->m_ti_rtxn))
+ throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
+ } else
+ {
+ return false;
+ }
+ m_tinfo->m_ti_rflags.m_rf_txn = true;
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ return true;
+}
+
+void BlockchainLMDB::block_rtxn_stop() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ mdb_txn_reset(m_tinfo->m_ti_rtxn);
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+}
+
+void BlockchainLMDB::block_txn_start(bool readonly)
+{
+ if (readonly)
+ {
+ bool didit = false;
+ if (m_write_txn)
+ return;
+ if (!m_tinfo.get())
+ {
+ m_tinfo.reset(new mdb_threadinfo);
+ memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+ if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
+ didit = true;
+ } else if (!m_tinfo->m_ti_rflags.m_rf_txn)
+ {
+ if (auto mdb_res = mdb_txn_renew(m_tinfo->m_ti_rtxn))
+ throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
+ didit = true;
+ }
+ if (didit)
+ {
+ m_tinfo->m_ti_rflags.m_rf_txn = true;
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__ << " RO");
+ }
+ return;
+ }
+
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
// Distinguish the exceptions here from exceptions that would be thrown while
// using the txn and committing it.
//
@@ -2266,7 +2374,7 @@ void BlockchainLMDB::block_txn_start()
m_write_txn = nullptr;
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
- memset(&m_cursors, 0, sizeof(m_cursors));
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
}
}
@@ -2275,14 +2383,22 @@ void BlockchainLMDB::block_txn_stop()
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (! m_batch_active)
{
- TIME_MEASURE_START(time1);
- m_write_txn->commit();
- TIME_MEASURE_FINISH(time1);
- time_commit1 += time1;
+ if (m_write_txn)
+ {
+ TIME_MEASURE_START(time1);
+ m_write_txn->commit();
+ TIME_MEASURE_FINISH(time1);
+ time_commit1 += time1;
- delete m_write_txn;
- m_write_txn = nullptr;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ delete m_write_txn;
+ m_write_txn = nullptr;
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
+ }
+ else if (m_tinfo->m_ti_rtxn)
+ {
+ mdb_txn_reset(m_tinfo->m_ti_rtxn);
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+ }
}
}
@@ -2295,8 +2411,13 @@ void BlockchainLMDB::block_txn_abort()
{
delete m_write_txn;
m_write_txn = nullptr;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
}
+ else if (m_tinfo->m_ti_rtxn)
+ {
+ mdb_txn_reset(m_tinfo->m_ti_rtxn);
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+ }
else
{
// This would probably mean an earlier exception was caught, but then we
@@ -2348,31 +2469,18 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
- mdb_txn_safe txn;
- if (! m_batch_active)
- {
- if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, txn))
- throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
- m_write_txn = &txn;
- memset(&m_cursors, 0, sizeof(m_cursors));
- }
+ block_txn_start(false);
uint64_t num_outputs = m_num_outputs;
try
{
BlockchainDB::pop_block(blk, txs);
- if (! m_batch_active)
- {
- m_write_txn = nullptr;
- memset(&m_cursors, 0, sizeof(m_cursors));
- txn.commit();
- }
+ block_txn_stop();
}
catch (...)
{
m_num_outputs = num_outputs;
- m_write_txn = nullptr;
- memset(&m_cursors, 0, sizeof(m_cursors));
+ block_txn_abort();
throw;
}
@@ -2387,13 +2495,16 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
tx_out_indices.clear();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_txs);
+ RCURSOR(output_indices);
for (const uint64_t &index : global_indices)
{
MDB_val_copy<uint64_t> k(index);
MDB_val v;
- auto get_result = mdb_get(*txn_ptr, m_output_txs, &k, &v);
+ auto get_result = mdb_cursor_get(m_cur_output_txs, &k, &v, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("output with given index not in db"));
else if (get_result)
@@ -2401,7 +2512,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
crypto::hash tx_hash = *(const crypto::hash*) v.mv_data;
- get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v);
+ get_result = mdb_cursor_get(m_cur_output_indices, &k, &v, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("output with given index not in db"));
else if (get_result)
@@ -2411,7 +2522,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
tx_out_indices.push_back(result);
}
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
}
void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std::vector<uint64_t> &offsets,
@@ -2430,19 +2541,19 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
}
TXN_PREFIX_RDONLY();
-
- lmdb_cur cur(*txn_ptr, m_output_amounts);
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(output_amounts);
MDB_val_copy<uint64_t> k(amount);
MDB_val v;
- auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
+ auto result = mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found"));
else if (result)
throw0(DB_ERROR("DB error attempting to get an output"));
mdb_size_t num_elems = 0;
- mdb_cursor_count(cur, &num_elems);
+ mdb_cursor_count(m_cur_output_amounts, &num_elems);
if (max <= 1 && num_elems <= max)
throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found"));
@@ -2452,13 +2563,13 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
{
for (const uint64_t& index : offsets)
{
- mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_FIRST_DUP);
for (uint64_t i = 0; i < index; ++i)
{
- mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_NEXT_DUP);
}
- mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_GET_CURRENT);
uint64_t glob_index = *(const uint64_t*) v.mv_data;
LOG_PRINT_L3("Amount: " << amount << " M0->v: " << glob_index);
global_indices.push_back(glob_index);
@@ -2477,10 +2588,10 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
}
if (!curcount && index > num_elems/2)
{
- mdb_cursor_get(cur, &k, &v, MDB_LAST_DUP);
- mdb_cursor_get(cur, &k, &v, MDB_PREV); /* kludge to unset C_EOF */
- mdb_cursor_get(cur, &k, &v, MDB_NEXT);
- mdb_cursor_get(cur, &k, &v, MDB_GET_MULTIPLE);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_LAST_DUP);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_PREV); /* kludge to unset C_EOF */
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_NEXT);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_GET_MULTIPLE);
curcount = num_elems;
while(1)
@@ -2490,7 +2601,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
curcount -= count;
if (curcount > index)
{
- mdb_cursor_get(cur, &k, &v, MDB_PREV_MULTIPLE);
+ mdb_cursor_get(m_cur_output_amounts, &k, &v, MDB_PREV_MULTIPLE);
} else
{
blockstart = curcount;
@@ -2506,7 +2617,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
while (index >= curcount)
{
TIME_MEASURE_START(db1);
- if (mdb_cursor_get(cur, &k, &v, curcount == 0 ? MDB_GET_MULTIPLE : MDB_NEXT_MULTIPLE) != 0)
+ if (mdb_cursor_get(m_cur_output_amounts, &k, &v, curcount == 0 ? MDB_GET_MULTIPLE : MDB_NEXT_MULTIPLE) != 0)
{
// allow partial results
result = false;
@@ -2536,8 +2647,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
}
}
- cur.close();
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
TIME_MEASURE_FINISH(txx);
LOG_PRINT_L3("txx: " << txx << " db1: " << t_dbmul << " db2: " << t_dbscan);
@@ -2550,20 +2660,21 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
check_open();
outputs.clear();
+ TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
std::vector <uint64_t> global_indices;
get_output_global_indices(amount, offsets, global_indices);
if (global_indices.size() > 0)
{
- TXN_PREFIX_RDONLY();
- lmdb_cur cur(*txn_ptr, m_output_keys);
+ RCURSOR(output_keys);
for (const uint64_t &index : global_indices)
{
MDB_val_copy<uint64_t> k(index);
MDB_val v;
- auto get_result = mdb_cursor_get(cur, &k, &v, MDB_SET);
+ auto get_result = mdb_cursor_get(m_cur_output_keys, &k, &v, MDB_SET);
if (get_result == MDB_NOTFOUND)
throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist"));
else if (get_result)
@@ -2573,8 +2684,8 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
outputs.push_back(data);
}
- TXN_POSTFIX_SUCCESS();
}
+ TXN_POSTFIX_RDONLY();
TIME_MEASURE_FINISH(db3);
LOG_PRINT_L3("db3: " << db3);
@@ -2662,14 +2773,19 @@ uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
MDB_val_copy<uint8_t> val_key(version);
MDB_val val_ret;
- auto result = mdb_get(*txn_ptr, m_hf_starting_heights, &val_key, &val_ret);
+ auto result = mdb_get(m_txn, m_hf_starting_heights, &val_key, &val_ret);
if (result == MDB_NOTFOUND)
return std::numeric_limits<uint64_t>::max();
if (result)
throw0(DB_ERROR("Error attempting to retrieve a hard fork starting height from the db"));
- uint64_t ret = *(const uint64_t*)val_ret.mv_data;
- TXN_POSTFIX_SUCCESS();
+ uint64_t ret;
+#ifdef MISALIGNED_OK
+ ret = *(const uint64_t*)val_ret.mv_data;
+#else
+ memcpy(&ret, val_ret.mv_data, sizeof(uint64_t));
+#endif
+ TXN_POSTFIX_RDONLY();
return ret;
}
@@ -2698,15 +2814,17 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
check_open();
TXN_PREFIX_RDONLY();
+ const mdb_txn_cursors *m_cursors = m_write_txn ? &m_wcursors : &m_tinfo->m_ti_rcursors;
+ RCURSOR(hf_versions);
MDB_val_copy<uint64_t> val_key(height);
MDB_val val_ret;
- auto result = mdb_get(*txn_ptr, m_hf_versions, &val_key, &val_ret);
+ auto result = mdb_cursor_get(m_cur_hf_versions, &val_key, &val_ret, MDB_SET);
if (result == MDB_NOTFOUND || result)
throw0(DB_ERROR("Error attempting to retrieve a hard fork version from the db"));
uint8_t ret = *(const uint8_t*)val_ret.mv_data;
- TXN_POSTFIX_SUCCESS();
+ TXN_POSTFIX_RDONLY();
return ret;
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 150f59475..e58643efa 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -30,6 +30,7 @@
#include "blockchain_db/blockchain_db.h"
#include "cryptonote_protocol/blobdatatype.h" // for type blobdata
+#include <boost/thread/tss.hpp>
#include <lmdb.h>
@@ -38,7 +39,7 @@
namespace cryptonote
{
-struct mdb_txn_cursors
+typedef struct mdb_txn_cursors
{
MDB_cursor *m_txc_blocks;
MDB_cursor *m_txc_block_heights;
@@ -59,24 +60,58 @@ struct mdb_txn_cursors
MDB_cursor *m_txc_tx_outputs;
MDB_cursor *m_txc_spent_keys;
-};
-#define m_cur_blocks m_cursors.m_txc_blocks
-#define m_cur_block_heights m_cursors.m_txc_block_heights
-#define m_cur_block_hashes m_cursors.m_txc_block_hashes
-#define m_cur_block_timestamps m_cursors.m_txc_block_timestamps
-#define m_cur_block_sizes m_cursors.m_txc_block_sizes
-#define m_cur_block_diffs m_cursors.m_txc_block_diffs
-#define m_cur_block_coins m_cursors.m_txc_block_coins
-#define m_cur_output_txs m_cursors.m_txc_output_txs
-#define m_cur_output_indices m_cursors.m_txc_output_indices
-#define m_cur_output_amounts m_cursors.m_txc_output_amounts
-#define m_cur_output_keys m_cursors.m_txc_output_keys
-#define m_cur_txs m_cursors.m_txc_txs
-#define m_cur_tx_heights m_cursors.m_txc_tx_heights
-#define m_cur_tx_unlocks m_cursors.m_txc_tx_unlocks
-#define m_cur_tx_outputs m_cursors.m_txc_tx_outputs
-#define m_cur_spent_keys m_cursors.m_txc_spent_keys
+ MDB_cursor *m_txc_hf_versions;
+} mdb_txn_cursors;
+
+#define m_cur_blocks m_cursors->m_txc_blocks
+#define m_cur_block_heights m_cursors->m_txc_block_heights
+#define m_cur_block_hashes m_cursors->m_txc_block_hashes
+#define m_cur_block_timestamps m_cursors->m_txc_block_timestamps
+#define m_cur_block_sizes m_cursors->m_txc_block_sizes
+#define m_cur_block_diffs m_cursors->m_txc_block_diffs
+#define m_cur_block_coins m_cursors->m_txc_block_coins
+#define m_cur_output_txs m_cursors->m_txc_output_txs
+#define m_cur_output_indices m_cursors->m_txc_output_indices
+#define m_cur_output_amounts m_cursors->m_txc_output_amounts
+#define m_cur_output_keys m_cursors->m_txc_output_keys
+#define m_cur_txs m_cursors->m_txc_txs
+#define m_cur_tx_heights m_cursors->m_txc_tx_heights
+#define m_cur_tx_unlocks m_cursors->m_txc_tx_unlocks
+#define m_cur_tx_outputs m_cursors->m_txc_tx_outputs
+#define m_cur_spent_keys m_cursors->m_txc_spent_keys
+#define m_cur_hf_versions m_cursors->m_txc_hf_versions
+
+typedef struct mdb_rflags
+{
+ bool m_rf_txn;
+ bool m_rf_blocks;
+ bool m_rf_block_heights;
+ bool m_rf_block_hashes;
+ bool m_rf_block_timestamps;
+ bool m_rf_block_sizes;
+ bool m_rf_block_diffs;
+ bool m_rf_block_coins;
+ bool m_rf_output_txs;
+ bool m_rf_output_indices;
+ bool m_rf_output_amounts;
+ bool m_rf_output_keys;
+ bool m_rf_txs;
+ bool m_rf_tx_heights;
+ bool m_rf_tx_unlocks;
+ bool m_rf_tx_outputs;
+ bool m_rf_spent_keys;
+ bool m_rf_hf_versions;
+} mdb_rflags;
+
+typedef struct mdb_threadinfo
+{
+ MDB_txn *m_ti_rtxn; // per-thread read txn
+ mdb_txn_cursors m_ti_rcursors; // per-thread read cursors
+ mdb_rflags m_ti_rflags; // per-thread read state
+
+ ~mdb_threadinfo();
+} mdb_threadinfo;
struct mdb_txn_safe
{
@@ -234,9 +269,11 @@ public:
virtual void batch_stop();
virtual void batch_abort();
- virtual void block_txn_start();
+ virtual void block_txn_start(bool readonly);
virtual void block_txn_stop();
virtual void block_txn_abort();
+ virtual bool block_rtxn_start() const;
+ virtual void block_rtxn_stop() const;
virtual void pop_block(block& blk, std::vector<transaction>& txs);
@@ -355,7 +392,8 @@ private:
bool m_batch_transactions; // support for batch transactions
bool m_batch_active; // whether batch transaction is in progress
- struct mdb_txn_cursors m_cursors;
+ mdb_txn_cursors m_wcursors;
+ mutable boost::thread_specific_ptr<mdb_threadinfo> m_tinfo;
#if defined(__arm__)
// force a value so it can compile with 32-bit ARM
diff --git a/src/blockchain_utilities/blockchain_converter.cpp b/src/blockchain_utilities/blockchain_converter.cpp
index 17b6d81bf..7c33ec399 100644
--- a/src/blockchain_utilities/blockchain_converter.cpp
+++ b/src/blockchain_utilities/blockchain_converter.cpp
@@ -45,8 +45,6 @@
#include <iostream>
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace
{
diff --git a/src/blockchain_utilities/blockchain_dump.cpp b/src/blockchain_utilities/blockchain_dump.cpp
index 53dc22f8b..6fa5ce801 100644
--- a/src/blockchain_utilities/blockchain_dump.cpp
+++ b/src/blockchain_utilities/blockchain_dump.cpp
@@ -38,8 +38,6 @@
#include "common/command_line.h"
#include "version.h"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace po = boost::program_options;
using namespace epee; // log_space
diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp
index f5dea731a..d90175a77 100644
--- a/src/blockchain_utilities/blockchain_export.cpp
+++ b/src/blockchain_utilities/blockchain_export.cpp
@@ -31,8 +31,6 @@
#include "common/command_line.h"
#include "version.h"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace po = boost::program_options;
using namespace epee; // log_space
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 67ad24031..1aaf2bddc 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -44,8 +44,6 @@
#include "fake_core.h"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace
{
// CONFIG
diff --git a/src/blockchain_utilities/cn_deserialize.cpp b/src/blockchain_utilities/cn_deserialize.cpp
index 6c6288aec..bf02dc150 100644
--- a/src/blockchain_utilities/cn_deserialize.cpp
+++ b/src/blockchain_utilities/cn_deserialize.cpp
@@ -32,8 +32,6 @@
#include "common/command_line.h"
#include "version.h"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace po = boost::program_options;
using namespace epee; // log_space
diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp
index eb0a7de1f..e6e53a5c0 100644
--- a/src/common/dns_utils.cpp
+++ b/src/common/dns_utils.cpp
@@ -181,6 +181,17 @@ struct DNSResolverData
ub_ctx* m_ub_context;
};
+// work around for bug https://www.nlnetlabs.nl/bugs-script/show_bug.cgi?id=515 needed for it to compile on e.g. Debian 7
+class string_copy {
+public:
+ string_copy(const char *s): str(strdup(s)) {}
+ ~string_copy() { free(str); }
+ operator char*() { return str; }
+
+public:
+ char *str;
+};
+
DNSResolver::DNSResolver() : m_data(new DNSResolverData())
{
int use_dns_public = 0;
@@ -201,9 +212,9 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData())
if (use_dns_public)
{
- ub_ctx_set_fwd(m_data->m_ub_context, dns_public_addr);
- ub_ctx_set_option(m_data->m_ub_context, "do-udp:", "no");
- ub_ctx_set_option(m_data->m_ub_context, "do-tcp:", "yes");
+ ub_ctx_set_fwd(m_data->m_ub_context, string_copy(dns_public_addr));
+ ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no"));
+ ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes"));
}
else {
// look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent
@@ -211,24 +222,7 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData())
ub_ctx_hosts(m_data->m_ub_context, NULL);
}
- #ifdef DEVELOPER_LIBUNBOUND_OLD
- #pragma message "Using the work around for old libunbound"
- { // work around for bug https://www.nlnetlabs.nl/bugs-script/show_bug.cgi?id=515 needed for it to compile on e.g. Debian 7
- char * ds_copy = NULL; // this will be the writable copy of string that bugged version of libunbound requires
- try {
- char * ds_copy = strdup( ::get_builtin_ds() );
- ub_ctx_add_ta(m_data->m_ub_context, ds_copy);
- } catch(...) { // probably not needed but to work correctly in every case...
- if (ds_copy) { free(ds_copy); ds_copy=NULL; } // for the strdup
- throw ;
- }
- if (ds_copy) { free(ds_copy); ds_copy=NULL; } // for the strdup
- }
- #else
- // normal version for fixed libunbound
- ub_ctx_add_ta(m_data->m_ub_context, ::get_builtin_ds() );
- #endif
-
+ ub_ctx_add_ta(m_data->m_ub_context, string_copy(::get_builtin_ds()));
}
DNSResolver::~DNSResolver()
@@ -258,7 +252,7 @@ std::vector<std::string> DNSResolver::get_record(const std::string& url, int rec
ub_result_ptr result;
// call DNS resolver, blocking. if return value not zero, something went wrong
- if (!ub_resolve(m_data->m_ub_context, url.c_str(), record_type, DNS_CLASS_IN, &result))
+ if (!ub_resolve(m_data->m_ub_context, string_copy(url.c_str()), record_type, DNS_CLASS_IN, &result))
{
dnssec_available = (result->secure || (!result->secure && result->bogus));
dnssec_valid = result->secure && !result->bogus;
diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp
index 9f00300ae..458d30cc3 100644
--- a/src/connectivity_tool/conn_tool.cpp
+++ b/src/connectivity_tool/conn_tool.cpp
@@ -49,8 +49,6 @@ namespace po = boost::program_options;
using namespace cryptonote;
using namespace nodetool;
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace
{
const command_line::arg_descriptor<std::string, true> arg_ip = {"ip", "set ip"};
diff --git a/src/cryptonote_core/account.cpp b/src/cryptonote_core/account.cpp
index 0d2175ed7..c3f2b4446 100644
--- a/src/cryptonote_core/account.cpp
+++ b/src/cryptonote_core/account.cpp
@@ -93,9 +93,10 @@ DISABLE_VS_WARNINGS(4244 4345)
return first;
}
//-----------------------------------------------------------------
- void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
+ void account_base::create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey)
{
m_keys.m_account_address = address;
+ m_keys.m_spend_secret_key = spendkey;
m_keys.m_view_secret_key = viewkey;
struct tm timestamp;
@@ -109,6 +110,13 @@ DISABLE_VS_WARNINGS(4244 4345)
m_creation_timestamp = mktime(&timestamp);
}
//-----------------------------------------------------------------
+ void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
+ {
+ crypto::secret_key fake;
+ memset(&fake, 0, sizeof(fake));
+ create_from_keys(address, fake, viewkey);
+ }
+ //-----------------------------------------------------------------
const account_keys& account_base::get_keys() const
{
return m_keys;
diff --git a/src/cryptonote_core/account.h b/src/cryptonote_core/account.h
index 38f61ebd4..41a119b07 100644
--- a/src/cryptonote_core/account.h
+++ b/src/cryptonote_core/account.h
@@ -58,6 +58,7 @@ namespace cryptonote
public:
account_base();
crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
+ void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
const account_keys& get_keys() const;
std::string get_public_address_str(bool testnet) const;
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index a3eb21187..a83f4bc9c 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -334,6 +334,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const cryptonote::te
m_db->fixup();
}
+ m_db->block_txn_start(true);
// check how far behind we are
uint64_t top_block_timestamp = m_db->get_top_block_timestamp();
uint64_t timestamp_diff = time(NULL) - top_block_timestamp;
@@ -354,6 +355,7 @@ bool Blockchain::init(BlockchainDB* db, const bool testnet, const cryptonote::te
#endif
LOG_PRINT_GREEN("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(), LOG_LEVEL_0);
+ m_db->block_txn_stop();
return true;
}
@@ -549,6 +551,7 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
if(!sz)
return true;
+ m_db->block_txn_start(true);
bool genesis_included = false;
uint64_t current_back_offset = 1;
while(current_back_offset < sz)
@@ -575,6 +578,7 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
{
ids.push_back(m_db->get_block_hash_from_height(0));
}
+ m_db->block_txn_stop();
return true;
}
@@ -996,12 +1000,14 @@ void Blockchain::get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count)
if(h == 0)
return;
+ m_db->block_txn_start(true);
// add size of last <count> blocks to vector <sz> (or less, if blockchain size < count)
size_t start_offset = h - std::min<size_t>(h, count);
for(size_t i = start_offset; i < h; i++)
{
sz.push_back(m_db->get_block_size(i));
}
+ m_db->block_txn_stop();
}
//------------------------------------------------------------------
uint64_t Blockchain::get_current_cumulative_blocksize_limit() const
@@ -1403,6 +1409,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ m_db->block_txn_start(true);
rsp.current_blockchain_height = get_current_blockchain_height();
std::list<block> blocks;
get_blocks(arg.blocks, blocks, rsp.missed_ids);
@@ -1424,6 +1431,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
// as done below if any standalone transactions were requested
// and missed.
rsp.missed_ids.splice(rsp.missed_ids.end(), missed_tx_ids);
+ m_db->block_txn_stop();
return false;
}
@@ -1442,6 +1450,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
for (const auto& tx: txs)
rsp.txs.push_back(t_serializable_object_to_blob(tx));
+ m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -1585,12 +1594,14 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
return false;
}
+ m_db->block_txn_start(true);
// make sure that the last block in the request's block list matches
// the genesis block
auto gen_hash = m_db->get_block_hash_from_height(0);
if(qblock_ids.back() != gen_hash)
{
LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block missmatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
+ m_db->block_txn_abort();
return false;
}
@@ -1612,9 +1623,11 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
catch (const std::exception& e)
{
LOG_PRINT_L1("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it);
+ m_db->block_txn_abort();
return false;
}
}
+ m_db->block_txn_stop();
// this should be impossible, as we checked that we share the genesis block,
// but just in case...
@@ -2427,9 +2440,12 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
CRITICAL_REGION_LOCAL(m_blockchain_lock);
TIME_MEASURE_START(t1);
+ m_db->block_txn_start(true);
if(bl.prev_id != get_tail_id())
{
LOG_PRINT_L1("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << get_tail_id());
+leave:
+ m_db->block_txn_stop();
return false;
}
@@ -2438,7 +2454,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
LOG_PRINT_L1("Block with id: " << id << std::endl << "has old version: " << (unsigned)bl.major_version << std::endl << "current: " << (unsigned)m_hardfork->get_current_version());
bvc.m_verifivation_failed = true;
- return false;
+ goto leave;
}
TIME_MEASURE_FINISH(t1);
@@ -2450,7 +2466,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
LOG_PRINT_L1("Block with id: " << id << std::endl << "has invalid timestamp: " << bl.timestamp);
bvc.m_verifivation_failed = true;
- return false;
+ goto leave;
}
TIME_MEASURE_FINISH(t2);
@@ -2490,7 +2506,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
LOG_PRINT_L1("Block with id is INVALID: " << id);
bvc.m_verifivation_failed = true;
- return false;
+ goto leave;
}
fast_check = true;
}
@@ -2511,7 +2527,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
LOG_PRINT_L1("Block with id: " << id << std::endl << "does not have enough proof of work: " << proof_of_work << std::endl << "unexpected difficulty: " << current_diffic);
bvc.m_verifivation_failed = true;
- return false;
+ goto leave;
}
}
@@ -2523,7 +2539,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
LOG_ERROR("CHECKPOINT VALIDATION FAILED");
bvc.m_verifivation_failed = true;
- return false;
+ goto leave;
}
}
@@ -2538,7 +2554,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
{
LOG_PRINT_L1("Block with id: " << id << " failed to pass prevalidation");
bvc.m_verifivation_failed = true;
- return false;
+ goto leave;
}
size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx);
@@ -2574,7 +2590,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
LOG_PRINT_L1("Block with id: " << id << " attempting to add transaction already in blockchain with id: " << tx_id);
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
- return false;
+ goto leave;
}
TIME_MEASURE_FINISH(aa);
@@ -2587,7 +2603,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
LOG_PRINT_L1("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
- return false;
+ goto leave;
}
TIME_MEASURE_FINISH(bb);
@@ -2624,7 +2640,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
LOG_PRINT_L1("Block with id " << id << " added as invalid because of wrong inputs in transactions");
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
- return false;
+ goto leave;
}
}
#if defined(PER_BLOCK_CHECKPOINT)
@@ -2640,7 +2656,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
LOG_PRINT_L1("Block with id " << id << " added as invalid because of wrong inputs in transactions");
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
- return false;
+ goto leave;
}
}
#endif
@@ -2660,7 +2676,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
LOG_PRINT_L1("Block with id: " << id << " has incorrect miner transaction");
bvc.m_verifivation_failed = true;
return_tx_to_pool(txs);
- return false;
+ goto leave;
}
TIME_MEASURE_FINISH(vmt);
@@ -2678,6 +2694,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
if(precomputed)
block_processing_time += m_fake_pow_calc_time;
+ m_db->block_txn_stop();
TIME_MEASURE_START(addblock);
uint64_t new_height = 0;
if (!bvc.m_verifivation_failed)
@@ -2754,10 +2771,12 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc
crypto::hash id = get_block_hash(bl);
CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process
CRITICAL_REGION_LOCAL1(m_blockchain_lock);
+ m_db->block_txn_start(true);
if(have_block(id))
{
LOG_PRINT_L3("block with id = " << id << " already exists");
bvc.m_already_exists = true;
+ m_db->block_txn_stop();
return false;
}
@@ -2766,10 +2785,12 @@ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc
{
//chain switching or wrong block
bvc.m_added_to_main_chain = false;
+ m_db->block_txn_stop();
return handle_alternative_block(bl, id, bvc);
//never relay alternative blocks
}
+ m_db->block_txn_stop();
return handle_block_to_main_chain(bl, id, bvc);
}
//------------------------------------------------------------------
@@ -2777,6 +2798,7 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor
{
const auto& pts = points.get_points();
+ m_db->batch_start();
for (const auto& pt : pts)
{
// if the checkpoint is for a block we don't have yet, move on
@@ -2800,6 +2822,7 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor
}
}
}
+ m_db->batch_stop();
}
//------------------------------------------------------------------
// returns false if any of the checkpoints loading returns false.
diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp
index e99736ff4..7e2e82c4a 100644
--- a/src/cryptonote_core/hardfork.cpp
+++ b/src/cryptonote_core/hardfork.cpp
@@ -254,8 +254,11 @@ bool HardFork::reorganize_from_chain_height(uint64_t height)
bool HardFork::rescan_from_block_height(uint64_t height)
{
CRITICAL_REGION_LOCAL(lock);
- if (height >= db.height())
+ db.block_txn_start(true);
+ if (height >= db.height()) {
+ db.block_txn_stop();
return false;
+ }
versions.clear();
@@ -273,6 +276,7 @@ bool HardFork::rescan_from_block_height(uint64_t height)
current_fork_index = 0;
while (current_fork_index + 1 < heights.size() && heights[current_fork_index].version != lastv)
++current_fork_index;
+ db.block_txn_stop();
return true;
}
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index ed6a66722..e79823d08 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -46,8 +46,6 @@ using namespace epee;
#include <functional>
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
namespace daemonize {
struct t_internals {
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index 089d8fb69..0717fd89b 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -132,7 +132,7 @@ int main(int argc, char const * argv[])
return 0;
}
- epee::g_test_dbg_lock_sleep = command_line::get_arg(vm, command_line::arg_test_dbg_lock_sleep);
+ epee::debug::g_test_dbg_lock_sleep() = command_line::get_arg(vm, command_line::arg_test_dbg_lock_sleep);
std::string db_type = command_line::get_arg(vm, command_line::arg_db_type);
diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp
index e04ffbbcf..ba956d90b 100644
--- a/src/miner/simpleminer.cpp
+++ b/src/miner/simpleminer.cpp
@@ -41,7 +41,6 @@
using namespace epee;
namespace po = boost::program_options;
-unsigned int epee::g_test_dbg_lock_sleep = 0;
int main(int argc, char** argv)
{
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 55bddcddd..65508b9d5 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -73,15 +73,14 @@ typedef cryptonote::simple_wallet sw;
#define EXTENDED_LOGS_FILE "wallet_details.log"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
#define DEFAULT_MIX 4
namespace
{
const command_line::arg_descriptor<std::string> arg_wallet_file = {"wallet-file", sw::tr("Use wallet <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg> or <address>.wallet by default"), ""};
- const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from (address:viewkey:filename) and save it to <filename>"), ""};
+ const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""};
+ const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""};
const command_line::arg_descriptor<std::string> arg_daemon_address = {"daemon-address", sw::tr("Use daemon instance at <host>:<port>"), ""};
const command_line::arg_descriptor<std::string> arg_daemon_host = {"daemon-host", sw::tr("Use daemon instance at host <arg> instead of localhost"), ""};
const command_line::arg_descriptor<std::string> arg_password = {"password", sw::tr("Wallet password"), "", true};
@@ -716,7 +715,7 @@ bool simple_wallet::ask_wallet_create_if_needed()
// add logic to error out if new wallet requested but named wallet file exists
if (keys_file_exists || wallet_file_exists)
{
- if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty())
+ if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty())
{
fail_msg_writer() << tr("attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.");
return false;
@@ -772,12 +771,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) > 1)
+ if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) > 1)
{
- fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\" and --generate-from-view-key");
+ fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\" and --generate-from-keys=\"wallet_name\"");
return false;
}
- else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty())
+ else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_keys.empty())
{
if(!ask_wallet_create_if_needed()) return false;
}
@@ -832,7 +831,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
}
- if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty())
+ if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty() || !m_generate_from_keys.empty())
{
if (m_wallet_file.empty()) m_wallet_file = m_generate_new; // alias for simplicity later
@@ -864,41 +863,108 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
if (!m_generate_from_view_key.empty())
{
- // split address:viewkey:filename triple
- std::vector<std::string> parts;
- boost::split(parts,m_generate_from_view_key, boost::is_any_of(":"));
- if (parts.size() < 3)
+ // parse address
+ std::string address_string = command_line::input_line("Standard address: ");
+ if (address_string.empty()) {
+ fail_msg_writer() << tr("No data supplied, cancelled");
+ return false;
+ }
+ cryptonote::account_public_address address;
+ bool has_payment_id;
+ crypto::hash8 new_payment_id;
+ if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, address_string))
{
- fail_msg_writer() << tr("--generate-from-view-key needs a address:viewkey:filename triple");
+ fail_msg_writer() << tr("failed to parse address");
+ return false;
+ }
+
+ // parse view secret key
+ std::string viewkey_string = command_line::input_line("View key: ");
+ if (viewkey_string.empty()) {
+ fail_msg_writer() << tr("No data supplied, cancelled");
return false;
}
+ cryptonote::blobdata viewkey_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data))
+ {
+ fail_msg_writer() << tr("failed to parse view key secret key");
+ return false;
+ }
+ crypto::secret_key viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data());
+
+ m_wallet_file = m_generate_from_view_key;
+ // check the view key matches the given address
+ crypto::public_key pkey;
+ if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
+ fail_msg_writer() << tr("failed to verify view key secret key");
+ return false;
+ }
+ if (address.m_view_public_key != pkey) {
+ fail_msg_writer() << tr("view key does not match standard address");
+ return false;
+ }
+
+ bool r = new_wallet(m_wallet_file, pwd_container.password(), address, viewkey, testnet);
+ CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ }
+ else if (!m_generate_from_keys.empty())
+ {
// parse address
+ std::string address_string = command_line::input_line("Standard address: ");
+ if (address_string.empty()) {
+ fail_msg_writer() << tr("No data supplied, cancelled");
+ return false;
+ }
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 new_payment_id;
- if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, parts[0]))
+ if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, address_string))
{
fail_msg_writer() << tr("failed to parse address");
return false;
}
+ // parse spend secret key
+ std::string spendkey_string = command_line::input_line("Spend key: ");
+ if (spendkey_string.empty()) {
+ fail_msg_writer() << tr("No data supplied, cancelled");
+ return false;
+ }
+ cryptonote::blobdata spendkey_data;
+ if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data))
+ {
+ fail_msg_writer() << tr("failed to parse spend key secret key");
+ return false;
+ }
+ crypto::secret_key spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
+
// parse view secret key
+ std::string viewkey_string = command_line::input_line("View key: ");
+ if (viewkey_string.empty()) {
+ fail_msg_writer() << tr("No data supplied, cancelled");
+ return false;
+ }
cryptonote::blobdata viewkey_data;
- if(!epee::string_tools::parse_hexstr_to_binbuff(parts[1], viewkey_data))
+ if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data))
{
fail_msg_writer() << tr("failed to parse view key secret key");
return false;
}
crypto::secret_key viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data());
- // parse filename
- m_wallet_file = parts[2];
- for (size_t n = 3; n < parts.size(); ++n)
- m_wallet_file += std::string(":") + parts[n];
+ m_wallet_file = m_generate_from_keys;
- // check the view key matches the given address
+ // check the spend and view keys match the given address
crypto::public_key pkey;
+ if (!crypto::secret_key_to_public_key(spendkey, pkey)) {
+ fail_msg_writer() << tr("failed to verify spend key secret key");
+ return false;
+ }
+ if (address.m_spend_public_key != pkey) {
+ fail_msg_writer() << tr("spend key does not match standard address");
+ return false;
+ }
if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
fail_msg_writer() << tr("failed to verify view key secret key");
return false;
@@ -908,7 +974,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- bool r = new_wallet(m_wallet_file, pwd_container.password(), address, viewkey, testnet);
+ bool r = new_wallet(m_wallet_file, pwd_container.password(), address, spendkey, viewkey, testnet);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
else
@@ -940,6 +1006,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key);
+ m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys);
m_daemon_address = command_line::get_arg(vm, arg_daemon_address);
m_daemon_host = command_line::get_arg(vm, arg_daemon_host);
m_daemon_port = command_line::get_arg(vm, arg_daemon_port);
@@ -1098,6 +1165,31 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
+ const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool testnet)
+{
+ m_wallet_file = wallet_file;
+
+ m_wallet.reset(new tools::wallet2(testnet));
+ m_wallet->callback(this);
+
+ try
+ {
+ m_wallet->generate(wallet_file, password, address, spendkey, viewkey);
+ message_writer(epee::log_space::console_color_white, true) << tr("Generated new wallet: ")
+ << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ }
+ catch (const std::exception& e)
+ {
+ fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
+ return false;
+ }
+
+ m_wallet->init(m_daemon_address);
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::open_wallet(const string &wallet_file, const std::string& password, bool testnet)
{
if (!tools::wallet2::wallet_valid_path_format(wallet_file))
@@ -2466,6 +2558,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_wallet_file);
command_line::add_arg(desc_params, arg_generate_new_wallet);
command_line::add_arg(desc_params, arg_generate_from_view_key);
+ command_line::add_arg(desc_params, arg_generate_from_keys);
command_line::add_arg(desc_params, arg_password);
command_line::add_arg(desc_params, arg_password_file);
command_line::add_arg(desc_params, arg_daemon_address);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 05f42f8de..5dac60447 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -83,6 +83,8 @@ namespace cryptonote
bool new_wallet(const std::string &wallet_file, const std::string& password, const crypto::secret_key& recovery_key,
bool recover, bool two_random, bool testnet, const std::string &old_language);
bool new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
+ const crypto::secret_key& spendkey, const crypto::secret_key& viewkey, bool testnet);
+ bool new_wallet(const std::string &wallet_file, const std::string& password, const cryptonote::account_public_address& address,
const crypto::secret_key& viewkey, bool testnet);
bool open_wallet(const std::string &wallet_file, const std::string& password, bool testnet);
bool close_wallet();
@@ -218,6 +220,7 @@ namespace cryptonote
std::string m_wallet_file;
std::string m_generate_new;
std::string m_generate_from_view_key;
+ std::string m_generate_from_keys;
std::string m_import_path;
std::string m_electrum_seed; // electrum-style seed parameter
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index ce829b00f..a86f2ffdf 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1186,6 +1186,41 @@ void wallet2::generate(const std::string& wallet_, const std::string& password,
}
/*!
+* \brief Creates a wallet from a public address and a spend/view secret key pair.
+* \param wallet_ Name of wallet file
+* \param password Password of wallet file
+* \param spendkey spend secret key
+* \param viewkey view secret key
+*/
+void wallet2::generate(const std::string& wallet_, const std::string& password,
+ const cryptonote::account_public_address &account_public_address,
+ const crypto::secret_key& spendkey, const crypto::secret_key& viewkey)
+{
+ clear();
+ prepare_file_names(wallet_);
+
+ boost::system::error_code ignored_ec;
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
+
+ m_account.create_from_keys(account_public_address, spendkey, viewkey);
+ m_account_public_address = account_public_address;
+ m_watch_only = false;
+
+ bool r = store_keys(m_keys_file, password, true);
+ THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+
+ r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet));
+ if(!r) LOG_PRINT_RED_L0("String with address text not saved");
+
+ cryptonote::block b;
+ generate_genesis(b);
+ m_blockchain.push_back(get_block_hash(b));
+
+ store();
+}
+
+/*!
* \brief Rewrites to the wallet file for wallet upgrade (doesn't generate key, assumes it's already there)
* \param wallet_name Name of wallet file (should exist)
* \param password Password for wallet file
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index c9f00bfc9..ceeef492e 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -185,6 +185,16 @@ namespace tools
const crypto::secret_key& recovery_param = crypto::secret_key(), bool recover = false,
bool two_random = false);
/*!
+ * \brief Creates a wallet from a public address and a spend/view secret key pair.
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param viewkey view secret key
+ * \param spendkey spend secret key
+ */
+ void generate(const std::string& wallet, const std::string& password,
+ const cryptonote::account_public_address &account_public_address,
+ const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
+ /*!
* \brief Creates a watch only wallet from a public address and a view secret key.
* \param wallet_ Name of wallet file
* \param password Password of wallet file
diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp
index 14a12e139..256faeccb 100644
--- a/tests/core_proxy/core_proxy.cpp
+++ b/tests/core_proxy/core_proxy.cpp
@@ -62,8 +62,6 @@ using namespace crypto;
BOOST_CLASS_VERSION(nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<tests::proxy_core> >, 1);
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char* argv[])
{
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index 40bce1e4e..9f8a57821 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -44,8 +44,6 @@ namespace
const command_line::arg_descriptor<bool> arg_test_transactions = {"test_transactions", ""};
}
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char* argv[])
{
TRY_ENTRY();
diff --git a/tests/functional_tests/main.cpp b/tests/functional_tests/main.cpp
index 0233c50b5..58a2a5c90 100644
--- a/tests/functional_tests/main.cpp
+++ b/tests/functional_tests/main.cpp
@@ -55,8 +55,6 @@ namespace
const command_line::arg_descriptor<size_t> arg_test_repeat_count = {"test_repeat_count", "", 1};
}
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char* argv[])
{
TRY_ENTRY();
diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp
index e6b5c0414..56089a4da 100644
--- a/tests/net_load_tests/clt.cpp
+++ b/tests/net_load_tests/clt.cpp
@@ -628,8 +628,6 @@ TEST_F(net_load_test_clt, permament_open_and_close_and_connections_closed_by_ser
ASSERT_EQ(RESERVED_CONN_CNT, m_tcp_server.get_config_object().get_connections_count());
}
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char** argv)
{
epee::debug::get_set_enable_assert(true, false);
diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp
index 5a737e616..d8d3eae2e 100644
--- a/tests/net_load_tests/srv.cpp
+++ b/tests/net_load_tests/srv.cpp
@@ -213,8 +213,6 @@ namespace
};
}
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char** argv)
{
//set up logging options
diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp
index 2e390fabc..84a51aa96 100644
--- a/tests/performance_tests/main.cpp
+++ b/tests/performance_tests/main.cpp
@@ -42,8 +42,6 @@
#include "generate_key_image_helper.h"
#include "is_out_to_acc.h"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char** argv)
{
set_process_affinity(1);
diff --git a/tests/unit_tests/main.cpp b/tests/unit_tests/main.cpp
index b96129a3a..faaf9475a 100644
--- a/tests/unit_tests/main.cpp
+++ b/tests/unit_tests/main.cpp
@@ -32,8 +32,6 @@
#include "include_base_utils.h"
-unsigned int epee::g_test_dbg_lock_sleep = 0;
-
int main(int argc, char** argv)
{
epee::debug::get_set_enable_assert(true, false);