Cleanup and clarify

Try to rationalize the variable names, document usage.
This commit is contained in:
Howard Chu 2016-04-04 02:10:58 +01:00
parent b2f1c58805
commit 591e421875
4 changed files with 129 additions and 146 deletions

View File

@ -82,21 +82,17 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
} }
} }
uint64_t tx_index = add_transaction_data(blk_hash, tx, tx_hash); uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash);
std::vector<uint64_t> amount_output_indices; std::vector<uint64_t> amount_output_indices;
std::vector<uint64_t> global_output_indices;
// iterate tx.vout using indices instead of C++11 foreach syntax because // iterate tx.vout using indices instead of C++11 foreach syntax because
// we need the index // we need the index
for (uint64_t i = 0; i < tx.vout.size(); ++i) for (uint64_t i = 0; i < tx.vout.size(); ++i)
{ {
uint64_t amount_output_index, global_output_index; amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time));
add_output(tx_hash, tx.vout[i], i, tx.unlock_time, amount_output_index, global_output_index);
amount_output_indices.push_back(amount_output_index);
global_output_indices.push_back(global_output_index);
} }
add_amount_and_global_output_indices(tx_index, amount_output_indices, global_output_indices); add_tx_amount_output_indices(tx_id, amount_output_indices);
} }
uint64_t BlockchainDB::add_block( const block& blk uint64_t BlockchainDB::add_block( const block& blk

View File

@ -63,6 +63,26 @@
* of this interface call to private members of the interface to be added * of this interface call to private members of the interface to be added
* later that will then populate as needed. * later that will then populate as needed.
* *
* Indices and Identifiers:
* The word "index" is used ambiguously throughout this code. It is
* particularly confusing when talking about the output or transaction
* tables since their indexing can refer to themselves or each other.
* I have attempted to clarify these usages here:
*
* Blocks, transactions, and outputs are all identified by a hash.
* For storage efficiency, a 64-bit integer ID is used instead of the hash
* inside the DB. Tables exist to map between hash and ID. A block ID is
* also referred to as its "height". Transactions and outputs generally are
* not referred to by ID outside of this module, but the tx ID is returned
* by tx_exists() and used by get_tx_amount_output_indices(). Like their
* corresponding hashes, IDs are globally unique.
*
* The remaining uses of the word "index" refer to local offsets, and are
* not globally unique. An "amount output index" N refers to the Nth output
* of a specific amount. An "output local index" N refers to the Nth output
* of a specific tx.
*
*
* General: * General:
* open() * open()
* is_open() * is_open()
@ -99,7 +119,7 @@
* void pop_block(block&, tx_list&) * void pop_block(block&, tx_list&)
* *
* Transactions: * Transactions:
* bool tx_exists(hash) * bool tx_exists(hash, tx_id)
* uint64_t get_tx_unlock_time(hash) * uint64_t get_tx_unlock_time(hash)
* tx get_tx(hash) * tx get_tx(hash)
* uint64_t get_tx_count() * uint64_t get_tx_count()
@ -111,7 +131,7 @@
* pub_key get_output_key(amount, index) * pub_key get_output_key(amount, index)
* hash,index get_output_tx_and_index_from_global(index) * hash,index get_output_tx_and_index_from_global(index)
* hash,index get_output_tx_and_index(amount, index) * hash,index get_output_tx_and_index(amount, index)
* vec<uint64> get_tx_output_indices(tx_hash) * vec<uint64> get_tx_amount_output_indices(tx_id)
* *
* *
* Spent Output Key Images: * Spent Output Key Images:
@ -151,9 +171,9 @@ struct output_data_t
#pragma pack(push, 1) #pragma pack(push, 1)
struct tx_data_t struct tx_data_t
{ {
uint64_t tx_index; uint64_t tx_id;
uint64_t unlock_time; uint64_t unlock_time;
uint64_t height; uint64_t block_id;
}; };
#pragma pack(pop) #pragma pack(pop)
@ -299,25 +319,22 @@ private:
// tells the subclass to remove data about the top block // tells the subclass to remove data about the top block
virtual void remove_block() = 0; virtual void remove_block() = 0;
// tells the subclass to store the transaction and its metadata // tells the subclass to store the transaction and its metadata, returns tx ID
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0; virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0;
// tells the subclass to remove data about a transaction // tells the subclass to remove data about a transaction
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0; virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0;
// tells the subclass to store an output // tells the subclass to store an output, returns amount output index
virtual void add_output(const crypto::hash& tx_hash, virtual uint64_t add_output(const crypto::hash& tx_hash,
const tx_out& tx_output, const tx_out& tx_output,
const uint64_t& local_index, const uint64_t& local_index,
const uint64_t unlock_time, const uint64_t unlock_time
uint64_t& amount_output_index,
uint64_t& global_output_index
) = 0; ) = 0;
// tells the subclass to store indices for a tx's outputs, both amount output indices and global output indices // tells the subclass to store amount output indices for a tx's outputs
virtual void add_amount_and_global_output_indices(const uint64_t tx_index, virtual void add_tx_amount_output_indices(const uint64_t tx_id,
const std::vector<uint64_t>& amount_output_indices, const std::vector<uint64_t>& amount_output_indices
const std::vector<uint64_t>& global_output_indices
) = 0; ) = 0;
// tells the subclass to remove an output // tells the subclass to remove an output
@ -482,7 +499,7 @@ public:
// return true if a transaction with hash <h> exists // return true if a transaction with hash <h> exists
virtual bool tx_exists(const crypto::hash& h) const = 0; virtual bool tx_exists(const crypto::hash& h) const = 0;
virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const = 0; virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_id) const = 0;
// return unlock time of tx with hash <h> // return unlock time of tx with hash <h>
virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0; virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0;
@ -523,16 +540,9 @@ public:
virtual bool can_thread_bulk_indices() const = 0; virtual bool can_thread_bulk_indices() const = 0;
// return two vectors of indices: vector of amount output indices and global
// output indices, corresponding to each output in the transaction with hash
// <h>
virtual void get_amount_and_global_output_indices(const uint64_t tx_index,
std::vector<uint64_t>& amount_output_indices,
std::vector<uint64_t>& global_output_indices) const = 0;
// return a vector of indices corresponding to the amount output index for // return a vector of indices corresponding to the amount output index for
// each output in the transaction with hash <h> // each output in the transaction with ID <tx_id>
virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const = 0; virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_id) const = 0;
// returns true if key image <img> is present in spent key images storage // returns true if key image <img> is present in spent key images storage
virtual bool has_key_image(const crypto::key_image& img) const = 0; virtual bool has_key_image(const crypto::key_image& img) const = 0;

View File

@ -145,9 +145,34 @@ int compare_string(const MDB_val *a, const MDB_val *b)
return strcmp(va, vb); return strcmp(va, vb);
} }
/* DB schema:
*
* Table Key Data
* ----- --- ----
* blocks block ID block blob
* block_heights block hash block height
* block_info block ID {block metadata}
*
* txs txn ID txn blob
* tx_indices txn hash {txn ID, metadata}
* tx_outputs txn ID [txn amount output indices]
*
* output_txs output ID {txn hash, local index}
* output_amounts amount [{amount output index, metadata}...]
*
* spent_keys output hash -
*
* 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
* attached as a prefix on the Data to serve as the DUPSORT key.
* (DUPFIXED saves 8 bytes per record.)
*
* The output_amounts table doesn't use a dummy key, but uses DUPSORT.
*/
const char* const LMDB_BLOCKS = "blocks"; const char* const LMDB_BLOCKS = "blocks";
const char* const LMDB_BLOCK_INFO = "block_info";
const char* const LMDB_BLOCK_HEIGHTS = "block_heights"; const char* const LMDB_BLOCK_HEIGHTS = "block_heights";
const char* const LMDB_BLOCK_INFO = "block_info";
const char* const LMDB_TXS = "txs"; const char* const LMDB_TXS = "txs";
const char* const LMDB_TX_INDICES = "tx_indices"; const char* const LMDB_TX_INDICES = "tx_indices";
@ -215,8 +240,8 @@ typedef struct mdb_block_info
} mdb_block_info; } mdb_block_info;
typedef struct blk_height { typedef struct blk_height {
crypto::hash key; crypto::hash bh_hash;
uint64_t height; uint64_t bh_height;
} blk_height; } blk_height;
typedef struct txindex { typedef struct txindex {
@ -226,12 +251,12 @@ typedef struct txindex {
typedef struct outkey { typedef struct outkey {
uint64_t amount_index; uint64_t amount_index;
uint64_t tx_index; uint64_t output_id;
output_data_t data; output_data_t data;
} outkey; } outkey;
typedef struct outtx { typedef struct outtx {
uint64_t txnum; uint64_t output_id;
crypto::hash tx_hash; crypto::hash tx_hash;
uint64_t local_index; uint64_t local_index;
} outtx; } outtx;
@ -560,14 +585,13 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
CURSOR(block_heights) CURSOR(block_heights)
blk_height bh = {blk_hash, m_height}; blk_height bh = {blk_hash, m_height};
MDB_val val_h = {sizeof(bh), (void *)&bh}; MDB_val_set(val_h, bh);
if (mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH) == 0) if (mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH) == 0)
throw1(BLOCK_EXISTS("Attempting to add block that's already in the db")); throw1(BLOCK_EXISTS("Attempting to add block that's already in the db"));
if (m_height > 0) if (m_height > 0)
{ {
blk_height ph = {blk.prev_id, 0}; MDB_val_set(parent_key, blk.prev_id);
MDB_val parent_key = {sizeof(ph), (void *)&ph};
int result = mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &parent_key, MDB_GET_BOTH); int result = mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &parent_key, MDB_GET_BOTH);
if (result) if (result)
{ {
@ -576,13 +600,13 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
throw0(DB_ERROR(lmdb_error("Failed to get top block hash to check for new block's parent: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to get top block hash to check for new block's parent: ", result).c_str()));
} }
blk_height *prev = (blk_height *)parent_key.mv_data; blk_height *prev = (blk_height *)parent_key.mv_data;
if (prev->height != m_height - 1) if (prev->bh_height != m_height - 1)
throw0(BLOCK_PARENT_DNE("Top block is not new block's parent")); throw0(BLOCK_PARENT_DNE("Top block is not new block's parent"));
} }
int result = 0; int result = 0;
MDB_val_copy<uint64_t> key(m_height); MDB_val_set(key, m_height);
CURSOR(blocks) CURSOR(blocks)
CURSOR(block_info) CURSOR(block_info)
@ -600,7 +624,7 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const
bi.bi_diff = cumulative_difficulty; bi.bi_diff = cumulative_difficulty;
bi.bi_hash = blk_hash; bi.bi_hash = blk_hash;
MDB_val val = {sizeof(bi), (void *)&bi}; MDB_val_set(val, bi);
result = mdb_cursor_put(m_cur_block_info, (MDB_val *)&zerokval, &val, MDB_APPENDDUP); result = mdb_cursor_put(m_cur_block_info, (MDB_val *)&zerokval, &val, MDB_APPENDDUP);
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to add block info to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add block info to db transaction: ", result).c_str()));
@ -657,26 +681,27 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
check_open(); check_open();
mdb_txn_cursors *m_cursors = &m_wcursors; mdb_txn_cursors *m_cursors = &m_wcursors;
int result = 0; int result;
uint64_t tx_index = m_num_txs; uint64_t tx_id = m_num_txs;
CURSOR(txs) CURSOR(txs)
CURSOR(tx_indices) CURSOR(tx_indices)
txindex ti = {tx_hash}; MDB_val_set(val_tx_id, tx_id);
MDB_val_copy<uint64_t> val_tx_index(tx_index); MDB_val_set(val_h, tx_hash);
MDB_val val_h = {sizeof(ti), (void *)&ti};
result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH); result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH);
if (result == 0) { if (result == 0) {
txindex *tip = (txindex *)val_h.mv_data; txindex *tip = (txindex *)val_h.mv_data;
throw1(TX_EXISTS(std::string("Attempting to add transaction that's already in the db (tx index ").append(boost::lexical_cast<std::string>(tip->data.tx_index)).append(")").c_str())); throw1(TX_EXISTS(std::string("Attempting to add transaction that's already in the db (tx id ").append(boost::lexical_cast<std::string>(tip->data.tx_id)).append(")").c_str()));
} else if (result != MDB_NOTFOUND) { } else if (result != MDB_NOTFOUND) {
throw1(DB_ERROR(lmdb_error(std::string("Error checking if tx index exists for tx hash ") + epee::string_tools::pod_to_hex(tx_hash) + ": ", result).c_str())); throw1(DB_ERROR(lmdb_error(std::string("Error checking if tx index exists for tx hash ") + epee::string_tools::pod_to_hex(tx_hash) + ": ", result).c_str()));
} }
ti.data.tx_index = tx_index; txindex ti;
ti.key = tx_hash;
ti.data.tx_id = tx_id;
ti.data.unlock_time = tx.unlock_time; ti.data.unlock_time = tx.unlock_time;
ti.data.height = m_height; ti.data.block_id = m_height; // we don't need blk_hash since we know m_height
val_h.mv_size = sizeof(ti); val_h.mv_size = sizeof(ti);
val_h.mv_data = (void *)&ti; val_h.mv_data = (void *)&ti;
@ -686,12 +711,12 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str()));
MDB_val_copy<blobdata> blob(tx_to_blob(tx)); MDB_val_copy<blobdata> blob(tx_to_blob(tx));
result = mdb_cursor_put(m_cur_txs, &val_tx_index, &blob, MDB_APPEND); result = mdb_cursor_put(m_cur_txs, &val_tx_id, &blob, MDB_APPEND);
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx blob to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add tx blob to db transaction: ", result).c_str()));
m_num_txs++; m_num_txs++;
return tx_index; return tx_id;
} }
// TODO: compare pros and cons of looking up the tx hash's tx index once and // TODO: compare pros and cons of looking up the tx hash's tx index once and
@ -708,24 +733,22 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
CURSOR(txs) CURSOR(txs)
CURSOR(tx_outputs) CURSOR(tx_outputs)
txindex ti = {tx_hash}; MDB_val_set(val_h, tx_hash);
MDB_val val_h = {sizeof(ti), (void *)&ti};
if (mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH)) if (mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH))
throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); throw1(TX_DNE("Attempting to remove transaction that isn't in the db"));
txindex *tip = (txindex *)val_h.mv_data; txindex *tip = (txindex *)val_h.mv_data;
uint64_t tx_index = tip->data.tx_index; MDB_val_set(val_tx_id, tip->data.tx_id);
MDB_val_copy<uint64_t> val_tx_index(tx_index);
if ((result = mdb_cursor_get(m_cur_txs, &val_tx_index, NULL, MDB_SET))) if ((result = mdb_cursor_get(m_cur_txs, &val_tx_id, NULL, MDB_SET)))
throw1(DB_ERROR(lmdb_error("Failed to locate tx for removal: ", result).c_str())); throw1(DB_ERROR(lmdb_error("Failed to locate tx for removal: ", result).c_str()));
result = mdb_cursor_del(m_cur_txs, 0); result = mdb_cursor_del(m_cur_txs, 0);
if (result) if (result)
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx to db transaction: ", result).c_str())); throw1(DB_ERROR(lmdb_error("Failed to add removal of tx to db transaction: ", result).c_str()));
remove_tx_outputs(tx_index, tx); remove_tx_outputs(tip->data.tx_id, tx);
result = mdb_cursor_get(m_cur_tx_outputs, &val_tx_index, NULL, MDB_SET); result = mdb_cursor_get(m_cur_tx_outputs, &val_tx_id, NULL, MDB_SET);
if (result == MDB_NOTFOUND) if (result == MDB_NOTFOUND)
LOG_PRINT_L1("tx has no outputs to remove: " << tx_hash); LOG_PRINT_L1("tx has no outputs to remove: " << tx_hash);
else if (result) else if (result)
@ -737,24 +760,17 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str())); throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str()));
} }
// Though other things could change, so long as earlier functions (like // Don't delete the tx_indices entry until the end, after we're done with val_tx_id
// remove_tx_outputs) need to do the lookup of tx hash -> tx index, don't
// delete the tx_indices entry until the end.
if (mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH))
throw1(TX_DNE("Attempting to remove transaction that isn't in the db"));
if (mdb_cursor_del(m_cur_tx_indices, 0)) if (mdb_cursor_del(m_cur_tx_indices, 0))
throw1(DB_ERROR("Failed to add removal of tx index to db transaction")); throw1(DB_ERROR("Failed to add removal of tx index to db transaction"));
m_num_txs--; m_num_txs--;
} }
// global_output_index is no longer used for locating outputs uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash,
void BlockchainLMDB::add_output(const crypto::hash& tx_hash,
const tx_out& tx_output, const tx_out& tx_output,
const uint64_t& local_index, const uint64_t& local_index,
const uint64_t unlock_time, const uint64_t unlock_time)
uint64_t& amount_output_index,
uint64_t& global_output_index)
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -791,7 +807,7 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash,
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
else else
ok.amount_index = 0; ok.amount_index = 0;
ok.tx_index = m_num_outputs; ok.output_id = m_num_outputs;
ok.data.pubkey = boost::get < txout_to_key > (tx_output.target).key; ok.data.pubkey = boost::get < txout_to_key > (tx_output.target).key;
ok.data.unlock_time = unlock_time; ok.data.unlock_time = unlock_time;
ok.data.height = m_height; ok.data.height = m_height;
@ -801,16 +817,12 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash,
if ((result = mdb_cursor_put(m_cur_output_amounts, &val_amount, &data, MDB_APPENDDUP))) if ((result = mdb_cursor_put(m_cur_output_amounts, &val_amount, &data, MDB_APPENDDUP)))
throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str()));
amount_output_index = ok.amount_index;
global_output_index = m_num_outputs;
m_num_outputs++; m_num_outputs++;
return ok.amount_index;
} }
// global_output_indices is now ignored void BlockchainLMDB::add_tx_amount_output_indices(const uint64_t tx_id,
void BlockchainLMDB::add_amount_and_global_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices)
const std::vector<uint64_t>& amount_output_indices,
const std::vector<uint64_t>& global_output_indices)
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -821,24 +833,22 @@ void BlockchainLMDB::add_amount_and_global_output_indices(const uint64_t tx_inde
int num_outputs = amount_output_indices.size(); int num_outputs = amount_output_indices.size();
MDB_val_copy<uint64_t> k_tx_index(tx_index); MDB_val_set(k_tx_id, tx_id);
MDB_val v; MDB_val v;
v.mv_data = (void *)amount_output_indices.data(); v.mv_data = (void *)amount_output_indices.data();
v.mv_size = sizeof(uint64_t) * num_outputs; v.mv_size = sizeof(uint64_t) * num_outputs;
// LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size); // LOG_PRINT_L1("tx_outputs[tx_hash] size: " << v.mv_size);
result = mdb_cursor_put(m_cur_tx_outputs, &k_tx_index, &v, MDB_APPEND); result = mdb_cursor_put(m_cur_tx_outputs, &k_tx_id, &v, MDB_APPEND);
if (result) if (result)
throw0(DB_ERROR(std::string("Failed to add <tx hash, amount output index array> to db transaction: ").append(mdb_strerror(result)).c_str())); throw0(DB_ERROR(std::string("Failed to add <tx hash, amount output index array> to db transaction: ").append(mdb_strerror(result)).c_str()));
} }
void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_index, const transaction& tx) void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_id, const transaction& tx)
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
// only need amount_output_indices std::vector<uint64_t> amount_output_indices = get_tx_amount_output_indices(tx_id);
std::vector<uint64_t> amount_output_indices, global_output_indices;
get_amount_and_global_output_indices(tx_index, amount_output_indices, global_output_indices);
if (amount_output_indices.empty()) if (amount_output_indices.empty())
{ {
@ -880,7 +890,7 @@ void BlockchainLMDB::remove_output(const uint64_t& out_index, const uint64_t amo
throw0(DB_ERROR(lmdb_error("DB error attempting to get an output", result).c_str())); throw0(DB_ERROR(lmdb_error("DB error attempting to get an output", result).c_str()));
outkey *ok = (outkey *)v.mv_data; outkey *ok = (outkey *)v.mv_data;
MDB_val_set(otxk, ok->tx_index); MDB_val_set(otxk, ok->output_id);
result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &otxk, MDB_GET_BOTH); result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &otxk, MDB_GET_BOTH);
if (result == MDB_NOTFOUND) if (result == MDB_NOTFOUND)
{ {
@ -1333,8 +1343,7 @@ bool BlockchainLMDB::block_exists(const crypto::hash& h) const
RCURSOR(block_heights); RCURSOR(block_heights);
bool ret = false; bool ret = false;
blk_height bh = {h, 0}; MDB_val_set(key, h);
MDB_val key = {sizeof(bh), (void *)&bh};
auto get_result = mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &key, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &key, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
{ {
@ -1365,8 +1374,7 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(block_heights); RCURSOR(block_heights);
blk_height bh = {h, 0}; MDB_val_set(key, h);
MDB_val key = {sizeof(bh), (void *)&bh};
auto get_result = mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &key, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_block_heights, (MDB_val *)&zerokval, &key, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(BLOCK_DNE("Attempted to retrieve non-existent block height")); throw1(BLOCK_DNE("Attempted to retrieve non-existent block height"));
@ -1374,7 +1382,7 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
throw0(DB_ERROR("Error attempting to retrieve a block height from the db")); throw0(DB_ERROR("Error attempting to retrieve a block height from the db"));
blk_height *bhp = (blk_height *)key.mv_data; blk_height *bhp = (blk_height *)key.mv_data;
uint64_t ret = bhp->height; uint64_t ret = bhp->bh_height;
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
return ret; return ret;
} }
@ -1635,7 +1643,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
RCURSOR(tx_indices); RCURSOR(tx_indices);
RCURSOR(txs); RCURSOR(txs);
MDB_val_copy<crypto::hash> key(h); MDB_val_set(key, h);
bool tx_found = false; bool tx_found = false;
TIME_MEASURE_START(time1); TIME_MEASURE_START(time1);
@ -1666,7 +1674,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
return true; return true;
} }
bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_id) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -1674,8 +1682,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(tx_indices); RCURSOR(tx_indices);
txindex ti = {h}; MDB_val_set(v, h);
MDB_val v = {sizeof(ti), (void *)&ti};
TIME_MEASURE_START(time1); TIME_MEASURE_START(time1);
auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
@ -1683,7 +1690,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h, uint64_t& tx_index) const
time_tx_exists += time1; time_tx_exists += time1;
if (!get_result) { if (!get_result) {
txindex *tip = (txindex *)v.mv_data; txindex *tip = (txindex *)v.mv_data;
tx_index = tip->data.tx_index; tx_id = tip->data.tx_id;
} }
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
@ -1709,8 +1716,7 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(tx_indices); RCURSOR(tx_indices);
txindex ti = {h}; MDB_val_set(v, h);
MDB_val v = {sizeof(ti), (void *)&ti};
auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(lmdb_error(std::string("tx data with hash ") + epee::string_tools::pod_to_hex(h) + " not found in db: ", get_result).c_str())); throw1(TX_DNE(lmdb_error(std::string("tx data with hash ") + epee::string_tools::pod_to_hex(h) + " not found in db: ", get_result).c_str()));
@ -1732,16 +1738,14 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
RCURSOR(tx_indices); RCURSOR(tx_indices);
RCURSOR(txs); RCURSOR(txs);
txindex ti = {h}; MDB_val_set(v, h);
MDB_val v = {sizeof(ti), (void *)&ti};
MDB_val result; MDB_val result;
auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == 0) if (get_result == 0)
{ {
txindex *tip = (txindex *)v.mv_data; txindex *tip = (txindex *)v.mv_data;
uint64_t tx_index = tip->data.tx_index; MDB_val_set(val_tx_id, tip->data.tx_id);
MDB_val_copy<uint64_t> val_tx_index(tx_index); get_result = mdb_cursor_get(m_cur_txs, &val_tx_id, &result, MDB_SET);
get_result = mdb_cursor_get(m_cur_txs, &val_tx_index, &result, MDB_SET);
} }
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
throw1(TX_DNE(std::string("tx with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str())); throw1(TX_DNE(std::string("tx with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
@ -1798,8 +1802,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(tx_indices); RCURSOR(tx_indices);
txindex ti = {h}; MDB_val_set(v, h);
MDB_val v = {sizeof(ti), (void *)&ti};
auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
{ {
@ -1809,7 +1812,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx height from hash", get_result).c_str())); throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx height from hash", get_result).c_str()));
txindex *tip = (txindex *)v.mv_data; txindex *tip = (txindex *)v.mv_data;
uint64_t ret = tip->data.height; uint64_t ret = tip->data.block_id;
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
return ret; return ret;
} }
@ -1867,7 +1870,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6
return ret; return ret;
} }
tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t& index) const tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t& output_id) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -1875,7 +1878,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(output_txs); RCURSOR(output_txs);
MDB_val_set(v, index); MDB_val_set(v, output_id);
auto get_result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
@ -1903,29 +1906,21 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, con
return indices[0]; return indices[0];
} }
// we don't have global_output_indices std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_t tx_id) const
void BlockchainLMDB::get_amount_and_global_output_indices(const uint64_t tx_index,
std::vector<uint64_t>& amount_output_indices,
std::vector<uint64_t>& global_output_indices) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
// If a new txn is created, it only needs to read.
//
// This must existence of m_write_txn too (not only m_batch_active), as
// that's what remove_tx_outputs() expected to use instead of creating a new
// txn, regardless of batch mode. Otherwise, remove_tx_outputs() would now
// create a new read-only txn here, which is incorrect.
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(tx_outputs); RCURSOR(tx_outputs);
int result = 0; int result = 0;
MDB_val_copy<uint64_t> k_tx_index(tx_index); MDB_val_set(k_tx_id, tx_id);
MDB_val v; MDB_val v;
std::vector<uint64_t> amount_output_indices;
result = mdb_cursor_get(m_cur_tx_outputs, &k_tx_index, &v, MDB_SET); result = mdb_cursor_get(m_cur_tx_outputs, &k_tx_id, &v, MDB_SET);
if (result == MDB_NOTFOUND) if (result == MDB_NOTFOUND)
LOG_PRINT_L0("WARNING: Unexpected: tx has no amount indices stored in " LOG_PRINT_L0("WARNING: Unexpected: tx has no amount indices stored in "
"tx_outputs, but it should have an empty entry even if it's a tx without " "tx_outputs, but it should have an empty entry even if it's a tx without "
@ -1944,21 +1939,10 @@ void BlockchainLMDB::get_amount_and_global_output_indices(const uint64_t tx_inde
indices = nullptr; indices = nullptr;
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
}
std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_t tx_index) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
std::vector<uint64_t> amount_output_indices, global_output_indices;
// only need amount_output_indices
get_amount_and_global_output_indices(tx_index, amount_output_indices, global_output_indices);
return amount_output_indices; return amount_output_indices;
} }
bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@ -2110,7 +2094,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
throw0(DB_ERROR("Failed to enumerate outputs")); throw0(DB_ERROR("Failed to enumerate outputs"));
uint64_t amount = *(const uint64_t*)k.mv_data; uint64_t amount = *(const uint64_t*)k.mv_data;
outkey *ok = (outkey *)v.mv_data; outkey *ok = (outkey *)v.mv_data;
tx_out_index toi = get_output_tx_and_index_from_global(ok->tx_index); tx_out_index toi = get_output_tx_and_index_from_global(ok->output_id);
if (!f(amount, toi.first, toi.second)) { if (!f(amount, toi.first, toi.second)) {
ret = false; ret = false;
break; break;
@ -2453,9 +2437,9 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_PREFIX_RDONLY(); TXN_PREFIX_RDONLY();
RCURSOR(output_txs); RCURSOR(output_txs);
for (const uint64_t &index : global_indices) for (const uint64_t &output_id : global_indices)
{ {
MDB_val_set(v, index); MDB_val_set(v, output_id);
auto get_result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); auto get_result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &v, MDB_GET_BOTH);
if (get_result == MDB_NOTFOUND) if (get_result == MDB_NOTFOUND)
@ -2527,7 +2511,7 @@ void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std::
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output from the db", get_result).c_str())); throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output from the db", get_result).c_str()));
outkey *okp = (outkey *)v.mv_data; outkey *okp = (outkey *)v.mv_data;
tx_indices.push_back(okp->tx_index); tx_indices.push_back(okp->output_id);
} }
TIME_MEASURE_START(db3); TIME_MEASURE_START(db3);

View File

@ -227,11 +227,7 @@ public:
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index); virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index);
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<tx_out_index> &indices); virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<tx_out_index> &indices);
virtual void get_amount_and_global_output_indices(const uint64_t tx_index, virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_id) const;
std::vector<uint64_t>& amount_output_indices,
std::vector<uint64_t>& global_output_indices) const;
virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const;
virtual bool has_key_image(const crypto::key_image& img) const; virtual bool has_key_image(const crypto::key_image& img) const;
@ -282,22 +278,19 @@ private:
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx); virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);
virtual void add_output(const crypto::hash& tx_hash, virtual uint64_t add_output(const crypto::hash& tx_hash,
const tx_out& tx_output, const tx_out& tx_output,
const uint64_t& local_index, const uint64_t& local_index,
const uint64_t unlock_time, const uint64_t unlock_time
uint64_t& amount_output_index,
uint64_t& global_output_index
); );
virtual void add_amount_and_global_output_indices(const uint64_t tx_index, virtual void add_tx_amount_output_indices(const uint64_t tx_id,
const std::vector<uint64_t>& amount_output_indices, const std::vector<uint64_t>& amount_output_indices
const std::vector<uint64_t>& global_output_indices
); );
virtual void remove_output(const tx_out& tx_output); virtual void remove_output(const tx_out& tx_output);
void remove_tx_outputs(const uint64_t tx_index, const transaction& tx); void remove_tx_outputs(const uint64_t tx_id, const transaction& tx);
void remove_output(const uint64_t& out_index, const uint64_t amount); void remove_output(const uint64_t& out_index, const uint64_t amount);