Fix transfers (without mixins)
Fix Blockchain::get_tx_outputs_gindexs() to return amount output indices. Implement BlockchainLMDB::get_tx_amount_output_indices() and call it from the function instead of BlockchainLMDB::get_tx_output_indices() Previously, Blockchain::get_tx_outputs_gindexs() was instead returning global output indices, which are internal to LMDB databases. Allows bitmonerod RPC /get_o_indexes.bin to return the amount output indices as expected. Allows simplewallet refresh to set correct amount output indices for incoming transfers. simplewallet can now construct and send valid transactions (currently only without mixins). This is a fix that doesn't require altering the structure of the current LMDB databases. TODO: This can be done more efficiently by adding another LMDB database (key-value table). It's not used during regular transaction validation by bitmonerod. I think it's currently used only or mainly by simplewallet for just its own incoming transactions. So the current behavior is not a primary bottleneck. Currently, it's using the "output_amounts" database, walking through a given amount's list of values, comparing each one to a given global output index. The iteration number of the match is the desired result: the amount output index. This is done for each global output index of the transaction. A tx's amount output indices can be stored in various other ways allowing for faster lookup. Since a tx is only written once, there are no special future write requirements for its list of indices.
This commit is contained in:
parent
429a740562
commit
d045dfa7ce
|
@ -1317,6 +1317,85 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_output_indices(const crypto::hash&
|
||||||
return index_vec;
|
return index_vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto::hash& h) const
|
||||||
|
{
|
||||||
|
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||||
|
check_open();
|
||||||
|
std::vector<uint64_t> index_vec;
|
||||||
|
std::vector<uint64_t> index_vec2;
|
||||||
|
|
||||||
|
// get the transaction's global output indices first
|
||||||
|
index_vec = get_tx_output_indices(h);
|
||||||
|
// these are next used to obtain the amount output indices
|
||||||
|
|
||||||
|
transaction tx = get_tx(h);
|
||||||
|
|
||||||
|
txn_safe txn;
|
||||||
|
if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||||
|
throw0(DB_ERROR("Failed to create a transaction for the db"));
|
||||||
|
|
||||||
|
uint64_t i = 0;
|
||||||
|
uint64_t global_index;
|
||||||
|
BOOST_FOREACH(const auto& vout, tx.vout)
|
||||||
|
{
|
||||||
|
uint64_t amount = vout.amount;
|
||||||
|
|
||||||
|
global_index = index_vec[i];
|
||||||
|
|
||||||
|
lmdb_cur cur(txn, m_output_amounts);
|
||||||
|
|
||||||
|
MDB_val_copy<uint64_t> k(amount);
|
||||||
|
MDB_val v;
|
||||||
|
|
||||||
|
auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
|
||||||
|
if (result == MDB_NOTFOUND)
|
||||||
|
throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found"));
|
||||||
|
else if (result)
|
||||||
|
throw0(DB_ERROR("DB error attempting to get an output"));
|
||||||
|
|
||||||
|
size_t num_elems = 0;
|
||||||
|
mdb_cursor_count(cur, &num_elems);
|
||||||
|
|
||||||
|
mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP);
|
||||||
|
|
||||||
|
uint64_t amount_output_index = 0;
|
||||||
|
uint64_t output_index = 0;
|
||||||
|
bool found_index = false;
|
||||||
|
for (uint64_t j = 0; j < num_elems; ++j)
|
||||||
|
{
|
||||||
|
mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT);
|
||||||
|
output_index = *(const uint64_t *)v.mv_data;
|
||||||
|
if (output_index == global_index)
|
||||||
|
{
|
||||||
|
amount_output_index = j;
|
||||||
|
found_index = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP);
|
||||||
|
}
|
||||||
|
if (found_index)
|
||||||
|
{
|
||||||
|
index_vec2.push_back(amount_output_index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// not found
|
||||||
|
cur.close();
|
||||||
|
txn.commit();
|
||||||
|
throw1(OUTPUT_DNE("specified output not found in db"));
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.close();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return index_vec2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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__);
|
||||||
|
|
|
@ -166,6 +166,7 @@ public:
|
||||||
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const;
|
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const;
|
||||||
|
|
||||||
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const;
|
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const;
|
||||||
|
virtual std::vector<uint64_t> get_tx_amount_output_indices(const crypto::hash& h) const;
|
||||||
|
|
||||||
virtual bool has_key_image(const crypto::key_image& img) const;
|
virtual bool has_key_image(const crypto::key_image& img) const;
|
||||||
|
|
||||||
|
|
|
@ -1789,7 +1789,8 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<u
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
indexs = m_db->get_tx_output_indices(tx_id);
|
// get amount output indexes, currently referred to in parts as "output global indices", but they are actually specific to amounts
|
||||||
|
indexs = m_db->get_tx_amount_output_indices(tx_id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
|
@ -452,6 +452,9 @@ public:
|
||||||
// return a vector of indices corresponding to the global output index for
|
// return a vector of indices corresponding to the global output index for
|
||||||
// each output in the transaction with hash <h>
|
// each output in the transaction with hash <h>
|
||||||
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const = 0;
|
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const = 0;
|
||||||
|
// return a vector of indices corresponding to the amount output index for
|
||||||
|
// each output in the transaction with hash <h>
|
||||||
|
virtual std::vector<uint64_t> get_tx_amount_output_indices(const crypto::hash& h) 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;
|
||||||
|
|
Loading…
Reference in New Issue