aboutsummaryrefslogtreecommitdiff
path: root/src/blockchain_db/lmdb/db_lmdb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/blockchain_db/lmdb/db_lmdb.cpp')
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp177
1 files changed, 168 insertions, 9 deletions
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 2695d83f8..1e7078c67 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -747,7 +747,7 @@ void BlockchainLMDB::remove_output(const uint64_t& out_index, const uint64_t amo
auto result = mdb_del(*m_write_txn, m_output_gindices, &k, NULL);
if (result != 0 && result != MDB_NOTFOUND)
- throw1(DB_ERROR("Error adding removal of output global index to db transaction"));
+ throw1(OUTPUT_DNE("Error adding removal of output global index to db transaction"));
result = mdb_del(*m_write_txn, m_outputs, &v, NULL);
if (result != 0 && result != MDB_NOTFOUND)
@@ -1242,7 +1242,7 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
auto get_result = mdb_get(txn, m_blocks, &key, &result);
if (get_result == MDB_NOTFOUND)
{
- throw0(DB_ERROR(std::string("Attempt to get block from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block not in db").c_str()));
+ 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()));
}
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a block from the db"));
@@ -1278,7 +1278,7 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
auto get_result = mdb_get(*txn_ptr, m_block_timestamps, &key, &result);
if (get_result == MDB_NOTFOUND)
{
- throw0(DB_ERROR(std::string("Attempt to get timestamp from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- timestamp not in db").c_str()));
+ 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()));
}
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a timestamp from the db"));
@@ -1322,7 +1322,7 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
auto get_result = mdb_get(*txn_ptr, m_block_sizes, &key, &result);
if (get_result == MDB_NOTFOUND)
{
- throw0(DB_ERROR(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()));
+ 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()));
}
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a block size from the db"));
@@ -1351,7 +1351,7 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
auto get_result = mdb_get(*txn_ptr, m_block_diffs, &key, &result);
if (get_result == MDB_NOTFOUND)
{
- throw0(DB_ERROR(std::string("Attempt to get cumulative difficulty from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- difficulty not in db").c_str()));
+ 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()));
}
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a cumulative difficulty from the db"));
@@ -1398,7 +1398,7 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
auto get_result = mdb_get(*txn_ptr, m_block_coins, &key, &result);
if (get_result == MDB_NOTFOUND)
{
- throw0(DB_ERROR(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()));
+ 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()));
}
else if (get_result)
throw0(DB_ERROR("Error attempting to retrieve a total generated coins from the db"));
@@ -1696,7 +1696,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
MDB_val v;
auto get_result = mdb_get(txn, m_output_keys, &k, &v);
if (get_result == MDB_NOTFOUND)
- throw0(DB_ERROR("Attempting to get output pubkey by global index, but key does not exist"));
+ 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"));
txn.commit();
@@ -1968,6 +1968,165 @@ bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
return false;
}
+bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_image&)> f) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ mdb_txn_safe txn;
+ if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
+ throw0(DB_ERROR("Failed to create a transaction for the db"));
+
+ MDB_val k;
+ MDB_val v;
+ bool ret = true;
+
+ lmdb_cur cur(txn, m_spent_keys);
+ MDB_cursor_op op = MDB_FIRST;
+ while (1)
+ {
+ int ret = mdb_cursor_get(cur, &k, &v, op);
+ op = MDB_NEXT;
+ if (ret == MDB_NOTFOUND)
+ break;
+ if (ret < 0)
+ throw0(DB_ERROR("Failed to enumerate key images"));
+ const crypto::key_image k_image = *(crypto::key_image*)k.mv_data;
+ if (!f(k_image)) {
+ ret = false;
+ break;
+ }
+ }
+
+ cur.close();
+ txn.commit();
+
+ return ret;
+}
+
+bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)> f) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ mdb_txn_safe txn;
+ if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
+ throw0(DB_ERROR("Failed to create a transaction for the db"));
+
+ MDB_val k;
+ MDB_val v;
+ bool ret = true;
+
+ lmdb_cur cur(txn, m_blocks);
+ MDB_cursor_op op = MDB_FIRST;
+ while (1)
+ {
+ int ret = mdb_cursor_get(cur, &k, &v, op);
+ op = MDB_NEXT;
+ if (ret == MDB_NOTFOUND)
+ break;
+ if (ret)
+ throw0(DB_ERROR("Failed to enumerate blocks"));
+ uint64_t height = *(uint64_t*)k.mv_data;
+ blobdata bd;
+ bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
+ block b;
+ if (!parse_and_validate_block_from_blob(bd, b))
+ throw0(DB_ERROR("Failed to parse block from blob retrieved from the db"));
+ crypto::hash hash;
+ if (!get_block_hash(b, hash))
+ throw0(DB_ERROR("Failed to get block hash from blob retrieved from the db"));
+ if (!f(height, hash, b)) {
+ ret = false;
+ break;
+ }
+ }
+
+ cur.close();
+ txn.commit();
+
+ return ret;
+}
+
+bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ mdb_txn_safe txn;
+ if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
+ throw0(DB_ERROR("Failed to create a transaction for the db"));
+
+ MDB_val k;
+ MDB_val v;
+ bool ret = true;
+
+ lmdb_cur cur(txn, m_txs);
+ MDB_cursor_op op = MDB_FIRST;
+ while (1)
+ {
+ int ret = mdb_cursor_get(cur, &k, &v, op);
+ op = MDB_NEXT;
+ if (ret == MDB_NOTFOUND)
+ break;
+ if (ret)
+ throw0(DB_ERROR("Failed to enumerate transactions"));
+ const crypto::hash hash = *(crypto::hash*)k.mv_data;
+ blobdata bd;
+ bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
+ transaction tx;
+ if (!parse_and_validate_tx_from_blob(bd, tx))
+ throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
+ if (!f(hash, tx)) {
+ ret = false;
+ break;
+ }
+ }
+
+ cur.close();
+ txn.commit();
+
+ return ret;
+}
+
+bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, size_t tx_idx)> f) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ mdb_txn_safe txn;
+ if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
+ throw0(DB_ERROR("Failed to create a transaction for the db"));
+
+ MDB_val k;
+ MDB_val v;
+ bool ret = true;
+
+ lmdb_cur cur(txn, m_output_amounts);
+ MDB_cursor_op op = MDB_FIRST;
+ while (1)
+ {
+ int ret = mdb_cursor_get(cur, &k, &v, op);
+ op = MDB_NEXT;
+ if (ret == MDB_NOTFOUND)
+ break;
+ if (ret)
+ throw0(DB_ERROR("Failed to enumerate outputs"));
+ uint64_t amount = *(uint64_t*)k.mv_data;
+ uint64_t global_index = *(uint64_t*)v.mv_data;
+ tx_out_index toi = get_output_tx_and_index_from_global(global_index);
+ if (!f(amount, toi.first, toi.second)) {
+ ret = false;
+ break;
+ }
+ }
+
+ cur.close();
+ txn.commit();
+
+ return ret;
+}
+
// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts.
void BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
{
@@ -2329,8 +2488,8 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
MDB_val v;
auto get_result = mdb_get(*txn_ptr, m_output_keys, &k, &v);
- if (get_result != 0)
- throw0(DB_ERROR("Attempting to get output pubkey by global index, but key does not exist"));
+ 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"));