From eb56d0f9941d4aed9d89a20007221cecd1dc6cbc Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 4 Jun 2016 14:18:37 +0100 Subject: [PATCH] blockchain_db: add functions for adding/removing/getting rct commitments --- src/blockchain_db/blockchain_db.h | 33 +++++++++ src/blockchain_db/lmdb/db_lmdb.cpp | 108 +++++++++++++++++++++++++++++ src/blockchain_db/lmdb/db_lmdb.h | 12 ++++ tests/unit_tests/hardfork.cpp | 4 ++ 4 files changed, 157 insertions(+) diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 4c2157a3..5b759db4 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -1199,6 +1199,39 @@ public: */ virtual bool has_key_image(const crypto::key_image& img) const = 0; + /** + * @brief returns the number of ringct outputs in the database + * + * @return the number of ringct outputs in the database + */ + virtual uint64_t get_num_rct_outputs() const = 0; + + /** + * @brief returns the commitment for a given ringct output + * + * Throws OUTPUT_DNE if the index is out of range + * Throws DB_ERROR on other error + * + * @return the commitment for the given index + */ + virtual rct::key get_rct_commitment(uint64_t idx) const = 0; + + /** + * @brief Adds a new ringct output with the given commitment + * + * Throws DB_ERROR if the addition fails + * + * @return the index of the newly added record + */ + virtual uint64_t add_rct_commitment(const rct::key &commitment) = 0; + + /** + * @brief Remove a ringct output with the given index + * + * Throws DB_ERROR if the removal fails + */ + virtual void remove_rct_commitment(uint64_t idx) = 0; + /** * @brief runs a function over all key images stored * diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 0464ece5..71ce846b 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -155,6 +155,8 @@ int compare_string(const MDB_val *a, const MDB_val *b) * * spent_keys input hash - * + * rct_commitments input ID {commitment key} + * * 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 @@ -175,6 +177,8 @@ 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_RCT_COMMITMENTS = "rct_commitments"; + const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights"; const char* const LMDB_HF_VERSIONS = "hf_versions"; @@ -1084,6 +1088,8 @@ 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_RCT_COMMITMENTS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_rct_commitments, "Failed to open db handle for m_rct_commitments"); + // 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. @@ -1250,6 +1256,8 @@ void BlockchainLMDB::reset() throw0(DB_ERROR(lmdb_error("Failed to drop m_output_amounts: ", result).c_str())); if (auto result = mdb_drop(txn, m_spent_keys, 0)) throw0(DB_ERROR(lmdb_error("Failed to drop m_spent_keys: ", result).c_str())); + if (auto result = mdb_drop(txn, m_rct_commitments, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_rct_commitments: ", result).c_str())); (void)mdb_drop(txn, m_hf_starting_heights, 0); // this one is dropped in new code if (auto result = mdb_drop(txn, m_hf_versions, 0)) throw0(DB_ERROR(lmdb_error("Failed to drop m_hf_versions: ", result).c_str())); @@ -2722,6 +2730,106 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const return ret; } +uint64_t BlockchainLMDB::get_num_rct_outputs() const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + RCURSOR(rct_commitments); + + mdb_size_t num_outputs = 0; + MDB_stat ms; + auto result = mdb_stat(m_txn, m_rct_commitments, &ms); + if (result == MDB_SUCCESS) + { + num_outputs = ms.ms_entries; + } + else if (result == MDB_NOTFOUND) + { + num_outputs = 0; + } + else + { + throw0(DB_ERROR("DB error attempting to get number of ringct outputs")); + } + + TXN_POSTFIX_RDONLY(); + + return num_outputs; +} + +rct::key BlockchainLMDB::get_rct_commitment(uint64_t idx) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + RCURSOR(rct_commitments); + + MDB_val_set(val_key, idx); + MDB_val val_ret; + auto result = mdb_cursor_get(m_cur_rct_commitments, &val_key, &val_ret, MDB_SET); + if (result == MDB_NOTFOUND) + throw0(OUTPUT_DNE(lmdb_error("Error attempting to retrieve rct commitment for " + boost::lexical_cast(idx) + " from the db: ", result).c_str())); + else if (result) + throw0(DB_ERROR(lmdb_error("Error attempting to retrieve rct commitment for " + boost::lexical_cast(idx) + " from the db: ", result).c_str())); + + rct::key commitment = *(const rct::key*)val_ret.mv_data; + TXN_POSTFIX_RDONLY(); + return commitment; +} + +void BlockchainLMDB::remove_rct_commitment(uint64_t idx) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + mdb_txn_cursors *m_cursors = &m_wcursors; + CURSOR(rct_commitments); + + MDB_val_set(val_key, idx); + MDB_val val_ret; + auto result = mdb_cursor_get(m_cur_rct_commitments, &val_key, &val_ret, MDB_SET); + if (result == MDB_NOTFOUND) + throw0(OUTPUT_DNE(lmdb_error("Error attempting to retrieve rct commitment for " + boost::lexical_cast(idx) + " from the db: ", result).c_str())); + else if (result) + throw0(DB_ERROR(lmdb_error("Error attempting to retrieve rct commitment for " + boost::lexical_cast(idx) + " from the db: ", result).c_str())); + result = mdb_cursor_del(m_cur_rct_commitments, 0); + if (result) + throw0(DB_ERROR(lmdb_error("Error attempting to remove rct commitment for " + boost::lexical_cast(idx) + " from the db: ", result).c_str())); +} + +uint64_t BlockchainLMDB::add_rct_commitment(const rct::key &commitment) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(rct_commitments); + + uint64_t num_outputs = 0; + MDB_stat ms; + auto result = mdb_stat(*m_write_txn, m_rct_commitments, &ms); + if (result == MDB_SUCCESS) + num_outputs = ms.ms_entries; + else if (result == MDB_NOTFOUND) + num_outputs = 0; + else + throw0(DB_ERROR("DB error attempting to get number of ringct outputs")); + + MDB_val_set(val_key, num_outputs); + MDB_val val_value; + val_value.mv_size = sizeof(rct::key); + val_value.mv_data = (void*)&commitment; + result = mdb_cursor_put(m_cur_rct_commitments, (MDB_val *)&val_key, &val_value, 0); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to add rct output to db transaction: ", result).c_str())); + + return num_outputs; +} + bool BlockchainLMDB::is_read_only() const { unsigned int flags; diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index d60701bb..9e92b066 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 "ringct/rctTypes.h" #include #include @@ -54,6 +55,8 @@ typedef struct mdb_txn_cursors MDB_cursor *m_txc_spent_keys; + MDB_cursor *m_txc_rct_commitments; + MDB_cursor *m_txc_hf_versions; } mdb_txn_cursors; @@ -66,6 +69,7 @@ typedef struct mdb_txn_cursors #define m_cur_tx_indices m_cursors->m_txc_tx_indices #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_rct_commitments m_cursors->m_txc_rct_commitments #define m_cur_hf_versions m_cursors->m_txc_hf_versions typedef struct mdb_rflags @@ -80,6 +84,7 @@ typedef struct mdb_rflags bool m_rf_tx_indices; bool m_rf_tx_outputs; bool m_rf_spent_keys; + bool m_rf_rct_commitments; bool m_rf_hf_versions; } mdb_rflags; @@ -231,6 +236,11 @@ public: virtual bool has_key_image(const crypto::key_image& img) const; + virtual uint64_t get_num_rct_outputs() const; + virtual rct::key get_rct_commitment(uint64_t idx) const; + virtual uint64_t add_rct_commitment(const rct::key &commitment); + virtual void remove_rct_commitment(uint64_t idx); + virtual bool for_all_key_images(std::function) const; virtual bool for_all_blocks(std::function) const; virtual bool for_all_transactions(std::function) const; @@ -359,6 +369,8 @@ private: MDB_dbi m_spent_keys; + MDB_dbi m_rct_commitments; + MDB_dbi m_hf_starting_heights; MDB_dbi m_hf_versions; diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index eab6b9cf..1eb73e15 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -100,6 +100,10 @@ public: virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector& amount_output_indices) {} virtual void add_spent_key(const crypto::key_image& k_image) {} virtual void remove_spent_key(const crypto::key_image& k_image) {} + virtual uint64_t get_num_rct_outputs() const { return 0; } + virtual rct::key get_rct_commitment(uint64_t idx) const { return rct::key(); } + virtual uint64_t add_rct_commitment(const rct::key &commitment) { return 0; } + virtual void remove_rct_commitment(uint64_t idx) {} virtual bool for_all_key_images(std::function) const { return true; } virtual bool for_all_blocks(std::function) const { return true; }