forked from lthn/blockchain
transition to multi-types vout(in progress)
This commit is contained in:
parent
d593cf53a9
commit
0833566d96
6 changed files with 524 additions and 340 deletions
41
src/common/variant_helper.h
Normal file
41
src/common/variant_helper.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// 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
|
||||
|
||||
#define VARIANT_SWITCH_BEGIN(v_type_obj) {decltype(v_type_obj)& local_reference_eokcmeokmeokcm = v_type_obj; if(false) {;
|
||||
#define VARIANT_CASE(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { v_type& typed_name = boost::get<v_type>(local_reference_eokcmeokmeokcm);
|
||||
#define VARIANT_CASE_TV(v_type) VARIANT_CASE(v_type, tv)
|
||||
#define VARIANT_CASE_OTHER() } else {
|
||||
#define VARIANT_CASE_THROW_ON_OTHER() } else { ASSERT_MES_AND_THROW("Unknown type in switch statemet: " << local_reference_eokcmeokmeokcm.type().name());
|
||||
|
||||
#define VARIANT_SWITCH_END() } }
|
||||
|
||||
|
||||
/*
|
||||
|
||||
usage:
|
||||
|
||||
|
||||
VARIANT_SWITCH_BEGIN(o);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
|
||||
|
||||
|
||||
VARIANT_SWITCH_BEGIN(o);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -2478,42 +2478,50 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU
|
|||
<< out_ptr->out_no << " more than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id);
|
||||
|
||||
const transaction& tx = tx_ptr->tx;
|
||||
if (tx.vout[out_ptr->out_no].target.type() == typeid(txout_htlc))
|
||||
VARIANT_SWITCH_BEGIN(tx.vout[out_ptr->out_no]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
{
|
||||
//silently return false, it's ok
|
||||
return false;
|
||||
if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
//silently return false, it's ok
|
||||
return false;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "unknown tx out type");
|
||||
const txout_to_key& otk = boost::get<txout_to_key>(o.target);
|
||||
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() == tx.vout.size(), false, "internal error");
|
||||
|
||||
//do not use outputs that obviously spent for mixins
|
||||
if (tx_ptr->m_spent_flags[out_ptr->out_no])
|
||||
return false;
|
||||
|
||||
// do not use burned coins
|
||||
if (otk.key == null_pkey)
|
||||
return false;
|
||||
|
||||
//check if transaction is unlocked
|
||||
if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx, out_ptr->out_no)))
|
||||
return false;
|
||||
|
||||
//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;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(tx.vout[out_ptr->out_no].target.type() == typeid(txout_to_key), false, "unknown tx out type");
|
||||
const txout_to_key& otk = boost::get<txout_to_key>(tx.vout[out_ptr->out_no].target);
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() == tx.vout.size(), false, "internal error");
|
||||
|
||||
//do not use outputs that obviously spent for mixins
|
||||
if (tx_ptr->m_spent_flags[out_ptr->out_no])
|
||||
return false;
|
||||
|
||||
// do not use burned coins
|
||||
if (otk.key == null_pkey)
|
||||
return false;
|
||||
|
||||
//check if transaction is unlocked
|
||||
if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx, out_ptr->out_no)))
|
||||
return false;
|
||||
|
||||
//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;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -3014,10 +3022,15 @@ void blockchain_storage::print_blockchain_outs_stats() const
|
|||
if (!spent)
|
||||
++stat.unspent;
|
||||
|
||||
if (!spent && p_tx->tx.vout[output_entry.out_no].target.type() == typeid(txout_to_key))
|
||||
if (!spent)// && p_tx->tx.vout[output_entry.out_no].target.type() == typeid(txout_to_key))
|
||||
{
|
||||
if (boost::get<txout_to_key>(p_tx->tx.vout[output_entry.out_no].target).mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
|
||||
++stat.mixable;
|
||||
VARIANT_SWITCH_BEGIN(p_tx->tx.vout[output_entry.out_no]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (boost::get<txout_to_key>(o.target).mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
|
||||
++stat.mixable;
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
@ -3329,28 +3342,33 @@ bool blockchain_storage::push_transaction_to_global_outs_index(const transaction
|
|||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const auto& ot, tx.vout)
|
||||
BOOST_FOREACH(const auto& otv, tx.vout)
|
||||
{
|
||||
if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
m_db_outputs.push_back_item(ot.amount, global_output_entry::construct(tx_id, i));
|
||||
global_indexes.push_back(m_db_outputs.get_item_size(ot.amount) - 1);
|
||||
if (ot.target.type() == typeid(txout_htlc) && !is_after_hardfork_3_zone())
|
||||
VARIANT_SWITCH_BEGIN(otv);
|
||||
VARIANT_CASE(tx_out_bare, ot)
|
||||
if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
LOG_ERROR("Error: Transaction with txout_htlc before is_after_hardfork_3_zone(before height " << m_core_runtime_config.hard_forks.hard_fork_03_starts_after_height <<")");
|
||||
return false;
|
||||
m_db_outputs.push_back_item(ot.amount, global_output_entry::construct(tx_id, i));
|
||||
global_indexes.push_back(m_db_outputs.get_item_size(ot.amount) - 1);
|
||||
if (ot.target.type() == typeid(txout_htlc) && !is_after_hardfork_3_zone())
|
||||
{
|
||||
LOG_ERROR("Error: Transaction with txout_htlc before is_after_hardfork_3_zone(before height " << m_core_runtime_config.hard_forks.hard_fork_03_starts_after_height << ")");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ot.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
|
||||
crypto::hash multisig_out_id = get_multisig_out_id(tx, i);
|
||||
CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id);
|
||||
CHECK_AND_ASSERT_MES(!m_db_multisig_outs.find(multisig_out_id), false, "Internal error: already have multisig_out_id " << multisig_out_id << "in multisig outs index");
|
||||
m_db_multisig_outs.set(multisig_out_id, ms_output_entry::construct(tx_id, i));
|
||||
global_indexes.push_back(0); // just stub to make other code easier
|
||||
}
|
||||
else if (ot.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
|
||||
crypto::hash multisig_out_id = get_multisig_out_id(tx, i);
|
||||
CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id);
|
||||
CHECK_AND_ASSERT_MES(!m_db_multisig_outs.find(multisig_out_id), false, "Internal error: already have multisig_out_id " << multisig_out_id << "in multisig outs index");
|
||||
m_db_multisig_outs.set(multisig_out_id, ms_output_entry::construct(tx_id, i));
|
||||
global_indexes.push_back(0); // just stub to make other code easier
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
++i;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -3378,13 +3396,20 @@ bool blockchain_storage::get_outs(uint64_t amount, std::list<crypto::public_key>
|
|||
CHECK_AND_ASSERT_MES(tx_ptr, false, "transactions outs global index consistency broken: can't find tx " << out_entry_ptr->tx_id << " in DB, for amount: " << amount << ", gindex: " << i);
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_entry_ptr->out_no, false, "transactions outs global index consistency broken: index in tx_outx == " << out_entry_ptr->out_no << " is greather than tx.vout size == " << tx_ptr->tx.vout.size() << ", for amount: " << amount << ", gindex: " << i);
|
||||
//CHECK_AND_ASSERT_MES(tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_to_key), false, "transactions outs global index consistency broken: out #" << out_entry_ptr->out_no << " in tx " << out_entry_ptr->tx_id << " has wrong type, for amount: " << amount << ", gindex: " << i);
|
||||
if (tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_to_key))
|
||||
{
|
||||
pkeys.push_back(boost::get<txout_to_key>(tx_ptr->tx.vout[out_entry_ptr->out_no].target).key);
|
||||
}else if(tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_htlc))
|
||||
{
|
||||
pkeys.push_back(boost::get<txout_htlc>(tx_ptr->tx.vout[out_entry_ptr->out_no].target).pkey_redeem);
|
||||
}
|
||||
VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[out_entry_ptr->out_no]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
pkeys.push_back(boost::get<txout_to_key>(o.target).key);
|
||||
}
|
||||
else if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
pkeys.push_back(boost::get<txout_htlc>(o.target).pkey_redeem);
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -3394,26 +3419,32 @@ bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx
|
|||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
size_t i = tx.vout.size()-1;
|
||||
BOOST_REVERSE_FOREACH(const auto& ot, tx.vout)
|
||||
BOOST_REVERSE_FOREACH(const auto& otv, tx.vout)
|
||||
{
|
||||
if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
uint64_t sz= m_db_outputs.get_item_size(ot.amount);
|
||||
CHECK_AND_ASSERT_MES(sz, false, "transactions outs global index: empty index for amount: " << ot.amount);
|
||||
auto back_item = m_db_outputs.get_subitem(ot.amount, sz - 1);
|
||||
CHECK_AND_ASSERT_MES(back_item->tx_id == tx_id, false, "transactions outs global index consistency broken: tx id missmatch");
|
||||
CHECK_AND_ASSERT_MES(back_item->out_no == i, false, "transactions outs global index consistency broken: in transaction index missmatch");
|
||||
m_db_outputs.pop_back_item(ot.amount);
|
||||
//if (!it->second.size())
|
||||
// m_db_outputs.erase(it);
|
||||
}
|
||||
else if (ot.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
crypto::hash multisig_out_id = get_multisig_out_id(tx, i);
|
||||
CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id);
|
||||
bool res = m_db_multisig_outs.erase_validate(multisig_out_id);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index");
|
||||
}
|
||||
VARIANT_SWITCH_BEGIN(otv);
|
||||
VARIANT_CASE(tx_out_bare, ot)
|
||||
if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
uint64_t sz = m_db_outputs.get_item_size(ot.amount);
|
||||
CHECK_AND_ASSERT_MES(sz, false, "transactions outs global index: empty index for amount: " << ot.amount);
|
||||
auto back_item = m_db_outputs.get_subitem(ot.amount, sz - 1);
|
||||
CHECK_AND_ASSERT_MES(back_item->tx_id == tx_id, false, "transactions outs global index consistency broken: tx id missmatch");
|
||||
CHECK_AND_ASSERT_MES(back_item->out_no == i, false, "transactions outs global index consistency broken: in transaction index missmatch");
|
||||
m_db_outputs.pop_back_item(ot.amount);
|
||||
//if (!it->second.size())
|
||||
// m_db_outputs.erase(it);
|
||||
}
|
||||
else if (ot.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
crypto::hash multisig_out_id = get_multisig_out_id(tx, i);
|
||||
CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id);
|
||||
bool res = m_db_multisig_outs.erase_validate(multisig_out_id);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index");
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
--i;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -4147,12 +4178,15 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const
|
|||
CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() == tx_ptr->m_global_output_indexes.size(), false, "Internal error: output size missmatch");
|
||||
for (uint64_t i = 0; i!= tx_ptr->tx.vout.size();i++)
|
||||
{
|
||||
strm_tx << "[" << i << "]: " << print_money(tx_ptr->tx.vout[i].amount) << ENDL;
|
||||
if (tx_ptr->tx.vout[i].target.type() != typeid(currency::txout_to_key))
|
||||
continue;
|
||||
|
||||
usage_stat[tx_ptr->tx.vout[i].amount][tx_ptr->m_global_output_indexes[i]];
|
||||
|
||||
VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[i]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
strm_tx << "[" << i << "]: " << print_money(o.amount) << ENDL;
|
||||
if (o.target.type() != typeid(currency::txout_to_key))
|
||||
continue;
|
||||
usage_stat[o.amount][tx_ptr->m_global_output_indexes[i]];
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
||||
LOG_PRINT_L0("Lookup in all transactions....");
|
||||
|
|
@ -4521,7 +4555,9 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index,
|
|||
LOC_CHK(is_tx_spendtime_unlocked(unlock_time), "Source transaction is LOCKED! unlock_time: " << unlock_time << ", now is " << m_core_runtime_config.get_core_time() << ", blockchain size is " << get_current_blockchain_size());
|
||||
|
||||
LOC_CHK(source_tx.vout.size() > out_n, "internal error: out_n==" << out_n << " is out-of-bounds of source_tx.vout, size=" << source_tx.vout.size());
|
||||
const tx_out_bare& source_tx_out = source_tx.vout[out_n];
|
||||
LOC_CHK(source_tx.vout[out_n].type() !== typeid(tx_out_bare), "internal error: out_n==" << out_n << " has unexpected type: " << source_tx.vout[out_n].type().name());
|
||||
|
||||
const tx_out_bare& source_tx_out = boost::get<tx_out_bare>(source_tx.vout[out_n]);
|
||||
const txout_multisig& source_ms_out_target = boost::get<txout_multisig>(source_tx_out.target);
|
||||
|
||||
LOC_CHK(txin.sigs_count == source_ms_out_target.minimum_sigs,
|
||||
|
|
@ -4614,7 +4650,8 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
auto source_tx_ptr = m_db_transactions.find(source_tx_id);
|
||||
LOC_CHK(source_tx_ptr, "Can't find source transaction");
|
||||
LOC_CHK(source_tx_ptr->tx.vout.size() > n, "ms output index is incorrect, source tx's vout size is " << source_tx_ptr->tx.vout.size());
|
||||
LOC_CHK(source_tx_ptr->tx.vout[n].target.type() == typeid(txout_multisig), "ms output has wrong type, txout_multisig expected");
|
||||
LOC_CHK(source_tx_ptr->tx.vout[n].type() != = typeid(tx_out_bare), "internal error: out_n==" << n << " has unexpected type: " << source_tx_ptr->tx.vout[n].type().name());
|
||||
LOC_CHK(boost::get<tx_out_bare>(source_tx_ptr->tx.vout[n]).target.type() == typeid(txout_multisig), "ms output has wrong type, txout_multisig expected");
|
||||
LOC_CHK(source_tx_ptr->m_spent_flags.size() > n, "Internal error, m_spent_flags size (" << source_tx_ptr->m_spent_flags.size() << ") less then expected, n: " << n);
|
||||
LOC_CHK(source_tx_ptr->m_spent_flags[n] == false, "Internal error, ms output is already spent"); // should never happen as multisig_ptr->spent_height is checked above
|
||||
|
||||
|
|
@ -4958,6 +4995,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
|
|||
bool var_is_after_hardfork_1_zone = is_after_hardfork_1_zone(block_height);
|
||||
bool var_is_after_hardfork_2_zone = is_after_hardfork_2_zone(block_height);
|
||||
bool var_is_after_hardfork_3_zone = is_after_hardfork_3_zone(block_height);
|
||||
bool var_is_after_hardfork_4_zone = is_after_hardfork_4_zone(block_height);
|
||||
|
||||
//inputs
|
||||
for (const auto in : tx.vin)
|
||||
|
|
@ -4971,11 +5009,17 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
|
|||
//outputs
|
||||
for (const auto out : tx.vout)
|
||||
{
|
||||
if (out.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
if (!var_is_after_hardfork_3_zone)
|
||||
VARIANT_SWITCH_BEGIN(out);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
if (!var_is_after_hardfork_3_zone)
|
||||
return false;
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
if (!var_is_after_hardfork_4_zone)
|
||||
return false;
|
||||
}
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
||||
//extra
|
||||
|
|
@ -5025,7 +5069,14 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio
|
|||
uint64_t unlock_value = ut2.unlock_time_array[i];
|
||||
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(unlock_value), false, "output #" << i << " is locked by time, not buy height, which is not allowed for PoS coinbase");
|
||||
if (unlock_value >= source_max_unlock_time)
|
||||
amount_of_coins_in_unlock_in_range += miner_tx.vout[i].amount;
|
||||
{
|
||||
VARIANT_SWITCH_BEGIN(miner_tx.vout[i]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
amount_of_coins_in_unlock_in_range += o.amount;
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
}
|
||||
|
||||
if (amount_of_coins_in_unlock_in_range >= staked_amount)
|
||||
|
|
@ -5780,6 +5831,18 @@ bool blockchain_storage::is_after_hardfork_3_zone(uint64_t height)const
|
|||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::is_after_hardfork_4_zone()const
|
||||
{
|
||||
return is_after_hardfork_4_zone(m_db_blocks.size());
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::is_after_hardfork_4_zone(uint64_t height)const
|
||||
{
|
||||
if (height > m_core_runtime_config.hard_forks.hard_fork_04_starts_after_height)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::prevalidate_block(const block& bl)
|
||||
{
|
||||
//before hard_fork1
|
||||
|
|
@ -6439,97 +6502,110 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
|
|||
uint64_t height_of_source_block = it->second.second;
|
||||
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
|
||||
|
||||
/*
|
||||
here we do validation against compatibility of input and output type
|
||||
|
||||
TxOutput | TxInput | Allowed
|
||||
----------------------------
|
||||
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
|
||||
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
|
||||
TO_KEY | HTLC | NOT
|
||||
TO_KEY | TO_KEY | YES
|
||||
*/
|
||||
|
||||
//source tx found in altchain
|
||||
CHECK_AND_ASSERT_MES(it->second.first.vout.size() > out_n, false, "Internal error: out_n(" << out_n << ") >= it->second.vout.size()(" << it->second.first.vout.size() << ")");
|
||||
txout_target_v out_target_v = it->second.first.vout[out_n].target;
|
||||
|
||||
bool r = is_output_allowed_for_input(out_target_v, input_v, height_of_current_alt_block - height_of_source_block);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
|
||||
VARIANT_SWITCH_BEGIN(it->second.first.vout[out_n]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
{
|
||||
/*
|
||||
here we do validation against compatibility of input and output type
|
||||
|
||||
TxOutput | TxInput | Allowed
|
||||
----------------------------
|
||||
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
|
||||
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
|
||||
TO_KEY | HTLC | NOT
|
||||
TO_KEY | TO_KEY | YES
|
||||
*/
|
||||
txout_target_v out_target_v = o.target;
|
||||
|
||||
if (out_target_v.type() == typeid(txout_htlc))
|
||||
{
|
||||
//source is hltc out
|
||||
const txout_htlc& htlc = boost::get<txout_htlc>(out_target_v);
|
||||
bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true;
|
||||
pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem;
|
||||
pub_key_pointers.push_back(&pk);
|
||||
continue;
|
||||
}
|
||||
else if (out_target_v.type() == typeid(txout_to_key))
|
||||
{
|
||||
//source is to_key out
|
||||
pk = boost::get<txout_to_key>(out_target_v).key;
|
||||
pub_key_pointers.push_back(&pk);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_MES_AND_THROW("Unexpected out type for tx_in in altblock: " << out_target_v.type().name());
|
||||
bool r = is_output_allowed_for_input(out_target_v, input_v, height_of_current_alt_block - height_of_source_block);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
|
||||
if (out_target_v.type() == typeid(txout_htlc))
|
||||
{
|
||||
//source is hltc out
|
||||
const txout_htlc& htlc = boost::get<txout_htlc>(out_target_v);
|
||||
bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true;
|
||||
pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem;
|
||||
pub_key_pointers.push_back(&pk);
|
||||
continue;
|
||||
}
|
||||
else if (out_target_v.type() == typeid(txout_to_key))
|
||||
{
|
||||
//source is to_key out
|
||||
pk = boost::get<txout_to_key>(out_target_v).key;
|
||||
pub_key_pointers.push_back(&pk);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_MES_AND_THROW("Unexpected out type for tx_in in altblock: " << out_target_v.type().name());
|
||||
}
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto p = m_db_transactions.get(tx_id);
|
||||
CHECK_AND_ASSERT_MES(p != nullptr && out_n < p->tx.vout.size(), false, "can't find output #" << out_n << " for tx " << tx_id << " referred by offset #" << pk_n);
|
||||
auto &t = p->tx.vout[out_n].target;
|
||||
|
||||
/*
|
||||
here we do validation against compatibility of input and output type
|
||||
|
||||
TxOutput | TxInput | Allowed
|
||||
----------------------------
|
||||
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
|
||||
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
|
||||
TO_KEY | HTLC | NOT
|
||||
TO_KEY | TO_KEY | YES
|
||||
*/
|
||||
uint64_t height_of_source_block = p->m_keeper_block_height;
|
||||
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
|
||||
bool r = is_output_allowed_for_input(t, input_v, height_of_current_alt_block - height_of_source_block);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
|
||||
|
||||
if (t.type() == typeid(txout_to_key))
|
||||
VARIANT_SWITCH_BEGIN(p->tx.vout[out_n]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
{
|
||||
const txout_to_key& out_tk = boost::get<txout_to_key>(t);
|
||||
pk = out_tk.key;
|
||||
auto &t = o.target;
|
||||
|
||||
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(out_tk.mix_attr, abs_key_offsets.size() - 1);
|
||||
CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size());
|
||||
/*
|
||||
here we do validation against compatibility of input and output type
|
||||
|
||||
TxOutput | TxInput | Allowed
|
||||
----------------------------
|
||||
HTLC | HTLC | ONLY IF HTLC NOT EXPIRED
|
||||
HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED
|
||||
TO_KEY | HTLC | NOT
|
||||
TO_KEY | TO_KEY | YES
|
||||
*/
|
||||
uint64_t height_of_source_block = p->m_keeper_block_height;
|
||||
CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed");
|
||||
bool r = is_output_allowed_for_input(t, input_v, height_of_current_alt_block - height_of_source_block);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
|
||||
|
||||
if (t.type() == typeid(txout_to_key))
|
||||
{
|
||||
const txout_to_key& out_tk = boost::get<txout_to_key>(t);
|
||||
pk = out_tk.key;
|
||||
|
||||
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(out_tk.mix_attr, abs_key_offsets.size() - 1);
|
||||
CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size());
|
||||
|
||||
}
|
||||
else if (t.type() == typeid(txout_htlc))
|
||||
{
|
||||
const txout_htlc& htlc = boost::get<txout_htlc>(t);
|
||||
bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true;
|
||||
pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem;
|
||||
}
|
||||
|
||||
// case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid)
|
||||
CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height);
|
||||
|
||||
if (p_max_related_block_height != nullptr && *p_max_related_block_height < p->m_keeper_block_height)
|
||||
*p_max_related_block_height = p->m_keeper_block_height;
|
||||
|
||||
// TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks()
|
||||
// make sure it was actually found
|
||||
|
||||
// let's disable this check due to missing equal check in main chain validation code
|
||||
//TODO: implement more strict validation with next hard fork
|
||||
//CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n);
|
||||
pub_key_pointers.push_back(&pk);
|
||||
}
|
||||
else if (t.type() == typeid(txout_htlc))
|
||||
{
|
||||
const txout_htlc& htlc = boost::get<txout_htlc>(t);
|
||||
bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true;
|
||||
pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem;
|
||||
}
|
||||
|
||||
// case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid)
|
||||
CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height);
|
||||
|
||||
if (p_max_related_block_height != nullptr && *p_max_related_block_height < p->m_keeper_block_height)
|
||||
*p_max_related_block_height = p->m_keeper_block_height;
|
||||
|
||||
// TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks()
|
||||
// make sure it was actually found
|
||||
|
||||
// let's disable this check due to missing equal check in main chain validation code
|
||||
//TODO: implement more strict validation with next hard fork
|
||||
//CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n);
|
||||
pub_key_pointers.push_back(&pk);
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
|
||||
// do input checks (attachment_info, ring signature and extra signature, etc.)
|
||||
|
|
@ -6689,17 +6765,22 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx
|
|||
|
||||
for (size_t out_n = 0; out_n < tx.vout.size(); ++out_n)
|
||||
{
|
||||
const tx_out_bare& out = tx.vout[out_n];
|
||||
if (out.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
const crypto::hash& ms_out_id = get_multisig_out_id(tx, out_n);
|
||||
if (ms_out_id == input.multisig_out_id)
|
||||
VARIANT_SWITCH_BEGIN(tx.vout[out_n]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
const tx_out_bare& out = o;
|
||||
if (out.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
// cases g3, g4, g5
|
||||
output_found = true;
|
||||
return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, tx, out_n);
|
||||
const crypto::hash& ms_out_id = get_multisig_out_id(tx, out_n);
|
||||
if (ms_out_id == input.multisig_out_id)
|
||||
{
|
||||
// cases g3, g4, g5
|
||||
output_found = true;
|
||||
return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, tx, out_n);
|
||||
}
|
||||
}
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
@ -6747,29 +6828,34 @@ bool blockchain_storage::get_transaction_from_pool_or_db(const crypto::hash& tx_
|
|||
bool blockchain_storage::update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei) const
|
||||
{
|
||||
//add tx outputs to gindex_lookup_table
|
||||
for (auto o : tx.vout)
|
||||
for (auto ov : tx.vout)
|
||||
{
|
||||
if (o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
//LOG_PRINT_MAGENTA("ALT_OUT KEY ON H[" << abei.height << "] AMOUNT: " << o.amount, LOG_LEVEL_0);
|
||||
// first, look at local gindexes tables
|
||||
if (abei.gindex_lookup_table.find(o.amount) == abei.gindex_lookup_table.end())
|
||||
VARIANT_SWITCH_BEGIN(ov);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
// amount was not found in altchain gindexes container, start indexing from current main chain gindex
|
||||
abei.gindex_lookup_table[o.amount] = m_db_outputs.get_item_size(o.amount);
|
||||
//LOG_PRINT_MAGENTA("FIRST TOUCH: size=" << abei.gindex_lookup_table[o.amount], LOG_LEVEL_0);
|
||||
//LOG_PRINT_MAGENTA("ALT_OUT KEY ON H[" << abei.height << "] AMOUNT: " << o.amount, LOG_LEVEL_0);
|
||||
// first, look at local gindexes tables
|
||||
if (abei.gindex_lookup_table.find(o.amount) == abei.gindex_lookup_table.end())
|
||||
{
|
||||
// amount was not found in altchain gindexes container, start indexing from current main chain gindex
|
||||
abei.gindex_lookup_table[o.amount] = m_db_outputs.get_item_size(o.amount);
|
||||
//LOG_PRINT_MAGENTA("FIRST TOUCH: size=" << abei.gindex_lookup_table[o.amount], LOG_LEVEL_0);
|
||||
}
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
abei.outputs_pub_keys[o.amount].push_back(boost::get<txout_to_key>(o.target).key);
|
||||
}
|
||||
else
|
||||
{
|
||||
abei.outputs_pub_keys[o.amount].push_back(boost::get<txout_htlc>(o.target));
|
||||
}
|
||||
|
||||
//TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation
|
||||
}
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
abei.outputs_pub_keys[o.amount].push_back(boost::get<txout_to_key>(o.target).key);
|
||||
}
|
||||
else
|
||||
{
|
||||
abei.outputs_pub_keys[o.amount].push_back(boost::get<txout_htlc>(o.target));
|
||||
}
|
||||
|
||||
//TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -667,8 +667,8 @@ namespace currency
|
|||
bool is_after_hardfork_2_zone(uint64_t height)const;
|
||||
bool is_after_hardfork_3_zone()const;
|
||||
bool is_after_hardfork_3_zone(uint64_t height)const;
|
||||
// bool is_after_hardfork_4_zone()const;
|
||||
// bool is_after_hardfork_4_zone(uint64_t height)const;
|
||||
bool is_after_hardfork_4_zone()const;
|
||||
bool is_after_hardfork_4_zone(uint64_t height)const;
|
||||
|
||||
|
||||
|
||||
|
|
@ -776,55 +776,65 @@ namespace currency
|
|||
TO_KEY | TO_KEY | YES
|
||||
*/
|
||||
|
||||
bool r = is_output_allowed_for_input(tx_ptr->tx.vout[n].target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
|
||||
|
||||
if (tx_ptr->tx.vout[n].target.type() == typeid(txout_to_key))
|
||||
VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[n]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(tx_ptr->tx.vout[n].target, const txout_to_key, outtk, false);
|
||||
//fix for burned money
|
||||
patch_out_if_needed(const_cast<txout_to_key&>(outtk), tx_id, n);
|
||||
bool r = is_output_allowed_for_input(o.target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
|
||||
|
||||
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(outtk.mix_attr, key_offsets.size() - 1);
|
||||
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx output #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size());
|
||||
}
|
||||
else if (tx_ptr->tx.vout[n].target.type() == typeid(txout_htlc))
|
||||
{
|
||||
//check for spend flags
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false,
|
||||
"Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}");
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected");
|
||||
|
||||
const txout_htlc& htlc_out = boost::get<txout_htlc>(tx_ptr->tx.vout[n].target);
|
||||
if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height)
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
//HTLC IS NOT expired, can be used ONLY by pkey_before_expiration and ONLY by HTLC input
|
||||
scan_context.htlc_is_expired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input
|
||||
scan_context.htlc_is_expired = true;
|
||||
}
|
||||
}else
|
||||
{
|
||||
LOG_ERROR("[scan_outputkeys_for_indexes]: Wrong output type in : " << tx_ptr->tx.vout[n].target.type().name());
|
||||
return false;
|
||||
}
|
||||
CHECKED_GET_SPECIFIC_VARIANT(o.target, const txout_to_key, outtk, false);
|
||||
//fix for burned money
|
||||
patch_out_if_needed(const_cast<txout_to_key&>(outtk), tx_id, n);
|
||||
|
||||
|
||||
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
if (!vis.handle_output(tx_ptr->tx, validated_tx, tx_ptr->tx.vout[n], n))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n);
|
||||
return false;
|
||||
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(outtk.mix_attr, key_offsets.size() - 1);
|
||||
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx output #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size());
|
||||
}
|
||||
else if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
//check for spend flags
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false,
|
||||
"Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}");
|
||||
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected");
|
||||
|
||||
const txout_htlc& htlc_out = boost::get<txout_htlc>(o.target);
|
||||
if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height)
|
||||
{
|
||||
//HTLC IS NOT expired, can be used ONLY by pkey_before_expiration and ONLY by HTLC input
|
||||
scan_context.htlc_is_expired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input
|
||||
scan_context.htlc_is_expired = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("[scan_outputkeys_for_indexes]: Wrong output type in : " << o.target.type().name());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
if (!vis.handle_output(tx_ptr->tx, validated_tx, tx_ptr->tx.vout[n], n))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
|
||||
if (max_related_block_height < tx_ptr->m_keeper_block_height)
|
||||
max_related_block_height = tx_ptr->m_keeper_block_height;
|
||||
|
||||
|
||||
if (max_related_block_height < tx_ptr->m_keeper_block_height)
|
||||
max_related_block_height = tx_ptr->m_keeper_block_height;
|
||||
|
||||
++output_index;
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop);
|
||||
|
|
|
|||
|
|
@ -525,8 +525,9 @@ namespace currency
|
|||
//msg.vin = tx.vin;
|
||||
msg.onetime_key = get_tx_pub_key_from_extra(tx);
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() > n, null_hash, "tx.vout.size() > n condition failed ");
|
||||
CHECK_AND_ASSERT_MES(tx.vout[n].target.type() == typeid(txout_multisig), null_hash, "tx.vout[n].target.type() == typeid(txout_multisig) condition failed");
|
||||
msg.vout.push_back(tx.vout[n]);
|
||||
CHECK_AND_ASSERT_MES(tx.vout[n].type() == typeid(tx_out_bare), null_hash, "Unexpected type of out:" << tx.vout[n].type().name());
|
||||
CHECK_AND_ASSERT_MES(boost::get<tx_out_bare>(tx.vout[n]).target.type() == typeid(txout_multisig), null_hash, "tx.vout[n].target.type() == typeid(txout_multisig) condition failed");
|
||||
msg.vout.push_back(boost::get<tx_out_bare>(tx.vout[n]));
|
||||
return get_object_hash(msg);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -1127,13 +1128,17 @@ namespace currency
|
|||
if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_CANCEL_PROPOSAL, tsa))
|
||||
return GUI_TX_TYPE_ESCROW_CANCEL_PROPOSAL;
|
||||
|
||||
for (auto o : tx.vout)
|
||||
for (auto ov : tx.vout)
|
||||
{
|
||||
if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
htlc_out = o;
|
||||
return GUI_TX_TYPE_HTLC_DEPOSIT;
|
||||
}
|
||||
VARIANT_SWITCH_BEGIN(ov);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
htlc_out = o;
|
||||
return GUI_TX_TYPE_HTLC_DEPOSIT;
|
||||
}
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
}
|
||||
|
||||
if (get_type_in_variant_container(tx.vin, htlc_in))
|
||||
|
|
@ -1272,7 +1277,7 @@ namespace currency
|
|||
{
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.signatures.clear();
|
||||
tx.signature.clear();
|
||||
tx.extra = extra;
|
||||
|
||||
tx.version = ftp.tx_version;
|
||||
|
|
@ -1597,7 +1602,12 @@ namespace currency
|
|||
uint64_t reward = 0;
|
||||
for (auto& out : tx.vout)
|
||||
{
|
||||
reward += out.amount;
|
||||
VARIANT_SWITCH_BEGIN(out);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
reward += o.amount;
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
reward -= income;
|
||||
return reward;
|
||||
|
|
@ -1648,14 +1658,20 @@ namespace currency
|
|||
size_t ms_out_index = SIZE_MAX;
|
||||
for (size_t i = 0; i < source_tx.vout.size(); ++i)
|
||||
{
|
||||
if (source_tx.vout[i].target.type() == typeid(txout_multisig) && ms_in.multisig_out_id == get_multisig_out_id(source_tx, i))
|
||||
{
|
||||
ms_out_index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
VARIANT_SWITCH_BEGIN(source_tx.vout[i]);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_multisig) && ms_in.multisig_out_id == get_multisig_out_id(source_tx, i))
|
||||
{
|
||||
ms_out_index = i;
|
||||
break;
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
LOC_CHK(ms_out_index != SIZE_MAX, "failed to find ms output in source tx " << get_transaction_hash(source_tx) << " by ms id " << ms_in.multisig_out_id);
|
||||
const txout_multisig& out_ms = boost::get<txout_multisig>(source_tx.vout[ms_out_index].target);
|
||||
const txout_multisig& out_ms = boost::get<txout_multisig>( boost::get<tx_out_bare>(source_tx.vout[ms_out_index]).target);
|
||||
|
||||
crypto::public_key source_tx_pub_key = get_tx_pub_key_from_extra(source_tx);
|
||||
|
||||
|
|
@ -1667,7 +1683,7 @@ namespace currency
|
|||
LOC_CHK(participant_index < out_ms.keys.size(), "Can't find given participant's ms key in ms output keys list");
|
||||
LOC_CHK(ms_input_index < tx.signatures.size(), "transaction does not have signatures vectory entry for ms input #" << ms_input_index);
|
||||
|
||||
auto& sigs = tx.signatures[ms_input_index];
|
||||
auto& sigs = tx.signature[ms_input_index];
|
||||
LOC_CHK(!sigs.empty(), "empty signatures container");
|
||||
|
||||
bool extra_signature_expected = (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) && ms_input_index == tx.vin.size() - 1;
|
||||
|
|
@ -1801,36 +1817,37 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_outs_valid(const transaction& tx)
|
||||
{
|
||||
for(const tx_out_bare& out : tx.vout)
|
||||
for(const auto& vo : tx.vout)
|
||||
{
|
||||
CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
|
||||
if (out.target.type() == typeid(txout_to_key))
|
||||
|
||||
VARIANT_SWITCH_BEGIN(vo);
|
||||
VARIANT_CASE(tx_out_bare, out)
|
||||
{
|
||||
if (!check_key(boost::get<txout_to_key>(out.target).key))
|
||||
return false;
|
||||
}
|
||||
else if (out.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
const txout_htlc& htlc = boost::get<txout_htlc>(out.target);
|
||||
if (!check_key(htlc.pkey_redeem))
|
||||
return false;
|
||||
if (!check_key(htlc.pkey_refund))
|
||||
return false;
|
||||
}
|
||||
else if (out.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
const txout_multisig& ms = boost::get<txout_multisig>(out.target);
|
||||
if (!(ms.keys.size() > 0 && ms.minimum_sigs > 0 && ms.minimum_sigs <= ms.keys.size()))
|
||||
{
|
||||
LOG_ERROR("wrong multisig in transaction id=" << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("wrong variant type: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
VARIANT_SWITCH_BEGIN(out.target);
|
||||
VARIANT_CASE(txout_to_key, tk)
|
||||
if (!check_key(tk.key))
|
||||
return false;
|
||||
VARIANT_CASE(txout_htlc, htlc)
|
||||
if (!check_key(htlc.pkey_redeem))
|
||||
return false;
|
||||
if (!check_key(htlc.pkey_refund))
|
||||
return false;
|
||||
VARIANT_CASE(txout_multisig, ms)
|
||||
if (!(ms.keys.size() > 0 && ms.minimum_sigs > 0 && ms.minimum_sigs <= ms.keys.size()))
|
||||
{
|
||||
LOG_ERROR("wrong multisig in transaction id=" << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
VARIANT_CASE_OTHER()
|
||||
LOG_ERROR("wrong variant type: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1878,9 +1895,14 @@ namespace currency
|
|||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
{
|
||||
if (money > o.amount + money)
|
||||
return false;
|
||||
money += o.amount;
|
||||
VARIANT_SWITCH_BEGIN(o);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (money > o.amount + money)
|
||||
return false;
|
||||
money += o.amount;
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1888,8 +1910,15 @@ namespace currency
|
|||
uint64_t get_outs_money_amount(const transaction& tx)
|
||||
{
|
||||
uint64_t outputs_amount = 0;
|
||||
for(const auto& o : tx.vout)
|
||||
outputs_amount += o.amount;
|
||||
for (const auto& o : tx.vout)
|
||||
{
|
||||
VARIANT_SWITCH_BEGIN(o);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
outputs_amount += o.amount;
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return outputs_amount;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -1962,7 +1991,10 @@ namespace currency
|
|||
return true;
|
||||
|
||||
CHECK_AND_ASSERT_MES(offset < tx.vout.size(), false, "condition failed: offset(" << offset << ") < tx.vout.size() (" << tx.vout.size() << ")");
|
||||
auto& o = tx.vout[offset];
|
||||
auto& ov = tx.vout[offset];
|
||||
CHECK_AND_ASSERT_MES(ov.type() == typeid(tx_out_bare), false, "unexpected type id in lookup_acc_outs_genesis:" << ov.type().name());
|
||||
const tx_out_bare& o = boost::get<tx_out_bare>(ov);
|
||||
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "condition failed: o.target.type() == typeid(txout_to_key)");
|
||||
if (is_out_to_acc(acc, boost::get<txout_to_key>(o.target), derivation, offset))
|
||||
{
|
||||
|
|
@ -1994,46 +2026,46 @@ namespace currency
|
|||
return true;
|
||||
|
||||
size_t i = 0;
|
||||
for(const tx_out_bare& o : tx.vout)
|
||||
for(const auto& ov : tx.vout)
|
||||
{
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
VARIANT_SWITCH_BEGIN(ov);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
{
|
||||
if (is_out_to_acc(acc, boost::get<txout_to_key>(o.target), derivation, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
money_transfered += o.amount;
|
||||
}
|
||||
}
|
||||
else if (o.target.type() == typeid(txout_multisig))
|
||||
{
|
||||
if (is_out_to_acc(acc, boost::get<txout_multisig>(o.target), derivation, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
//don't count this money
|
||||
}
|
||||
}
|
||||
else if (o.target.type() == typeid(txout_htlc))
|
||||
{
|
||||
htlc_info hi = AUTO_VAL_INIT(hi);
|
||||
const txout_htlc& htlc = boost::get<txout_htlc>(o.target);
|
||||
if (is_out_to_acc(acc, htlc.pkey_redeem, derivation, i))
|
||||
{
|
||||
hi.hltc_our_out_is_before_expiration = true;
|
||||
htlc_info_list.push_back(hi);
|
||||
outs.push_back(i);
|
||||
}
|
||||
else if (is_out_to_acc(acc, htlc.pkey_refund, derivation, i))
|
||||
{
|
||||
hi.hltc_our_out_is_before_expiration = false;
|
||||
htlc_info_list.push_back(hi);
|
||||
outs.push_back(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name());
|
||||
return false;
|
||||
VARIANT_SWITCH_BEGIN(o.target);
|
||||
VARIANT_CASE(txout_to_key, t)
|
||||
if (is_out_to_acc(acc, t, derivation, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
money_transfered += o.amount;
|
||||
}
|
||||
VARIANT_CASE(txout_multisig, t)
|
||||
if (is_out_to_acc(acc, t, derivation, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
//don't count this money
|
||||
}
|
||||
VARIANT_CASE(txout_htlc, htlc)
|
||||
htlc_info hi = AUTO_VAL_INIT(hi);
|
||||
if (is_out_to_acc(acc, htlc.pkey_redeem, derivation, i))
|
||||
{
|
||||
hi.hltc_our_out_is_before_expiration = true;
|
||||
htlc_info_list.push_back(hi);
|
||||
outs.push_back(i);
|
||||
}
|
||||
else if (is_out_to_acc(acc, htlc.pkey_refund, derivation, i))
|
||||
{
|
||||
hi.hltc_our_out_is_before_expiration = false;
|
||||
htlc_info_list.push_back(hi);
|
||||
outs.push_back(i);
|
||||
}
|
||||
VARIANT_CASE_OTHER()
|
||||
LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name());
|
||||
return false;
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "serialization/serialization.h"
|
||||
#include "currency_format_utils.h"
|
||||
#include "currency_format_utils_abstract.h"
|
||||
#include "variant_helper.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
|
@ -34,10 +35,6 @@ namespace currency
|
|||
//---------------------------------------------------------------
|
||||
|
||||
|
||||
#define VARIANT_SWITCH_BEGIN(v_type_obj) {decltype(v_type_obj)& local_reference_eokcmeokmeokcm = v_type_obj; if(false) {;
|
||||
#define VARIANT_CASE(v_type) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { v_type& v_type_obj##_typed = boost::get<v_type>(local_reference_eokcmeokmeokcm);
|
||||
#define VARIANT_CASE_OTHER(v_type) } else {
|
||||
#define VARIANT_SWITCH_END() } }
|
||||
|
||||
|
||||
|
||||
|
|
@ -46,11 +43,17 @@ namespace currency
|
|||
uint64_t res = 0;
|
||||
for (auto& o : tx.vout)
|
||||
{
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
if (boost::get<txout_to_key>(o.target).key == null_pkey)
|
||||
res += o.amount;
|
||||
}
|
||||
VARIANT_SWITCH_BEGIN(o);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
if (boost::get<txout_to_key>(o.target).key == null_pkey)
|
||||
res += o.amount;
|
||||
}
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1330,8 +1330,15 @@ namespace currency
|
|||
idx = 0;
|
||||
for (const auto& out : tx.vout)
|
||||
{
|
||||
if (out.target.type() == typeid(txout_multisig))
|
||||
result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false }));
|
||||
VARIANT_SWITCH_BEGIN(out);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_multisig))
|
||||
result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false }));
|
||||
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
|
@ -1347,8 +1354,13 @@ namespace currency
|
|||
size_t idx = 0;
|
||||
for (const auto& out : tx.vout)
|
||||
{
|
||||
if (out.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id)
|
||||
return true;
|
||||
VARIANT_SWITCH_BEGIN(out);
|
||||
VARIANT_CASE(tx_out_bare, o)
|
||||
if (o.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id)
|
||||
return true;
|
||||
VARIANT_CASE_TV(tx_out_zarcanum)
|
||||
//@#@
|
||||
VARIANT_SWITCH_END();
|
||||
++idx;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue