// Copyright (c) 2014-2021 Zano Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chaingen.h" // htlc clean up, WIP -- sowle #if 0 #include "escrow_wallet_tests.h" #include "random_helper.h" #include "chaingen_helpers.h" #include "atomic_tests.h" using namespace epee; using namespace crypto; using namespace currency; #define INIT_RUNTIME_WALLET(instance_name) \ currency::account_base instance_name##acc_base; \ instance_name##acc_base.generate(); \ instance_name##acc_base.set_createtime(m_genesis_timestamp); \ LOG_PRINT_MAGENTA(": " << currency::get_account_address_as_str(instance_name##acc_base.get_public_address()), LOG_LEVEL_0); \ std::shared_ptr instance_name = init_playtime_test_wallet(events, c, instance_name##acc_base); //============================================================================================================================== struct wallet_tests_callback_handler : public tools::i_wallet2_callback { virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { all_wtis.push_back(wti); } std::vector all_wtis; }; ////////////////////////////////////////////////////////////////////////// atomic_base_test::atomic_base_test() { REGISTER_CALLBACK_METHOD(atomic_base_test, c1); REGISTER_CALLBACK_METHOD(atomic_base_test, configure_core); m_hardforks.set_hardfork_height(1, 10); m_hardforks.set_hardfork_height(2, 11); m_hardforks.set_hardfork_height(3, 12); } bool atomic_base_test::generate(std::vector& events) const { random_state_test_restorer::reset_random(0); // to make the test deterministic m_genesis_timestamp = 1450000000; test_core_time::adjust(m_genesis_timestamp); //epee::debug::get_set_enable_assert(true, true); currency::account_base genesis_acc; genesis_acc.generate(); m_mining_accunt.generate(); m_mining_accunt.set_createtime(m_genesis_timestamp); block blk_0 = AUTO_VAL_INIT(blk_0); generator.construct_genesis_block(blk_0, genesis_acc, test_core_time::get_time()); events.push_back(blk_0); set_hard_fork_heights_to_generator(generator); DO_CALLBACK(events, "configure_core"); // default callback will initialize core current runtime config with m_hardforks REWIND_BLOCKS_N(events, blk_0r, blk_0, m_mining_accunt, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5); DO_CALLBACK(events, "c1"); //epee::debug::get_set_enable_assert(true, false); return true; } /************************************************************************/ /* */ /************************************************************************/ bool atomic_simple_test::c1(currency::core& c, size_t ev_index, const std::vector& events) { //epee::debug::get_set_enable_assert(true, true); //misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); /* let's pretend that we have two different blockchains: A and B Alice and Bob want to have atomic swap via htlc, both has wallets in blockchain A and B Steps are following: 1. Alice initiate swap by sending to Bob HTLC in blockchain A 2. Bob see HTLC to his address in blockchain A and create HTLC with the same hash addressed to Alice in blockchain B 3. Alice see HTLC addressed to her in blockchain B and creates there redeem transaction, which reveals HTLC origin 4. Bob observe origin revealed by Alice in blockchain B and create redeem transaction in blockchain A 5. Everybody check balances and celebrate successful atomic swap */ LOG_PRINT_MAGENTA("Mining Address: " << currency::get_account_address_as_str(m_mining_accunt.get_public_address()), LOG_LEVEL_0); //create wallet instances and calculate balances INIT_RUNTIME_WALLET(alice_a_wlt_instance); INIT_RUNTIME_WALLET(alice_b_wlt_instance); INIT_RUNTIME_WALLET(bob_a_wlt_instance); INIT_RUNTIME_WALLET(bob_b_wlt_instance); INIT_RUNTIME_WALLET(refund_test_instance); INIT_RUNTIME_WALLET(refund_test_instance2); #define AMOUNT_TO_TRANSFER_HTLC (TESTS_DEFAULT_FEE*10) std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_mining_accunt); size_t blocks_fetched = 0; bool received_money = false; std::atomic atomic_false = ATOMIC_VAR_INIT(false); miner_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); uint64_t transfer_amount = AMOUNT_TO_TRANSFER_HTLC + TESTS_DEFAULT_FEE; miner_wlt->transfer(transfer_amount, alice_a_wlt_instance->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Alice A: " << transfer_amount, LOG_LEVEL_0); miner_wlt->transfer(transfer_amount, bob_b_wlt_instance->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Bob B: " << transfer_amount, LOG_LEVEL_0); miner_wlt->transfer(transfer_amount, refund_test_instance->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Refund test: " << transfer_amount, LOG_LEVEL_0); bool r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); bob_a_wlt_instance->refresh(); bob_b_wlt_instance->refresh(); refund_test_instance->refresh(); refund_test_instance2->refresh(); CHECK_AND_FORCE_ASSERT_MES(alice_a_wlt_instance->balance() == transfer_amount, false, "Incorrect balance"); CHECK_AND_FORCE_ASSERT_MES(bob_b_wlt_instance->balance() == transfer_amount, false, "Incorrect balance"); CHECK_AND_FORCE_ASSERT_MES(refund_test_instance->balance() == transfer_amount, false, "Incorrect balance"); //============= phase 1 ============= //----------- preparation ----------- //a) basic full atomic process test std::string alice_origin; //will be deterministically generated by Alice's A wallet currency::transaction res_tx = AUTO_VAL_INIT(res_tx); alice_a_wlt_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, bob_a_wlt_instance->get_account().get_public_address(), 100, res_tx, currency::null_hash, alice_origin); //b) htlc refund test std::string refund_origin; //will be deterministically generated by Alice's A wallet currency::transaction refund_res_tx = AUTO_VAL_INIT(refund_res_tx); refund_test_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, miner_wlt->get_account().get_public_address(), 8, refund_res_tx, currency::null_hash, refund_origin); //----------- rewinding ----------- r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); bob_a_wlt_instance->refresh(); bob_b_wlt_instance->refresh(); refund_test_instance->refresh(); refund_test_instance2->refresh(); //----------- checks ----------- //a) basic full atomic process test std::list htlcs_alice_a; alice_a_wlt_instance->get_list_of_active_htlc(htlcs_alice_a, false); CHECK_AND_ASSERT_MES(htlcs_alice_a.size() == 1, false, "htlcs_alice.size() == 1 failed"); std::list htlcs_bob_a; bob_a_wlt_instance->get_list_of_active_htlc(htlcs_bob_a, false); CHECK_AND_ASSERT_MES(htlcs_bob_a.size() == 1, false, "htlcs_bob.size() == 1 failed"); const tools::wallet_public::htlc_entry_info& hei_bob = *htlcs_bob_a.begin(); CHECK_AND_ASSERT_MES(hei_bob.is_redeem == true, false, "hei_bob.is_redeem == true failed"); const tools::wallet_public::htlc_entry_info& hei_alice = *htlcs_alice_a.begin(); CHECK_AND_ASSERT_MES(hei_alice.is_redeem == false, false, "hei_alice.is_redeem == false failed"); CHECK_AND_ASSERT_MES(hei_alice.amount == hei_bob.amount && hei_alice.sha256_hash == hei_bob.sha256_hash && hei_alice.tx_id == hei_bob.tx_id, false, "hei_alice !=hei_bob "); //b) htlc refund test //money at refund_test_instance should be released as refunded, and balance should get to transfer_amount - TESTS_DEFAULT_FEE CHECK_AND_ASSERT_MES(refund_test_instance->balance() == transfer_amount - TESTS_DEFAULT_FEE, false, "refund_test_instance->balance() == transfer_amount - TESTS_DEFAULT_FEE failed"); //============= phase 2 ============= //----------- preparation ----------- //a) basic full atomic process test currency::transaction res_bob_tx = AUTO_VAL_INIT(res_tx); std::string dummy_origin; bob_b_wlt_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, alice_b_wlt_instance->get_account().get_public_address(), 100, res_tx, hei_bob.sha256_hash, dummy_origin); //b) htlc refund test //try to spend refunded money to make sure it's spendable refund_test_instance->transfer(transfer_amount - TESTS_DEFAULT_FEE * 2, refund_test_instance2->get_account().get_public_address()); //----------- rewinding ----------- r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); bob_a_wlt_instance->refresh(); bob_b_wlt_instance->refresh(); refund_test_instance->refresh(); refund_test_instance2->refresh(); //----------- checks ----------- //a) basic full atomic process test std::list htlcs_alice_b; alice_b_wlt_instance->get_list_of_active_htlc(htlcs_alice_b, false); CHECK_AND_ASSERT_MES(htlcs_alice_b.size() == 1, false, "htlcs_alice_b.size() == 1 failed"); std::list htlcs_bob_b; bob_b_wlt_instance->get_list_of_active_htlc(htlcs_bob_b, false); CHECK_AND_ASSERT_MES(htlcs_bob_b.size() == 1, false, "htlcs_bob_b.size() == 1 failed"); std::list htlcs_bob_a_2; bob_a_wlt_instance->get_list_of_active_htlc(htlcs_bob_a_2, false); CHECK_AND_ASSERT_MES(htlcs_bob_a_2.size() == 1, false, "htlcs_bob_a.size() == 1 failed"); const tools::wallet_public::htlc_entry_info& hei_bob_b = *htlcs_bob_b.begin(); CHECK_AND_ASSERT_MES(hei_bob_b.is_redeem == false, false, "hei_bob_b.is_redeem == true failed"); const tools::wallet_public::htlc_entry_info& hei_alice_b = *htlcs_alice_b.begin(); CHECK_AND_ASSERT_MES(hei_alice_b.is_redeem == true, false, "hei_alice_b.is_redeem == false failed"); CHECK_AND_ASSERT_MES(hei_alice_b.amount == hei_bob_b.amount && hei_alice_b.sha256_hash == hei_bob_b.sha256_hash && hei_alice_b.tx_id == hei_bob_b.tx_id, false, "hei_alice !=hei_bob "); //b) htlc refund test CHECK_AND_ASSERT_MES(refund_test_instance->balance() == 0, false, "refund_test_instance->balance() == 0 failed"); CHECK_AND_ASSERT_MES(refund_test_instance2->balance() == transfer_amount - TESTS_DEFAULT_FEE * 2, false, "refund_test_instance->balance() == transfer_amount - TESTS_DEFAULT_FEE * 2 failed"); //============= phase 3 ============= //----------- preparation ----------- //now alice redeem her contract in blockchain B alice_b_wlt_instance->redeem_htlc(hei_alice_b.tx_id, alice_origin); //----------- rewinding ----------- r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); bob_a_wlt_instance->refresh(); bob_b_wlt_instance->refresh(); //----------- checks ----------- std::list htlcs_bob_a_3; bob_a_wlt_instance->get_list_of_active_htlc(htlcs_bob_a_3, false); CHECK_AND_ASSERT_MES(htlcs_bob_a_3.size() == 1, false, "htlcs_bob_a.size() == 1 failed"); //============= phase 4 ============= //----------- preparation ----------- std::string bob_detected_origin; crypto::hash redeem_tx_id = AUTO_VAL_INIT(redeem_tx_id); r = bob_b_wlt_instance->check_htlc_redeemed(hei_bob_b.tx_id, bob_detected_origin, redeem_tx_id); CHECK_AND_ASSERT_MES(r, false, "bob_a_wlt_instance->check_htlc_redeemed(hei_bob_b.tx_id, bob_detected_origin); returned false"); CHECK_AND_ASSERT_MES(bob_detected_origin == alice_origin, false, "bob_detected_origin == alice_origin failed"); bob_a_wlt_instance->redeem_htlc(hei_bob.tx_id, bob_detected_origin); //----------- rewinding ----------- r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); bob_a_wlt_instance->refresh(); bob_b_wlt_instance->refresh(); //----------- checks ----------- //now we have to check if all balances to make sure that atomic swap passed properly CHECK_AND_FORCE_ASSERT_MES(alice_a_wlt_instance->balance() == 0, false, "Incorrect balance"); CHECK_AND_FORCE_ASSERT_MES(bob_b_wlt_instance->balance() == 0, false, "Incorrect balance"); CHECK_AND_FORCE_ASSERT_MES(alice_b_wlt_instance->balance() == transfer_amount - TESTS_DEFAULT_FEE*2 , false, "Incorrect balance"); CHECK_AND_FORCE_ASSERT_MES(bob_a_wlt_instance->balance() == transfer_amount - TESTS_DEFAULT_FEE*2, false, "Incorrect balance"); return r; } //------------------------------------------------------------------------------ //============================================================================== //============================================================================== //============================================================================== bool atomic_test_wrong_redeem_wrong_refund::c1(currency::core& c, size_t ev_index, const std::vector& events) { /* we create two HTLC and then we make attempt to spend it: 1. spend it as refund when it supposed to be redeem 2. spend it as redeem when it supposed to be refund */ LOG_PRINT_MAGENTA("Mining Address: " << currency::get_account_address_as_str(m_mining_accunt.get_public_address()), LOG_LEVEL_0); //create wallet instances and calculate balances INIT_RUNTIME_WALLET(alice_a_wlt_instance); INIT_RUNTIME_WALLET(alice_b_wlt_instance); INIT_RUNTIME_WALLET(alice_c_wlt_instance); INIT_RUNTIME_WALLET(double_spend_test_instance_1); INIT_RUNTIME_WALLET(double_spend_test_instance_2); #define AMOUNT_TO_TRANSFER_HTLC (TESTS_DEFAULT_FEE*10) std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_mining_accunt); size_t blocks_fetched = 0; bool received_money = false; std::atomic atomic_false = ATOMIC_VAR_INIT(false); miner_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); uint64_t transfer_amount = AMOUNT_TO_TRANSFER_HTLC + TESTS_DEFAULT_FEE; miner_wlt->transfer(transfer_amount, alice_a_wlt_instance->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Alice A: " << transfer_amount, LOG_LEVEL_0); miner_wlt->transfer(transfer_amount, alice_b_wlt_instance->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Alice A: " << transfer_amount, LOG_LEVEL_0); miner_wlt->transfer(transfer_amount, double_spend_test_instance_1->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Double spend test: " << transfer_amount, LOG_LEVEL_0); bool r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); alice_c_wlt_instance->refresh(); double_spend_test_instance_1->refresh(); double_spend_test_instance_2->refresh(); std::string alice_origin; //will be deterministically generated by Alice's A wallet currency::transaction res_tx = AUTO_VAL_INIT(res_tx); alice_a_wlt_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, alice_b_wlt_instance->get_account().get_public_address(), 9, res_tx, currency::null_hash, alice_origin); std::string alice_origin_b; //will be deterministically generated by Alice's A wallet currency::transaction res_tx_b = AUTO_VAL_INIT(res_tx_b); alice_b_wlt_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, alice_c_wlt_instance->get_account().get_public_address(), 12, res_tx, currency::null_hash, alice_origin_b); //c) htlc double spend test std::string double_spend_origin; //will be deterministically generated by Alice's A wallet currency::transaction double_spend_res_tx = AUTO_VAL_INIT(double_spend_res_tx); double_spend_test_instance_1->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, double_spend_test_instance_2->get_account().get_public_address(), 9, double_spend_res_tx, currency::null_hash, double_spend_origin); //forward blockchain to create redeem transaction r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); alice_c_wlt_instance->refresh(); double_spend_test_instance_1->refresh(); CHECK_AND_FORCE_ASSERT_MES(alice_a_wlt_instance->balance() == transfer_amount - TESTS_DEFAULT_FEE, false, "Incorrect balance"); //create refund tx currency::transaction refund_tx = AUTO_VAL_INIT(refund_tx); alice_a_wlt_instance->transfer(transfer_amount - TESTS_DEFAULT_FEE*2, alice_b_wlt_instance->get_account().get_public_address(), refund_tx); //create double spend refund tx currency::transaction ds_refund_tx = AUTO_VAL_INIT(refund_tx); CHECK_AND_FORCE_ASSERT_MES(double_spend_test_instance_1->balance() == transfer_amount - TESTS_DEFAULT_FEE, false, "Incorrect balance"); double_spend_test_instance_1->transfer(transfer_amount - TESTS_DEFAULT_FEE * 2, double_spend_test_instance_2->get_account().get_public_address(), ds_refund_tx); //create redeem tx std::list htlcs; alice_c_wlt_instance->get_list_of_active_htlc(htlcs, true); CHECK_AND_FORCE_ASSERT_MES(htlcs.size() == 1, false, "Epected htlc not found"); currency::transaction result_redeem_tx = AUTO_VAL_INIT(result_redeem_tx); alice_c_wlt_instance->redeem_htlc(htlcs.front().tx_id, alice_origin_b, result_redeem_tx); //truncte blockchain c.get_tx_pool().clear(); c.get_blockchain_storage().truncate_blockchain(c.get_blockchain_storage().get_current_blockchain_size() - 8); double_spend_test_instance_2->refresh(); //create redeem tx for ds std::list htlcs_ds; double_spend_test_instance_2->get_list_of_active_htlc(htlcs_ds, true); CHECK_AND_FORCE_ASSERT_MES(htlcs_ds.size() == 1, false, "Epected htlc not found"); currency::transaction result_redeem_tx_ds = AUTO_VAL_INIT(result_redeem_tx_ds); double_spend_test_instance_2->redeem_htlc(htlcs_ds.front().tx_id, double_spend_origin, result_redeem_tx_ds); //try to submit wrong transaction that do refund before expiration std::vector txs; txs.push_back(refund_tx); r = mine_next_pow_block_in_playtime_with_given_txs(m_mining_accunt.get_public_address(), c, txs); CHECK_AND_FORCE_ASSERT_MES(!r, false, "Block with wrong refund tx accepted"); txs.clear(); txs.push_back(result_redeem_tx_ds); r = mine_next_pow_block_in_playtime_with_given_txs(m_mining_accunt.get_public_address(), c, txs); CHECK_AND_FORCE_ASSERT_MES(r, false, "Block with wrong refund tx accepted"); //forward blockchain and try to submit wrong tx that do redeem after expiration r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); //try to put wrong redeem tx (after expiration) txs.clear(); txs.push_back(result_redeem_tx); r = mine_next_pow_block_in_playtime_with_given_txs(m_mining_accunt.get_public_address(), c, txs); CHECK_AND_FORCE_ASSERT_MES(!r, false, "Blo k with wrong refund tx accepted"); //try to put wrong refund tx (double spend) txs.clear(); txs.push_back(ds_refund_tx); r = mine_next_pow_block_in_playtime_with_given_txs(m_mining_accunt.get_public_address(), c, txs); CHECK_AND_FORCE_ASSERT_MES(!r, false, "Blo k with wrong refund tx accepted"); return true; } //------------------------------------------------------------------------------ //============================================================================== //============================================================================== //============================================================================== bool atomic_test_altchain_simple::c1(currency::core& c, size_t ev_index, const std::vector& events) { /* 1. Create HTLC proposal 2. Do switch to altchain to the point before HTLC proposal creation (core and wallet) 3. Do redeem in altchain 4. Do switch to altchain to the point before HTLC redeem (core and wallet) 5. Do redeem in altchain 6. Validate correct state of core and wallet 7. Do redeem in altchain 8. Validate state TODO: play with expirations TODO: do refund, and then redeem in altchain */ LOG_PRINT_MAGENTA("Mining Address: " << currency::get_account_address_as_str(m_mining_accunt.get_public_address()), LOG_LEVEL_0); //create wallet instances and calculate balances INIT_RUNTIME_WALLET(alice_a_wlt_instance); INIT_RUNTIME_WALLET(alice_b_wlt_instance); #define AMOUNT_TO_TRANSFER_HTLC (TESTS_DEFAULT_FEE*10) std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_mining_accunt); size_t blocks_fetched = 0; bool received_money = false; std::atomic atomic_false = ATOMIC_VAR_INIT(false); miner_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); uint64_t transfer_amount = AMOUNT_TO_TRANSFER_HTLC + TESTS_DEFAULT_FEE; miner_wlt->transfer(transfer_amount, alice_a_wlt_instance->get_account().get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Alice A: " << transfer_amount, LOG_LEVEL_0); bool r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); std::string alice_origin; //will be deterministically generated by Alice's A wallet currency::transaction htlc_proposal_tx = AUTO_VAL_INIT(htlc_proposal_tx); alice_a_wlt_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, alice_b_wlt_instance->get_account().get_public_address(), 12, htlc_proposal_tx, currency::null_hash, alice_origin); crypto::hash split_id = c.get_blockchain_storage().get_top_block_id(); uint64_t split_height = c.get_blockchain_storage().get_top_block_height(); //forward blockchain to create redeem transaction r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 3); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); //memorize block id at split height before split to make sure split happened crypto::hash id_first_splited_block = c.get_blockchain_storage().get_block_id_by_height(split_height + 1); //validate state of a std::list htlcs_a; alice_a_wlt_instance->get_list_of_active_htlc(htlcs_a, false); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.size() == 1, false, "Epected htlc not found"); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.back().is_redeem == false, false, "type of htlc mismatched"); //validate state of b std::list htlcs_b; alice_b_wlt_instance->get_list_of_active_htlc(htlcs_b, true); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.size() == 1, false, "Epected htlc not found"); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.back().is_redeem == true, false, "type of htlc mismatched"); //create altchain std::vector txs; txs.push_back(htlc_proposal_tx); r = mine_next_pow_blocks_in_playtime_with_given_txs(m_mining_accunt.get_public_address(), txs, c, 10, split_id); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); //make sure reorganize happened crypto::hash id_new_chain = c.get_blockchain_storage().get_block_id_by_height(split_height + 1); CHECK_AND_ASSERT_MES(id_new_chain != id_first_splited_block, false, "Reorganize didn't happen"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); htlcs_a.clear(); alice_a_wlt_instance->get_list_of_active_htlc(htlcs_a, false); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.size() == 1, false, "Epected htlc not found"); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.back().is_redeem == false, false, "type of htlc mismatched"); //validate state of b htlcs_b.clear(); alice_b_wlt_instance->get_list_of_active_htlc(htlcs_b, true); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.size() == 1, false, "Epected htlc not found"); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.back().is_redeem == true, false, "type of htlc mismatched"); currency::transaction result_redeem_tx = AUTO_VAL_INIT(result_redeem_tx); alice_b_wlt_instance->redeem_htlc(htlcs_b.front().tx_id, alice_origin, result_redeem_tx); crypto::hash split_id_2 = c.get_blockchain_storage().get_top_block_id(); uint64_t split_height_2 = c.get_blockchain_storage().get_top_block_height(); //forward blockchain r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 3); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); //here should be zero htlcs_a.clear(); alice_a_wlt_instance->get_list_of_active_htlc(htlcs_a, false); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.size() == 0, false, "Epected htlc not found"); //validate state of b htlcs_b.clear(); alice_b_wlt_instance->get_list_of_active_htlc(htlcs_b, true); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.size() == 0, false, "Epected htlc not found"); //memorize block id at split height before split to make sure split happened crypto::hash id_first_splited_block_2 = c.get_blockchain_storage().get_block_id_by_height(split_height_2 + 1); txs.clear(); txs.push_back(result_redeem_tx); r = mine_next_pow_blocks_in_playtime_with_given_txs(m_mining_accunt.get_public_address(), txs, c, 4, split_id_2); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); c.get_blockchain_storage().truncate_blockchain(c.get_top_block_height() - 2); //make sure reorganize happened crypto::hash id_new_chain_2 = c.get_blockchain_storage().get_block_id_by_height(split_height_2 + 1); CHECK_AND_ASSERT_MES(id_new_chain_2 != id_first_splited_block_2, false, "Reorganize didn't happen"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); htlcs_a.clear(); alice_a_wlt_instance->get_list_of_active_htlc(htlcs_a, false); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.size() == 1, false, "Epected htlc not found"); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.back().is_redeem == false, false, "type of htlc mismatched"); //validate state of b htlcs_b.clear(); alice_b_wlt_instance->get_list_of_active_htlc(htlcs_b, true); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.size() == 1, false, "Epected htlc not found"); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.back().is_redeem == true, false, "type of htlc mismatched"); //forward blockchain r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 3); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); htlcs_a.clear(); alice_a_wlt_instance->get_list_of_active_htlc(htlcs_a, false); CHECK_AND_FORCE_ASSERT_MES(htlcs_a.size() == 0, false, "htlc contracts count is wrong"); //validate state of b htlcs_b.clear(); alice_b_wlt_instance->get_list_of_active_htlc(htlcs_b, true); CHECK_AND_FORCE_ASSERT_MES(htlcs_b.size() == 0, false, "htlc contracts count is wrong"); return true; } //------------------------------------------------------------------------------ atomic_test_check_hardfork_rules::atomic_test_check_hardfork_rules() { m_hardforks.clear(); m_hardforks.set_hardfork_height(1, 10); m_hardforks.set_hardfork_height(2, 10); m_hardforks.set_hardfork_height(3, 10); } bool atomic_test_check_hardfork_rules::c1(currency::core& c, size_t ev_index, const std::vector& events) { //epee::debug::get_set_enable_assert(true, true); //misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&]() {epee::debug::get_set_enable_assert(true, false); }); INIT_RUNTIME_WALLET(alice_a_wlt_instance); #define AMOUNT_TO_TRANSFER_HTLC (TESTS_DEFAULT_FEE*10) std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, m_mining_accunt); size_t blocks_fetched = 0; bool received_money = false; std::atomic atomic_false = ATOMIC_VAR_INIT(false); miner_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); currency::transaction res_tx = AUTO_VAL_INIT(res_tx); std::string alice_origin; miner_wlt->create_htlc_proposal(AMOUNT_TO_TRANSFER_HTLC - TESTS_DEFAULT_FEE, alice_a_wlt_instance->get_account().get_public_address(), 100, res_tx, currency::null_hash, alice_origin); currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config(); pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; //four blocks pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; //four blocks pc.hard_forks.set_hardfork_height(1, 10); pc.hard_forks.set_hardfork_height(2, 10); pc.hard_forks.set_hardfork_height(3, 30); c.get_blockchain_storage().set_core_runtime_config(pc); bool r = mine_next_pow_block_in_playtime(m_mining_accunt.get_public_address(), c); CHECK_AND_FORCE_ASSERT_MES(!r, false, "Block with HTLC before hard fork accepted"); return true; } #endif