From 82d0e335e6dc3f2e52b1ef2750f58df429724b7c Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Sat, 13 Feb 2021 00:57:24 +0100 Subject: [PATCH] added double spend protection in htlc(great that i've thought about it now), wallet loading optimization --- src/currency_core/blockchain_storage.cpp | 6 +- src/currency_core/blockchain_storage.h | 5 ++ src/currency_core/currency_format_utils.cpp | 6 +- src/currency_core/currency_format_utils.h | 2 +- src/wallet/wallet2.cpp | 12 ++-- tests/core_tests/atomic_tests.cpp | 67 +++++++++++++++++++-- 6 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 558997da..a04a7c63 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -744,8 +744,7 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans } bool operator()(const txin_htlc& inp) const { - //HTLC TODO - return true; + return this->operator()(static_cast(inp)); } }; @@ -3845,8 +3844,7 @@ namespace currency } bool operator()(const txin_htlc& in) const { - //HTLC TODO - return true; + return this->operator()(static_cast(in)); } bool operator()(const txin_gen& in) const { return true; } bool operator()(const txin_multisig& in) const diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index b20c2965..bb3dd331 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -779,6 +779,11 @@ namespace currency } else if (tx_ptr->tx.vout[n].target.type() == typeid(txout_htlc)) { + //check for spend flags + CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false, + "Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}"); + CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected"); + const txout_htlc& htlc_out = boost::get(tx_ptr->tx.vout[n].target); if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height) { diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index bda19214..2a01891f 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -997,7 +997,7 @@ namespace currency void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x) { x.is_service = currency::is_service_tx(x.tx); - x.is_mixing = currency::is_mixin_tx(x.tx); + x.is_mixing = currency::does_tx_have_only_mixin_inputs(x.tx); x.is_mining = currency::is_coinbase(x.tx); if (!x.is_mining) x.fee = currency::get_tx_fee(x.tx); @@ -1010,7 +1010,7 @@ namespace currency x.tx_type = get_tx_type_ex(x.tx, htlc_out, htlc_in); if(x.tx_type == GUI_TX_TYPE_HTLC_DEPOSIT && x.is_income == true) { - //need to correct amount + //need to override amount x.amount = htlc_out.amount; } } @@ -2366,7 +2366,7 @@ namespace currency return have_type_in_variant_container(tx.attachment) || have_type_in_variant_container(tx.attachment); } //--------------------------------------------------------------- - bool is_mixin_tx(const transaction& tx) + bool does_tx_have_only_mixin_inputs(const transaction& tx) { for (const auto& e : tx.vin) { diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 1d8b6b8d..00240e6c 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -334,7 +334,7 @@ namespace currency bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id); bool add_padding_to_tx(transaction& tx, size_t count); bool is_service_tx(const transaction& tx); - bool is_mixin_tx(const transaction& tx); + bool does_tx_have_only_mixin_inputs(const transaction& tx); bool is_showing_sender_addres(const transaction& tx); uint64_t get_amount_for_zero_pubkeys(const transaction& tx); //std::string get_comment_from_tx(const transaction& tx); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7727d3e5..2d78bfe4 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2245,8 +2245,6 @@ void wallet2::detach_blockchain(uint64_t including_height) // skip coinbase txs as they are not expected to go into the pool if (is_coinbase(it->tx)) { - if (!it->is_mining) - WLT_LOG_ERROR("is_mining flag is not consistent for tx " << it ->tx_hash); continue; } @@ -3086,7 +3084,7 @@ void wallet2::get_recent_transfers_history(std::vectortx)) + if(currency::is_coinbase(it->tx)) continue; } trs.push_back(*it); @@ -3424,7 +3422,7 @@ void wallet2::get_unconfirmed_transfers(std::vectortransfer(ctp, ft, true, nullptr); diff --git a/tests/core_tests/atomic_tests.cpp b/tests/core_tests/atomic_tests.cpp index f94941e5..fea9167c 100644 --- a/tests/core_tests/atomic_tests.cpp +++ b/tests/core_tests/atomic_tests.cpp @@ -99,8 +99,8 @@ bool atomic_simple_test::c1(currency::core& c, size_t ev_index, const std::vecto miner_wlt->transfer(transfer_amount, accunt_alice_blockchain_a.get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to Alice A: " << transfer_amount, LOG_LEVEL_0); - miner_wlt->transfer(transfer_amount, accunt_bob_blockchain_a.get_public_address()); - LOG_PRINT_MAGENTA("Transaction sent to Bob A: " << transfer_amount, LOG_LEVEL_0); + miner_wlt->transfer(transfer_amount, accunt_bob_blockchain_b.get_public_address()); + LOG_PRINT_MAGENTA("Transaction sent to Bob B: " << 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"); @@ -116,19 +116,76 @@ bool atomic_simple_test::c1(currency::core& c, size_t ev_index, const std::vecto alice_a_wlt_instance->refresh(); alice_b_wlt_instance->refresh(); bob_a_wlt_instance->refresh(); - bob_a_wlt_instance->refresh(); + bob_b_wlt_instance->refresh(); CHECK_AND_FORCE_ASSERT_MES(alice_a_wlt_instance->balance() == transfer_amount, false, "Incorrect balance"); - CHECK_AND_FORCE_ASSERT_MES(bob_a_wlt_instance->balance() == transfer_amount, false, "Incorrect balance"); + CHECK_AND_FORCE_ASSERT_MES(bob_b_wlt_instance->balance() == transfer_amount, false, "Incorrect balance"); 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(), 20, res_tx, alice_origin); + alice_a_wlt_instance->create_htlc_proposal(transfer_amount - TESTS_DEFAULT_FEE, bob_a_wlt_instance->get_account().get_public_address(), 20, res_tx, currency::null_hash, alice_origin); 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(); + + 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 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 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 "); + + + //std::string bob_origin; + 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(), + 20, + res_tx, hei_bob.sha256_hash, dummy_origin); + + 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(); + + + 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_a_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"); + + const wallet_public::htlc_entry_info& hei_bob_b = *htlcs_bob_b.begin(); + CHECK_AND_ASSERT_MES(hei_bob_b.is_redeem == true, false, "hei_bob.is_redeem == true failed"); + + + const wallet_public::htlc_entry_info& hei_alice_b = *htlcs_alice_b.begin(); + CHECK_AND_ASSERT_MES(hei_alice_b.is_redeem == false, false, "hei_alice.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 "); return r; }