From b5477a836ca21917ee94a5e797525797b4393817 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 20 Oct 2021 21:18:21 +0200 Subject: [PATCH] export transactions refactoring for #245 --- contrib/epee/include/time_helper.h | 2 +- src/simplewallet/simplewallet.cpp | 106 +++++++++++++++++------------ src/wallet/wallet2.cpp | 81 ++++++++++++++++++++++ src/wallet/wallet2.h | 7 +- src/wallet/wallet_rpc_server.cpp | 4 +- 5 files changed, 151 insertions(+), 49 deletions(-) diff --git a/contrib/epee/include/time_helper.h b/contrib/epee/include/time_helper.h index f11dae91..c2b439e2 100644 --- a/contrib/epee/include/time_helper.h +++ b/contrib/epee/include/time_helper.h @@ -87,7 +87,7 @@ DISABLE_VS_WARNINGS(4996) POP_VS_WARNINGS if(pt) - strftime( tmpbuf, 199, "%Y_%m_%d %H_%M_%S", pt ); + strftime( tmpbuf, 199, "%Y-%m-%d %H:%M:%S", pt ); else { std::stringstream strs; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 71fbffc0..1de92a33 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -228,6 +228,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), "sign_transfer - sign unsigned tx from a watch-only wallet"); m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), "submit_transfer - broadcast signed tx"); + m_cmd_binder.set_handler("export_history", boost::bind(&simple_wallet::submit_transfer, this, _1), "Export transaction history in CSV file"); } //---------------------------------------------------------------------------------------------------- simple_wallet::~simple_wallet() @@ -798,12 +799,7 @@ bool simple_wallet::list_recent_transfers(const std::vector& args) std::string wti_to_text_line(const tools::wallet_public::wallet_transfer_info& wti) { stringstream ss; - ss << (wti.is_income ? "[INC]" : "[OUT]") << "\t" - << epee::misc_utils::get_time_str(wti.timestamp) << "\t" - << print_money(wti.amount) << "\t" - << print_money(wti.fee) << "\t" - << wti.remote_addresses << "\t" - << wti.comment << "\t"; + return ss.str(); } //---------------------------------------------------------------------------------------------------- @@ -811,57 +807,77 @@ bool simple_wallet::export_recent_transfers(const std::vector& args { bool export_to_json = true; bool ignore_pos = false; - if (args.size()) - { - if (args[0] == "json") - export_to_json = true; - else if (args[0] == "txt") - export_to_json = false; - } if (args.size() > 1) { if (args[1] == "ignore-pos") ignore_pos = true; } - std::vector unconfirmed; - std::vector recent; - uint64_t total = 0; - uint64_t last_index = 0; - m_wallet->get_recent_transfers_history(recent, 0, 0, total, last_index, false); - m_wallet->get_unconfirmed_transfers(unconfirmed, false); - //workaround for missed fee - stringstream ss; - LOG_PRINT_GREEN("Generating text....", LOG_LEVEL_0); - ss << "Unconfirmed transfers: " << ENDL; - for (auto & wti : unconfirmed) + std::string format = "csv"; + if (args.size() > 0) { - if(ignore_pos && wti.is_mining) - continue; - if (!wti.fee) - wti.fee = currency::get_tx_fee(wti.tx); - if(export_to_json) - ss << epee::serialization::store_t_to_json(wti) << ENDL; + if (args[0] == "json" || args[0] == "csv" || args[0] == "text") + { + format = args[0]; + } else - ss << wti_to_text_line(wti) << ENDL; + { + fail_msg_writer() << "Unknown format: \"" << args[0] << "\", only \"csv\"(default), \"json\" and \"text\" supported"; + } + } + try { + boost::filesystem::ofstream fstream; + fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(log_space::log_singletone::get_default_log_folder() + "/wallet_recent_transfers.txt", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + m_wallet->export_transaction_history(fstream, format, !ignore_pos); + fstream.close(); } - ss << "Recent transfers: " << ENDL; - for (auto & wti : recent) + catch (...) { - if (ignore_pos && wti.is_mining) - continue; - if (!wti.fee) - wti.fee = currency::get_tx_fee(wti.tx); - - if (export_to_json) - ss << epee::serialization::store_t_to_json(wti) << ENDL; - else - ss << wti_to_text_line(wti) << ENDL; + success_msg_writer() << "Failed"; + return false; } - LOG_PRINT_GREEN("Storing text to wallet_recent_transfers.txt....", LOG_LEVEL_0); - file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/wallet_recent_transfers.txt", ss.str()); - LOG_PRINT_GREEN("Done", LOG_LEVEL_0); + + +// std::vector unconfirmed; +// std::vector recent; +// uint64_t total = 0; +// uint64_t last_index = 0; +// m_wallet->get_recent_transfers_history(recent, 0, 0, total, last_index, false); +// m_wallet->get_unconfirmed_transfers(unconfirmed, false); +// //workaround for missed fee +// stringstream ss; +// LOG_PRINT_GREEN("Generating text....", LOG_LEVEL_0); +// ss << "Unconfirmed transfers: " << ENDL; +// for (auto & wti : unconfirmed) +// { +// if(ignore_pos && wti.is_mining) +// continue; +// if (!wti.fee) +// wti.fee = currency::get_tx_fee(wti.tx); +// if(export_to_json) +// ss << epee::serialization::store_t_to_json(wti) << ENDL; +// else +// ss << wti_to_text_line(wti) << ENDL; +// +// } +// ss << "Recent transfers: " << ENDL; +// for (auto & wti : recent) +// { +// if (ignore_pos && wti.is_mining) +// continue; +// if (!wti.fee) +// wti.fee = currency::get_tx_fee(wti.tx); +// +// if (export_to_json) +// ss << epee::serialization::store_t_to_json(wti) << ENDL; +// else +// ss << wti_to_text_line(wti) << ENDL; +// } +// LOG_PRINT_GREEN("Storing text to wallet_recent_transfers.txt....", LOG_LEVEL_0); +// file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/wallet_recent_transfers.txt", ss.str()); +// LOG_PRINT_GREEN("Done", LOG_LEVEL_0); return true; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 546ccff1..5c9028f2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3254,6 +3254,87 @@ void wallet2::get_recent_transfers_history(std::vector(ss, " ")); + ss << "]" << ","; + ss << wti.tx_hash << ","; + ss << wti.height << ","; + ss << wti.unlock_time << ","; + ss << wti.tx_blob_size << ","; + ss << epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) << ","; + ss << "["; + std::copy(wti.recipients_aliases.begin(), wti.recipients_aliases.end(), std::ostream_iterator(ss, " ")); + ss << "]" << ","; + ss << (wti.is_income ? "in" : "out") << ","; + ss << (wti.is_service ? "[SERVICE]" : "") << (wti.is_mixing ? "[MIXINS]" : "") << (wti.is_mining ? "[MINING]" : "") << ","; + ss << wti.tx_type << ","; + ss << wti.fee << ENDL; +}; + +void wallet2::wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) +{ + ss << (wti.is_income ? "[INC]" : "[OUT]") << "\t" + << epee::misc_utils::get_time_str(wti.timestamp) << "\t" + << print_money(wti.amount) << "\t" + << print_money(wti.fee) << "\t" + << wti.remote_addresses << "\t" + << wti.comment << ENDL; +}; + +void wallet2::wti_to_json_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) +{ + ss << epee::serialization::store_t_to_json(wti, 4) << ","; +}; + + +//---------------------------------------------------------------------------------------------------- +void wallet2::export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions) +{ + //typedef int(*t_somefunc)(int, int); + typedef void(*playout_cb_type)(std::ostream&, const wallet_public::wallet_transfer_info&, size_t); + playout_cb_type cb_csv = &wallet2::wti_to_csv_entry; + playout_cb_type cb_json = &wallet2::wti_to_json_line; + playout_cb_type cb_plain_text = &wallet2::wti_to_txt_line; + + playout_cb_type cb = cb_csv; + if (format == "json") + { + ss << "{ \"history\": ["; + cb = cb_json; + } + else if (format == "text") + { + cb = cb_plain_text; + } + else + { + //csv by default + ss << "N, Date, Amount, Comment, Address, ID, Height, Unlock timestamp, Tx size, Alias, In/Out, Flags, Type, Fee" << ENDL; + } + + + enum_container(m_transfer_history.begin(), m_transfer_history.end(), [&](wallet_public::wallet_transfer_info& wti, size_t index) { + if (!include_pos_transactions) + { + if (currency::is_coinbase(wti.tx)) + return true; + } + cb(ss, wti, index); + return true; + }); + + if (format == "json") + { + ss << "{}]}"; + } + } //---------------------------------------------------------------------------------------------------- bool wallet2::get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 70a674a1..4609ec92 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -861,6 +861,8 @@ namespace tools uint64_t get_wallet_file_size()const; void set_use_deffered_global_outputs(bool use); construct_tx_param get_default_construct_tx_param_inital(); + + void wallet2::export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions = true); /* create_htlc_proposal: if htlc_hash == null_hash, then this wallet is originator of the atomic process, and @@ -872,7 +874,6 @@ namespace tools 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, crypto::hash& redeem_tx_id); - private: void add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id); @@ -1006,6 +1007,10 @@ private: void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector& extra); void remove_transfer_from_amount_gindex_map(uint64_t tid); + static void wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + static void wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + static void wti_to_json_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + currency::account_base m_account; bool m_watch_only; std::string m_log_prefix; // part of pub address, prefix for logging functions diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index e762ebbf..e40f2194 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -309,7 +309,7 @@ namespace tools else { //put it to attachments - ctp.attachments.insert(ctp.extra.end(), req.service_entries.begin(), req.service_entries.end()); + ctp.attachments.insert(ctp.attachments.end(), req.service_entries.begin(), req.service_entries.end()); } bool wrap = false; std::vector& dsts = ctp.dsts; @@ -397,7 +397,7 @@ namespace tools currency::finalized_tx result = AUTO_VAL_INIT(result); std::string unsigned_tx_blob_str; ctp.fee = req.fee; - ctp.fake_outputs_count = 0; + ctp.fake_outputs_count = req.mixin; m_wallet.transfer(ctp, result, true, &unsigned_tx_blob_str); if (m_wallet.is_watch_only()) {