forked from lthn/blockchain
implemented deferred fetching of global output indexes on receiving phase(preparation phase is todo)
This commit is contained in:
parent
267053964d
commit
8f9f9f1698
8 changed files with 106 additions and 25 deletions
|
|
@ -77,6 +77,32 @@ namespace epee
|
|||
|
||||
namespace misc_utils
|
||||
{
|
||||
template<class _Ty1,
|
||||
class _Ty2,
|
||||
class _Ty3>
|
||||
struct triple
|
||||
{ // store a pair of values
|
||||
typedef _Ty1 first_type;
|
||||
typedef _Ty2 second_type;
|
||||
typedef _Ty3 third_type;
|
||||
|
||||
triple()
|
||||
: first(), second(), third()
|
||||
{ // default construct
|
||||
}
|
||||
|
||||
triple(const _Ty1& _Val1, const _Ty2& _Val2, const _Ty3& _Val3)
|
||||
: first(_Val1), second(_Val2), third(_Val3)
|
||||
{ // construct from specified values
|
||||
}
|
||||
|
||||
_Ty1 first; // the first stored value
|
||||
_Ty2 second; // the second stored value
|
||||
_Ty3 third; // the second stored value
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename t_type>
|
||||
t_type get_max_t_val(t_type t)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3112,7 +3112,7 @@ bool blockchain_storage::find_blockchain_supplement(const std::list<crypto::hash
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height)const
|
||||
bool blockchain_storage::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height, bool request_coinbase_info)const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
if (!find_blockchain_supplement(qblock_ids, start_height))
|
||||
|
|
@ -3129,6 +3129,8 @@ bool blockchain_storage::find_blockchain_supplement(const std::list<crypto::hash
|
|||
std::list<crypto::hash> mis;
|
||||
get_transactions_direct(m_db_blocks[i]->bl.tx_hashes, blocks.back().second, mis);
|
||||
CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, block " << get_block_hash(m_db_blocks[i]->bl) << " [" << i << "] contains missing transactions: " << mis);
|
||||
if(request_coinbase_info)
|
||||
blocks.back().third = m_db_transactions.find(get_transaction_hash(m_db_blocks[i]->bl.miner_tx));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ namespace currency
|
|||
|
||||
typedef tools::db::basic_key_to_array_accessor<uint64_t, global_output_entry, false> outputs_container; // out_amount => ['global_output', ...]
|
||||
typedef tools::db::cached_key_value_accessor<crypto::key_image, uint64_t, false, false> key_images_container;
|
||||
typedef std::list<std::pair<std::shared_ptr<const block_extended_info>, std::list<std::shared_ptr<const transaction_chain_entry> > > > blocks_direct_container;
|
||||
typedef std::list<epee::misc_utils::triple<std::shared_ptr<const block_extended_info>, std::list<std::shared_ptr<const transaction_chain_entry> >, std::shared_ptr<const transaction_chain_entry> > > blocks_direct_container;
|
||||
|
||||
friend struct add_transaction_input_visitor;
|
||||
//---------------------------------------------------------------------------------
|
||||
|
|
@ -255,7 +255,7 @@ namespace currency
|
|||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp)const;
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset)const;
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0, bool need_global_indexes = false)const;
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0)const;
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0, bool request_coinbase_info = false)const;
|
||||
//bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const;
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const;
|
||||
bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const;
|
||||
|
|
|
|||
|
|
@ -1739,12 +1739,24 @@ namespace currency
|
|||
bool r = currency::parse_and_validate_block_from_blob(bl_entry.block, blextin_ptr->bl);
|
||||
bdde.block_ptr = blextin_ptr;
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse block from blob: " << string_tools::buff_to_hex_nodelimer(bl_entry.block));
|
||||
size_t i = 0;
|
||||
if (bl_entry.tx_global_outs.size())
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(bl_entry.tx_global_outs.size() == bl_entry.txs.size(), false, "tx_global_outs count " << bl_entry.tx_global_outs.size() << " count missmatch with bl_entry.txs count " << bl_entry.txs.size());
|
||||
}
|
||||
|
||||
for (const auto& tx_blob : bl_entry.txs)
|
||||
{
|
||||
std::shared_ptr<currency::transaction_chain_entry> tche_ptr(new currency::transaction_chain_entry());
|
||||
r = parse_and_validate_tx_from_blob(tx_blob, tche_ptr->tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse tx from blob: " << string_tools::buff_to_hex_nodelimer(tx_blob));
|
||||
bdde.txs_ptr.push_back(tche_ptr);
|
||||
if (bl_entry.tx_global_outs.size())
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(bl_entry.tx_global_outs[i].v.size() == tche_ptr->tx.vout.size(), false, "tx_global_outs for tx" << bl_entry.tx_global_outs[i].v.size() << " count missmatch with tche_ptr->tx.vout.size() count " << tche_ptr->tx.vout.size());
|
||||
tche_ptr->m_global_output_indexes = bl_entry.tx_global_outs[i].v;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ namespace currency
|
|||
struct block_direct_data_entry
|
||||
{
|
||||
std::shared_ptr<const block_extended_info> block_ptr;
|
||||
std::shared_ptr<const transaction_chain_entry> coinbase_ptr;
|
||||
std::list<std::shared_ptr<const transaction_chain_entry> > txs_ptr;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ namespace currency
|
|||
}
|
||||
|
||||
blockchain_storage::blocks_direct_container bs;
|
||||
if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height))
|
||||
if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height, req.need_global_indexes))
|
||||
{
|
||||
res.status = API_RETURN_CODE_FAIL;
|
||||
return false;
|
||||
|
|
@ -290,6 +290,7 @@ namespace currency
|
|||
res.blocks.resize(res.blocks.size()+1);
|
||||
res.blocks.back().block_ptr = b.first;
|
||||
res.blocks.back().txs_ptr = std::move(b.second);
|
||||
res.blocks.back().coinbase_ptr = b.third;
|
||||
}
|
||||
|
||||
res.status = API_RETURN_CODE_OK;
|
||||
|
|
|
|||
|
|
@ -239,7 +239,24 @@ size_t wallet2::scan_for_transaction_entries(const crypto::hash& tx_id, const cr
|
|||
return details.size();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b)
|
||||
void wallet2::fetch_tx_global_indixes(const currency::transaction& tx, std::vector<uint64_t>& goutputs_indexes)
|
||||
{
|
||||
currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request req = AUTO_VAL_INIT(req);
|
||||
currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res);
|
||||
req.txid = get_transaction_hash(tx);
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(req, res);
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::no_connection_to_daemon, "get_o_indexes.bin");
|
||||
THROW_IF_TRUE_WALLET_EX(res.status == API_RETURN_CODE_BUSY, error::daemon_busy, "get_o_indexes.bin");
|
||||
THROW_IF_TRUE_WALLET_EX(res.status != API_RETURN_CODE_OK, error::get_out_indices_error, res.status);
|
||||
THROW_IF_TRUE_WALLET_EX(res.o_indexes.size() != tx.vout.size(), error::wallet_internal_error,
|
||||
"transactions outputs size=" + std::to_string(tx.vout.size()) +
|
||||
" not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" + std::to_string(res.o_indexes.size()));
|
||||
|
||||
goutputs_indexes = res.o_indexes;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector<uint64_t>* pglobal_indexes)
|
||||
{
|
||||
std::vector<std::string> recipients, recipients_aliases;
|
||||
process_unconfirmed(tx, recipients, recipients_aliases);
|
||||
|
|
@ -365,20 +382,23 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
pwallet_info->m_block_height = height;
|
||||
pwallet_info->m_block_timestamp = b.timestamp;
|
||||
|
||||
if (is_auditable())
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes && pglobal_indexes->size() == tx.vout.size(), "wrong pglobal_indexes = " << pglobal_indexes << "");
|
||||
}
|
||||
std::vector<uint64_t> outputs_index_local;
|
||||
|
||||
if (!pglobal_indexes)
|
||||
{
|
||||
#ifndef MOBILE_WALLET_BUILD
|
||||
//good news - got money! take care about it
|
||||
//usually we have only one transfer for user in transaction
|
||||
currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request req = AUTO_VAL_INIT(req);
|
||||
currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response res = AUTO_VAL_INIT(res);
|
||||
req.txid = get_transaction_hash(tx);
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(req, res);
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::no_connection_to_daemon, "get_o_indexes.bin");
|
||||
THROW_IF_TRUE_WALLET_EX(res.status == API_RETURN_CODE_BUSY, error::daemon_busy, "get_o_indexes.bin");
|
||||
THROW_IF_TRUE_WALLET_EX(res.status != API_RETURN_CODE_OK, error::get_out_indices_error, res.status);
|
||||
THROW_IF_TRUE_WALLET_EX(res.o_indexes.size() != tx.vout.size(), error::wallet_internal_error,
|
||||
"transactions outputs size=" + std::to_string(tx.vout.size()) +
|
||||
" not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response size=" + std::to_string(res.o_indexes.size()));
|
||||
//good news - got money! take care about it
|
||||
//usually we have only one transfer for user in transaction
|
||||
fetch_tx_global_indixes(tx, outputs_index_local);
|
||||
pglobal_indexes = &outputs_index_local;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (size_t i_in_outs = 0; i_in_outs != outs.size(); i_in_outs++)
|
||||
{
|
||||
|
|
@ -458,9 +478,13 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
td.m_internal_output_index = o;
|
||||
td.m_key_image = ki;
|
||||
#ifdef MOBILE_WALLET_BUILD
|
||||
td.m_global_output_index = WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED;
|
||||
if (pglobal_indexes && pglobal_indexes->size() > o)
|
||||
td.m_global_output_index = (*pglobal_indexes)[o];
|
||||
else
|
||||
td.m_global_output_index = WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED;
|
||||
#else
|
||||
td.m_global_output_index = res.o_indexes[o];
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes, "pglobal_indexes IS NULL in non mobile wallet");
|
||||
td.m_global_output_index = (*pglobal_indexes)[o];
|
||||
#endif
|
||||
|
||||
if (coin_base_tx)
|
||||
|
|
@ -477,9 +501,13 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
add_transfer_to_transfers_cache(tx.vout[o].amount, transfer_index);
|
||||
uint64_t amount = tx.vout[o].amount;
|
||||
|
||||
auto amount_gindex_pair = std::make_pair(amount, td.m_global_output_index);
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(m_amount_gindex_to_transfer_id.count(amount_gindex_pair) == 0, "update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists");
|
||||
m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index;
|
||||
if (is_watch_only() && is_auditable())
|
||||
{
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(td.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, "td.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED validation failed");
|
||||
auto amount_gindex_pair = std::make_pair(amount, td.m_global_output_index);
|
||||
WLT_CHECK_AND_ASSERT_MES_NO_RET(m_amount_gindex_to_transfer_id.count(amount_gindex_pair) == 0, "update m_amount_gindex_to_transfer_id: amount " << amount << ", gindex " << td.m_global_output_index << " already exists");
|
||||
m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index;
|
||||
}
|
||||
|
||||
if (max_out_unlock_time < get_tx_unlock_time(tx, o))
|
||||
max_out_unlock_time = get_tx_unlock_time(tx, o);
|
||||
|
|
@ -1161,16 +1189,22 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre
|
|||
"current_index=" + std::to_string(height) + ", get_blockchain_current_height()=" + std::to_string(get_blockchain_current_size()));
|
||||
|
||||
//optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
|
||||
const std::vector<uint64_t>* pglobal_index = nullptr;
|
||||
if (b.timestamp + 60 * 60 * 24 > m_account.get_createtime())
|
||||
{
|
||||
pglobal_index = nullptr;
|
||||
if (bche.coinbase_ptr.get())
|
||||
{
|
||||
pglobal_index = &(bche.coinbase_ptr->m_global_output_indexes);
|
||||
}
|
||||
TIME_MEASURE_START(miner_tx_handle_time);
|
||||
process_new_transaction(b.miner_tx, height, b);
|
||||
process_new_transaction(b.miner_tx, height, b, pglobal_index);
|
||||
TIME_MEASURE_FINISH(miner_tx_handle_time);
|
||||
|
||||
TIME_MEASURE_START(txs_handle_time);
|
||||
for(const auto& tx_entry: bche.txs_ptr)
|
||||
{
|
||||
process_new_transaction(tx_entry->tx, height, b);
|
||||
process_new_transaction(tx_entry->tx, height, b, &(tx_entry->m_global_output_indexes));
|
||||
}
|
||||
TIME_MEASURE_FINISH(txs_handle_time);
|
||||
WLT_LOG_L3("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms");
|
||||
|
|
@ -1245,6 +1279,9 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic<bool>& stop)
|
|||
currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response res = AUTO_VAL_INIT(res);
|
||||
|
||||
req.minimum_height = get_wallet_minimum_height();
|
||||
if (is_auditable())
|
||||
req.need_global_indexes = true;
|
||||
|
||||
m_chain.get_short_chain_history(req.block_ids);
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_BLOCKS_DIRECT(req, res);
|
||||
if (!r)
|
||||
|
|
@ -2865,6 +2902,7 @@ bool wallet2::get_pos_entries(currency::COMMAND_RPC_SCAN_POS::request& req)
|
|||
{
|
||||
for (size_t i = 0; i != m_transfers.size(); i++)
|
||||
{
|
||||
WLT_CHECK_AND_ASSERT_MES(tr.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, false, "Wrong output input in transaction");
|
||||
auto& tr = m_transfers[i];
|
||||
uint64_t stake_unlock_time = 0;
|
||||
if (!is_transfer_okay_for_pos(tr, stake_unlock_time))
|
||||
|
|
|
|||
|
|
@ -830,7 +830,8 @@ private:
|
|||
void add_transfers_to_expiration_list(const std::vector<uint64_t>& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id);
|
||||
void remove_transfer_from_expiration_list(uint64_t transfer_index);
|
||||
void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature);
|
||||
void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b);
|
||||
void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector<uint64_t>* pglobal_indexes);
|
||||
void fetch_tx_global_indixes(const currency::transaction& tx, std::vector<uint64_t>& goutputs_indexes);
|
||||
void detach_blockchain(uint64_t including_height);
|
||||
bool extract_offers_from_transfer_entry(size_t i, std::unordered_map<crypto::hash, bc_services::offer_details_ex>& offers_local);
|
||||
bool select_my_offers(std::list<bc_services::offer_details_ex>& offers);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue