From 589f37bcd9aed1fb72004b1f2121af7f75f2943f Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 6 Sep 2019 18:59:02 +0300 Subject: [PATCH 1/5] coretests: pos_block_builder improved --- tests/core_tests/pos_block_builder.cpp | 80 +++++++++++++------------- tests/core_tests/pos_block_builder.h | 15 ++++- 2 files changed, 53 insertions(+), 42 deletions(-) diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index 71819a64..80c5f0b1 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -105,9 +105,21 @@ void pos_block_builder::step3_build_stake_kernel( m_step = 3; } +void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, + const boost::multiprecision::uint128_t& already_generated_coins, + const account_public_address &reward_and_stake_receiver_address, + const blobdata& extra_nonce, + size_t max_outs, + const extra_alias_entry& alias, + keypair tx_one_time_key) +{ + step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, alias, tx_one_time_key); +} + void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, const account_public_address &reward_receiver_address, + const account_public_address &stakeholder_address, const blobdata& extra_nonce, size_t max_outs, const extra_alias_entry& alias, @@ -118,7 +130,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, // generate miner tx using incorrect current_block_size only for size estimation size_t estimated_block_size = m_txs_total_size; bool r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage, - m_pos_stake_output_gindex, reward_receiver_address, m_block.miner_tx, extra_nonce, max_outs, alias, tx_one_time_key); + m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx); @@ -126,7 +138,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, for (size_t try_count = 0; try_count != 10; ++try_count) { r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage, - m_pos_stake_output_gindex, reward_receiver_address, m_block.miner_tx, extra_nonce, max_outs, alias, tx_one_time_key); + m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx); @@ -171,11 +183,11 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo uint64_t pos_stake_amount, crypto::key_image pos_stake_keyimage, size_t pos_stake_gindex, - const account_public_address &miner_address, + const account_public_address &reward_receiving_address, + const account_public_address &stakeholder_address, transaction& tx, const blobdata& extra_nonce /*= blobdata()*/, size_t max_outs /*= CURRENCY_MINER_TX_MAX_OUTS*/, - const extra_alias_entry& alias /*= alias_info()*/, keypair tx_one_time_key /*= keypair::generate()*/) { boost::value_initialized new_tx; @@ -189,12 +201,6 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo bool r = get_block_reward(true, median_size, current_block_size, already_generated_coins, block_reward, height); CHECK_AND_ASSERT_MES(r, false, "Block is too big"); block_reward += fee; - block_reward += pos_stake_amount; - - uint64_t alias_reward = 0; - if (!alias.m_alias.empty()) - alias_reward = currency::get_alias_coast_from_fee(alias.m_alias, TESTS_DEFAULT_FEE); - block_reward -= alias_reward; // decompose reward into outputs and populate tx.vout std::vector out_amounts; @@ -202,14 +208,15 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); - CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); - while (max_outs < out_amounts.size()) + CHECK_AND_ASSERT_MES(2 <= max_outs, false, "max_out must be greather than 1"); + while (out_amounts.size() + 1 > max_outs) { out_amounts[out_amounts.size() - 2] += out_amounts.back(); out_amounts.resize(out_amounts.size() - 1); } - bool burn_money = miner_address.m_spend_public_key == null_pkey && miner_address.m_view_public_key == null_pkey; // if true, burn money, so no one on Earth can spend them + // reward + bool burn_money = reward_receiving_address.m_spend_public_key == null_pkey && reward_receiving_address.m_view_public_key == null_pkey; // if true, burn reward, so no one on Earth can spend them for (size_t output_index = 0; output_index < out_amounts.size(); ++output_index) { txout_to_key tk; @@ -218,7 +225,7 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo if (!burn_money) { - r = currency::derive_public_key_from_target_address(miner_address, tx_one_time_key.sec, output_index, tk.key); // derivation(view_pub; tx_sec).derive(output_index, spend_pub) => output pub key + r = currency::derive_public_key_from_target_address(reward_receiving_address, tx_one_time_key.sec, output_index, tk.key); // derivation(view_pub; tx_sec).derive(output_index, spend_pub) => output pub key CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); } @@ -228,36 +235,31 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo tx.vout.push_back(out); } + // stake + burn_money = stakeholder_address.m_spend_public_key == null_pkey && stakeholder_address.m_view_public_key == null_pkey; // if true, burn stake + { + txout_to_key tk; + tk.key = null_pkey; // null means burn money + tk.mix_attr = 0; + + if (!burn_money) + { + r = currency::derive_public_key_from_target_address(stakeholder_address, tx_one_time_key.sec, tx.vout.size(), tk.key); + CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); + } + + tx_out out; + out.amount = pos_stake_amount; + out.target = tk; + tx.vout.push_back(out); + } + // take care about extra add_tx_pub_key_to_extra(tx, tx_one_time_key.pub); if (extra_nonce.size()) if (!add_tx_extra_userdata(tx, extra_nonce)) return false; - if (alias.m_alias.size()) - { - if (!add_tx_extra_alias(tx, alias)) - return false; - - // decompose alias reward into digits and create additional outputs - out_amounts.clear(); - decompose_amount_into_digits(alias_reward, DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); - while (out_amounts.size() > max_outs) - { - out_amounts[out_amounts.size() - 2] += out_amounts.back(); - out_amounts.resize(out_amounts.size() - 1); - } - for (size_t output_index = 0; output_index < out_amounts.size(); ++output_index) - { - txout_to_key tk; - tk.key = null_pkey; // burn money for the sake of alias! - tk.mix_attr = 0; - tx_out out; - out.amount = out_amounts[output_index]; - out.target = tk; - tx.vout.push_back(out); - } - } - + // populate ins with 1) money-generating and 2) PoS txin_gen in; in.height = height; diff --git a/tests/core_tests/pos_block_builder.h b/tests/core_tests/pos_block_builder.h index 62d2a9b5..8ea965c2 100644 --- a/tests/core_tests/pos_block_builder.h +++ b/tests/core_tests/pos_block_builder.h @@ -27,11 +27,20 @@ struct pos_block_builder void step4_generate_coinbase_tx(size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, const currency::account_public_address &reward_receiver_address, + const currency::account_public_address &stakeholder_address, const currency::blobdata& extra_nonce = currency::blobdata(), size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, const currency::extra_alias_entry& alias = currency::extra_alias_entry(), currency::keypair tx_one_time_key = currency::keypair::generate()); - + + void step4_generate_coinbase_tx(size_t median_size, + const boost::multiprecision::uint128_t& already_generated_coins, + const currency::account_public_address &reward_and_stake_receiver_address, + const currency::blobdata& extra_nonce = currency::blobdata(), + size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, + const currency::extra_alias_entry& alias = currency::extra_alias_entry(), + currency::keypair tx_one_time_key = currency::keypair::generate()); + void step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, const currency::account_base& stakeholder_account); currency::block m_block; @@ -50,11 +59,11 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo uint64_t pos_stake_amount, crypto::key_image pos_stake_keyimage, size_t pos_stake_gindex, - const currency::account_public_address &miner_address, + const currency::account_public_address &reward_receiving_address, + const currency::account_public_address &stakeholder_address, currency::transaction& tx, const currency::blobdata& extra_nonce = currency::blobdata(), size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, - const currency::extra_alias_entry& alias = currency::extra_alias_entry(), currency::keypair tx_one_time_key = currency::keypair::generate()); bool mine_next_pos_block_in_playtime_sign_cb(currency::core& c, const currency::block& prev_block, const currency::block& coinstake_scr_block, const currency::account_base& acc, From eb7bf075cfb3ecc4e8ddfce01ef515a0548f3d18 Mon Sep 17 00:00:00 2001 From: sowle Date: Fri, 6 Sep 2019 18:59:59 +0300 Subject: [PATCH 2/5] coretests: hard_fork_1_pos_locked_height_vs_time greatly improved with additional checks --- tests/core_tests/hard_fork_1.cpp | 84 +++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/tests/core_tests/hard_fork_1.cpp b/tests/core_tests/hard_fork_1.cpp index eb2b4d3b..e8683a5f 100644 --- a/tests/core_tests/hard_fork_1.cpp +++ b/tests/core_tests/hard_fork_1.cpp @@ -614,14 +614,16 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector Alice, miner -> Bob + uint64_t stake_unlock_time = 100; // locked until block 100 + uint64_t stake_amount = MK_TEST_COINS(10); std::vector extra; etc_tx_details_unlock_time ut = AUTO_VAL_INIT(ut); - ut.v = 100; // locked until block 100 + ut.v = stake_unlock_time; extra.push_back(ut); std::vector destinations; - destinations.push_back(tx_destination_entry(MK_TEST_COINS(10), alice_acc.get_public_address())); - destinations.push_back(tx_destination_entry(MK_TEST_COINS(10), bob_acc.get_public_address())); + destinations.push_back(tx_destination_entry(stake_amount, alice_acc.get_public_address())); + destinations.push_back(tx_destination_entry(stake_amount, bob_acc.get_public_address())); transaction tx_0 = AUTO_VAL_INIT(tx_0); r = construct_tx_to_key(events, tx_0, blk_0r, miner_acc, destinations, TESTS_DEFAULT_FEE, 0, 0, extra); @@ -635,7 +637,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector()); pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp); - pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address()); + pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address()); // set etc_tx_details_unlock_time2 remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock @@ -672,11 +674,57 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector(stake.vout[stake_output_idx].target).key; + + pos_block_builder pb; + pb.step1_init_header(height, prev_id); + pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION; + pb.step2_set_txs(std::vector()); + pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp); + pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address()); + + // set etc_tx_details_unlock_time2 + remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock + std::vector extra; + etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2); + ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock + for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i) + ut2.unlock_time_array.push_back(stake_unlock_time - 1); // stake locked by 1 less height that stake_unlock_time, that is incorrect as lock time of this coin is decreased + extra.push_back(ut2); + pb.m_block.miner_tx.extra.push_back(ut2); + + pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder); + blk_b2 = pb.m_block; + } + + // should no pass because stake output has less lock time than stake input + DO_CALLBACK(events, "mark_invalid_block"); + events.push_back(blk_b2); block blk_good; { @@ -702,7 +750,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector()); pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp); - pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address()); + pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address()); // set etc_tx_details_unlock_time2 remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock @@ -710,7 +758,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector()); // add modified block info + + MAKE_NEXT_BLOCK(events, blk_2, blk_good, miner_acc); + + std::vector sources; + r = fill_tx_sources(sources, events, blk_2, alice_acc.get_keys(), stake_amount / 2 + TESTS_DEFAULT_FEE, 0 /* nmix */, true /* check for spends */, false /* check for unlock time */); + CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); + transaction tx_1 = AUTO_VAL_INIT(tx_1); + r = construct_tx(alice_acc.get_keys(), sources, std::vector{ tx_destination_entry(stake_amount / 2, miner_acc.get_public_address()) }, + empty_attachment, tx_1, stake_unlock_time /* try to use stake unlock time -- should not work as it is not a coinbase */); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(tx_1); return true; } From fd0e7c3f7d2418601b5bf49d016bd1267a8ba985 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 7 Sep 2019 12:46:25 +0300 Subject: [PATCH 3/5] minor fixes and impovements --- src/currency_core/blockchain_storage.cpp | 4 ++-- tests/core_tests/chaingen.cpp | 4 ++-- tests/core_tests/chaingen_main.cpp | 8 ++++++++ tests/core_tests/pos_block_builder.cpp | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 959e2765..4da0c24a 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -4861,7 +4861,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool"); purge_block_data_from_blockchain(bl, tx_processed_count); add_block_as_invalid(bl, id); - LOG_PRINT_L0("Block with id " << id << " added as invalid becouse of wrong inputs in transactions"); + LOG_PRINT_L0("Block with id " << id << " added as invalid because of wrong inputs in transactions"); bvc.m_verification_failed = true; return false; } @@ -5361,7 +5361,7 @@ bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt else { bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_MODFIFIER"); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_KERNEL_HASH"); } sm.last_pow_id = get_block_hash(pbei_last_pow->bl); diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 430f2d6f..b03d2b9b 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -176,7 +176,7 @@ bool test_generator::add_block_info(const currency::block& b, const std::listks_hash; else { - CHECK_AND_ASSERT_MES(string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sk.stake_modifier.last_pos_kernel_id), false, "Failed to parse POS_STARTER_MODFIFIER"); + CHECK_AND_ASSERT_MES(string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sk.stake_modifier.last_pos_kernel_id), false, "Failed to parse POS_STARTER_KERNEL_HASH"); } uint64_t pow_idx = get_last_block_of_type(false, chain); sk.stake_modifier.last_pow_id = get_block_hash(chain[pow_idx]->b); @@ -686,7 +686,7 @@ bool test_generator::build_stake_modifier(stake_modifier_type& sm, const test_ge else { bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id); - CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_MODFIFIER"); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_KERNEL_HASH"); } sm.last_pow_id = get_block_hash(blck_chain[last_pow_i]->b); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 42445b45..42f8f112 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1024,3 +1024,11 @@ void tx2log(const currency::transaction& tx) currency::transaction ltx = tx; LOG_PRINT("!dbg transaction: " << currency::get_transaction_hash(ltx) << ENDL << currency::obj_to_json_str(ltx), LOG_LEVEL_0); } + +const char* amount2log(const uint64_t amount) +{ + static std::string s; + s = currency::print_money_brief(amount); + LOG_PRINT("!dbg amount: " << s, LOG_LEVEL_0); + return s.c_str(); +} diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index 80c5f0b1..4127e948 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -78,7 +78,7 @@ void pos_block_builder::step3_build_stake_kernel( if (last_pos_block_kernel_hash == null_hash) { bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, m_stake_kernel.stake_modifier.last_pos_kernel_id); - CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse POS_STARTER_MODFIFIER"); + CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse POS_STARTER_KERNEL_HASH"); } wide_difficulty_type stake_difficulty = difficulty / stake_output_amount; From 37d447845b88741cb061ce3983088fb1700dfc71 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 7 Sep 2019 12:47:31 +0300 Subject: [PATCH 4/5] coretests: hard_fork_1_locked_mining_test enhanced --- .../hard_fork_1_locked_pos_test.cpp | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/tests/core_tests/hard_fork_1_locked_pos_test.cpp b/tests/core_tests/hard_fork_1_locked_pos_test.cpp index 3c96e07c..5c6696e9 100644 --- a/tests/core_tests/hard_fork_1_locked_pos_test.cpp +++ b/tests/core_tests/hard_fork_1_locked_pos_test.cpp @@ -21,7 +21,7 @@ hard_fork_1_locked_mining_test::hard_fork_1_locked_mining_test() bool hard_fork_1_locked_mining_test::generate(std::vector& events) const { - random_state_test_restorer::reset_random(); + // Test idea: make sure PoS mining on locked coins is possible GENERATE_ACCOUNT(preminer_acc); GENERATE_ACCOUNT(miner_acc); @@ -36,20 +36,30 @@ bool hard_fork_1_locked_mining_test::generate(std::vector& eve DO_CALLBACK(events, "configure_core"); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); - //construc tx that locks transaction for some period of time - // make a couple of huge txs + //construct tx that locks coins for some period of time + //make a couple of huge txs bool r = false; std::vector extra; std::vector sources_1; - r = fill_tx_sources(sources_1, events, blk_0r, miner_acc.get_keys(), 2000000000000+TESTS_DEFAULT_FEE, 0); + r = fill_tx_sources(sources_1, events, blk_0r, miner_acc.get_keys(), CURRENCY_BLOCK_REWARD + TESTS_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); - std::vector destinations({ tx_destination_entry(2010000000000, pos_miner_acc.get_public_address()) }); + std::vector destinations({ tx_destination_entry(CURRENCY_BLOCK_REWARD, pos_miner_acc.get_public_address()) }); crypto::secret_key stub; transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources_1, destinations, extra, empty_attachment, tx_1, stub, get_block_height(blk_0r)+2000); + uint64_t unlock_time = get_block_height(blk_0r) + 2000; + r = construct_tx(miner_acc.get_keys(), sources_1, destinations, extra, empty_attachment, tx_1, stub, unlock_time); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1); // push it to the pool + + uint64_t ut1 = get_tx_x_detail(tx_1); + etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2); + get_type_in_variant_container(tx_1.extra, ut2); + std::stringstream ss; + for (auto v : ut2.unlock_time_array) + ss << v << " "; + LOG_PRINT_YELLOW("tx1: ut1: " << ut1 << ", ut2: " << ss.str(), LOG_LEVEL_0); + MAKE_NEXT_BLOCK_TX1(events, blk_0r_tx, blk_0r, miner_acc, tx_1); @@ -61,13 +71,30 @@ bool hard_fork_1_locked_mining_test::generate(std::vector& eve events.push_back(event_core_time(next_blk_pow.timestamp - 10)); last_block = next_blk_pow; } + + MAKE_NEXT_BLOCK(events, blk_1, last_block, miner_acc); + MAKE_NEXT_POS_BLOCK(events, blk_2, blk_1, miner_acc, miner_acc_lst); + MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); std::list accounts_2; accounts_2.push_back(pos_miner_acc); - //let's try to mint PoS block from locked account + //mint PoS block from locked account into an altchain MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, pos_miner_acc, accounts_2); - DO_CALLBACK(events, "c1"); + // switch chains + MAKE_NEXT_BLOCK(events, blk_2a, next_blk_pos, miner_acc); + MAKE_NEXT_BLOCK(events, blk_3a, blk_2a, miner_acc); + MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc); + + // make sure switch happened + DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_4a)); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_4ar, blk_4a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // mint another PoS block from locked account + MAKE_NEXT_POS_BLOCK(events, blk_5a, blk_4ar, pos_miner_acc, accounts_2); + + return true; } From e61d8de3df4bdb6ec1d926113b14bbb7324ff5e7 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 7 Sep 2019 12:48:13 +0300 Subject: [PATCH 5/5] coretests: hard_fork_1_checkpoint_basic_test completed --- tests/core_tests/hard_fork_1.cpp | 95 ++++++++++++++++++++++++++++++-- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/tests/core_tests/hard_fork_1.cpp b/tests/core_tests/hard_fork_1.cpp index e8683a5f..fdbe9617 100644 --- a/tests/core_tests/hard_fork_1.cpp +++ b/tests/core_tests/hard_fork_1.cpp @@ -312,22 +312,28 @@ bool hard_fork_1_checkpoint_basic_test::generate(std::vector& MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); generator.set_hardfork_height(m_hardfork_height); DO_CALLBACK(events, "configure_core"); - DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2)); + DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 7)); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + DO_CALLBACK(events, "check_being_in_cp_zone"); // make sure CP was has passed + // // before hardfork 1 // std::vector sources; + CHECK_AND_ASSERT_MES(fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), MK_TEST_COINS(90) + TESTS_DEFAULT_FEE, 0), false, ""); + + uint64_t stake_lock_time = 100; // locked till block 100 + std::vector destinations; - CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_0r, miner_acc, alice_acc, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations), false, ""); + destinations.push_back(tx_destination_entry(MK_TEST_COINS(90), alice_acc.get_public_address())); // set unlock_time_2, should be rejected before hardfork 1 std::vector extra; etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2); ut2.unlock_time_array.resize(destinations.size()); - ut2.unlock_time_array[0] = 1; // not zero, unlocked from block 1 + ut2.unlock_time_array[0] = stake_lock_time; extra.push_back(ut2); transaction tx_0 = AUTO_VAL_INIT(tx_0); crypto::secret_key tx_sec_key; @@ -342,13 +348,94 @@ bool hard_fork_1_checkpoint_basic_test::generate(std::vector& DO_CALLBACK(events, "clear_tx_pool"); MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc); - MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); // <-- checkpoint + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); // <-- hard fork MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc); // make sure hardfork went okay CHECK_AND_ASSERT_MES(blk_3.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_4.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected"); + // + // after hardfork 1 + // + + // now tx_0 is okay and can be added to the blockchain + events.push_back(tx_0); + MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4, miner_acc, tx_0); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_5r, blk_5, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0); + REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_5r, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5); + CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(90)); + + // try to mine a PoS block using locked coins + block blk_6; + { + const block& prev_block = blk_5r; + const transaction& stake = tx_0; + const account_base& stakeholder = alice_acc; + + crypto::hash prev_id = get_block_hash(prev_block); + size_t height = get_block_height(prev_block) + 1; + currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false); + + crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake); + size_t stake_output_idx = 0; + size_t stake_output_gidx = 0; + uint64_t stake_output_amount = stake.vout[stake_output_idx].amount; + crypto::key_image stake_output_key_image; + keypair kp; + generate_key_image_helper(stakeholder.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image); + crypto::public_key stake_output_pubkey = boost::get(stake.vout[stake_output_idx].target).key; + + pos_block_builder pb; + pb.step1_init_header(height, prev_id); + pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION; + pb.step2_set_txs(std::vector()); + pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp); + pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address()); + + // set etc_tx_details_unlock_time2 + remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock + std::vector extra; + etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2); + ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock + for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i) + ut2.unlock_time_array.push_back(stake_lock_time); // using the same lock time as stake input + extra.push_back(ut2); + pb.m_block.miner_tx.extra.push_back(ut2); + + pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder); + blk_6 = pb.m_block; + } + events.push_back(blk_6); + generator.add_block_info(blk_6, std::list()); // add modified block info + + + MAKE_NEXT_BLOCK(events, blk_7, blk_6, miner_acc); // <-- checkpoint + MAKE_NEXT_BLOCK(events, blk_8, blk_7, miner_acc); + + DO_CALLBACK(events, "check_not_being_in_cp_zone"); // make sure CP was has passed + + REWIND_BLOCKS_N_WITH_TIME(events, blk_8r, blk_8, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // make sure locked Alice's coins still can't be spent + sources.clear(); + r = fill_tx_sources(sources, events, blk_8r, alice_acc.get_keys(), MK_TEST_COINS(90), 0 /* nmix */, true /* check for spends */, false /* check for unlock time */); + CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); + transaction tx_1 = AUTO_VAL_INIT(tx_1); + r = construct_tx(alice_acc.get_keys(), sources, std::vector{ tx_destination_entry(MK_TEST_COINS(90) - TESTS_DEFAULT_FEE, miner_acc.get_public_address()) }, + empty_attachment, tx_1, stake_lock_time /* try to use stake unlock time -- should not work as it is not a coinbase */); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(tx_1); + + // mine another PoS block using the same stake after a checkpoint + std::list pos_stakeing_accounts{alice_acc}; + MAKE_NEXT_POS_BLOCK(events, blk_9, blk_8r, miner_acc, pos_stakeing_accounts); + return true; }