From a31670f22598d0c99fa0ba67ba6149863ee9733f Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 2 Feb 2021 19:02:28 +0100 Subject: [PATCH] in the middle of prepare_tx_sources_htlc --- src/common/error_codes.h | 1 + src/crypto/RIPEMD160_helper.cpp | 8 ++ src/crypto/RIPEMD160_helper.h | 1 + src/currency_core/currency_format_utils.cpp | 17 +-- src/currency_core/currency_format_utils.h | 2 +- .../currency_format_utils_transactions.h | 48 +++++-- src/wallet/wallet2.cpp | 120 ++++++++++++++++-- src/wallet/wallet2.h | 6 +- 8 files changed, 166 insertions(+), 37 deletions(-) diff --git a/src/common/error_codes.h b/src/common/error_codes.h index a9644517..648bd6fd 100644 --- a/src/common/error_codes.h +++ b/src/common/error_codes.h @@ -39,3 +39,4 @@ #define API_RETURN_CODE_UNINITIALIZED "UNINITIALIZED" #define API_RETURN_CODE_TX_IS_TOO_BIG "TX_IS_TOO_BIG" #define API_RETURN_CODE_TX_REJECTED "TX_REJECTED" +#define API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED "HTLC_ORIGIN_HASH_MISSMATCHED" diff --git a/src/crypto/RIPEMD160_helper.cpp b/src/crypto/RIPEMD160_helper.cpp index b2ecee62..68419195 100644 --- a/src/crypto/RIPEMD160_helper.cpp +++ b/src/crypto/RIPEMD160_helper.cpp @@ -56,4 +56,12 @@ namespace crypto { return h; } + hash RIPEMD160_hash_256(const void *data, size_t length) + { + hash160 h = RIPEMD160_hash(data, length); + hash h256 = AUTO_VAL_INIT(h256); + memcpy(&h256, &h, sizeof(h)); + return h256; + } + } diff --git a/src/crypto/RIPEMD160_helper.h b/src/crypto/RIPEMD160_helper.h index 6e923fcb..2257e2bb 100644 --- a/src/crypto/RIPEMD160_helper.h +++ b/src/crypto/RIPEMD160_helper.h @@ -17,6 +17,7 @@ namespace crypto { void RIPEMD160_hash(const void *data, size_t length, hash160 &h); hash160 RIPEMD160_hash(const void *data, size_t length); + hash RIPEMD160_hash_256(const void *data, size_t length); } diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index e8272e50..3673425b 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -591,11 +591,11 @@ namespace currency // return true; // } //--------------------------------------------------------------- - std::string generate_origin_for_htlc(const crypto::public_key& redeem, const crypto::public_key& refund, const account_keys& acc_keys) + std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys) { std::string blob; - string_tools::apped_pod_to_strbuff(blob, redeem); - string_tools::apped_pod_to_strbuff(blob, refund); + string_tools::apped_pod_to_strbuff(blob, htlc.pkey_redeem); + string_tools::apped_pod_to_strbuff(blob, htlc.pkey_refund); string_tools::apped_pod_to_strbuff(blob, acc_keys.spend_secret_key); crypto::hash origin_hs = crypto::cn_fast_hash(blob.data(), blob.size()); std::string origin_blob; @@ -635,12 +635,13 @@ namespace currency tx_out out; out.amount = de.amount; - if (de.htlc) + if (de.additional_options.type() == typeid(destination_option_htlc_out)) { + const destination_option_htlc_out& htlc_dest = boost::get(de.additional_options); //out htlc CHECK_AND_ASSERT_MES(target_keys.size() == 1, false, "Unexpected htl keys count = " << target_keys.size() << ", expected ==1"); txout_htlc htlc = AUTO_VAL_INIT(htlc); - htlc.expiration = de.unlock_time; + htlc.expiration = htlc_dest.expiration; htlc.flags = 0; //0 - SHA256, 1 - RIPEMD160, by default leave SHA256 //receiver key htlc.pkey_redeem = *target_keys.begin(); @@ -651,10 +652,10 @@ namespace currency CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); htlc.pkey_refund = out_eph_public_key; - if (de.htlc_hash == null_hash) + if (htlc_dest.htlc_hash == null_hash) { //we use deterministic origin, to make possible access origin on different wallets copies - std::string hltc_origin = generate_origin_for_htlc(htlc.pkey_redeem, htlc.pkey_refund, self); + std::string hltc_origin = generate_origin_for_htlc(htlc, self); //calculate hash if (htlc.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK) @@ -669,7 +670,7 @@ namespace currency } else { - htlc.htlc_hash = de.htlc_hash; + htlc.htlc_hash = htlc_dest.htlc_hash; } } diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 0210d3e4..deb20f94 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -299,7 +299,7 @@ namespace currency void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map& gindices); std::string get_word_from_timstamp(uint64_t timestamp, bool use_password); uint64_t get_timstamp_from_word(std::string word, bool& password_used); - std::string generate_origin_for_htlc(const crypto::public_key& redeem, const crypto::public_key& refund, const account_keys& acc_keys); + std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys); template typename std::conditional::value, const std::vector, std::vector >::type& get_txin_etc_options(t_txin_v& in) { diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index 9028d0cc..881aae98 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -28,6 +28,7 @@ namespace currency size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation + std::string htlc_origin; //for htlc, specify origin bool is_multisig() const { return ms_sigs_count > 0; } @@ -42,23 +43,43 @@ namespace currency FIELD(ms_sigs_count) FIELD(ms_keys_count) FIELD(separately_signed_tx_complete) - END_SERIALIZE() + FIELD(htlc_origin) + END_SERIALIZE() }; + struct destination_option_void + { + BEGIN_SERIALIZE_OBJECT() + END_SERIALIZE() + }; + + //if this struct is present, then creating htlc out, expiration -> number of blocks that htlc proposal is active + struct destination_option_htlc_out + { + uint64_t expiration; + crypto::hash htlc_hash; + BEGIN_SERIALIZE_OBJECT() + FIELD(transfer) + FIELD(origin) + END_SERIALIZE() + }; + + typedef boost::variant destination_option_v; + struct tx_destination_entry { - uint64_t amount; //money - std::list addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig - size_t minimum_sigs; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used - uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions + uint64_t amount; //money + std::list addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig + size_t minimum_sigs; //if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used + uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions uint64_t unlock_time; - bool htlc; //if this flag is set, then creating htlc out, unlock_time -> number of blocks that htlc proposal is active - crypto::hash htlc_hash; - - tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc(false), htlc_hash(null_hash){} - tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc(false), htlc_hash(null_hash) {} - tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut), htlc(false), htlc_hash(null_hash) {} - tx_destination_entry(uint64_t a, const std::list& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0), htlc(false), htlc_hash(null_hash) {} + destination_option_v additional_options; //additional options + + + tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0), additional_options(destination_option_void()){} + tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0), additional_options(destination_option_void()) {} + tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut), additional_options(destination_option_void()) {} + tx_destination_entry(uint64_t a, const std::list& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0), additional_options(destination_option_void()) {} BEGIN_SERIALIZE_OBJECT() FIELD(amount) @@ -66,8 +87,7 @@ namespace currency FIELD(minimum_sigs) FIELD(amount_to_provide) FIELD(unlock_time) - FIELD(htlc) - FIELD(htlc_hash) + FIELD(additional_options) END_SERIALIZE() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 01eb6486..6feb5b07 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -4021,9 +4021,10 @@ void wallet2::create_htlc_proposal(uint64_t amount, const currency::account_publ dst.resize(1); dst.back().addr.push_back(addr); dst.back().amount = amount; - dst.back().htlc = true; - dst.back().htlc_hash = htlc_hash; - dst.back().unlock_time = 740; //about 12 hours + destination_option_htlc_out htlc_option = AUTO_VAL_INIT(htlc_option); + htlc_option.expiration = 740; //about 12 hours + htlc_option.htlc_hash = htlc_hash; + dst.back().additional_options = htlc_option; transaction result_tx = AUTO_VAL_INIT(result_tx); this->transfer(dst, 0, 0, TX_DEFAULT_FEE, extra, attachments, tools::detail::ssi_digit, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx); @@ -4050,15 +4051,45 @@ void wallet2::get_list_of_active_htlc(bool only_redeem_txs, std::list dst; + dst.resize(1); + dst.back().addr.push_back(m_account.get_keys().account_address); + dst.back().amount = 0; + + + construct_tx_param ctp = get_default_construct_tx_param(); + ctp.fee = TX_DEFAULT_FEE; + ctp.htlc_tx_id = htlc_tx_id; + ctp.htlc_origin = origin; + + /* + struct destination_option_htlc_in { - WLT_THROW_IF_FALSE_WITH_CODE(false, - "htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND); - } + uint64_t transfer; + std::string origin; + BEGIN_SERIALIZE_OBJECT() + FIELD(transfer) + FIELD(origin) + END_SERIALIZE() + }; + transfer(const construct_tx_param& ctp, + currency::transaction &tx, + bool send_to_network, + std::string* p_unsigned_filename_or_tx_blob_str); + + + */ + + + currency::transaction result_tx = AUTO_VAL_INIT(tx); + transaction result_tx = AUTO_VAL_INIT(result_tx); + this->transfer(ctp, result_tx, true, nullptr); + + + } //---------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector& sources, std::vector& selected_indicies, uint64_t& found_money) @@ -4232,6 +4263,55 @@ bool wallet2::prepare_tx_sources(crypto::hash multisig_id, std::vector& sources, uint64_t& found_money) +{ + //lets figure out, if we have active htlc for this htlc + auto it = m_active_htlcs_txid.find(htlc_tx_id); + if (it == m_active_htlcs_txid.end()) + { + WLT_THROW_IF_FALSE_WITH_CODE(false, + "htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND); + } + + WLT_THROW_IF_FALSE_WITH_CODE(m_transfers.size() > it->second, + "Internal error: index in m_active_htlcs_txid <" << it->second << "> is bigger then size of m_transfers <" << m_transfers.size() << ">", API_RETURN_CODE_INTERNAL_ERROR); + + const transfer_details& td = m_transfers[it->second]; + WLT_THROW_IF_FALSE_WITH_CODE(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].target.type() == typeid(txout_htlc), + "Unexpected type in active htlc", API_RETURN_CODE_INTERNAL_ERROR); + + const txout_htlc& htlc_out = boost::get(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].target); + bool use_sha256 = !(htlc_out.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK); + + //check origin + WLT_THROW_IF_FALSE_WITH_CODE(origin.size() != 0, + "Origin for htlc is empty", API_RETURN_CODE_BAD_ARG); + + crypto::hash htlc_calculated_hash = currency::null_hash; + if (use_sha256) + { + htlc_calculated_hash = crypto::sha256_hash(origin.data(), origin.size()); + } + else + { + htlc_calculated_hash = crypto::RIPEMD160_hash_256(origin.data(), origin.size()); + } + WLT_THROW_IF_FALSE_WITH_CODE(htlc_calculated_hash == htlc_out.htlc_hash, + "Origin hash is missmatched with txout_htlc", API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED); + + sources.push_back(AUTO_VAL_INIT(currency::tx_source_entry())); + currency::tx_source_entry& src = sources.back(); + src.amount = found_money = td.amount(); + src.real_output_in_tx_index = td.m_internal_output_index; + src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx); + src.htlc_origin = origin; + //src.multisig_id = multisig_id; + //src.ms_sigs_count = ms_out.minimum_sigs; + //src.ms_keys_count = ms_out.keys.size(); + return true; + +} +//---------------------------------------------------------------------------------------------------------------- uint64_t wallet2::get_needed_money(uint64_t fee, const std::vector& dsts) { uint64_t needed_money = fee; @@ -4247,6 +4327,7 @@ uint64_t wallet2::get_needed_money(uint64_t fee, const std::vector extra; @@ -835,7 +838,7 @@ namespace tools void create_htlc_proposal(uint64_t amount, const currency::account_public_address& addr, uint64_t lock_blocks_count, currency::transaction &tx, const crypto::hash& htlc_hash = currency::null_hash); void get_list_of_active_htlc(bool only_redeem_txs, std::list& htlcs); - void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin); + void redeem_htlc(const crypto::hash& htlc_tx_id, std::string origin); private: @@ -895,6 +898,7 @@ private: bool prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector& sources, std::vector& selected_indicies, uint64_t& found_money); bool prepare_tx_sources(size_t fake_outputs_count, std::vector& sources, std::vector& selected_indicies, uint64_t& found_money); bool prepare_tx_sources(crypto::hash multisig_id, std::vector& sources, uint64_t& found_money); + bool prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string& origin, std::vector& sources, uint64_t& found_money); bool prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector& sources, std::vector& selected_indicies, uint64_t& found_money); void prefetch_global_indicies_if_needed(std::vector& selected_indicies); uint64_t get_needed_money(uint64_t fee, const std::vector& dsts);