forked from lthn/blockchain
Merge branch 'zarcanum' into multiassets
This commit is contained in:
commit
37f96db8d5
5 changed files with 120 additions and 55 deletions
|
|
@ -4378,9 +4378,10 @@ bool blockchain_storage::have_tx_keyimges_as_spent(const transaction &tx) const
|
|||
// check all tx's inputs for being already spent
|
||||
for (const txin_v& in : tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc))
|
||||
crypto::key_image ki = AUTO_VAL_INIT(ki);
|
||||
if (get_key_image_from_txin_v(in, ki))
|
||||
{
|
||||
if (have_tx_keyimg_as_spent(get_to_key_input_from_txin_v(in).k_image))
|
||||
if (have_tx_keyimg_as_spent(ki))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4390,12 +4391,6 @@ bool blockchain_storage::have_tx_keyimges_as_spent(const transaction &tx) const
|
|||
if (is_multisig_output_spent(boost::get<const txin_multisig>(in).multisig_out_id))
|
||||
return true;
|
||||
}
|
||||
else if (in.type() == typeid(txin_zc_input))
|
||||
{
|
||||
const auto& zcin = boost::get<txin_zc_input>(in);
|
||||
if (have_tx_keyimg_as_spent(zcin.k_image))
|
||||
return true;
|
||||
}
|
||||
else if (in.type() == typeid(txin_gen))
|
||||
{
|
||||
// skip txin_gen
|
||||
|
|
@ -4551,7 +4546,7 @@ struct outputs_visitor
|
|||
, m_scan_context(scan_context)
|
||||
{}
|
||||
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out_bare& out, uint64_t out_i)
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out_v& out_v, uint64_t out_i)
|
||||
{
|
||||
//check tx unlock time
|
||||
uint64_t source_out_unlock_time = get_tx_unlock_time(source_tx, out_i);
|
||||
|
|
@ -4571,15 +4566,20 @@ struct outputs_visitor
|
|||
}
|
||||
}
|
||||
|
||||
VARIANT_SWITCH_BEGIN(out.target)
|
||||
VARIANT_CASE_CONST(txout_to_key, out_tk)
|
||||
m_results_collector.push_back(out_tk.key);
|
||||
VARIANT_CASE_CONST(txout_htlc, out_htlc)
|
||||
m_scan_context.htlc_outs.push_back(out_htlc);
|
||||
m_results_collector.push_back(m_scan_context.htlc_is_expired ? out_htlc.pkey_refund : out_htlc.pkey_redeem);
|
||||
VARIANT_CASE_OTHER()
|
||||
LOG_PRINT_L0("Output have wrong type id, which=" << out.target.which());
|
||||
return false;
|
||||
VARIANT_SWITCH_BEGIN(out_v)
|
||||
VARIANT_CASE_CONST(tx_out_bare, out)
|
||||
VARIANT_SWITCH_BEGIN(out.target)
|
||||
VARIANT_CASE_CONST(txout_to_key, out_tk)
|
||||
m_results_collector.push_back(out_tk.key);
|
||||
VARIANT_CASE_CONST(txout_htlc, out_htlc)
|
||||
m_scan_context.htlc_outs.push_back(out_htlc);
|
||||
m_results_collector.push_back(m_scan_context.htlc_is_expired ? out_htlc.pkey_refund : out_htlc.pkey_redeem);
|
||||
VARIANT_CASE_OTHER()
|
||||
LOG_PRINT_L0("Output has wrong target type id: " << out.target.which());
|
||||
return false;
|
||||
VARIANT_SWITCH_END()
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, out_zc)
|
||||
m_scan_context.zc_outs.push_back(out_zc);
|
||||
VARIANT_SWITCH_END()
|
||||
|
||||
return true;
|
||||
|
|
@ -4881,15 +4881,15 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
// somehow we need to get a list<tx_out_zarcanum> this input is referring to
|
||||
// we need a list<tx_out_zarcanum> this input is referring to
|
||||
// and make sure that all of them are good (i.e. check 1) source tx unlock time validity; 2) mixin restrictions; 3) general gindex/ref_by_id corectness)
|
||||
// get_output_keys_for_input_with_checks is used for that
|
||||
//
|
||||
// get_output_keys_for_input_with_checks may be used for that, but at that time it needs refactoring
|
||||
//
|
||||
std::vector<crypto::public_key> output_keys; // won't be used
|
||||
std::vector<crypto::public_key> dummy_output_keys; // won't be used
|
||||
uint64_t dummy_source_max_unlock_time_for_pos_coinbase_dummy = 0; // won't be used
|
||||
scan_for_keys_context scan_contex = AUTO_VAL_INIT(scan_contex);
|
||||
uint64_t source_max_unlock_time_for_pos_coinbase_dummy = 0;
|
||||
if (!get_output_keys_for_input_with_checks(tx, zc_in, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase_dummy, scan_contex))
|
||||
|
||||
if (!get_output_keys_for_input_with_checks(tx, zc_in, dummy_output_keys, max_related_block_height, dummy_source_max_unlock_time_for_pos_coinbase_dummy, scan_contex))
|
||||
{
|
||||
LOG_PRINT_L0("get_output_keys_for_input_with_checks failed for input #" << in_index << ", key_offset.size = " << zc_in.key_offsets.size() << ")");
|
||||
return false;
|
||||
|
|
@ -4899,7 +4899,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
|
||||
// here we don't need to check zc_in.k_image validity because it is checked in verify_CLSAG_GG()
|
||||
|
||||
CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() > 0, false, "zero referenced outputs found");
|
||||
CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() == zc_in.key_offsets.size(), false, "incorrect number of referenced outputs found: " << scan_contex.zc_outs.size() << ", while " << zc_in.key_offsets.size() << " is expected.");
|
||||
CHECK_AND_ASSERT_MES(in_index < tx.signatures.size(), false, "tx.signatures.size (" << tx.signatures.size() << ") is less than or equal to in_index (" << in_index << ")");
|
||||
// TODO: consider additional checks here
|
||||
|
||||
|
|
@ -5048,23 +5048,15 @@ std::shared_ptr<const transaction_chain_entry> blockchain_storage::find_key_imag
|
|||
}
|
||||
for (auto& in : tx_chain_entry->tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc))
|
||||
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
|
||||
if (get_key_image_from_txin_v(in, k_image))
|
||||
{
|
||||
if (get_to_key_input_from_txin_v(in).k_image == ki)
|
||||
if (k_image == ki)
|
||||
{
|
||||
id_result = get_transaction_hash(tx_chain_entry->tx); // ??? @#@# why not just use tx_id ?
|
||||
return tx_chain_entry;
|
||||
}
|
||||
}
|
||||
else if (in.type() == typeid(txin_zc_input))
|
||||
{
|
||||
const auto& zc_in = boost::get<txin_zc_input>(in);
|
||||
if (zc_in.k_image == ki)
|
||||
{
|
||||
id_result = tx_id;
|
||||
return tx_chain_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6988,6 +6980,12 @@ bool blockchain_storage::is_output_allowed_for_input(const output_key_or_htlc_v&
|
|||
}
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in_v.type() == typeid(txin_zc_input), false, "tx_out_zarcanum can only be referenced by txin_zc_input, not by " << in_v.type().name());
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, uint64_t split_height, const alt_chain_type& alt_chain) const
|
||||
{
|
||||
// Main and alt chain outline:
|
||||
|
|
|
|||
|
|
@ -240,11 +240,11 @@ namespace currency
|
|||
|
||||
|
||||
template<class visitor_t>
|
||||
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_to_key& tx_in_to_key, visitor_t& vis)
|
||||
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& in_v, visitor_t& vis)
|
||||
{
|
||||
scan_for_keys_context cntx_stub = AUTO_VAL_INIT(cntx_stub);
|
||||
uint64_t stub = 0;
|
||||
return scan_outputkeys_for_indexes(validated_tx, tx_in_to_key, vis, stub, cntx_stub);
|
||||
return scan_outputkeys_for_indexes(validated_tx, in_v, vis, stub, cntx_stub);
|
||||
}
|
||||
template<class visitor_t>
|
||||
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& /*scan_context*/) const;
|
||||
|
|
@ -674,6 +674,7 @@ namespace currency
|
|||
bool is_output_allowed_for_input(const output_key_or_htlc_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
|
||||
bool is_output_allowed_for_input(const txout_to_key& out_v, const txin_v& in_v)const;
|
||||
bool is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
|
||||
bool is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const;
|
||||
|
||||
// returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage)
|
||||
bool is_hardfork_active(size_t hardfork_id) const;
|
||||
|
|
@ -724,10 +725,8 @@ namespace currency
|
|||
template<class visitor_t>
|
||||
bool blockchain_storage::scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& scan_context) const
|
||||
{
|
||||
const txin_to_key& input_to_key = get_to_key_input_from_txin_v(verified_input);
|
||||
|
||||
uint64_t amount = input_to_key.amount;
|
||||
const std::vector<txout_ref_v>& key_offsets = input_to_key.key_offsets;
|
||||
uint64_t amount = get_amount_from_variant(verified_input);
|
||||
const std::vector<txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(verified_input);
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size);
|
||||
|
|
@ -797,7 +796,7 @@ namespace currency
|
|||
patch_out_if_needed(const_cast<txout_to_key&>(outtk), tx_id, n);
|
||||
|
||||
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());
|
||||
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx input ref #" << 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))
|
||||
{
|
||||
|
|
@ -828,14 +827,25 @@ namespace currency
|
|||
|
||||
if (!vis.handle_output(tx_ptr->tx, validated_tx, o, n))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n);
|
||||
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id);
|
||||
return false;
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
}
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, oz)
|
||||
//@#@
|
||||
return false;
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, out_zc)
|
||||
bool r = is_output_allowed_for_input(out_zc, verified_input);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible");
|
||||
|
||||
r = is_mixattr_applicable_for_fake_outs_counter(out_zc.mix_attr, key_offsets.size() - 1);
|
||||
CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size());
|
||||
|
||||
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n))
|
||||
{
|
||||
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id);
|
||||
return false;
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
|
||||
VARIANT_CASE_THROW_ON_OTHER();
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
|
|
|
|||
|
|
@ -1688,7 +1688,7 @@ namespace currency
|
|||
sigs.resize(src_entr.outputs.size());
|
||||
|
||||
if (!watch_only_mode)
|
||||
crypto::generate_ring_signature(tx_hash_for_signature, get_to_key_input_from_txin_v(tx.vin[input_index]).k_image, keys_ptrs, in_context.in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
crypto::generate_ring_signature(tx_hash_for_signature, get_key_image_from_txin_v(tx.vin[input_index]), keys_ptrs, in_context.in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
|
||||
if (pss_ring_s)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ namespace currency
|
|||
return found;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// DEPRECATED, should be removed soon -- sowle
|
||||
inline
|
||||
const txin_to_key& get_to_key_input_from_txin_v(const txin_v& in_v)
|
||||
{
|
||||
|
|
@ -234,7 +235,22 @@ namespace currency
|
|||
if (in_v.type() == typeid(txin_zc_input))
|
||||
return boost::get<txin_zc_input>(in_v).k_image;
|
||||
|
||||
ASSERT_MES_AND_THROW("[get_key_image_from_txin_v] Wrong type: " << in_v.type().name());
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "[get_key_image_from_txin_v] Wrong type: " << in_v.type().name());
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
inline
|
||||
const std::vector<currency::txout_ref_v>& get_key_offsets_from_txin_v(const txin_v& in_v)
|
||||
{
|
||||
if (in_v.type() == typeid(txin_to_key))
|
||||
return boost::get<txin_to_key>(in_v).key_offsets;
|
||||
|
||||
if (in_v.type() == typeid(txin_htlc))
|
||||
return boost::get<txin_htlc>(in_v).key_offsets;
|
||||
|
||||
if (in_v.type() == typeid(txin_zc_input))
|
||||
return boost::get<txin_zc_input>(in_v).key_offsets;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "[get_key_offsets_from_txin_v] Wrong type: " << in_v.type().name());
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
//, txin_htlc, txin_zc_input
|
||||
|
|
|
|||
|
|
@ -24,6 +24,23 @@ const currency::account_base null_account = AUTO_VAL_INIT(null_account);
|
|||
//@#@: TODO: need refactoring, unsafe operations
|
||||
POD_MAKE_COMPARABLE(currency, tx_out_bare);
|
||||
|
||||
bool get_stealth_address_form_tx_out_v(const tx_out_v& out_v, crypto::public_key& result)
|
||||
{
|
||||
VARIANT_SWITCH_BEGIN(out_v);
|
||||
VARIANT_CASE_CONST(tx_out_bare, out_b);
|
||||
VARIANT_SWITCH_BEGIN(out_b.target);
|
||||
VARIANT_CASE_CONST(txout_to_key, otk);
|
||||
result = otk.key;
|
||||
return true;
|
||||
VARIANT_SWITCH_END();
|
||||
VARIANT_CASE_CONST(tx_out_zarcanum, out_zc);
|
||||
result = out_zc.stealth_address;
|
||||
return true;
|
||||
VARIANT_SWITCH_END();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determines which output is real and actually spent in tx inputs, when there are fake outputs.
|
||||
bool determine_tx_real_inputs(currency::core& c, const currency::transaction& tx, const currency::account_keys& keys, std::vector<size_t>& real_inputs)
|
||||
{
|
||||
|
|
@ -36,9 +53,10 @@ bool determine_tx_real_inputs(currency::core& c, const currency::transaction& tx
|
|||
, m_found(false)
|
||||
{}
|
||||
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out_bare& out, uint64_t out_i)
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out_v& out_v, uint64_t source_tx_output_index)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!m_found, false, "Internal error: m_found is true but the visitor is still being applied");
|
||||
/*
|
||||
auto is_even = [&](const tx_out_v& v) { return boost::get<tx_out_bare>(v) == out; };
|
||||
auto it = std::find_if(validated_tx.vout.begin(), validated_tx.vout.end(), is_even);
|
||||
if (it == validated_tx.vout.end())
|
||||
|
|
@ -57,8 +75,20 @@ bool determine_tx_real_inputs(currency::core& c, const currency::transaction& tx
|
|||
/*crypto::public_key ephemeral_public_key;
|
||||
derive_public_key(derivation, output_tx_index, m_keys.account_address.spend_public_key, ephemeral_public_key);*/
|
||||
|
||||
/*
|
||||
crypto::key_image ki;
|
||||
generate_key_image(output_public_key, ephemeral_secret_key, ki);
|
||||
s*/
|
||||
|
||||
crypto::key_image ki = AUTO_VAL_INIT(ki);
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(validated_tx);
|
||||
currency::keypair ephemeral_key = AUTO_VAL_INIT(ephemeral_key);
|
||||
currency::generate_key_image_helper(m_keys, tx_pub_key, source_tx_output_index, ephemeral_key, ki);
|
||||
|
||||
crypto::public_key stealth_address = AUTO_VAL_INIT(stealth_address);
|
||||
bool r = get_stealth_address_form_tx_out_v(out_v, stealth_address);
|
||||
CHECK_AND_ASSERT_MES(r, false, "can't get stealth address from output #" << source_tx_output_index << " tx " << get_transaction_hash(source_tx));
|
||||
CHECK_AND_ASSERT_MES(stealth_address == ephemeral_key.pub, false, "derived pub key doesn't match with the stealth address, tx " << get_transaction_hash(source_tx) << " out #" << source_tx_output_index);
|
||||
|
||||
if (ki == m_txin_key_image)
|
||||
{
|
||||
|
|
@ -76,15 +106,26 @@ bool determine_tx_real_inputs(currency::core& c, const currency::transaction& tx
|
|||
bool m_found;
|
||||
};
|
||||
|
||||
for (auto& txin : tx.vin)
|
||||
for (auto& in : tx.vin)
|
||||
{
|
||||
const txin_to_key& in = boost::get<txin_to_key>(txin);
|
||||
if (in.key_offsets.size() == 1)
|
||||
try
|
||||
{
|
||||
if (get_key_offsets_from_txin_v(in).size() == 1)
|
||||
{
|
||||
real_inputs.push_back(0); // trivial case when no mixin is used
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
real_inputs.push_back(0); // trivial case when no mixin is used
|
||||
continue;
|
||||
}
|
||||
local_visitor vis(keys, in.k_image);
|
||||
|
||||
crypto::key_image ki = AUTO_VAL_INIT(ki);
|
||||
if (!get_key_image_from_txin_v(in, ki))
|
||||
continue;
|
||||
|
||||
local_visitor vis(keys, ki);
|
||||
bool r = c.get_blockchain_storage().scan_outputkeys_for_indexes(tx, in, vis);
|
||||
CHECK_AND_ASSERT_MES(r || vis.m_found, false, "scan_outputkeys_for_indexes failed");
|
||||
if (!vis.m_found)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue