From bfeccee2a33a6875c867bc749d7c7f1f54daaefe Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sun, 12 Apr 2020 00:07:27 +0200 Subject: [PATCH 01/18] Better parsing in lmdb --- src/blockchain_db/lmdb/db_lmdb.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 39f991d5d..1e648941d 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -5044,7 +5044,10 @@ bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txou current = parse_output_advanced_data_from_mdb(value_blob); - if(parse_and_validate_object_from_blob(current.data, restored_sfx_offer_create)){ + if(current.output_type == static_cast(tx_out_type::out_safex_offer)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_offer_create); + if(sfx_offer.offer_id == restored_sfx_offer_create.offer_id) { sfx_offer.quantity = restored_sfx_offer_create.quantity; sfx_offer.price = restored_sfx_offer_create.price; @@ -5057,7 +5060,10 @@ bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txou return; } } - else if(parse_and_validate_object_from_blob(current.data, restored_sfx_offer_update)){ + else if(current.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_offer_update); + if(sfx_offer.offer_id == restored_sfx_offer_update.offer_id) { sfx_offer.quantity = restored_sfx_offer_update.quantity; sfx_offer.price = restored_sfx_offer_update.price; @@ -5104,7 +5110,10 @@ bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txou current = parse_output_advanced_data_from_mdb(value_blob); - if(parse_and_validate_object_from_blob(current.data, restored_sfx_price_peg_create)){ + if(current.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_price_peg_create); + if(sfx_price_peg.price_peg_id == restored_sfx_price_peg_create.price_peg_id) { sfx_price_peg.creator = restored_sfx_price_peg_create.creator; sfx_price_peg.rate = restored_sfx_price_peg_create.rate; @@ -5114,7 +5123,10 @@ bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txou return; } } - else if(parse_and_validate_object_from_blob(current.data, restored_sfx_price_peg_update)){ + else if(current.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_price_peg_update); + if(sfx_price_peg.price_peg_id == restored_sfx_price_peg_update.price_peg_id) { sfx_price_peg.rate = restored_sfx_price_peg_update.rate; return; @@ -5355,13 +5367,19 @@ bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txou current = parse_output_advanced_data_from_mdb(value_blob); - if (parse_and_validate_object_from_blob(current.data, restored_sfx_account_create)) { + if(current.output_type == static_cast(tx_out_type::out_safex_account)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_account_create); + if (sfx_account.username == restored_sfx_account_create.username) { sfx_account.account_data = restored_sfx_account_create.account_data; return; } } - else if (parse_and_validate_object_from_blob(current.data, restored_sfx_account_update)){ + else if(current.output_type == static_cast(tx_out_type::out_safex_account_update)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_account_update); + sfx_account.account_data = restored_sfx_account_update.account_data; return; } From 3ddae3accb579b6f06273900ef7e701c4525412a Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sun, 12 Apr 2020 00:08:41 +0200 Subject: [PATCH 02/18] Use correct command_types when finding outputs --- src/cryptonote_core/blockchain.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index fba3588a6..3278710af 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -351,7 +351,7 @@ bool Blockchain::scan_outputkeys_for_indexes outputs; bool found = false; @@ -961,6 +965,7 @@ block Blockchain::pop_block_from_blockchain() m_blocks_longhash_table.clear(); m_scan_table.clear(); + m_scan_table_adv.clear(); m_blocks_txs_check.clear(); m_check_txin_table.clear(); @@ -5131,6 +5136,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) TIME_MEASURE_FINISH(t1); m_blocks_longhash_table.clear(); m_scan_table.clear(); + m_scan_table_adv.clear(); m_blocks_txs_check.clear(); m_check_txin_table.clear(); @@ -5444,6 +5450,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list>()); + its_advanced = m_scan_table_adv.find(tx_prefix_hash); + assert(its_advanced != m_scan_table_adv.end()); + + // get all amounts from tx.vin(s) for (const auto &txin : tx.vin) { From 624b087017047016bebcdff3ba8136b746970f61 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sun, 12 Apr 2020 22:43:19 +0200 Subject: [PATCH 03/18] Add missing tx_types for visitor --- src/blockchain_db/lmdb/db_lmdb.cpp | 2 ++ src/cryptonote_basic/cryptonote_basic.h | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 1e648941d..d6ddd3790 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -3132,6 +3132,8 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6 if (result == MDB_SUCCESS) { output = parse_output_advanced_data_from_mdb(value_blob); + if(output.output_type != static_cast(output_type)) + throw0(DB_ERROR(lmdb_error("Attemting to get keys from output with ID " + std::to_string(output_id) + " for type "+ std::to_string(static_cast(output_type)) + " but not found: ", result).c_str())); } else if (result == MDB_NOTFOUND) throw0(DB_ERROR(lmdb_error("Attemting to get keys from output with ID " + std::to_string(output_id) + " but not found: ", result).c_str())); diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index b7c40f653..347ae77e4 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -552,11 +552,24 @@ namespace cryptonote { switch (txin.command_type) { case safex::command_t::donate_network_fee: + case safex::command_t::simple_purchase: return tx_out_type::out_cash; case safex::command_t::token_stake: return tx_out_type::out_token; case safex::command_t::token_unstake: return tx_out_type::out_staked_token; + case safex::command_t::create_account: + return tx_out_type::out_token; + case safex::command_t::edit_account: + case safex::command_t::create_offer: + case safex::command_t::create_price_peg: + return tx_out_type::out_safex_account; + case safex::command_t::edit_offer: + return tx_out_type::out_safex_offer; + case safex::command_t::update_price_peg: + return tx_out_type::out_safex_price_peg; + case safex::command_t::create_feedback: + return tx_out_type::out_safex_feedback_token; case safex::command_t::nop: default: return tx_out_type::out_invalid; From 314bc1c2f704fe5057939539e2ec0dfb70b18caa Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sun, 12 Apr 2020 22:43:49 +0200 Subject: [PATCH 04/18] Faster block check for sync --- src/cryptonote_core/blockchain.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 3278710af..f678ca886 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -5468,6 +5468,8 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list, std::vector> tx_map; + std::set types; + // [input] store all found advanced output types and vector of their output ids std::map> advanced_output_ids_map; // [output] stores all output_advanced_data_t for each tx_out_type @@ -5523,6 +5525,10 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::listsecond.end()) SCAN_TABLE_QUIT("Duplicate key_image found from incoming blocks."); + auto it_advanced = its_advanced->second.find(k_image); + if (it_advanced != its_advanced->second.end()) + SCAN_TABLE_QUIT("Duplicate advanced key_image found from incoming blocks."); + const tx_out_type output_type = boost::apply_visitor(tx_output_type_visitor(), txin); if (output_type == tx_out_type::out_cash || output_type == tx_out_type::out_token) { @@ -5531,7 +5537,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list()); } + for(auto type: types) + { + if(tx_advanced_map.find(type)== tx_advanced_map.end()) + tx_advanced_map.emplace(type, std::vector()); + } + // add new absolute_offsets to offset_map for (const auto &txin : tx.vin) { From 6bf849741fe1e050c0395b049ec2e84c688fa02d Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 14 Apr 2020 15:33:05 +0200 Subject: [PATCH 05/18] Refactor wallet process and callback for advanced output --- src/simplewallet/simplewallet_safex.cpp | 51 +++++------------ src/wallet/wallet.cpp | 41 +++++--------- src/wallet/wallet.h | 1 + src/wallet/wallet_safex.cpp | 74 +++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 63 deletions(-) diff --git a/src/simplewallet/simplewallet_safex.cpp b/src/simplewallet/simplewallet_safex.cpp index f85d3ac3a..c41714f16 100644 --- a/src/simplewallet/simplewallet_safex.cpp +++ b/src/simplewallet/simplewallet_safex.cpp @@ -1496,73 +1496,61 @@ namespace cryptonote const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); cryptonote::parse_and_validate_from_blob(accblob, account); std::string accusername(begin(account.username), end(account.username)); - m_wallet->update_safex_account_data(accusername, account.account_data); - message_writer(console_color_green, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << tr("Output of type account, username: ") << accusername << " received, " << tr("idx ") << subaddr_index; + } else if (txout.output_type == static_cast(tx_out_type::out_safex_account_update)) { safex::edit_account_data account; const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); cryptonote::parse_and_validate_from_blob(accblob, account); std::string accusername(begin(account.username), end(account.username)); - m_wallet->update_safex_account_data(accusername, account.account_data); - - message_writer(console_color_green, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << tr("Updated for account, username: ") << accusername << " received, " << tr("idx ") << subaddr_index; + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer)){ safex::create_offer_data offer; const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); cryptonote::parse_and_validate_from_blob(offblob, offer); safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price,offer.description,offer.offer_id, std::string{offer.seller.begin(),offer.seller.end()},offer.active,offer.seller_address,offer.price_peg_used,offer.price_peg_id,offer.min_sfx_price}; - - m_wallet->add_safex_offer(sfx_offer); message_writer(console_color_green, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << - tr("Updated for account, username: ") << sfx_offer.seller << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << tr("Offer title: ") << sfx_offer.title << " received, " << tr("idx ") << subaddr_index; + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer_update)){ safex::edit_offer_data offer; const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); cryptonote::parse_and_validate_from_blob(offblob, offer); safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price, offer.description,offer.offer_id,std::string{offer.seller.begin(),offer.seller.end()}}; - if(offer.price_peg_used) - sfx_offer.set_price_peg(offer.price_peg_id,offer.price,offer.min_sfx_price); - sfx_offer.active = offer.active; - - m_wallet->update_safex_offer(sfx_offer); message_writer(console_color_green, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << - tr("Updated for account, username: ") << sfx_offer.seller << - tr("Offer title: ") << sfx_offer.title << " update received, " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr(" Offer title: ") << sfx_offer.title << " update received, " << tr("idx ") << subaddr_index; } else if (txout.output_type == static_cast(tx_out_type::out_safex_purchase)){ safex::create_purchase_data purchase_data; const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); cryptonote::parse_and_validate_from_blob(offblob, purchase_data); - safex::safex_offer my_offer = m_wallet->get_my_safex_offer(purchase_data.offer_id); - message_writer(console_color_blue, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << - tr("Updated for account, username: ") << my_offer.seller << + tr("Updated for account, username: ") << my_offer.seller << ", " << tr("Purchased offer: ") << my_offer.title << " received, " << - tr("Quantity purchased: ") << purchase_data.quantity << + tr("Quantity purchased: ") << purchase_data.quantity << ", " << tr("idx ") << subaddr_index; - m_wallet->update_safex_offer(purchase_data); } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback_token)){ safex::create_feedback_token_data feedback_token; @@ -1573,7 +1561,6 @@ namespace cryptonote tr("txid ") << txid << ", " << tr("Feedback token received for offer: ") << feedback_token.offer_id << " received, " << tr("idx ") << subaddr_index; - m_wallet->add_safex_feedback_token(feedback_token); } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback)){ safex::create_feedback_data feedback; @@ -1584,10 +1571,9 @@ namespace cryptonote tr("Height ") << height << ", " << tr("txid ") << txid << ", " << tr("Feedback sent received for offer: ") << feedback.offer_id << " received, " << - tr("Stars given: ") << feedback.stars_given << - tr("Comment given: ") << comment << + tr("Stars given: ") << feedback.stars_given << ", " << + tr("Comment given: ") << comment << ", " << tr("idx ") << subaddr_index; - m_wallet->remove_safex_feedback_token(feedback.offer_id); } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg)){ safex::create_price_peg_data price_peg; @@ -1600,15 +1586,11 @@ namespace cryptonote tr("Height ") << height << ", " << tr("txid ") << txid << ", " << tr("Price peg creation for account: ") << creator << " received, " << - tr("Price peg ID: ") << price_peg.price_peg_id << - tr("Price peg rate: ") << print_money(price_peg.rate) << - tr("Price peg currency: ") << currency << + tr("Price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("Price peg currency: ") << currency << ", " << tr("idx ") << subaddr_index; - safex::safex_price_peg sfx_price_peg{title,creator,currency,price_peg.description,price_peg.price_peg_id,price_peg.rate}; - - m_wallet->add_safex_price_peg(sfx_price_peg); - } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ safex::update_price_peg_data price_peg; const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); @@ -1616,12 +1598,9 @@ namespace cryptonote message_writer(console_color_blue, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << - tr("Price peg update for price peg ID: ") << price_peg.price_peg_id << - tr("Price peg rate: ") << print_money(price_peg.rate) << + tr("Price peg update for price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << tr("idx ") << subaddr_index; - - m_wallet->update_safex_price_peg(price_peg.price_peg_id,price_peg.rate); - } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 11654718c..a1919a12e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1209,22 +1209,16 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: if (0 != m_callback) { if (td.m_token_transfer) m_callback->on_tokens_received(height, txid, tx, td.m_token_amount, td.m_subaddr_index); - else if ((output_type == tx_out_type::out_safex_account) || - (output_type == tx_out_type::out_safex_account_update) || - (output_type == tx_out_type::out_safex_offer) || - (output_type == tx_out_type::out_safex_offer_update)|| - (output_type == tx_out_type::out_safex_purchase)|| - (output_type == tx_out_type::out_safex_feedback_token)|| - (output_type == tx_out_type::out_safex_feedback) || - (output_type == tx_out_type::out_safex_price_peg) || - (output_type == tx_out_type::out_safex_price_peg_update)) { - const txout_to_script &txout = boost::get(tx.vout[o].target); - m_callback->on_advanced_output_received(height, txid, tx, txout, td.m_subaddr_index); + else if ((output_type > tx_out_type::out_advanced) && (output_type < tx_out_type::out_invalid)){ + const txout_to_script &txout = boost::get(tx.vout[o].target); + m_callback->on_advanced_output_received(height, txid, tx, txout, td.m_subaddr_index); + process_advanced_output(txout, output_type); } else m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); } } + total_received_1 += amount; total_token_received_1 += token_amount; } @@ -1328,22 +1322,15 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); if (0 != m_callback) { - if (td.m_token_transfer) - m_callback->on_tokens_received(height, txid, tx, td.m_token_amount, td.m_subaddr_index); - else if ((td.m_output_type == tx_out_type::out_safex_account) || - (td.m_output_type == tx_out_type::out_safex_account_update) || - (td.m_output_type == tx_out_type::out_safex_offer) || - (td.m_output_type == tx_out_type::out_safex_offer_update) || - (td.m_output_type == tx_out_type::out_safex_purchase) || - (td.m_output_type == tx_out_type::out_safex_feedback_token) || - (td.m_output_type == tx_out_type::out_safex_feedback) || - (td.m_output_type == tx_out_type::out_safex_price_peg) || - (td.m_output_type == tx_out_type::out_safex_price_peg_update)) { - const txout_to_script &txout = boost::get(tx.vout[o].target); - m_callback->on_advanced_output_received(height, txid, tx, txout, td.m_subaddr_index); - } - else - m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); + if (td.m_token_transfer) + m_callback->on_tokens_received(height, txid, tx, td.m_token_amount, td.m_subaddr_index); + else if ((td.m_output_type > tx_out_type::out_advanced) && (td.m_output_type < tx_out_type::out_invalid)){ + const txout_to_script &txout = boost::get(tx.vout[o].target); + m_callback->on_advanced_output_received(height, txid, tx, txout, td.m_subaddr_index); + process_advanced_output(txout, td.m_output_type); + } + else + m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); } total_received_1 += extra_amount; total_token_received_1 += extra_token_amount; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 943a04550..e662c3548 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1103,6 +1103,7 @@ namespace tools bool calculate_sfx_price(const safex::safex_offer& sfx_offer, uint64_t& sfx_price); + void process_advanced_output(const cryptonote::txout_to_script &txout, const cryptonote::tx_out_type& output_type); std::vector get_safex_offers(); std::vector get_safex_ratings(const crypto::hash& offer_id); diff --git a/src/wallet/wallet_safex.cpp b/src/wallet/wallet_safex.cpp index 3f081943d..a697220fa 100644 --- a/src/wallet/wallet_safex.cpp +++ b/src/wallet/wallet_safex.cpp @@ -626,5 +626,79 @@ namespace tools return safex::safex_offer{}; } + void wallet::process_advanced_output(const cryptonote::txout_to_script &txout, const cryptonote::tx_out_type& output_type){ + if (txout.output_type == static_cast(tx_out_type::out_safex_account)) { + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + update_safex_account_data(accusername, account.account_data); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_account_update)) { + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + update_safex_account_data(accusername, account.account_data); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer)){ + safex::create_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price,offer.description,offer.offer_id, + std::string{offer.seller.begin(),offer.seller.end()},offer.active,offer.seller_address,offer.price_peg_used,offer.price_peg_id,offer.min_sfx_price}; + add_safex_offer(sfx_offer); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + safex::edit_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price, + offer.description,offer.offer_id,std::string{offer.seller.begin(),offer.seller.end()}}; + if(offer.price_peg_used) + sfx_offer.set_price_peg(offer.price_peg_id,offer.price,offer.min_sfx_price); + sfx_offer.active = offer.active; + update_safex_offer(sfx_offer); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_purchase)){ + safex::create_purchase_data purchase_data; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, purchase_data); + safex::safex_offer my_offer = get_my_safex_offer(purchase_data.offer_id); + update_safex_offer(purchase_data); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback_token)){ + safex::create_feedback_token_data feedback_token; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback_token); + add_safex_feedback_token(feedback_token); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback)){ + safex::create_feedback_data feedback; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback); + std::string comment{feedback.comment.begin(),feedback.comment.end()}; + remove_safex_feedback_token(feedback.offer_id); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + std::string creator{price_peg.creator.begin(),price_peg.creator.end()}; + std::string title{price_peg.title.begin(),price_peg.title.end()}; + std::string currency{price_peg.currency.begin(),price_peg.currency.end()}; + safex::safex_price_peg sfx_price_peg{title,creator,currency,price_peg.description,price_peg.price_peg_id,price_peg.rate}; + add_safex_price_peg(sfx_price_peg); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + update_safex_price_peg(price_peg.price_peg_id,price_peg.rate); + + } + + } + } From 1749cae2e02099daf0e96512c42b82b13bf23e54 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 14 Apr 2020 17:28:15 +0200 Subject: [PATCH 06/18] Don't display inactive offers in listing --- src/simplewallet/simplewallet_safex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simplewallet/simplewallet_safex.cpp b/src/simplewallet/simplewallet_safex.cpp index c41714f16..8447fb1da 100644 --- a/src/simplewallet/simplewallet_safex.cpp +++ b/src/simplewallet/simplewallet_safex.cpp @@ -961,7 +961,7 @@ namespace cryptonote for (auto &offer: m_wallet->get_safex_offers()) { - if(!offer.active && offer.quantity == 0) + if(!offer.active || offer.quantity == 0) continue; if(first) From d3e8da8ddc07bfd29579430dc7a181ee3342911c Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 14 Apr 2020 18:08:44 +0200 Subject: [PATCH 07/18] Fix for correct calculation of fee and outs for tx version 2 --- src/wallet/wallet.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a1919a12e..da4502a6d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1413,7 +1413,7 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: } } - uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_cash_amount(tx) : tx.rct_signatures.txnFee; + uint64_t fee = miner_tx ? 0 : tx_money_spent_in_ins - get_outs_cash_amount(tx); if ((tx_money_spent_in_ins > 0 || tx_tokens_spent_in_ins > 0) && !pool) { @@ -1604,15 +1604,8 @@ void wallet::process_outgoing(const crypto::hash &txid, const cryptonote::transa // we only see 0 input amounts, so have to deduce amount out from other parameters. entry.first->second.m_amount_in = spent; entry.first->second.m_token_amount_in = tokens_spent; - if (tx.version == 1) - { - entry.first->second.m_amount_out = get_outs_cash_amount(tx); - entry.first->second.m_token_amount_out = get_outs_token_amount(tx); - } - else - { - entry.first->second.m_amount_out = spent - tx.rct_signatures.txnFee; - } + entry.first->second.m_amount_out = get_outs_cash_amount(tx); + entry.first->second.m_token_amount_out = get_outs_token_amount(tx); entry.first->second.m_change = received; entry.first->second.m_token_change = tokens_received; From ddc829c3ad84244a874e0c3941a4452e9df39475 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 14 Apr 2020 19:28:46 +0200 Subject: [PATCH 08/18] Add SafexOffer and getMySafexOffers and listSafexOffers to the API --- src/wallet/api/wallet.cpp | 42 ++++++++++++++++++ src/wallet/api/wallet.h | 6 +++ src/wallet/api/wallet_api.h | 88 ++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 19c1c7050..28ec4f184 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1452,6 +1452,48 @@ bool WalletImpl::removeSafexAccount(const std::string& username){ return false; } +std::vector WalletImpl::getMySafexOffers(){ + + auto price_pegs = m_wallet->get_safex_price_pegs(""); + + + std::vector offers; + for(auto &offer: m_wallet->get_my_safex_offers()){ + auto price_peg_id = offer.price_peg_id; + std::string currency = "SFX"; + + auto it = std::find_if(price_pegs.begin(), price_pegs.end(), [price_peg_id](const safex::safex_price_peg &sfx_price_peg) { return price_peg_id == sfx_price_peg.price_peg_id; }); + std::string offerID = epee::string_tools::pod_to_hex(offer.offer_id); + std::string pricePegID = epee::string_tools::pod_to_hex(offer.price_peg_id); + if(it!=price_pegs.end()) + currency = it->currency; + + offers.emplace_back(offer.title,offer.quantity,offer.price,offer.min_sfx_price, std::string{offer.description.begin(),offer.description.end()}, + offer.active, offer.price_peg_used, offerID, offer.seller, pricePegID, currency); + } + + return offers; +} + +std::vector WalletImpl::listSafexOffers(bool active){ + std::vector offers; + std::string currency = "SFX"; + + for (auto &offer: m_wallet->get_safex_offers()) + if(!active || offer.active){ + uint64_t sfx_price; + bool res = m_wallet->calculate_sfx_price(offer,sfx_price); + if(!res) + continue; + std::string offerID = epee::string_tools::pod_to_hex(offer.offer_id); + std::string pricePegID = epee::string_tools::pod_to_hex(offer.price_peg_id); + + offers.emplace_back(offer.title,offer.quantity,sfx_price,offer.min_sfx_price, std::string{offer.description.begin(),offer.description.end()}, + offer.active, offer.price_peg_used, offerID, offer.seller, pricePegID, currency); + } + return offers; +} + PendingTransaction * WalletImpl::createAdvancedTransaction(const string &dst_addr, const string &payment_id, optional value_amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, AdvancedCommand& advancedCommnand){ diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 442d1f7b0..9feb72bc9 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -138,12 +138,18 @@ class WalletImpl : public Wallet std::set subaddr_indices = {}, const TransactionType tx_type = TransactionType::CashTransaction); + + //Safex account realted functions bool createSafexAccount(const std::string& username, const std::vector& description); std::vector getSafexAccounts(); SafexAccount getSafexAccount(const std::string& username); bool recoverSafexAccount(const std::string& username, const std::string& private_key); bool removeSafexAccount(const std::string& username); + //Safex offer realted functions + std::vector getMySafexOffers(); + std::vector listSafexOffers(bool active); + PendingTransaction * createAdvancedTransaction(const std::string &dst_addr, const std::string &payment_id, optional value_amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, AdvancedCommand& advancedCommnand); diff --git a/src/wallet/api/wallet_api.h b/src/wallet/api/wallet_api.h index 1d6c06b4b..14b7cdcd0 100644 --- a/src/wallet/api/wallet_api.h +++ b/src/wallet/api/wallet_api.h @@ -349,7 +349,7 @@ struct TransactionHistory struct SafexAccount { public: SafexAccount(){} - SafexAccount(std::string &usr, const std::string &_data, const std::string &_pub_key, const std::string &_sec_key, const uint8_t& _status): + SafexAccount(const std::string &usr, const std::string &_data, const std::string &_pub_key, const std::string &_sec_key, const uint8_t& _status): username(usr), data(_data), pub_key(_pub_key), @@ -370,6 +370,50 @@ struct SafexAccount { uint8_t getStatus() const {return status;} }; +struct SafexOffer { +public: + SafexOffer(){} + SafexOffer(const std::string &_title, const uint64_t _quantity, const uint64_t _price, const uint64_t _min_sfx_price, const std::string& _description, + const bool _active, const bool _price_peg_used, const std::string& _offer_id, const std::string& _seller, const std::string& _price_peg_id, const std::string& _currency): + title(_title), + quantity(_quantity), + price(_price), + min_sfx_price(_min_sfx_price), + description(_description), + active(_active), + price_peg_used(_price_peg_used), + offer_id(_offer_id), + price_peg_id(_price_peg_id), + seller(_seller), + currency(_currency){} + +private: + std::string title; + uint64_t quantity; + uint64_t price; + uint64_t min_sfx_price; + std::string description; + bool active; + bool price_peg_used; + std::string offer_id; + std::string price_peg_id; + std::string seller; + std::string currency; +public: + + std::string getTitle() const {return title;}; + uint64_t getQuantity() const {return quantity;}; + uint64_t getPrice() const {return price;}; + uint64_t getMin_sfx_price() const {return min_sfx_price;}; + std::string getDescription() const {return description;}; + bool getActive() const {return active;}; + bool getPrice_peg_used() const {return price_peg_used;}; + std::string getOffer_id() const {return offer_id;}; + std::string getPrice_peg_id() const {return price_peg_id;}; + std::string getSeller() const {return seller;}; + std::string getCurrency() const {return currency;}; +}; + /** * @brief AddressBookRow - provides functions to manage address book */ @@ -662,15 +706,55 @@ struct Wallet */ virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0; - + /*! + * \brief createSafexAccount - Generates keys and creates safex account inside the wallet + * + * \param username - Username of the safex account + * \param description - Description of the safex account + */ virtual bool createSafexAccount(const std::string& username, const std::vector& description) = 0; + /*! + * \brief getSafexAccounts - Returns all Safex accounts in the wallet + * + */ virtual std::vector getSafexAccounts() = 0; + /*! + * \brief getSafexAccount - Returns requested safex account data + * + * \param username - Username of the specific safex account + */ virtual SafexAccount getSafexAccount(const std::string& username) = 0; + + /*! + * \brief recoverSafexAccount - Generates safex account that was created before + * + * \param username - Username of the specific safex account + * \param private_key - Private key of the safex account + */ virtual bool recoverSafexAccount(const std::string& username, const std::string& private_key) = 0; + + /*! + * \brief removeSafexAccount - Removes safex account from the wallet file + * + * \param username - Username of the specific safex account + */ virtual bool removeSafexAccount(const std::string& username) = 0; + /*! + * \brief getMySafexOffers - Returns all Safex offers created by safex accounts from whis wallet + * + */ + virtual std::vector getMySafexOffers() = 0; + + /*! + * \brief listSafexOffers - Returns all Safex offers currently in the blockchain + * + * \param active - True if you want to return only offers that can be purchased + */ + virtual std::vector listSafexOffers(bool active) = 0; + /*! * \brief getRestoreHeight - get wallet creation height * From 71bb03a8670412be23f1808c5126c27260b422d3 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Wed, 15 Apr 2020 22:31:17 +0200 Subject: [PATCH 09/18] Block multiple txs from 1 sfx account or purchase of 1 offer in the pool --- src/cryptonote_core/tx_pool.cpp | 255 ++++++++++++++++++++++++++++++++ src/cryptonote_core/tx_pool.h | 56 ++++++- 2 files changed, 310 insertions(+), 1 deletion(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 3ccbc399b..36e83c952 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -46,6 +46,7 @@ #include "warnings.h" #include "common/perf_timer.h" #include "crypto/hash.h" +#include "safex/command.h" #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "txpool" @@ -239,6 +240,14 @@ namespace cryptonote } } + if (have_tx_safex_restricted(tx)) + { + LOG_PRINT_L1("Transaction with id= "<< id << " has restricted safex usage"); + tvc.m_verifivation_failed = true; + tvc.m_invalid_output = true; + return false; + } + if (!m_blockchain.check_tx_outputs(tx, tvc)) { LOG_PRINT_L1("Transaction with id= "<< id << " has at least one invalid output"); @@ -282,6 +291,8 @@ namespace cryptonote m_blockchain.add_txpool_tx(tx, meta); if (!insert_key_images(tx, kept_by_block)) return false; + if (!insert_safex_restrictions(tx, kept_by_block)) + return false; m_txs_by_fee_and_receive_time.emplace(std::pair(fee / (double)blob_size, receive_time), id); } catch (const std::exception &e) @@ -324,6 +335,8 @@ namespace cryptonote m_blockchain.add_txpool_tx(tx, meta); if (!insert_key_images(tx, kept_by_block)) return false; + if (!insert_safex_restrictions(tx, kept_by_block)) + return false; m_txs_by_fee_and_receive_time.emplace(std::pair(fee / (double)blob_size, receive_time), id); } catch (const std::exception &e) @@ -409,6 +422,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(txid); m_txpool_size -= txblob.size(); remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); MINFO("Pruned tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first); m_txs_by_fee_and_receive_time.erase(it--); } @@ -443,6 +457,72 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::insert_safex_restrictions(const transaction &tx, bool kept_by_block) + { + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, offer); + std::string username{offer.seller.begin(),offer.seller.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, offer); + std::string username{offer.seller.begin(),offer.seller.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, price_peg); + std::string username{price_peg.creator.begin(),price_peg.creator.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + //TODO: GRKI check this case as we do not have creator in update price peg +// const txout_to_script &out = boost::get(vout.target); +// safex::update_price_peg_data price_peg; +// const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); +// cryptonote::parse_and_validate_from_blob(accblob, price_peg); +// std::string username{price_peg..begin(),price_peg.creator.end()}; +// m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, purchase); + m_safex_purchase_in_progress.push_back(purchase.offer_id); + } + } + return true; + } + //--------------------------------------------------------------------------------- //FIXME: Can return early before removal of all of the key images. // At the least, need to make sure that a false return here // is treated properly. Should probably not return early, however. @@ -482,6 +562,86 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::remove_safex_restrictions(const transaction &tx) + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + CRITICAL_REGION_LOCAL1(m_blockchain); + + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_account" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_account_update" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, offer); + std::string username{offer.seller.begin(),offer.seller.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_offer" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, offer); + std::string username{offer.seller.begin(),offer.seller.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_offer_update" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, price_peg); + std::string username{price_peg.creator.begin(),price_peg.creator.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_price_peg" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + //TODO: GRKI check this case as we do not have creator in update price peg + // const txout_to_script &out = boost::get(vout.target); + // safex::update_price_peg_data price_peg; + // const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + // cryptonote::parse_and_validate_from_blob(accblob, price_peg); + // std::string username{price_peg.creator.begin(),price_peg.creator.end()}; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, purchase); + auto it = std::find(m_safex_purchase_in_progress.begin(), m_safex_purchase_in_progress.end(), purchase.offer_id); + CHECK_AND_ASSERT_MES(it != m_safex_purchase_in_progress.end(), false, "failed to find safex restriction for type out_safex_purchase" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_purchase_in_progress.erase(it); + } + } + return true; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen) { CRITICAL_REGION_LOCAL(m_transactions_lock); @@ -516,6 +676,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(id); m_txpool_size -= blob_size; remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); } catch (const std::exception &e) { @@ -589,6 +750,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(txid); m_txpool_size -= bd.size(); remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); } } catch (const std::exception &e) @@ -962,12 +1124,97 @@ namespace cryptonote return false; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_restricted(const transaction &tx) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + CRITICAL_REGION_LOCAL1(m_blockchain); + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, offer); + std::string username{offer.seller.begin(),offer.seller.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, offer); + std::string username{offer.seller.begin(),offer.seller.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, price_peg); + std::string username{price_peg.creator.begin(),price_peg.creator.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + //TODO: GRKI check this case as we do not have creator in update price peg + // const txout_to_script &out = boost::get(vout.target); + // safex::update_price_peg_data price_peg; + // const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + // cryptonote::parse_and_validate_from_blob(accblob, price_peg); + // std::string username{price_peg..begin(),price_peg.creator.end()}; + // m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, purchase); + if(have_tx_safex_purchase_in_progress(purchase.offer_id)) + return true; + } + } + return false; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const { CRITICAL_REGION_LOCAL(m_transactions_lock); return m_spent_key_images.end() != m_spent_key_images.find(key_im); } //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_account_in_use(const std::string &username) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + return m_safex_accounts_in_use.end() != std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_purchase_in_progress(const crypto::hash &offer_id) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + return m_safex_purchase_in_progress.end() != std::find(m_safex_purchase_in_progress.begin(), m_safex_purchase_in_progress.end(), offer_id); + } + //--------------------------------------------------------------------------------- void tx_memory_pool::lock() const { m_transactions_lock.lock(); @@ -1314,6 +1561,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(txid); m_txpool_size -= txblob.size(); remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); auto sorted_it = find_tx_in_sorted_container(txid); if (sorted_it == m_txs_by_fee_and_receive_time.end()) { @@ -1343,6 +1591,8 @@ namespace cryptonote m_txpool_max_size = max_txpool_size ? max_txpool_size : DEFAULT_TXPOOL_MAX_SIZE; m_txs_by_fee_and_receive_time.clear(); m_spent_key_images.clear(); + m_safex_accounts_in_use.clear(); + m_safex_purchase_in_progress.clear(); m_txpool_size = 0; std::vector remove; @@ -1365,6 +1615,11 @@ namespace cryptonote MFATAL("Failed to insert key images from txpool tx"); return false; } + if (!insert_safex_restrictions(tx, meta.kept_by_block)) + { + MFATAL("Failed to insert safex data from txpool tx"); + return false; + } m_txs_by_fee_and_receive_time.emplace(std::pair(meta.fee / (double)meta.blob_size, meta.receive_time), txid); m_txpool_size += meta.blob_size; return true; diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 740f07e1f..acf0baad0 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -430,6 +430,13 @@ namespace cryptonote */ bool insert_key_images(const transaction &tx, bool kept_by_block); + /** + * @brief insert safex data into m_safex_accounts_in_use and m_safex_purchase_in_progress + * + * @return true on success, false on error + */ + bool insert_safex_restrictions(const transaction &tx, bool kept_by_block); + /** * @brief remove old transactions from the pool * @@ -450,6 +457,24 @@ namespace cryptonote */ bool have_tx_keyimg_as_spent(const crypto::key_image& key_im) const; + /** + * @brief check if a transaction in the pool has a safex account usage + * + * @param username Username of the account that is in use + * + * @return true if the safex account is in use already, otherwise false + */ + bool have_tx_safex_account_in_use(const std::string& username) const; + + /** + * @brief check if a transaction in the pool is purchase for particular offer + * + * @param offer_id Offer ID of the offer that is already purchased in the pool + * + * @return true if the purchase with offer ID is in the pool already, otherwise false + */ + bool have_tx_safex_purchase_in_progress(const crypto::hash& offer_id) const; + /** * @brief check if any spent key image in a transaction is in the pool * @@ -464,6 +489,22 @@ namespace cryptonote */ bool have_tx_keyimges_as_spent(const transaction& tx) const; + /** + * @brief check if any safex restriction in a transaction is in the pool + * + * Checks if any of the safex restrictions(same account doing 2 updates or purchase of same offer) + * in a given transaction are present + * in any of the transactions in the transaction pool. + * + * @note see tx_pool::have_tx_safex_account_in_use + * @note see tx_poo::have_tx_safex_purchase_in_progress + * + * @param tx the transaction to check safex restrictions + * + * @return true if any safex restrictions are present in the pool, otherwise false + */ + bool have_tx_safex_restricted(const transaction& tx) const; + /** * @brief forget a transaction's spent key images * @@ -477,6 +518,15 @@ namespace cryptonote */ bool remove_transaction_keyimages(const transaction& tx); + /** + * @brief forget a transaction's safex restrictions + * + * @param tx the transaction + * + * @return false if any restriction to be removed cannot be found, otherwise true + */ + bool remove_safex_restrictions(const transaction& tx); + /** * @brief check if any of a transaction's spent key images are present in a given set * @@ -538,7 +588,11 @@ namespace cryptonote #endif //! container for spent key images from the transactions in the pool - key_images_container m_spent_key_images; + key_images_container m_spent_key_images; + + // Safex related members + std::vector m_safex_accounts_in_use; + std::vector m_safex_purchase_in_progress; //TODO: this time should be a named constant somewhere, not hard-coded //! interval on which to check for stale/"stuck" transactions From 3e9a0f70aa5b62cca5cc235fba2c945e7ec3cff7 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 16 Apr 2020 01:25:08 +0200 Subject: [PATCH 10/18] Add kept_by_block for safex checks also --- src/cryptonote_core/tx_pool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 36e83c952..5cef92071 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -195,7 +195,7 @@ namespace cryptonote } //Here check for tx related safex logic - if ((tx.version > HF_VERSION_MIN_SUPPORTED_TX_VERSION) && !m_blockchain.check_safex_tx(tx, tvc)) + if ( !kept_by_block && (tx.version > HF_VERSION_MIN_SUPPORTED_TX_VERSION) && !m_blockchain.check_safex_tx(tx, tvc)) { tvc.m_verifivation_failed = true; tvc.m_safex_verification_failed = true; From f79463731f980fe3036e0252d3e61423b591c0bf Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 16 Apr 2020 14:44:57 +0200 Subject: [PATCH 11/18] Add kept_by_block for have_tx_safex_restricted --- src/cryptonote_core/tx_pool.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 5cef92071..99fa1b874 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -238,14 +238,14 @@ namespace cryptonote tvc.m_double_spend = true; return false; } - } - if (have_tx_safex_restricted(tx)) - { - LOG_PRINT_L1("Transaction with id= "<< id << " has restricted safex usage"); - tvc.m_verifivation_failed = true; - tvc.m_invalid_output = true; - return false; + if (have_tx_safex_restricted(tx)) + { + LOG_PRINT_L1("Transaction with id= "<< id << " has restricted safex usage"); + tvc.m_verifivation_failed = true; + tvc.m_invalid_output = true; + return false; + } } if (!m_blockchain.check_tx_outputs(tx, tvc)) From d4222057bc9eed15d2455918cc699d42615e57d5 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 16 Apr 2020 19:42:07 +0200 Subject: [PATCH 12/18] Fix "show transfer" for unstake token to show something reasonable --- src/simplewallet/simplewallet.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 813a227e1..200a6091c 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6117,6 +6117,8 @@ namespace { return std::string("Token transfer"); }else if(type == tx_out_type::out_staked_token) { return std::string("Stake token transfer"); + }else if(type == tx_out_type::out_network_fee) { + return std::string("Collect network fee transfer"); }else if(type == tx_out_type::out_bitcoin_migration) { return std::string("Migration transfer"); }else if(type == tx_out_type::out_safex_account) { @@ -6205,6 +6207,9 @@ bool simple_wallet::show_transfer(const std::vector &args) uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known uint64_t token_change = pd.m_token_change == (uint64_t)-1 ? 0 : pd.m_token_change; uint64_t fee = pd.m_amount_in - pd.m_amount_out; + bool unstake_token_transfer = false; + if(pd.m_amount_out > pd.m_amount_in) + unstake_token_transfer = true; std::string dests; for (const auto &d: pd.m_dests) { if (!dests.empty()) @@ -6216,7 +6221,7 @@ bool simple_wallet::show_transfer(const std::vector &args) payment_id = payment_id.substr(0,16); success_msg_writer() << "Outgoing transaction found"; success_msg_writer() << "txid: " << txid; - success_msg_writer() << "Transfer type: " << get_output_type_string(pd.m_output_type); + success_msg_writer() << "Transfer type: " << get_output_type_string(unstake_token_transfer ? tx_out_type::out_network_fee : pd.m_output_type); success_msg_writer() << "Height: " << pd.m_block_height; success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); success_msg_writer() << "Amount: " << print_money(pd.m_amount_in - change - fee); @@ -6224,7 +6229,10 @@ bool simple_wallet::show_transfer(const std::vector &args) success_msg_writer() << "Payment ID: " << payment_id; success_msg_writer() << "Change: " << print_money(change); success_msg_writer() << "Token Change: " << print_money(token_change); - success_msg_writer() << "Fee: " << print_money(fee); + if(unstake_token_transfer) + success_msg_writer() << "Network fee collected(after tx fee payed): " << print_money(pd.m_amount_out - pd.m_amount_in); + else + success_msg_writer() << "Fee: " << print_money(fee); success_msg_writer() << "Destinations: " << dests; success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); return true; From 67c89318c877ca51866693044df812b1942b6dc2 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 16 Apr 2020 20:03:37 +0200 Subject: [PATCH 13/18] Don't save and edit safex_account data if the wrong password is used --- src/simplewallet/simplewallet.cpp | 9 ++------- src/simplewallet/simplewallet.h | 2 +- src/simplewallet/simplewallet_safex.cpp | 25 ++++++++++++++++++++----- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 200a6091c..bc65f049b 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2328,24 +2328,19 @@ bool simple_wallet::save(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::save_safex(const std::vector &args) +bool simple_wallet::save_safex(const epee::wipeable_string& password) { try { LOCK_IDLE_SCOPE(); - auto pass = get_and_verify_password(); - - if(!pass) - return true; - - auto password = pass->password(); m_wallet->store_safex(password); success_msg_writer() << tr("Wallet safex data saved"); } catch (const std::exception& e) { fail_msg_writer() << e.what(); + return false; } return true; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 4f9f05398..8b4aca10d 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -199,7 +199,7 @@ namespace cryptonote bool print_integrated_address(const std::vector &args = std::vector()); bool address_book(const std::vector &args = std::vector()); bool save(const std::vector &args); - bool save_safex(const std::vector &args); + bool save_safex(const epee::wipeable_string& password); bool save_watch_only(const std::vector &args); bool set_variable(const std::vector &args); bool rescan_spent(const std::vector &args); diff --git a/src/simplewallet/simplewallet_safex.cpp b/src/simplewallet/simplewallet_safex.cpp index 8447fb1da..fa925db94 100644 --- a/src/simplewallet/simplewallet_safex.cpp +++ b/src/simplewallet/simplewallet_safex.cpp @@ -1338,8 +1338,12 @@ namespace cryptonote return true; } - if (m_wallet->generate_safex_account(username, accdata)) { - save_safex({}); + auto pass = get_and_verify_password(); + + if(!pass) + return true; + + if (m_wallet->generate_safex_account(username, accdata) && save_safex(pass->password()) ) { success_msg_writer() << tr("New account created"); } else { fail_msg_writer() << tr("Failed to create account"); @@ -1350,7 +1354,13 @@ namespace cryptonote const std::string &username = local_args[0]; - if (m_wallet->remove_safex_account(username)) { + auto pass = get_and_verify_password(); + + if(!pass) + return true; + + if (m_wallet->remove_safex_account(username) && save_safex(pass->password()) ) { + save_safex(pass->password()); success_msg_writer() << tr("Account removed"); } else { fail_msg_writer() << tr("Failed to remove account ") << username; @@ -1371,8 +1381,13 @@ namespace cryptonote crypto::secret_key skey{}; epee::string_tools::hex_to_pod(private_key, skey); - if (m_wallet->recover_safex_account(username, skey)) { - save_safex({}); + auto pass = get_and_verify_password(); + + if(!pass) + return true; + + if (m_wallet->recover_safex_account(username, skey) && save_safex(pass->password()) ) { + save_safex(pass->password()); success_msg_writer() << tr("Account recovered"); } else { fail_msg_writer() << tr("Failed to recover account ") << username; From af3479d8ac90c05987d97a104cf5ebd68e6d4648 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Thu, 16 Apr 2020 22:00:30 +0200 Subject: [PATCH 14/18] Don't crash on sweep_unmixable --- src/wallet/wallet.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index da4502a6d..9049aa6cb 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4297,6 +4297,7 @@ size_t wallet::pop_best_value_from(const transfer_container &transfers, std::vec candidates.push_back(n); } + THROW_WALLET_EXCEPTION_IF(candidates.empty(), error::no_matching_available_outputs); // we have all the least related outputs in candidates, so we can pick either // the smallest, or a random one, depending on request size_t idx; From 7a54dd35bc38812a08327367f54f551bd1ddbeb5 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Sat, 18 Apr 2020 15:39:20 +0200 Subject: [PATCH 15/18] Add initial on_advanced_output API endpoint --- src/wallet/api/wallet.cpp | 121 ++++++++++++++++++++++++++++++++++++ src/wallet/api/wallet_api.h | 7 +++ 2 files changed, 128 insertions(+) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 28ec4f184..c3369fda3 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -214,6 +214,127 @@ struct WalletCallbackImpl : public tools::i_wallet_callback } } + virtual void on_advanced_output_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, const cryptonote::txout_to_script &txout, const cryptonote::subaddress_index& subaddr_index) { + + std::string tx_hash = epee::string_tools::pod_to_hex(txid); + + if (txout.output_type == static_cast(tx_out_type::out_safex_account)) { + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Output of type account, username: ") << accusername << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_account_update)) { + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << accusername << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer)){ + safex::create_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price,offer.description,offer.offer_id, + std::string{offer.seller.begin(),offer.seller.end()},offer.active,offer.seller_address,offer.price_peg_used,offer.price_peg_id,offer.min_sfx_price}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr("Offer title: ") << sfx_offer.title << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + safex::edit_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price, + offer.description,offer.offer_id,std::string{offer.seller.begin(),offer.seller.end()}}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr(" Offer title: ") << sfx_offer.title << " update received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_purchase)){ + safex::create_purchase_data purchase_data; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, purchase_data); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Purchased offer: ") << purchase_data.offer_id << " received, " << + tr("Quantity purchased: ") << purchase_data.quantity << ", " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback_token)){ + safex::create_feedback_token_data feedback_token; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback_token); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Feedback token received for offer: ") << feedback_token.offer_id << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback)){ + safex::create_feedback_data feedback; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback); + std::string comment{feedback.comment.begin(),feedback.comment.end()}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Feedback sent received for offer: ") << feedback.offer_id << " received, " << + tr("Stars given: ") << feedback.stars_given << ", " << + tr("Comment given: ") << comment << ", " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + std::string creator{price_peg.creator.begin(),price_peg.creator.end()}; + std::string title{price_peg.title.begin(),price_peg.title.end()}; + std::string currency{price_peg.currency.begin(),price_peg.currency.end()}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Price peg creation for account: ") << creator << " received, " << + tr("Price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("Price peg currency: ") << currency << ", " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Price peg update for price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("idx ") << subaddr_index); + } + // do not signal on advanced tx if wallet is not syncronized completely + if (m_listener && m_wallet->synchronized()) + { + m_listener->advancedReceived(tx_hash, static_cast(txout.output_type)); + m_listener->updated(); + } + } + virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) { // TODO; diff --git a/src/wallet/api/wallet_api.h b/src/wallet/api/wallet_api.h index 14b7cdcd0..6196c607b 100644 --- a/src/wallet/api/wallet_api.h +++ b/src/wallet/api/wallet_api.h @@ -566,6 +566,13 @@ struct WalletListener */ virtual void unconfirmedTokensReceived(const std::string &txId, uint64_t token_amount) = 0; + /** + * @brief advancedReceived - called when advanced outputs are received + * @param txId - transaction id + * @param output_type - type of advanced output + */ + virtual void advancedReceived(const std::string &txId, const uint8_t output_type) = 0; + /** * @brief newBlock - called when new block received * @param height - block height From 4ce21c5fbb6a3096932cdb9bbceb3a4e84b190e0 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 21 Apr 2020 15:41:11 +0200 Subject: [PATCH 16/18] Small cleanup --- src/cryptonote_core/blockchain.cpp | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f678ca886..ac903694d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4221,14 +4221,7 @@ bool Blockchain::check_tx_input_generic(size_t tx_version, const T& txin, const CHECK_AND_ASSERT_MES(sig.size() == output_keys.size(), false, "internal error: tx signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size()); return true; } -//TODO: GRKI Add this where needed -// -// std::vector& m_output_keys; -// const Blockchain& m_bch; -// outputs_visitor(std::vector& output_keys, const Blockchain& bch) : -// m_output_keys(output_keys), m_bch(bch) -// { -// } + // // bool get_pwned(const public_key &key) // { @@ -4361,14 +4354,6 @@ bool Blockchain::check_tx_input_generic(size_t tx_version, const T& txin, const // return false; // } // -// bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey, const rct::key &commitment) -// { -// //check tx unlock time -// if (!m_bch.is_tx_spendtime_unlocked(unlock_time)) -// { -// MERROR_VER("One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time); -// return false; -// } // // // From d448c26d6d3d5e32acd411e628b2382cbbc006d4 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Tue, 21 Apr 2020 19:28:10 +0200 Subject: [PATCH 17/18] Ban lock of purchase tx --- src/cryptonote_core/blockchain.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index ac903694d..2ae08a7de 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3358,6 +3358,13 @@ bool Blockchain::check_safex_tx(const transaction &tx, tx_verification_context & crypto::secret_key secret_seller_view_key; crypto::public_key public_seller_spend_key; + if (tx.unlock_time > m_db->height()) + { + MERROR("Purchase TX should not be locked"); + tvc.m_safex_invalid_input = true; + return false; + } + for (const auto &vout: tx.vout) { if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) { From 448eaa151c8dafc629ebc0ce469e4f43a636a054 Mon Sep 17 00:00:00 2001 From: Igor Grkavac Date: Wed, 22 Apr 2020 17:28:57 +0200 Subject: [PATCH 18/18] Add testnet 6.3 configs --- src/checkpoints/checkpoints.cpp | 2 +- src/cryptonote_config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index 942bde7e5..31bb4f566 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -165,7 +165,7 @@ namespace cryptonote if (nettype == TESTNET) { ADD_CHECKPOINT(1, "753e1454ebc44ffb18d7b390f7393a66ce7f3a8aaaf1e4e857af9df4e80d5784"); - ADD_CHECKPOINT(185120,"e20c0cb90538e3fefb4e2ef4c7895dbe0747075c4900f476288ea8217a2309b6"); + ADD_CHECKPOINT(100000,"f3b4a9e3c8fdc040cd78eb108910f1e24d5190cc4539b3cebd4f80aa686e6291"); return true; } diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index c8e1195af..f9f17e286 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -243,7 +243,7 @@ namespace config std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b1010002d4372ec2272690ccd59880807d1fa00f7bd2fa67f7abb350cafbdc24a4ba372c8301011a1ca7d7e74037e4d000a0fc2cc61389ac7d8b0a6b600c62e77374477c4c414d1103a83b4a507df5b0dc5af701078828a1372d77761339a28a7ebb1ff450622f7456d1083f35430eba3353a9e42514480a0cbccbda5ee6abb2d856f8a9aae056a92a6ece1020496a36a4b68341e3b401653139683f8dc27d76ff9eb9c26c2528c26a"; uint32_t const GENESIS_NONCE = 10003; uint64_t const HARDFORK_V4_INIT_DIFF = 6000; - uint64_t const HARDFORK_V4_START_HEIGHT = 185120; + uint64_t const HARDFORK_V4_START_HEIGHT = 100000; } namespace stagenet