1
0
Fork 0
forked from lthn/blockchain

get_random_outs_for_amounts adaptation, get_mix_attr_from_tx_out_v implemented

This commit is contained in:
sowle 2022-10-12 17:50:02 +02:00
parent a0bdc08633
commit ab268af7b8
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
4 changed files with 75 additions and 49 deletions

View file

@ -2475,15 +2475,21 @@ size_t blockchain_storage::get_alternative_blocks_count() const
return m_alternative_chains.size();
}
//------------------------------------------------------------------
bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix) const
bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t g_index, uint64_t mix_count,
bool use_only_forced_to_mix, uint64_t height_upper_limit) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
auto out_ptr = m_db_outputs.get_subitem(amount, i);
auto out_ptr = m_db_outputs.get_subitem(amount, g_index);
auto tx_ptr = m_db_transactions.find(out_ptr->tx_id);
CHECK_AND_ASSERT_MES(tx_ptr, false, "internal error: transaction with id " << out_ptr->tx_id << ENDL <<
", used in mounts global index for amount=" << amount << ": i=" << i << "not found in transactions index");
", used in mounts global index for amount=" << amount << ": g_index=" << g_index << "not found in transactions index");
CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_ptr->out_no, false, "internal error: in global outs index, transaction out index="
<< out_ptr->out_no << " more than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id);
CHECK_AND_ASSERT_MES(amount != 0 || height_upper_limit != 0, false, "height_upper_limit must be nonzero for hidden amounts (amount = 0)");
if (height_upper_limit != 0 && tx_ptr->m_keeper_block_height > height_upper_limit)
return false;
const transaction& tx = tx_ptr->tx;
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() == tx.vout.size(), false, "internal error: spent_flag.size()=" << tx_ptr->m_spent_flags.size() << ", tx.vout.size()=" << tx.vout.size());
@ -2495,12 +2501,25 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU
//check if transaction is unlocked
if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx, out_ptr->out_no)))
return false;
const tx_out_v& out_v = tx.vout[out_ptr->out_no];
// do not use burned coins
if (is_out_burned(tx.vout[out_ptr->out_no]))
if (is_out_burned(out_v))
return false;
VARIANT_SWITCH_BEGIN(tx.vout[out_ptr->out_no]);
// check mix_attr
uint8_t mix_attr = CURRENCY_TO_KEY_OUT_RELAXED;
if (!get_mix_attr_from_tx_out_v(out_v, mix_attr))
return false; // output has no mix_attr, skip it
if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
return false; //COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS call means that ring signature will have more than one entry.
else if (use_only_forced_to_mix && mix_attr == CURRENCY_TO_KEY_OUT_RELAXED)
return false; //relaxed not allowed
else if (mix_attr != CURRENCY_TO_KEY_OUT_RELAXED && mix_attr > mix_count)
return false; //mix_attr set to specific minimum, and mix_count is less then desired count
VARIANT_SWITCH_BEGIN(out_v);
VARIANT_CASE_CONST(tx_out_bare, o)
{
if (o.target.type() == typeid(txout_htlc))
@ -2508,41 +2527,20 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU
//silently return false, it's ok
return false;
}
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "unknown tx out type");
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "unexpected out target type: " << o.target.type().name());
const txout_to_key& otk = boost::get<txout_to_key>(o.target);
// TODO #@#@ remove code duplication, make extracting mix_attr in a more generalized way
//use appropriate mix_attr out
uint8_t mix_attr = otk.mix_attr;
if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
return false; //COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS call means that ring signature will have more than one entry.
else if (use_only_forced_to_mix && mix_attr == CURRENCY_TO_KEY_OUT_RELAXED)
return false; //relaxed not allowed
else if (mix_attr != CURRENCY_TO_KEY_OUT_RELAXED && mix_attr > mix_count)
return false;//mix_attr set to specific minimum, and mix_count is less then desired count
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry());
oen.global_amount_index = i;
oen.out_key = otk.key;
oen.global_amount_index = g_index;
oen.stealth_address = otk.key;
}
VARIANT_CASE_CONST(tx_out_zarcanum, toz)
{
//use appropriate mix_attr out
uint8_t mix_attr = toz.mix_attr;
if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
return false; //COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS call means that ring signature will have more than one entry.
else if (use_only_forced_to_mix && mix_attr == CURRENCY_TO_KEY_OUT_RELAXED)
return false; //relaxed not allowed
else if (mix_attr != CURRENCY_TO_KEY_OUT_RELAXED && mix_attr > mix_count)
return false;//mix_attr set to specific minimum, and mix_count is less then desired count
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry());
oen.global_amount_index = i;
oen.out_key = toz.amount_commitment;
// TODO @#@# this is certainly not enough
oen.amount_commitment = toz.amount_commitment;
oen.concealing_point = toz.concealing_point;
oen.global_amount_index = g_index;
oen.stealth_address = toz.stealth_address;
}
VARIANT_SWITCH_END();
@ -2572,7 +2570,7 @@ size_t blockchain_storage::find_end_of_allowed_index(uint64_t amount) const
bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const
{
CRITICAL_REGION_LOCAL(m_read_lock);
BOOST_FOREACH(uint64_t amount, req.amounts)
for(uint64_t amount : req.amounts)
{
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount());
result_outs.amount = amount;
@ -2586,31 +2584,32 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO
//lets find upper bound of not fresh outs
size_t up_index_limit = find_end_of_allowed_index(amount);
CHECK_AND_ASSERT_MES(up_index_limit <= outs_container_size, false, "internal error: find_end_of_allowed_index returned wrong index=" << up_index_limit << ", with amount_outs.size = " << outs_container_size);
if (up_index_limit >= req.outs_count)
if (up_index_limit >= req.decoys_count)
{
std::set<size_t> used;
size_t try_count = 0;
for(uint64_t j = 0; j != req.outs_count && try_count < up_index_limit;)
for(uint64_t j = 0; j != req.decoys_count && try_count < up_index_limit;)
{
size_t i = crypto::rand<size_t>()%up_index_limit;
if(used.count(i))
size_t g_index = crypto::rand<size_t>() % up_index_limit;
if(used.count(g_index))
continue;
bool added = add_out_to_get_random_outs(result_outs, amount, i, req.outs_count, req.use_forced_mix_outs);
used.insert(i);
bool added = add_out_to_get_random_outs(result_outs, amount, g_index, req.decoys_count, req.use_forced_mix_outs, req.height_upper_limit);
used.insert(g_index);
if(added)
++j;
++try_count;
}
if (result_outs.outs.size() < req.outs_count)
if (result_outs.outs.size() < req.decoys_count)
{
LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.outs_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total");
LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total");
}
}else
}
else
{
size_t added = 0;
for (size_t i = 0; i != up_index_limit; i++)
added += add_out_to_get_random_outs(result_outs, amount, i, req.outs_count, req.use_forced_mix_outs) ? 1 : 0;
LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.outs_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs");
added += add_out_to_get_random_outs(result_outs, amount, i, req.decoys_count, req.use_forced_mix_outs, req.height_upper_limit) ? 1 : 0;
LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs");
}
}
return true;

View file

@ -618,7 +618,7 @@ namespace currency
bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp);
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id);
bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false) const;
bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false, uint64_t height_upper_limit = 0) const;
bool add_block_as_invalid(const block& bl, const crypto::hash& h);
bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h);
size_t find_end_of_allowed_index(uint64_t amount)const;

View file

@ -246,10 +246,8 @@ namespace currency
}
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed.");
tx = AUTO_VAL_INIT_T(transaction);
tx.version = tx_version;
tx.vin.clear();
tx.vout.clear();
tx.extra.clear();
keypair txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub);

View file

@ -229,6 +229,35 @@ namespace currency
CHECK_AND_ASSERT_THROW_MES(false, "[get_key_offsets_from_txin_v] Wrong type: " << in_v.type().name());
}
//---------------------------------------------------------------
inline
bool get_mix_attr_from_tx_out_v(const tx_out_v& out_v, uint8_t& result) noexcept
{
try
{
if (out_v.type() == typeid(tx_out_bare))
{
const tx_out_bare& ob = boost::get<tx_out_bare>(out_v);
if (ob.target.type() == typeid(txout_to_key))
{
result = boost::get<txout_to_key>(ob.target).mix_attr;
return true;
}
}
if (out_v.type() == typeid(tx_out_zarcanum))
{
result = boost::get<tx_out_zarcanum>(out_v).mix_attr;
return true;
}
}
catch(...)
{
// should never go here, just precaution
}
return false;
}
//---------------------------------------------------------------
//, txin_htlc, txin_zc_input
inline bool compare_variant_by_types(const txin_multisig& left, const txin_multisig& right)
{