diff options
Diffstat (limited to 'src/blockchain_db/lmdb/db_lmdb.cpp')
-rw-r--r-- | src/blockchain_db/lmdb/db_lmdb.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 784fabf4a..78db37b5a 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -194,6 +194,8 @@ namespace * txpool_meta txn hash txn metadata * txpool_blob txn hash txn blob * + * alt_blocks block hash {block data, block 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 @@ -221,6 +223,8 @@ 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_ALT_BLOCKS = "alt_blocks"; + const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights"; const char* const LMDB_HF_VERSIONS = "hf_versions"; @@ -1400,6 +1404,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) 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"); + lmdb_db_open(txn, LMDB_ALT_BLOCKS, MDB_CREATE, m_alt_blocks, "Failed to open db handle for m_alt_blocks"); + // 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. @@ -1423,6 +1429,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) mdb_set_compare(txn, m_txpool_meta, compare_hash32); mdb_set_compare(txn, m_txpool_blob, compare_hash32); + mdb_set_compare(txn, m_alt_blocks, compare_hash32); mdb_set_compare(txn, m_properties, compare_string); if (!(mdb_flags & MDB_RDONLY)) @@ -2290,6 +2297,50 @@ bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, return ret; } +bool BlockchainLMDB::for_all_alt_blocks(std::function<bool(const crypto::hash&, const alt_block_data_t&, const cryptonote::blobdata*)> f, bool include_blob) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + RCURSOR(alt_blocks); + + MDB_val k; + MDB_val v; + bool ret = true; + + MDB_cursor_op op = MDB_FIRST; + while (1) + { + int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, op); + op = MDB_NEXT; + if (result == MDB_NOTFOUND) + break; + if (result) + throw0(DB_ERROR(lmdb_error("Failed to enumerate alt blocks: ", result).c_str())); + const crypto::hash &blkid = *(const crypto::hash*)k.mv_data; + if (v.mv_size < sizeof(alt_block_data_t)) + throw0(DB_ERROR("alt_blocks record is too small")); + const alt_block_data_t *data = (const alt_block_data_t*)v.mv_data; + const cryptonote::blobdata *passed_bd = NULL; + cryptonote::blobdata bd; + if (include_blob) + { + bd.assign(reinterpret_cast<const char*>(v.mv_data) + sizeof(alt_block_data_t), v.mv_size - sizeof(alt_block_data_t)); + passed_bd = &bd; + } + + if (!f(blkid, *data, 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__); @@ -4111,6 +4162,110 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const return ret; } +void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(alt_blocks) + + MDB_val k = {sizeof(blkid), (void *)&blkid}; + const size_t val_size = sizeof(alt_block_data_t) + blob.size(); + std::unique_ptr<char[]> val(new char[val_size]); + memcpy(val.get(), &data, sizeof(alt_block_data_t)); + memcpy(val.get() + sizeof(alt_block_data_t), blob.data(), blob.size()); + MDB_val v = {val_size, (void *)val.get()}; + if (auto result = mdb_cursor_put(m_cur_alt_blocks, &k, &v, MDB_NODUPDATA)) { + if (result == MDB_KEYEXIST) + throw1(DB_ERROR("Attempting to add alternate block that's already in the db")); + else + throw1(DB_ERROR(lmdb_error("Error adding alternate block to db transaction: ", result).c_str())); + } +} + +bool BlockchainLMDB::get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) +{ + LOG_PRINT_L3("BlockchainLMDB:: " << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + RCURSOR(alt_blocks); + + MDB_val_set(k, blkid); + MDB_val v; + int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, MDB_SET); + if (result == MDB_NOTFOUND) + return false; + + if (result) + throw0(DB_ERROR(lmdb_error("Error attempting to retrieve alternate block " + epee::string_tools::pod_to_hex(blkid) + " from the db: ", result).c_str())); + if (v.mv_size < sizeof(alt_block_data_t)) + throw0(DB_ERROR("Record size is less than expected")); + + const alt_block_data_t *ptr = (const alt_block_data_t*)v.mv_data; + if (data) + *data = *ptr; + if (blob) + blob->assign((const char*)(ptr + 1), v.mv_size - sizeof(alt_block_data_t)); + + TXN_POSTFIX_RDONLY(); + return true; +} + +void BlockchainLMDB::remove_alt_block(const crypto::hash &blkid) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(alt_blocks) + + MDB_val k = {sizeof(blkid), (void *)&blkid}; + MDB_val v; + int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, MDB_SET); + if (result) + throw0(DB_ERROR(lmdb_error("Error locating alternate block " + epee::string_tools::pod_to_hex(blkid) + " in the db: ", result).c_str())); + result = mdb_cursor_del(m_cur_alt_blocks, 0); + if (result) + throw0(DB_ERROR(lmdb_error("Error deleting alternate block " + epee::string_tools::pod_to_hex(blkid) + " from the db: ", result).c_str())); +} + +uint64_t BlockchainLMDB::get_alt_block_count() +{ + LOG_PRINT_L3("BlockchainLMDB:: " << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + RCURSOR(alt_blocks); + + MDB_stat db_stats; + int result = mdb_stat(m_txn, m_alt_blocks, &db_stats); + uint64_t count = 0; + if (result != MDB_NOTFOUND) + { + if (result) + throw0(DB_ERROR(lmdb_error("Failed to query m_alt_blocks: ", result).c_str())); + count = db_stats.ms_entries; + } + TXN_POSTFIX_RDONLY(); + return count; +} + +void BlockchainLMDB::drop_alt_blocks() +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX(0); + + auto result = mdb_drop(*txn_ptr, m_alt_blocks, 0); + if (result) + throw1(DB_ERROR(lmdb_error("Error dropping alternative blocks: ", result).c_str())); + + TXN_POSTFIX_SUCCESS(); +} + bool BlockchainLMDB::is_read_only() const { unsigned int flags; |