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.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index dab09e8f4..1f0831874 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -169,6 +169,9 @@ int compare_string(const MDB_val *a, const MDB_val *b)
*
* spent_keys input hash -
*
+ * txpool_meta txn hash txn metadata
+ * txpool_blob txn hash txn blob
+ *
* Note: where the data items are of uniform size, DUPFIXED tables have
* been used to save space. In most of these cases, a dummy "zerokval"
* key is used when accessing the table; the Key listed above will be
@@ -189,6 +192,9 @@ const char* const LMDB_OUTPUT_TXS = "output_txs";
const char* const LMDB_OUTPUT_AMOUNTS = "output_amounts";
const char* const LMDB_SPENT_KEYS = "spent_keys";
+const char* const LMDB_TXPOOL_META = "txpool_meta";
+const char* const LMDB_TXPOOL_BLOB = "txpool_blob";
+
const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights";
const char* const LMDB_HF_VERSIONS = "hf_versions";
@@ -1164,6 +1170,9 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
lmdb_db_open(txn, LMDB_SPENT_KEYS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_spent_keys, "Failed to open db handle for m_spent_keys");
+ lmdb_db_open(txn, LMDB_TXPOOL_META, MDB_CREATE, m_txpool_meta, "Failed to open db handle for m_txpool_meta");
+ lmdb_db_open(txn, LMDB_TXPOOL_BLOB, MDB_CREATE, m_txpool_blob, "Failed to open db handle for m_txpool_blob");
+
// this subdb is dropped on sight, so it may not be present when we open the DB.
// Since we use MDB_CREATE, we'll get an exception if we open read-only and it does not exist.
// So we don't open for read-only, and also not drop below. It is not used elsewhere.
@@ -1181,6 +1190,8 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags)
mdb_set_dupsort(txn, m_output_txs, compare_uint64);
mdb_set_dupsort(txn, m_block_info, compare_uint64);
+ mdb_set_compare(txn, m_txpool_meta, compare_hash32);
+ mdb_set_compare(txn, m_txpool_blob, compare_hash32);
mdb_set_compare(txn, m_properties, compare_string);
if (!(mdb_flags & MDB_RDONLY))
@@ -1429,6 +1440,211 @@ void BlockchainLMDB::unlock()
auto_txn.commit(); \
} while(0)
+void BlockchainLMDB::add_txpool_tx(const transaction &tx, const txpool_tx_meta_t &meta)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ CURSOR(txpool_meta)
+ CURSOR(txpool_blob)
+
+ const crypto::hash txid = get_transaction_hash(tx);
+
+ MDB_val k = {sizeof(txid), (void *)&txid};
+ MDB_val v = {sizeof(meta), (void *)&meta};
+ if (auto result = mdb_cursor_put(m_cur_txpool_meta, &k, &v, MDB_NODUPDATA)) {
+ if (result == MDB_KEYEXIST)
+ throw1(DB_ERROR("Attempting to add txpool tx metadata that's already in the db"));
+ else
+ throw1(DB_ERROR(lmdb_error("Error adding txpool tx metadata to db transaction: ", result).c_str()));
+ }
+ MDB_val_copy<cryptonote::blobdata> blob_val(tx_to_blob(tx));
+ if (auto result = mdb_cursor_put(m_cur_txpool_blob, &k, &blob_val, MDB_NODUPDATA)) {
+ if (result == MDB_KEYEXIST)
+ throw1(DB_ERROR("Attempting to add txpool tx blob that's already in the db"));
+ else
+ throw1(DB_ERROR(lmdb_error("Error adding txpool tx blob to db transaction: ", result).c_str()));
+ }
+}
+
+void BlockchainLMDB::update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ CURSOR(txpool_meta)
+ CURSOR(txpool_blob)
+
+ MDB_val k = {sizeof(txid), (void *)&txid};
+ MDB_val v;
+ auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET);
+ if (result != 0)
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta to update: ", result).c_str()));
+ result = mdb_cursor_del(m_cur_txpool_meta, 0);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Error adding removal of txpool tx metadata to db transaction: ", result).c_str()));
+ v = MDB_val({sizeof(meta), (void *)&meta});
+ if ((result = mdb_cursor_put(m_cur_txpool_meta, &k, &v, MDB_NODUPDATA)) != 0) {
+ if (result == MDB_KEYEXIST)
+ throw1(DB_ERROR("Attempting to add txpool tx metadata that's already in the db"));
+ else
+ throw1(DB_ERROR(lmdb_error("Error adding txpool tx metadata to db transaction: ", result).c_str()));
+ }
+}
+
+uint64_t BlockchainLMDB::get_txpool_tx_count() const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ int result;
+
+ MDB_stat db_stats;
+ if ((result = mdb_stat(m_txn, m_txpool_meta, &db_stats)))
+ throw0(DB_ERROR(lmdb_error("Failed to query m_txpool_meta: ", result).c_str()));
+
+ TXN_POSTFIX_RDONLY();
+
+ return db_stats.ms_entries;
+}
+
+bool BlockchainLMDB::txpool_has_tx(const crypto::hash& txid) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(txpool_meta)
+
+ MDB_val k = {sizeof(txid), (void *)&txid};
+ auto result = mdb_cursor_get(m_cur_txpool_meta, &k, NULL, MDB_SET);
+ if (result != 0 && result != MDB_NOTFOUND)
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
+ TXN_POSTFIX_RDONLY();
+ return result != MDB_NOTFOUND;
+}
+
+void BlockchainLMDB::remove_txpool_tx(const crypto::hash& txid)
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+ mdb_txn_cursors *m_cursors = &m_wcursors;
+
+ CURSOR(txpool_meta)
+ CURSOR(txpool_blob)
+
+ MDB_val k = {sizeof(txid), (void *)&txid};
+ auto result = mdb_cursor_get(m_cur_txpool_meta, &k, NULL, MDB_SET);
+ if (result != 0 && result != MDB_NOTFOUND)
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta to remove: ", result).c_str()));
+ if (!result)
+ {
+ result = mdb_cursor_del(m_cur_txpool_meta, 0);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Error adding removal of txpool tx metadata to db transaction: ", result).c_str()));
+ }
+ result = mdb_cursor_get(m_cur_txpool_blob, &k, NULL, MDB_SET);
+ if (result != 0 && result != MDB_NOTFOUND)
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx blob to remove: ", result).c_str()));
+ if (!result)
+ {
+ result = mdb_cursor_del(m_cur_txpool_blob, 0);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Error adding removal of txpool tx blob to db transaction: ", result).c_str()));
+ }
+}
+
+txpool_tx_meta_t BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(txpool_meta)
+
+ MDB_val k = {sizeof(txid), (void *)&txid};
+ MDB_val v;
+ auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET);
+ if (result != 0)
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
+
+ const txpool_tx_meta_t meta = *(const txpool_tx_meta_t*)v.mv_data;
+ TXN_POSTFIX_RDONLY();
+ return meta;
+}
+
+cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(txpool_blob)
+
+ MDB_val k = {sizeof(txid), (void *)&txid};
+ MDB_val v;
+ auto result = mdb_cursor_get(m_cur_txpool_blob, &k, &v, MDB_SET);
+ if (result != 0)
+ throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
+
+ blobdata bd;
+ bd.assign(reinterpret_cast<const char*>(v.mv_data), v.mv_size);
+ TXN_POSTFIX_RDONLY();
+ return bd;
+}
+
+bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob) const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ check_open();
+
+ TXN_PREFIX_RDONLY();
+ RCURSOR(txpool_meta);
+ RCURSOR(txpool_blob);
+
+ MDB_val k;
+ MDB_val v;
+ bool ret = true;
+
+ MDB_cursor_op op = MDB_FIRST;
+ while (1)
+ {
+ int result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, op);
+ op = MDB_NEXT;
+ if (result == MDB_NOTFOUND)
+ break;
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to enumerate txpool tx metadata: ", result).c_str()));
+ const crypto::hash txid = *(const crypto::hash*)k.mv_data;
+ const txpool_tx_meta_t &meta = *(const txpool_tx_meta_t*)v.mv_data;
+ const cryptonote::blobdata *passed_bd = NULL;
+ cryptonote::blobdata bd;
+ if (include_blob)
+ {
+ MDB_val b;
+ result = mdb_cursor_get(m_cur_txpool_blob, &k, &b, MDB_SET);
+ if (result == MDB_NOTFOUND)
+ throw0(DB_ERROR("Failed to find txpool tx blob to match metadata"));
+ if (result)
+ throw0(DB_ERROR(lmdb_error("Failed to enumerate txpool tx blob: ", result).c_str()));
+ bd.assign(reinterpret_cast<const char*>(b.mv_data), b.mv_size);
+ passed_bd = &bd;
+ }
+
+ if (!f(txid, meta, passed_bd)) {
+ ret = false;
+ break;
+ }
+ }
+
+ TXN_POSTFIX_RDONLY();
+
+ return ret;
+}
+
bool BlockchainLMDB::block_exists(const crypto::hash& h, uint64_t *height) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);