diff options
Diffstat (limited to 'src/blockchain_db/lmdb/db_lmdb.cpp')
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 216 |
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__); |