aboutsummaryrefslogtreecommitdiff
path: root/src/blockchain_db
diff options
context:
space:
mode:
authorluigi1111 <luigi1111w@gmail.com>2019-07-24 14:04:16 -0500
committerluigi1111 <luigi1111w@gmail.com>2019-07-24 14:04:16 -0500
commit4b76656f5caf7c37825c6db4b916f258fc8a0faf (patch)
tree5c4c894f5aa41af0f71adf10f2dafe4e7683da88 /src/blockchain_db
parentMerge pull request #5514 (diff)
parentblockchain: keep alternative blocks in LMDB (diff)
downloadmonero-4b76656f5caf7c37825c6db4b916f258fc8a0faf.tar.xz
Merge pull request #5524
06b8f29 blockchain: keep alternative blocks in LMDB (moneromooo-monero)
Diffstat (limited to 'src/blockchain_db')
-rw-r--r--src/blockchain_db/blockchain_db.h65
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp155
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h13
-rw-r--r--src/blockchain_db/testdb.h7
4 files changed, 239 insertions, 1 deletions
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index b6b8c6c3e..bb4de3ce6 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -129,6 +129,15 @@ struct tx_data_t
};
#pragma pack(pop)
+struct alt_block_data_t
+{
+ uint64_t height;
+ uint64_t cumulative_weight;
+ uint64_t cumulative_difficulty_low;
+ uint64_t cumulative_difficulty_high;
+ uint64_t already_generated_coins;
+};
+
/**
* @brief a struct containing txpool per transaction metadata
*/
@@ -1543,8 +1552,45 @@ public:
*
* @param: sz the block size
*/
-
virtual void add_max_block_size(uint64_t sz) = 0;
+
+ /**
+ * @brief add a new alternative block
+ *
+ * @param: blkid the block hash
+ * @param: data: the metadata for the block
+ * @param: blob: the block's blob
+ */
+ virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) = 0;
+
+ /**
+ * @brief get an alternative block by hash
+ *
+ * @param: blkid the block hash
+ * @param: data: the metadata for the block
+ * @param: blob: the block's blob
+ *
+ * @return true if the block was found in the alternative blocks list, false otherwise
+ */
+ virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) = 0;
+
+ /**
+ * @brief remove an alternative block
+ *
+ * @param: blkid the block hash
+ */
+ virtual void remove_alt_block(const crypto::hash &blkid) = 0;
+
+ /**
+ * @brief get the number of alternative blocks stored
+ */
+ virtual uint64_t get_alt_block_count() = 0;
+
+ /**
+ * @brief drop all alternative blocks
+ */
+ virtual void drop_alt_blocks() = 0;
+
/**
* @brief runs a function over all txpool transactions
*
@@ -1634,6 +1680,23 @@ public:
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const = 0;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const = 0;
+ /**
+ * @brief runs a function over all alternative blocks stored
+ *
+ * The subclass should run the passed function for each alt block it has
+ * stored, passing (blkid, data, blob) as its parameters.
+ *
+ * If any call to the function returns false, the subclass should return
+ * false. Otherwise, the subclass returns true.
+ *
+ * The subclass should throw DB_ERROR if any of the expected values are
+ * not found. Current implementations simply return false.
+ *
+ * @param std::function f the function to run
+ *
+ * @return false if the function returns false for any output, otherwise true
+ */
+ virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const = 0;
//
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;
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 4b46f081e..61a551476 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -67,6 +67,8 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_txpool_meta;
MDB_cursor *m_txc_txpool_blob;
+ MDB_cursor *m_txc_alt_blocks;
+
MDB_cursor *m_txc_hf_versions;
MDB_cursor *m_txc_properties;
@@ -87,6 +89,7 @@ typedef struct mdb_txn_cursors
#define m_cur_spent_keys m_cursors->m_txc_spent_keys
#define m_cur_txpool_meta m_cursors->m_txc_txpool_meta
#define m_cur_txpool_blob m_cursors->m_txc_txpool_blob
+#define m_cur_alt_blocks m_cursors->m_txc_alt_blocks
#define m_cur_hf_versions m_cursors->m_txc_hf_versions
#define m_cur_properties m_cursors->m_txc_properties
@@ -108,6 +111,7 @@ typedef struct mdb_rflags
bool m_rf_spent_keys;
bool m_rf_txpool_meta;
bool m_rf_txpool_blob;
+ bool m_rf_alt_blocks;
bool m_rf_hf_versions;
bool m_rf_properties;
} mdb_rflags;
@@ -288,6 +292,12 @@ public:
virtual bool update_pruning();
virtual bool check_pruning();
+ virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob);
+ virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob);
+ virtual void remove_alt_block(const crypto::hash &blkid);
+ virtual uint64_t get_alt_block_count();
+ virtual void drop_alt_blocks();
+
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const;
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
@@ -295,6 +305,7 @@ public:
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const;
+ virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const;
virtual uint64_t add_block( const std::pair<block, blobdata>& blk
, size_t block_weight
@@ -452,6 +463,8 @@ private:
MDB_dbi m_txpool_meta;
MDB_dbi m_txpool_blob;
+ MDB_dbi m_alt_blocks;
+
MDB_dbi m_hf_starting_heights;
MDB_dbi m_hf_versions;
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 34e635899..ac19fae25 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -156,6 +156,13 @@ public:
virtual uint64_t get_max_block_size() override { return 100000000; }
virtual void add_max_block_size(uint64_t sz) override { }
+
+ virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) override {}
+ virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) override { return false; }
+ virtual void remove_alt_block(const crypto::hash &blkid) override {}
+ virtual uint64_t get_alt_block_count() override { return 0; }
+ virtual void drop_alt_blocks() override {}
+ virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const override { return true; }
};
}