diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 4f8e9320..97d9480e 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -310,7 +310,7 @@ namespace currency account_public_address ad = AUTO_VAL_INIT(ad); if (!get_account_address_from_str(ad, str)) { - LOG_ERROR("cannot parse address from string: " << str); + CHECK_AND_ASSERT_THROW_MES(false, "cannot parse address from string: " << str); } return ad; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ab71af8f..6b0baf21 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -400,6 +400,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t m_transfers[it->second].m_spent_height = height; transfer_details_extra_option_htlc_info& tdeohi = get_or_add_field_to_variant_vector(td.varian_options); tdeohi.origin = in_htlc.hltc_origin; + tdeohi.redeem_tx_id = get_transaction_hash(tx); } } i++; @@ -4141,6 +4142,11 @@ void wallet2::get_list_of_active_htlc(std::list& "[get_list_of_active_htlc]Internal error: unexpected type of out"); const txout_htlc& htlc = boost::get(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].target); entry.sha256_hash = htlc.htlc_hash; + + currency::tx_payer payer = AUTO_VAL_INIT(payer); + if (currency::get_type_in_variant_container(td.m_ptx_wallet_info->m_tx.extra, payer)) + entry.counterparty_address = payer.acc_addr; + entry.is_redeem = td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? true : false; htlcs.push_back(entry); } @@ -4170,7 +4176,7 @@ void wallet2::redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& ori this->transfer(ctp, result_tx, true, nullptr); } //---------------------------------------------------------------------------------------------------- -bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin) +bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin, crypto::hash& redeem_tx_id) { auto it = m_active_htlcs_txid.find(htlc_tx_id); @@ -4185,6 +4191,7 @@ bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& o if (htlc_options.origin.size()) { origin = htlc_options.origin; + redeem_tx_id = htlc_options.redeem_tx_id; return true; } return false; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 203fd272..9821567f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -400,6 +400,7 @@ namespace tools struct transfer_details_extra_option_htlc_info { std::string origin; //this field filled only if htlc had been redeemed + crypto::hash redeem_tx_id; }; typedef boost::variant transfer_details_extra_options_v; @@ -862,7 +863,7 @@ namespace tools void get_list_of_active_htlc(std::list& htlcs, bool only_redeem_txs); void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin, currency::transaction& result_tx); void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin); - bool check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin); + bool check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin, crypto::hash& redeem_tx_id); private: diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 4e8fa6cd..efafaf97 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -74,6 +74,11 @@ namespace tools return m_what.c_str(); } + virtual const std::string error_code() const noexcept + { + return m_error_code; + } + wallet_error_base(std::string&& loc, const std::string& message, const std::string& error_code) : Base(message) , m_loc(loc) diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 60ae06be..22aaea2e 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -980,6 +980,7 @@ namespace wallet_public struct htlc_entry_info { + currency::account_public_address counterparty_address; crypto::hash sha256_hash; crypto::hash tx_id; uint64_t amount; @@ -987,15 +988,116 @@ namespace wallet_public BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) - KV_SERIALIZE(sha256_hash) - KV_SERIALIZE(tx_id) + KV_SERIALIZE_ADDRESS_AS_TEXT(counterparty_address) + KV_SERIALIZE_POD_AS_HEX_STRING(sha256_hash) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) KV_SERIALIZE(is_redeem) END_KV_SERIALIZE_MAP() }; + struct COMMAND_CREATE_HTLC_PROPOSAL + { + struct request + { + uint64_t amount; + currency::account_public_address counterparty_address; + uint64_t lock_blocks_count; + crypto::hash htlc_hash; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE_ADDRESS_AS_TEXT(counterparty_address) + KV_SERIALIZE(lock_blocks_count) + KV_SERIALIZE_POD_AS_HEX_STRING(htlc_hash) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string result_tx_blob; + crypto::hash result_tx_id; + std::string derived_origin_secret; // this field derived in a deterministic way if no htlc_hash was provided + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_BLOB_AS_HEX_STRING(result_tx_blob) + KV_SERIALIZE_POD_AS_HEX_STRING(result_tx_id) + KV_SERIALIZE_BLOB_AS_HEX_STRING_N(derived_origin_secret, "derived_origin_secret_as_hex") + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_GET_LIST_OF_ACTIVE_HTLC + { + struct request + { + bool income_redeem_only; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(income_redeem_only) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list m_htlcs; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_htlcs) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_REDEEM_HTLC + { + struct request + { + crypto::hash tx_id; + std::string origin_secret; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) + KV_SERIALIZE_BLOB_AS_HEX_STRING_N(origin_secret, "origin_secret_as_hex") + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string result_tx_blob; + crypto::hash result_tx_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_BLOB_AS_HEX_STRING(result_tx_blob) + KV_SERIALIZE_POD_AS_HEX_STRING(result_tx_id) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_CHECK_HTLC_REDEEMED + { + struct request + { + crypto::hash htlc_tx_id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(htlc_tx_id) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string origin_secrete; + crypto::hash redeem_tx_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_BLOB_AS_HEX_STRING_N(origin_secrete, "origin_secrete_as_hex") + KV_SERIALIZE_POD_AS_HEX_STRING(redeem_tx_id) + END_KV_SERIALIZE_MAP() + }; + }; + inline std::string get_escrow_contract_state_name(uint32_t state) { switch (state) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index fef4f1a4..4c30bdcd 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -19,6 +19,12 @@ using namespace epee; #define WALLET_RPC_BEGIN_TRY_ENTRY() try { #define WALLET_RPC_CATCH_TRY_ENTRY() } \ + catch (const tools::error::wallet_error& e) \ + { \ + er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ + er.message = e.error_code(); \ + return false; \ + } \ catch (const std::exception& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ @@ -779,7 +785,45 @@ namespace tools return true; WALLET_RPC_CATCH_TRY_ENTRY(); } - + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_create_htlc_proposal(const wallet_public::COMMAND_CREATE_HTLC_PROPOSAL::request& req, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + WALLET_RPC_BEGIN_TRY_ENTRY(); + currency::transaction tx = AUTO_VAL_INIT(tx); + m_wallet.create_htlc_proposal(req.amount, req.counterparty_address, req.lock_blocks_count, tx, req.htlc_hash, res.derived_origin_secret); + res.result_tx_blob = currency::tx_to_blob(tx); + res.result_tx_id = get_transaction_hash(tx); + WALLET_RPC_CATCH_TRY_ENTRY(); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_get_list_of_active_htlc(const wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC::request& req, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + WALLET_RPC_BEGIN_TRY_ENTRY(); + m_wallet.get_list_of_active_htlc(res.m_htlcs, req.income_redeem_only); + WALLET_RPC_CATCH_TRY_ENTRY(); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_redeem_htlc(const wallet_public::COMMAND_REDEEM_HTLC::request& req, wallet_public::COMMAND_REDEEM_HTLC::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + WALLET_RPC_BEGIN_TRY_ENTRY(); + currency::transaction tx = AUTO_VAL_INIT(tx); + m_wallet.redeem_htlc(req.tx_id, req.origin_secret, tx); + res.result_tx_blob = currency::tx_to_blob(tx); + res.result_tx_id = get_transaction_hash(tx); + WALLET_RPC_CATCH_TRY_ENTRY(); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_check_htlc_redeemed(const wallet_public::COMMAND_CHECK_HTLC_REDEEMED::request& req, wallet_public::COMMAND_CHECK_HTLC_REDEEMED::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + WALLET_RPC_BEGIN_TRY_ENTRY(); + m_wallet.check_htlc_redeemed(req.htlc_tx_id, res.origin_secrete, res.redeem_tx_id); + WALLET_RPC_CATCH_TRY_ENTRY(); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ } // namespace tools diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index ccf26798..2d94bc52 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -65,6 +65,12 @@ namespace tools MAP_JON_RPC_WE("marketplace_push_offer", on_marketplace_push_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_OFFER) MAP_JON_RPC_WE("marketplace_push_update_offer", on_marketplace_push_update_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_UPDATE_OFFER) MAP_JON_RPC_WE("marketplace_cancel_offer", on_marketplace_cancel_offer, wallet_public::COMMAND_MARKETPLACE_CANCEL_OFFER) + //HTLC API + MAP_JON_RPC_WE("atomics_create_htlc_proposal", on_create_htlc_proposal, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL) + MAP_JON_RPC_WE("atomics_get_list_of_active_htlc", on_get_list_of_active_htlc, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC) + MAP_JON_RPC_WE("atomics_redeem_htlc", on_redeem_htlc, wallet_public::COMMAND_REDEEM_HTLC) + MAP_JON_RPC_WE("atomics_check_htlc_redeemed", on_check_htlc_redeemed, wallet_public::COMMAND_CHECK_HTLC_REDEEMED) + END_JSON_RPC_MAP() END_URI_MAP2() @@ -98,6 +104,11 @@ namespace tools bool on_marketplace_push_update_offer(const wallet_public::COMMAND_MARKETPLACE_PUSH_UPDATE_OFFER::request& req, wallet_public::COMMAND_MARKETPLACE_PUSH_UPDATE_OFFER::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_marketplace_cancel_offer(const wallet_public::COMMAND_MARKETPLACE_CANCEL_OFFER::request& req, wallet_public::COMMAND_MARKETPLACE_CANCEL_OFFER::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_create_htlc_proposal(const wallet_public::COMMAND_CREATE_HTLC_PROPOSAL::request& req, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_get_list_of_active_htlc(const wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC::request& req, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_redeem_htlc(const wallet_public::COMMAND_REDEEM_HTLC::request& req, wallet_public::COMMAND_REDEEM_HTLC::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_check_htlc_redeemed(const wallet_public::COMMAND_CHECK_HTLC_REDEEMED::request& req, wallet_public::COMMAND_CHECK_HTLC_REDEEMED::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool handle_command_line(const boost::program_options::variables_map& vm); diff --git a/tests/core_tests/atomic_tests.cpp b/tests/core_tests/atomic_tests.cpp index 68c7a82f..1c3f4fcd 100644 --- a/tests/core_tests/atomic_tests.cpp +++ b/tests/core_tests/atomic_tests.cpp @@ -297,7 +297,8 @@ bool atomic_simple_test::c1(currency::core& c, size_t ev_index, const std::vecto //============= phase 4 ============= //----------- preparation ----------- std::string bob_detected_origin; - r = bob_b_wlt_instance->check_htlc_redeemed(hei_bob_b.tx_id, 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");