From e4efbb47f2cf654597c2ccad08fefae6975f9a86 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 26 Oct 2022 17:39:10 +0200 Subject: [PATCH] coretests: chaingen adaptation for zarcanum, wip --- .../currency_format_utils_transactions.h | 4 +- tests/core_tests/chaingen.cpp | 324 ++++++++++-------- tests/core_tests/pos_block_builder.h | 4 +- 3 files changed, 177 insertions(+), 155 deletions(-) diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index c38c9cc4..c8ce1209 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -22,8 +22,8 @@ namespace currency output_entry(const output_entry &) = default; output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address) : out_reference(out_reference), stealth_address(stealth_address), concealing_point(null_pkey), amount_commitment(null_pkey) {} - //output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment) - // : out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment) {} + output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment) + : out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment) {} txout_ref_v out_reference; // either global output index or ref_by_id crypto::public_key stealth_address; // a.k.a output's one-time public key diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 8f2cfadf..f82ed764 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -929,23 +929,25 @@ bool test_generator::construct_pow_block_with_alias_info_in_coinbase(const accou struct output_index { - const currency::txout_target_v out; + const currency::tx_out_v out_v; uint64_t amount; size_t blk_height; // block height size_t tx_no; // index of transaction in block size_t out_no; // index of out in transaction size_t idx; bool spent; + bool zc_out; const currency::block *p_blk; const currency::transaction *p_tx; + crypto::scalar_t blinding_mask; // zc outs - output_index(const currency::txout_target_v &_out, uint64_t _a, size_t _h, size_t tno, size_t ono, const currency::block *_pb, const currency::transaction *_pt) - : out(_out), amount(_a), blk_height(_h), tx_no(tno), out_no(ono), idx(0), spent(false), p_blk(_pb), p_tx(_pt) + output_index(const currency::tx_out_v &_out_v, uint64_t _a, size_t _h, size_t tno, size_t ono, const currency::block *_pb, const currency::transaction *_pt) + : out_v(_out_v), amount(_a), blk_height(_h), tx_no(tno), out_no(ono), idx(0), spent(false), zc_out(false), p_blk(_pb), p_tx(_pt), blinding_mask(0) {} - output_index(const output_index &other) - : out(other.out), amount(other.amount), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), idx(other.idx), spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx) - {} + output_index(const output_index &other) = default; + // : out(other.out), amount(other.amount), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), idx(other.idx), spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx) + //{} const std::string to_string() const { @@ -956,6 +958,7 @@ struct output_index << " amount=" << amount << " idx=" << idx << " spent=" << spent + << " zc_out=" << zc_out << "}"; return ss.str(); } @@ -1017,7 +1020,7 @@ bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const { std::vector& outs_vec = outs[out.amount]; size_t out_global_idx = outs_vec.size(); - output_index oi(out.target, out.amount, height, i, j, &blk, vtx[i]); + output_index oi(out, out.amount, height, i, j, &blk, vtx[i]); oi.idx = out_global_idx; outs_vec.emplace_back(std::move(oi)); // Is out to me? @@ -1028,16 +1031,18 @@ bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector& outs_vec = outs[0]; // amount = 0 for ZC outs size_t out_global_idx = outs_vec.size(); - output_index oi(currency::txout_target_v(), 0 /* amount */, height, i, j, &blk, vtx[i]); + output_index oi(out, 0 /* amount */, height, i, j, &blk, vtx[i]); + oi.zc_out = true; oi.idx = out_global_idx; outs_vec.emplace_back(std::move(oi)); uint64_t decoded_amount = 0; - crypto::scalar_t blinding_mask{}; - if (is_out_to_acc(acc_keys, out, derivation, j, decoded_amount, blinding_mask)) + crypto::scalar_t decoded_blinding_mask{}; + if (is_out_to_acc(acc_keys, out, derivation, j, decoded_amount, decoded_blinding_mask)) { outs_vec.back().amount = decoded_amount; - outs_mine[decoded_amount /* TODO @#@# use 0 here?? */].push_back(out_global_idx); + outs_vec.back().blinding_mask = decoded_blinding_mask; + outs_mine[0].push_back(out_global_idx); } VARIANT_SWITCH_END() } @@ -1049,59 +1054,58 @@ bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector& blockchain, const map_hash2tx_t& mtx, const currency::account_keys& from) { - for(const map_output_t::value_type &o : outs_mine) + // 1. make a hashset of spend key images + std::unordered_set spent_key_images; + auto add_key_images_from_tx = [&](const transaction& tx) -> bool { + for(const txin_v& in: tx.vin) { - for (size_t i = 0; i < o.second.size(); ++i) - { - output_index &oi = outs[o.first][o.second[i]]; - - // construct key image for this output - crypto::key_image out_ki; - keypair in_ephemeral; - generate_key_image_helper(from, get_tx_pub_key_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, out_ki); - - // lookup for this key image in the events std::vector - for(auto& tx_pair : mtx) - { - const transaction& tx = *tx_pair.second; - for(const txin_v &in : tx.vin) - { - if (typeid(txin_to_key) == in.type()) - { - const txin_to_key &itk = boost::get(in); - if (itk.k_image == out_ki) - oi.spent = true; - } - } - } - - // check whether this key image has been spent in miner tx of a PoS block - // TODO change this check to simply adding PoS miner tx to mtx map - for (auto& b : blockchain) - { - if (!is_pos_block(b)) - continue; - for (const txin_v &in : b.miner_tx.vin) - { - if (in.type() == typeid(txin_to_key)) - { - const txin_to_key &itk = boost::get(in); - if (itk.k_image == out_ki) - oi.spent = true; - } - } - } - } + crypto::key_image ki{}; + if (get_key_image_from_txin_v(in, ki)) + if (!spent_key_images.insert(ki).second) + return false; } - return true; + }; + + for(auto& tx_pair : mtx) + { + CHECK_AND_ASSERT_MES(add_key_images_from_tx(*tx_pair.second), false, "insertion of spent key image failed for tx " << get_transaction_hash(*tx_pair.second)); + } + + for (auto& b : blockchain) + { + if (is_pos_block(b)) + CHECK_AND_ASSERT_MES(add_key_images_from_tx(b.miner_tx), false, "insertion of spent key image failed for miner tx " << get_transaction_hash(b.miner_tx)); + } + + // 2. check outputs from outs_mine against spent key images + if (spent_key_images.empty()) + return true; + + for(const map_output_t::value_type &o : outs_mine) + { + for (size_t i = 0; i < o.second.size(); ++i) + { + output_index &oi = outs[o.first][o.second[i]]; + + // construct key image for this output + crypto::key_image out_ki; + keypair in_ephemeral; + generate_key_image_helper(from, get_tx_pub_key_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, out_ki); // TODO: store ki and secret ephemeral for further use + + if (spent_key_images.count(out_ki) != 0) + oi.spent = true; + } + } + + return true; } -bool fill_output_entries(std::vector& out_indices, - size_t sender_out, size_t nmix, uint64_t& real_entry_idx, - std::vector& output_entries, - bool use_ref_by_id) +bool fill_output_entries(const std::vector& out_indices, size_t sender_out, size_t nmix, bool use_ref_by_id, + uint64_t& real_entry_idx, std::vector& output_entries) { + // use_ref_by_id = true; // <-- HINT: this could be used to enforce using ref_by_id across all the tests if needed + if (out_indices.size() <= nmix) return false; @@ -1122,8 +1126,12 @@ bool fill_output_entries(std::vector& out_indices, } else if (0 < rest) { - if(boost::get(oi.out).mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || boost::get(oi.out).mix_attr > nmix+1) - continue; + uint8_t mix_attr = 0; + if (get_mix_attr_from_tx_out_v(oi.out_v, mix_attr)) + { + if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || mix_attr > nmix + 1) + continue; + } --rest; append = true; @@ -1131,20 +1139,28 @@ bool fill_output_entries(std::vector& out_indices, if (append) { - tx_source_entry::output_entry oe = AUTO_VAL_INIT(oe); - const txout_to_key& otk = boost::get(oi.out); - if (use_ref_by_id) // <-- HINT: this could be replaced by 'true' to enforce using ref_by_id across all the tests if needed + txout_ref_v out_ref_v{}; + if (use_ref_by_id) { ref_by_id rbi = AUTO_VAL_INIT(rbi); rbi.n = oi.out_no; rbi.tx_id = get_transaction_hash(*oi.p_tx); - oe = tx_source_entry::output_entry(rbi, otk.key); + out_ref_v = rbi; } else { - oe = tx_source_entry::output_entry(oi.idx, otk.key); + out_ref_v = oi.idx; } - output_entries.push_back(oe); + + VARIANT_SWITCH_BEGIN(oi.out_v) + VARIANT_CASE_CONST(tx_out_bare, ob) + VARIANT_SWITCH_BEGIN(ob.target) + VARIANT_CASE_CONST(txout_to_key, otk) + output_entries.emplace_back(out_ref_v, otk.key); + VARIANT_SWITCH_END() + VARIANT_CASE_CONST(tx_out_zarcanum, ozc) + output_entries.emplace_back(out_ref_v, ozc.stealth_address, ozc.concealing_point, ozc.amount_commitment); + VARIANT_SWITCH_END() } } @@ -1163,110 +1179,116 @@ bool fill_tx_sources(std::vector& sources, const std: const currency::block& blk_head, const currency::account_keys& from, uint64_t amount, size_t nmix, const std::vector& sources_to_avoid, bool check_for_spends, bool check_for_unlocktime, bool use_ref_by_id, uint64_t* p_sources_amount_found /* = nullptr */) { - map_output_idx_t outs; - map_output_t outs_mine; + map_output_idx_t outs; + map_output_t outs_mine; - std::vector blockchain; - map_hash2tx_t mtx; - if (!find_block_chain(events, blockchain, mtx, get_block_hash(blk_head))) - return false; + std::vector blockchain; + map_hash2tx_t mtx; + if (!find_block_chain(events, blockchain, mtx, get_block_hash(blk_head))) + return false; - if (!init_output_indices(outs, outs_mine, blockchain, mtx, from)) - return false; + if (!init_output_indices(outs, outs_mine, blockchain, mtx, from)) + return false; - if(check_for_spends) + if(check_for_spends) + { + if (!init_spent_output_indices(outs, outs_mine, blockchain, mtx, from)) + return false; + } + + // mark some outputs as spent to avoid their using + for (const auto& s : sources_to_avoid) + { + for (const auto& s_outputs_el : s.outputs) // avoid all outputs, including fake mix-ins { - if (!init_spent_output_indices(outs, outs_mine, blockchain, mtx, from)) - return false; - } - - // mark some outputs as spent to avoid their using - for (const auto& s : sources_to_avoid) - { - for (const auto& s_outputs_el : s.outputs) // avoid all outputs, including fake mix-ins + txout_ref_v sout = s_outputs_el.out_reference; + if (sout.type().hash_code() == typeid(uint64_t).hash_code()) // output by global index { - txout_ref_v sout = s_outputs_el.out_reference; - if (sout.type().hash_code() == typeid(uint64_t).hash_code()) // output by global index + uint64_t gindex = boost::get(sout); + auto& outs_by_amount = outs[s.amount]; + if (gindex >= outs_by_amount.size()) + return false; + outs_by_amount[gindex].spent = true; + } + else if (sout.type().hash_code() == typeid(ref_by_id).hash_code()) // output by ref_by_id + { + ref_by_id out_ref_by_id = boost::get(sout); + const auto it = mtx.find(out_ref_by_id.tx_id); + if (it == mtx.end()) + return false; + const transaction* p_tx = it->second; + for (auto& e : outs[s.amount]) // linear search by transaction among all outputs with such amount { - uint64_t gindex = boost::get(sout); - auto& outs_by_amount = outs[s.amount]; - if (gindex >= outs_by_amount.size()) - return false; - outs_by_amount[gindex].spent = true; - } - else if (sout.type().hash_code() == typeid(ref_by_id).hash_code()) // output by ref_by_id - { - ref_by_id out_ref_by_id = boost::get(sout); - const auto it = mtx.find(out_ref_by_id.tx_id); - if (it == mtx.end()) - return false; - const transaction* p_tx = it->second; - for (auto& e : outs[s.amount]) // linear search by transaction among all outputs with such amount + if (e.p_tx == p_tx) { - if (e.p_tx == p_tx) - { - e.spent = true; - p_tx = nullptr; // means 'found' - break; - } + e.spent = true; + p_tx = nullptr; // means 'found' + break; } - if (p_tx != nullptr) - return false; // output, referring by ref_by_id was not found - } - else - { - return false; // unknown output type } + if (p_tx != nullptr) + return false; // output, referring by ref_by_id was not found + } + else + { + return false; // unknown output type } } + } - // Iterate in reverse is more efficiency - uint64_t sources_amount = 0; - bool sources_found = false; - BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine) + uint64_t head_block_ts = get_actual_timestamp(blk_head); + + // Iterate in reverse is more efficiency + uint64_t sources_amount = 0; + bool sources_found = false; + BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine) + { + for (size_t i = 0; i < o.second.size() && !sources_found; ++i) { - for (size_t i = 0; i < o.second.size() && !sources_found; ++i) + size_t sender_out = o.second[i]; + const output_index& oi = outs[o.first][sender_out]; + if (oi.spent) + continue; + if (check_for_unlocktime) + { + uint64_t unlock_time = currency::get_tx_max_unlock_time(*oi.p_tx); + if (unlock_time < CURRENCY_MAX_BLOCK_NUMBER) { - size_t sender_out = o.second[i]; - const output_index& oi = outs[o.first][sender_out]; - if (oi.spent) - continue; - if (check_for_unlocktime) - { - if (currency::get_tx_max_unlock_time(*oi.p_tx) < CURRENCY_MAX_BLOCK_NUMBER) - { - //interpret as block index - if (currency::get_tx_max_unlock_time(*oi.p_tx) > blockchain.size()) - continue; - } - else - { - //interpret as time - } - } - - - currency::tx_source_entry ts = AUTO_VAL_INIT(ts); - ts.amount = oi.amount; - ts.real_output_in_tx_index = oi.out_no; - ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key - if (!fill_output_entries(outs[o.first], sender_out, nmix, ts.real_output, ts.outputs, use_ref_by_id)) - continue; - - sources.push_back(ts); - - sources_amount += ts.amount; - sources_found = amount <= sources_amount; + //interpret as block index + if (unlock_time > blockchain.size()) + continue; } + else + { + //interpret as time + if (unlock_time > head_block_ts + DIFFICULTY_TOTAL_TARGET) + continue; + } + } - if (sources_found) - break; + + currency::tx_source_entry ts = AUTO_VAL_INIT(ts); + ts.amount = oi.amount; + ts.real_out_amount_blinding_mask = oi.blinding_mask; + ts.real_output_in_tx_index = oi.out_no; + ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // source tx public key + if (!fill_output_entries(outs[o.first], sender_out, nmix, use_ref_by_id, ts.real_output, ts.outputs)) + continue; + + sources.push_back(ts); + + sources_amount += ts.amount; + sources_found = amount <= sources_amount; } - if (p_sources_amount_found != nullptr) - *p_sources_amount_found = sources_amount; + if (sources_found) + break; + } - return sources_found; + if (p_sources_amount_found != nullptr) + *p_sources_amount_found = sources_amount; + + return sources_found; } bool fill_tx_sources_and_destinations(const std::vector& events, const block& blk_head, diff --git a/tests/core_tests/pos_block_builder.h b/tests/core_tests/pos_block_builder.h index 39503805..eb1592f2 100644 --- a/tests/core_tests/pos_block_builder.h +++ b/tests/core_tests/pos_block_builder.h @@ -29,13 +29,13 @@ struct pos_block_builder uint64_t timestamp_step = POS_SCAN_STEP); - void pos_block_builder::step3a( + void step3a( currency::wide_difficulty_type difficulty, const crypto::hash& last_pow_block_hash, const crypto::hash& last_pos_block_kernel_hash ); - void pos_block_builder::step3b( + void step3b( uint64_t stake_output_amount, const crypto::key_image& stake_output_key_image, const crypto::public_key& stake_source_tx_pub_key,