1
0
Fork 0
forked from lthn/blockchain

Merge branch 'wallet_delayed_outputs_sync' into predevelop

This commit is contained in:
cryptozoidberg 2020-06-14 19:48:07 +02:00
commit c9c33566b9
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
16 changed files with 325 additions and 103 deletions

View file

@ -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)
{

View file

@ -0,0 +1,27 @@
// Copyright (c) 2014-2018 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "warnings.h"
PUSH_VS_WARNINGS
DISABLE_VS_WARNINGS(4100)
DISABLE_VS_WARNINGS(4503)
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage_template_helper.h"
POP_VS_WARNINGS
namespace currency
{
template<typename t_type>
struct struct_with_one_t_type
{
t_type v;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(v)
END_KV_SERIALIZE_MAP()
};
}

View file

@ -3098,7 +3098,7 @@ bool blockchain_storage::get_est_height_from_date(uint64_t date, uint64_t& res_h
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::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)const
bool blockchain_storage::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, bool need_global_indexes)const
{
CRITICAL_REGION_LOCAL(m_read_lock);
blocks_direct_container blocks_direct;
@ -3117,7 +3117,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))
@ -3134,6 +3134,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;
}

View file

@ -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;
//---------------------------------------------------------------------------------
@ -254,8 +254,8 @@ namespace currency
bool get_short_chain_history(std::list<crypto::hash>& ids)const;
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)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, 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, 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;

View file

@ -1734,12 +1734,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;

View file

@ -13,6 +13,7 @@
#include "currency_core/connection_context.h"
#include "currency_core/blockchain_storage_basic.h"
#include "currency_protocol/blobdatatype.h"
#include "currency_core/basic_kv_structs.h"
namespace currency
{
@ -20,7 +21,7 @@ namespace currency
#define BC_COMMANDS_POOL_BASE 2000
/************************************************************************/
/* */
/************************************************************************/
@ -28,15 +29,19 @@ namespace currency
{
blobdata block;
std::list<blobdata> txs;
std::vector<struct_with_one_t_type<std::vector<uint64_t> > > tx_global_outs;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block)
KV_SERIALIZE(txs)
KV_SERIALIZE(tx_global_outs)
END_KV_SERIALIZE_MAP()
};
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;
};

View file

@ -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;
@ -314,20 +315,31 @@ namespace currency
return true;
}
std::list<std::pair<block, std::list<transaction> > > 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))
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))
{
res.status = API_RETURN_CODE_FAIL;
return false;
}
BOOST_FOREACH(auto& b, bs)
for (auto& b : bs)
{
res.blocks.resize(res.blocks.size()+1);
res.blocks.back().block = block_to_blob(b.first);
res.blocks.back().block = block_to_blob(b.first->bl);
if (req.need_global_indexes)
{
res.blocks.back().tx_global_outs.resize(b.second.size());
}
size_t i = 0;
BOOST_FOREACH(auto& t, b.second)
{
res.blocks.back().txs.push_back(tx_to_blob(t));
res.blocks.back().txs.push_back(tx_to_blob(t->tx));
if (req.need_global_indexes)
{
res.blocks.back().tx_global_outs[i].v = t->m_global_output_indexes;
}
i++;
}
}
@ -367,14 +379,19 @@ namespace currency
bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx)
{
CHECK_CORE_READY();
bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
if(!r)
res.tx_global_outs.resize(req.txids.size());
size_t i = 0;
for (auto& txid : req.txids)
{
res.status = "Failed";
return true;
bool r = m_core.get_tx_outputs_gindexs(txid, res.tx_global_outs[i].v);
if (!r)
{
res.status = API_RETURN_CODE_FAIL;
return true;
}
i++;
}
res.status = API_RETURN_CODE_OK;
LOG_PRINT_L2("COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES: [" << res.o_indexes.size() << "]");
return true;
}
//------------------------------------------------------------------------------------------------------------------------------

View file

@ -109,10 +109,12 @@ namespace currency
struct request
{
bool need_global_indexes;
uint64_t minimum_height;
std::list<crypto::hash> block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(need_global_indexes)
KV_SERIALIZE(minimum_height)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids)
END_KV_SERIALIZE_MAP()
@ -236,19 +238,21 @@ namespace currency
{
struct request
{
crypto::hash txid;
std::list<crypto::hash> txids;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_VAL_POD_AS_BLOB(txid)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(txids)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::vector<uint64_t> o_indexes;
std::vector<struct_with_one_t_type<std::vector<uint64_t> > > tx_global_outs;
//std::vector<uint64_t> o_indexes;
std::string status;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(o_indexes)
KV_SERIALIZE(tx_global_outs)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
};

View file

@ -207,6 +207,8 @@ namespace plain_wallet
return GENERAL_INTERNAL_ERRROR_INIT;
}
ptr->gwm.set_use_deffered_global_outputs(true);
if(!ptr->gwm.start())
{
LOG_ERROR("Failed to start wallets_manager");

View file

@ -19,8 +19,10 @@ DISABLE_VS_WARNINGS(4503)
#include "rpc/core_rpc_server_commands_defs.h"
#include "wallet/wallet_public_structs_defs.h"
#include "currency_core/offers_services_helpers.h"
#include "currency_core/basic_kv_structs.h"
#include "currency_core/basic_api_response_codes.h"
#include "common/error_codes.h"
POP_VS_WARNINGS
//#endif
@ -769,16 +771,6 @@ public:
END_KV_SERIALIZE_MAP()
};
template<typename t_type>
struct struct_with_one_t_type
{
t_type v;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(v)
END_KV_SERIALIZE_MAP()
};
#define API_MAX_ALIASES_COUNT 10000
struct i_view

View file

@ -35,7 +35,24 @@ using namespace currency;
ENABLE_CHANNEL_BY_DEFAULT("wallet")
namespace tools
{
wallet2::wallet2() : m_stop(false),
m_wcallback(new i_wallet2_callback()), //stub
m_core_proxy(new default_http_core_proxy()),
m_upper_transaction_size_limit(0),
m_height_of_start_sync(0),
m_last_sync_percent(0),
m_fake_outputs_count(0),
m_do_rise_transfer(false),
m_log_prefix("???"),
m_watch_only(false),
m_last_pow_block_h(0),
m_minimum_height(WALLET_MINIMUM_HEIGHT_UNSET_CONST),
m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE),
m_current_wallet_file_size(0),
m_use_deffered_global_outputs(false)
{
m_core_runtime_config = currency::get_default_core_runtime_config();
}
//---------------------------------------------------------------
uint64_t wallet2::get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td)
{
@ -239,7 +256,48 @@ 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)
{
std::list<std::reference_wrapper<const currency::transaction>> txs;
txs.push_back(tx);
std::vector<std::vector<uint64_t> > res;
fetch_tx_global_indixes(txs, res);
THROW_IF_FALSE_WALLET_INT_ERR_EX(res.size() == 1, "fetch_tx_global_indixes for single entry returned wrong result: res.size()=" << res.size());
goutputs_indexes = res[0];
}
//----------------------------------------------------------------------------------------------------
void wallet2::fetch_tx_global_indixes(const std::list<std::reference_wrapper<const currency::transaction>>& txs, std::vector<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);
for (auto& tx : txs)
{
req.txids.push_back(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_FALSE_WALLET_INT_ERR_EX(res.tx_global_outs.size() == txs.size(), "res.tx_global_outs.size()(" << res.tx_global_outs.size()
<< ") == txs.size()(" << txs.size() << ")");
goutputs_indexes.resize(txs.size());
auto it_resp = res.tx_global_outs.begin();
auto it_txs = txs.begin();
size_t i = 0;
for (; it_resp != res.tx_global_outs.end();)
{
THROW_IF_FALSE_WALLET_INT_ERR_EX(it_resp->v.size() == it_txs->get().vout.size(),
"transactions outputs size=" << it_txs->get().vout.size() <<
" not match with COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES response[i] size=" << it_resp->v.size());
goutputs_indexes[i] = it_resp->v;
it_resp++; it_txs++; i++;
}
}
//----------------------------------------------------------------------------------------------------
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);
@ -359,25 +417,34 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
if(!outs.empty() /*&& tx_money_got_in_outs*/)
{
//good news - got money! take care about it
//usually we have only one transfer for user in transaction
//create once instance of tx for all entries
std::shared_ptr<transaction_wallet_info> pwallet_info(new transaction_wallet_info());
pwallet_info->m_tx = tx;
pwallet_info->m_block_height = height;
pwallet_info->m_block_timestamp = b.timestamp;
//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()));
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 || (pglobal_indexes->size() == 0 && tx.vout.size() != 0))
{
if (m_use_deffered_global_outputs)
{
pglobal_indexes = nullptr;
}
else
{
fetch_tx_global_indixes(tx, outputs_index_local);
pglobal_indexes = &outputs_index_local;
}
}
for (size_t i_in_outs = 0; i_in_outs != outs.size(); i_in_outs++)
{
size_t o = outs[i_in_outs];
@ -455,7 +522,20 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
td.m_ptx_wallet_info = pwallet_info;
td.m_internal_output_index = o;
td.m_key_image = ki;
td.m_global_output_index = res.o_indexes[o];
LOG_PRINT_L0("pglobal_indexes = " << pglobal_indexes);
if (m_use_deffered_global_outputs)
{
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
{
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes, "pglobal_indexes IS NULL in non mobile wallet");
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes->size() > o, "pglobal_indexes size()(" << pglobal_indexes->size() << ") <= o " << o );
td.m_global_output_index = (*pglobal_indexes)[o];
}
if (coin_base_tx)
{
//last out in coinbase tx supposed to be change from coinstake
@ -470,9 +550,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);
@ -1164,16 +1248,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");
@ -1248,6 +1338,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)
@ -2869,9 +2962,20 @@ bool wallet2::get_pos_entries(currency::COMMAND_RPC_SCAN_POS::request& req)
for (size_t i = 0; i != m_transfers.size(); i++)
{
auto& tr = m_transfers[i];
uint64_t stake_unlock_time = 0;
if (!is_transfer_okay_for_pos(tr, stake_unlock_time))
continue;
if (tr.m_global_output_index == WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED)
{
//TODO: this code needed mostly for coretests, since in real life cases only mobile wallet supposed to
// have WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, and mobile wallet is not supposed to do PoS mining
std::vector<uint64_t> indicies; indicies.push_back(i);
prefetch_global_indicies_if_needed(indicies);
}
//WLT_CHECK_AND_ASSERT_MES(tr.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, false, "Wrong output input in transaction");
currency::pos_entry pe = AUTO_VAL_INIT(pe);
pe.amount = tr.amount();
pe.index = tr.m_global_output_index;
@ -3753,6 +3857,32 @@ bool wallet2::prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_coun
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies, found_money);
}
//----------------------------------------------------------------------------------------------------
void wallet2::prefetch_global_indicies_if_needed(std::vector<uint64_t>& selected_indicies)
{
std::list<std::reference_wrapper<const currency::transaction>> txs;
std::list<uint64_t> indices_that_requested_global_indicies;
for (uint64_t i : selected_indicies)
{
if (m_transfers[i].m_global_output_index == WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED)
{
indices_that_requested_global_indicies.push_back(i);
txs.push_back(m_transfers[i].m_ptx_wallet_info->m_tx);
}
}
std::vector<std::vector<uint64_t> > outputs_for_all_txs;
fetch_tx_global_indixes(txs, outputs_for_all_txs);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(txs.size() == outputs_for_all_txs.size(), "missmatch sizes txs.size() == outputs_for_all_txs.size()");
auto it_indices = indices_that_requested_global_indicies.begin();
auto it_ooutputs = outputs_for_all_txs.begin();
for (; it_ooutputs != outputs_for_all_txs.end();)
{
transfer_details& td = m_transfers[*it_indices];
td.m_global_output_index = (*it_ooutputs)[td.m_internal_output_index];
it_ooutputs++; it_indices++;
}
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
{
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
@ -3791,6 +3921,9 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
}
//lets prefetch m_global_output_index for selected_indicies
prefetch_global_indicies_if_needed(selected_indicies);
//prepare inputs
size_t i = 0;
for (uint64_t J : selected_indicies)
@ -4296,7 +4429,7 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis)
m_last_bc_timestamp = genesis.timestamp;
WLT_LOG_L2("Processing genesis block: " << genesis_hash);
process_new_transaction(genesis.miner_tx, 0, genesis);
process_new_transaction(genesis.miner_tx, 0, genesis, nullptr);
}
//----------------------------------------------------------------------------------------------------
void wallet2::set_genesis(const crypto::hash& genesis_hash)
@ -4681,9 +4814,9 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
amount_total = 0;
outs_swept = 0;
std::vector<size_t> selected_transfers;
std::vector<uint64_t> selected_transfers;
selected_transfers.reserve(m_transfers.size());
for (size_t i = 0; i < m_transfers.size(); ++i)
for (uint64_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
uint64_t amount = td.amount();
@ -4699,12 +4832,14 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!selected_transfers.empty(), "No spendable outputs meet the criterion");
// sort by amount descending in order to spend bigger outputs first
std::sort(selected_transfers.begin(), selected_transfers.end(), [this](size_t a, size_t b) { return m_transfers[b].amount() < m_transfers[a].amount(); });
std::sort(selected_transfers.begin(), selected_transfers.end(), [this](uint64_t a, uint64_t b) { return m_transfers[b].amount() < m_transfers[a].amount(); });
// limit RPC request with reasonable number of sources
if (selected_transfers.size() > tx_sources_for_querying_random_outs_max)
selected_transfers.erase(selected_transfers.begin() + tx_sources_for_querying_random_outs_max, selected_transfers.end());
prefetch_global_indicies_if_needed(selected_transfers);
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
typedef currency::tx_source_entry::output_entry tx_output_entry;
@ -4714,7 +4849,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
req.use_forced_mix_outs = false;
req.outs_count = fake_outs_count + 1;
for (size_t i : selected_transfers)
for (uint64_t i : selected_transfers)
req.amounts.push_back(m_transfers[i].amount());
r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rpc_get_random_outs_resp);
@ -4767,7 +4902,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
for (size_t st_index = 0; st_index < st_index_upper_boundary; ++st_index)
{
currency::tx_source_entry& src = ftp.sources[st_index];
size_t tr_index = selected_transfers[st_index];
uint64_t tr_index = selected_transfers[st_index];
transfer_details& td = m_transfers[tr_index];
src.transfer_index = tr_index;
src.amount = td.amount();

View file

@ -48,7 +48,15 @@
#define WALLET_DEFAULT_POS_MINT_PACKING_SIZE 100
#define WALLET_TRANSFER_DETAIL_FLAG_SPENT uint32_t(1 << 0)
#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED uint32_t(1 << 1)
#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION uint32_t(1 << 2)
#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3)
#define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing)
const uint64_t WALLET_MINIMUM_HEIGHT_UNSET_CONST = std::numeric_limits<uint64_t>::max();
const uint64_t WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED = std::numeric_limits<uint64_t>::max();
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "wallet"
@ -316,41 +324,9 @@ namespace tools
class wallet2
{
wallet2(const wallet2&) : m_stop(false),
m_wcallback(new i_wallet2_callback()),
m_height_of_start_sync(0),
m_last_sync_percent(0),
m_do_rise_transfer(false),
m_watch_only(false),
m_last_pow_block_h(0),
m_minimum_height(WALLET_MINIMUM_HEIGHT_UNSET_CONST),
m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE),
m_current_wallet_file_size(0)
{};
wallet2(const wallet2&) = delete;
public:
wallet2() : m_stop(false),
m_wcallback(new i_wallet2_callback()), //stub
m_core_proxy(new default_http_core_proxy()),
m_upper_transaction_size_limit(0),
m_height_of_start_sync(0),
m_last_sync_percent(0),
m_fake_outputs_count(0),
m_do_rise_transfer(false),
m_log_prefix("???"),
m_watch_only(false),
m_last_pow_block_h(0),
m_minimum_height(WALLET_MINIMUM_HEIGHT_UNSET_CONST),
m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE),
m_current_wallet_file_size(0)
{
m_core_runtime_config = currency::get_default_core_runtime_config();
};
#define WALLET_TRANSFER_DETAIL_FLAG_SPENT uint32_t(1 << 0)
#define WALLET_TRANSFER_DETAIL_FLAG_BLOCKED uint32_t(1 << 1)
#define WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION uint32_t(1 << 2)
#define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3)
#define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing)
wallet2();
static std::string transfer_flags_to_str(uint32_t flags);
static std::string transform_tx_to_str(const currency::transaction& tx);
@ -821,13 +797,16 @@ namespace tools
bool get_utxo_distribution(std::map<uint64_t, uint64_t>& distribution);
uint64_t get_sync_progress();
uint64_t get_wallet_file_size()const;
void set_use_deffered_global_outputs(bool use) { m_use_deffered_global_outputs = use;}
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 fetch_tx_global_indixes(const std::list<std::reference_wrapper<const currency::transaction>>& txs, std::vector<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);
@ -879,6 +858,7 @@ private:
bool prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
bool prepare_tx_sources(crypto::hash multisig_id, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
bool prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
void prefetch_global_indicies_if_needed(std::vector<uint64_t>& selected_indicies);
uint64_t get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts);
void prepare_tx_destinations(uint64_t needed_money,
uint64_t found_money,
@ -995,6 +975,7 @@ private:
std::string m_miner_text_info;
mutable uint64_t m_current_wallet_file_size;
bool m_use_deffered_global_outputs;
//this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions
friend class test_generator;

View file

@ -63,7 +63,8 @@ wallets_manager::wallets_manager():m_pview(&m_view_stub),
m_remote_node_mode(false),
m_is_pos_allowed(false),
m_qt_logs_enbaled(false),
m_dont_save_wallet_at_stop(false)
m_dont_save_wallet_at_stop(false),
m_use_deffered_global_outputs(false)
{
#ifndef MOBILE_WALLET_BUILD
m_offers_service.set_disabled(true);
@ -814,6 +815,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
w->set_use_deffered_global_outputs(m_use_deffered_global_outputs);
owr.wallet_id = m_wallet_id_counter++;
w->callback(std::shared_ptr<tools::i_wallet2_callback>(new i_wallet_to_i_backend_adapter(this, owr.wallet_id)));
@ -927,6 +929,7 @@ std::string wallets_manager::get_recent_transfers(size_t wallet_id, uint64_t off
std::string wallets_manager::generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr)
{
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
w->set_use_deffered_global_outputs(m_use_deffered_global_outputs);
owr.wallet_id = m_wallet_id_counter++;
w->callback(std::shared_ptr<tools::i_wallet2_callback>(new i_wallet_to_i_backend_adapter(this, owr.wallet_id)));
if (m_remote_node_mode)
@ -1012,6 +1015,7 @@ void wallets_manager::get_gui_options(view::gui_options& opt)
std::string wallets_manager::restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, bool auditable_watch_only, view::open_wallet_response& owr)
{
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
w->set_use_deffered_global_outputs(m_use_deffered_global_outputs);
owr.wallet_id = m_wallet_id_counter++;
w->callback(std::shared_ptr<tools::i_wallet2_callback>(new i_wallet_to_i_backend_adapter(this, owr.wallet_id)));
if (m_remote_node_mode)

View file

@ -63,6 +63,7 @@ public:
std::atomic<bool> stop_for_refresh; //use separate var for passing to "refresh" member function,
//because it can be changed there due to internal interruption logis
std::atomic<bool> break_mining_loop;
std::atomic<uint64_t> wallet_state;
std::atomic<uint64_t> last_wallet_synch_height;
@ -154,7 +155,7 @@ public:
void get_gui_options(view::gui_options& opt);
std::string get_wallet_log_prefix(size_t wallet_id) const;
bool is_qt_logs_enabled() const { return m_qt_logs_enbaled; }
void set_use_deffered_global_outputs(bool use) { m_use_deffered_global_outputs = use; }
private:
void main_worker(const po::variables_map& vm);
bool init_local_daemon();
@ -186,6 +187,7 @@ private:
std::shared_ptr<tools::i_core_proxy> m_rpc_proxy;
po::variables_map m_vm;
bool m_use_deffered_global_outputs;
std::atomic<uint64_t> m_last_daemon_height;
std::atomic<uint64_t> m_last_daemon_network_state;
std::atomic<bool> m_last_daemon_is_disconnected;

View file

@ -384,10 +384,16 @@ bool test_generator::build_wallets(const blockchain_vector& blocks,
{}
virtual bool call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(const currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& rqt, currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& rsp)
{
auto it = m_txs_outs.find(rqt.txid);
CHECK_AND_ASSERT_MES(it != m_txs_outs.end(), false, "tx " << rqt.txid << " was not found in tx global outout indexes");
rsp.tx_global_outs.resize(rqt.txids.size());
size_t i = 0;
for (auto& txid : rqt.txids)
{
auto it = m_txs_outs.find(txid);
CHECK_AND_ASSERT_MES(it != m_txs_outs.end(), false, "tx " << txid << " was not found in tx global outout indexes");
rsp.tx_global_outs[i].v = it->second;
i++;
}
rsp.status = API_RETURN_CODE_OK;
rsp.o_indexes = it->second;
return true;
}
};

View file

@ -45,12 +45,18 @@ bool wallet_test_core_proxy::update_blockchain(const std::vector<test_event_entr
return true;
}
bool wallet_test_core_proxy::call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(const currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& rqt, currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& rsp)
bool wallet_test_core_proxy::call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(const currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res)
{
auto it = m_txs_outs.find(rqt.txid);
CHECK_AND_ASSERT_MES(it != m_txs_outs.end(), false, "tx " << rqt.txid << " was not found in tx global outout indexes");
rsp.status = API_RETURN_CODE_OK;
rsp.o_indexes = it->second;
res.tx_global_outs.resize(req.txids.size());
size_t i = 0;
for (auto& txid : req.txids)
{
auto it = m_txs_outs.find(txid);
CHECK_AND_ASSERT_MES(it != m_txs_outs.end(), false, "tx " << txid << " was not found in tx global outout indexes");
res.tx_global_outs[i].v = it->second;
i++;
}
res.status = API_RETURN_CODE_OK;
return true;
}
@ -98,6 +104,8 @@ bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::
{
currency::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req);
req.block_ids = rqt.block_ids;
req.minimum_height = rqt.minimum_height;
req.need_global_indexes = rqt.need_global_indexes;
currency::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
bool r = this->call_COMMAND_RPC_GET_BLOCKS_FAST(req, res);
rsp.status = res.status;
@ -108,7 +116,6 @@ bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::
r = unserialize_block_complete_entry(res, rsp);
}
return r;
}
bool wallet_test_core_proxy::call_COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE(const currency::COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::request& rqt, currency::COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::response& rsp)