1
0
Fork 0
forked from lthn/blockchain

Merge branch 'release'

This commit is contained in:
cryptozoidberg 2021-12-03 21:31:50 +01:00
commit 854a2f063e
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
52 changed files with 962 additions and 215 deletions

View file

@ -376,7 +376,7 @@ namespace epee
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
{
async_console_handler console_handler;
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, boost::placeholders::_1, boost::placeholders::_2, handlr), prompt, usage);
}
template<class t_server, class t_handler>
@ -460,7 +460,7 @@ namespace epee
/*template<class t_srv>
bool start_handling(t_srv& srv, const std::string& usage_string = "")
{
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, boost::placeholders::_1));
return true;
}*/
@ -489,7 +489,7 @@ namespace epee
/*template<class t_srv>
bool run_handling(t_srv& srv, const std::string& usage_string)
{
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, boost::placeholders::_1), usage_string);
}*/
};
@ -510,7 +510,7 @@ namespace epee
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string)
{
return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, boost::placeholders::_1, boost::placeholders::_2), prompt, usage_string);
}
void stop_handling()

View file

@ -0,0 +1,40 @@
// Copyright (c) 2006-2021, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
namespace epee
{
template<class _Ty1, class _Ty2>
struct kvserializable_pair : public std::pair<_Ty1, _Ty2>
{
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(first)
KV_SERIALIZE(second)
END_KV_SERIALIZE_MAP()
};
}

View file

@ -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;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

After

Width:  |  Height:  |  Size: 439 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 KiB

After

Width:  |  Height:  |  Size: 805 KiB

View file

@ -151,7 +151,7 @@ namespace command_line
}
template<typename F>
bool handle_error_helper(const boost::program_options::options_description& desc, F parser)
bool handle_error_helper(const boost::program_options::options_description& desc, std::string& err, F parser)
{
try
{
@ -159,6 +159,7 @@ namespace command_line
}
catch (std::exception& e)
{
err = e.what();
std::cerr << "Failed to parse arguments: " << e.what() << std::endl;
std::cerr << desc << std::endl;
return false;
@ -171,6 +172,13 @@ namespace command_line
}
}
template<typename F>
bool handle_error_helper(const boost::program_options::options_description& desc, F parser)
{
std::string stub_err;
return handle_error_helper(desc, stub_err, parser);
}
template<typename T, bool required>
bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
{

View file

@ -143,9 +143,10 @@ namespace tools
else
{
int res = 0;
//MDBX_txn_flags_t flags = MDBX_txn_flags_t();
unsigned int flags = 0;
if (read_only)
flags += MDBX_RDONLY;
flags = MDBX_RDONLY;//flags = MDBX_TXN_RDONLY;
//don't use parent tx in write transactions if parent tx was read-only (restriction in mdbx)
//see "Nested transactions: Max 1 child, write txns only, no writemap"
@ -340,7 +341,9 @@ namespace tools
data[0].iov_base = (void*)v;
data[0].iov_len = vs;
res = mdbx_put(get_current_tx(), static_cast<MDBX_dbi>(h), &key, data, 0);
//MDBX_put_flags_t flags = MDBX_put_flags_t();
unsigned flags = 0;
res = mdbx_put(get_current_tx(), static_cast<MDBX_dbi>(h), &key, data, flags);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_put");
return true;
}

View file

@ -70,8 +70,7 @@ namespace currency
iv = *((crypto::chacha8_iv*)&pass_hash);
crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data);
}
//-----------------------------------------------------------------
std::string account_base::get_seed_phrase(const std::string& password) const
{
if (m_keys_seed_binary.empty())

View file

@ -578,13 +578,13 @@ bool blockchain_storage::set_checkpoints(checkpoints&& chk_pts)
catch (const std::exception& ex)
{
m_db.abort_transaction();
LOG_ERROR("UNKNOWN EXCEPTION WHILE ADDINIG NEW BLOCK: " << ex.what());
LOG_ERROR("UNKNOWN EXCEPTION WHILE SETTING CHECKPOINTS: " << ex.what());
return false;
}
catch (...)
{
m_db.abort_transaction();
LOG_ERROR("UNKNOWN EXCEPTION WHILE ADDINIG NEW BLOCK.");
LOG_ERROR("UNKNOWN EXCEPTION WHILE SETTING CHECKPOINTS.");
return false;
}
@ -594,7 +594,7 @@ bool blockchain_storage::prune_ring_signatures_and_attachments(uint64_t height,
{
CRITICAL_REGION_LOCAL(m_read_lock);
CHECK_AND_ASSERT_MES(height < m_db_blocks.size(), false, "prune_ring_signatures called with wrong parameter: " << height << ", m_blocks.size() " << m_db_blocks.size());
CHECK_AND_ASSERT_MES(height < m_db_blocks.size(), false, "prune_ring_signatures called with wrong parameter: " << height << ", m_blocks.size() = " << m_db_blocks.size());
auto vptr = m_db_blocks[height];
CHECK_AND_ASSERT_MES(vptr.get(), false, "Failed to get block on height");
@ -626,22 +626,20 @@ bool blockchain_storage::prune_ring_signatures_and_attachments_if_need()
{
CRITICAL_REGION_LOCAL(m_read_lock);
if (m_db_blocks.size() > 1 && m_checkpoints.get_top_checkpoint_height() && m_checkpoints.get_top_checkpoint_height() > m_db_current_pruned_rs_height)
{
uint64_t pruning_last_height = std::min(m_db_blocks.size() - 1, m_checkpoints.get_top_checkpoint_height());
if (pruning_last_height > m_db_current_pruned_rs_height)
uint64_t top_block_height = get_top_block_height();
uint64_t pruning_end_height = m_checkpoints.get_checkpoint_before_height(top_block_height);
if (pruning_end_height > m_db_current_pruned_rs_height)
{
LOG_PRINT_CYAN("Starting pruning ring signatues and attachments from height " << m_db_current_pruned_rs_height + 1 << " to height " << pruning_end_height
<< " (" << pruning_end_height - m_db_current_pruned_rs_height << " blocks), top block height is " << top_block_height, LOG_LEVEL_0);
uint64_t tx_count = 0, sig_count = 0, attach_count = 0;
for(uint64_t height = m_db_current_pruned_rs_height + 1; height <= pruning_end_height; height++)
{
LOG_PRINT_CYAN("Starting pruning ring signatues and attachments from height " << m_db_current_pruned_rs_height + 1 << " to height " << pruning_last_height
<< " (" << pruning_last_height - m_db_current_pruned_rs_height << " blocks)", LOG_LEVEL_0);
uint64_t tx_count = 0, sig_count = 0, attach_count = 0;
for(uint64_t height = m_db_current_pruned_rs_height + 1; height <= pruning_last_height; height++)
{
bool res = prune_ring_signatures_and_attachments(height, tx_count, sig_count, attach_count);
CHECK_AND_ASSERT_MES(res, false, "failed to prune_ring_signatures_and_attachments for height = " << height);
}
m_db_current_pruned_rs_height = pruning_last_height;
LOG_PRINT_CYAN("Transaction pruning finished: " << sig_count << " signatures and " << attach_count << " attachments released in " << tx_count << " transactions.", LOG_LEVEL_0);
bool res = prune_ring_signatures_and_attachments(height, tx_count, sig_count, attach_count);
CHECK_AND_ASSERT_MES(res, false, "failed to prune_ring_signatures_and_attachments for height = " << height);
}
m_db_current_pruned_rs_height = pruning_end_height;
LOG_PRINT_CYAN("Transaction pruning finished: " << sig_count << " signatures and " << attach_count << " attachments released in " << tx_count << " transactions.", LOG_LEVEL_0);
}
return true;
}
@ -1036,7 +1034,9 @@ void blockchain_storage::purge_alt_block_txs_hashs(const block& b)
//------------------------------------------------------------------
void blockchain_storage::do_erase_altblock(alt_chain_container::iterator it)
{
purge_altblock_keyimages_from_big_heap(it->second.bl, get_block_hash(it->second.bl));
crypto::hash id = get_block_hash(it->second.bl);
LOG_PRINT_L1("erasing alt block " << print16(id) << " @ " << get_block_height(it->second.bl));
purge_altblock_keyimages_from_big_heap(it->second.bl, id);
purge_alt_block_txs_hashs(it->second.bl);
m_alternative_chains.erase(it);
}

View file

@ -396,7 +396,7 @@ namespace currency
else
{
CHECK_AND_ASSERT_MES(*block_ind_ptr < m_db_blocks.size(), false, "Internal error: bl_id=" << string_tools::pod_to_hex(bl_id)
<< " have index record with offset=" << *block_ind_ptr << ", bigger then m_blocks.size()=" << m_db_blocks.size());
<< " have index record with offset=" << *block_ind_ptr << ", bigger then m_db_blocks.size()=" << m_db_blocks.size());
blocks.push_back(m_db_blocks[*block_ind_ptr]->bl);
}
}

View file

@ -36,11 +36,11 @@ namespace currency
if(height > blockchain_last_block_height)
return false;
auto it = m_points.lower_bound(height);
auto it = m_points.lower_bound(height); // if found, it->first >= height
if(it == m_points.end())
return false;
if(it->first <= blockchain_last_block_height)
return true;
return true; // this is the case only if height <= it->first <= blockchain_last_block_height
else
return false;
}
@ -68,4 +68,27 @@ namespace currency
return false;
}
}
//---------------------------------------------------------------------------
uint64_t checkpoints::get_checkpoint_before_height(uint64_t height) const
{
// returns height of the leftmost CP with height that is LESS than the given height
// ex:
// If there are two CP at 11 and 15:
// get_checkpoint_before_height(10) = 0
// get_checkpoint_before_height(11) = 0
// get_checkpoint_before_height(12) = 11
// get_checkpoint_before_height(13) = 11
// get_checkpoint_before_height(14) = 11
// get_checkpoint_before_height(15) = 11
// get_checkpoint_before_height(16) = 15
uint64_t top_cp = get_top_checkpoint_height();
if (height > top_cp)
return top_cp;
auto it = m_points.lower_bound(height); // if found, it->first >= height
if (it == m_points.end() || it == m_points.begin())
return 0;
return (--it)->first;
}
}

View file

@ -20,6 +20,8 @@ namespace currency
bool is_height_passed_zone(uint64_t height, uint64_t blockchain_last_block_height) const;
bool check_block(uint64_t height, const crypto::hash& h) const;
uint64_t get_top_checkpoint_height() const;
uint64_t get_checkpoint_before_height(uint64_t height) const;
private:
std::map<uint64_t, crypto::hash> m_points;
};

View file

@ -211,7 +211,7 @@
#define MINER_CONFIG_FILENAME "miner_conf.json"
#define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin"
#define GUI_CONFIG_FILENAME "gui_settings.json"
#define GUI_INTERNAL_CONFIG "gui_internal_config.bin"
#define GUI_INTERNAL_CONFIG2 "gui_internal_config.json"

View file

@ -914,7 +914,8 @@ namespace currency
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with \r\nm_total_height=" << arg.total_height
<< "\r\nm_start_height=" << arg.start_height
<< "\r\nm_block_ids.size()=" << arg.m_block_ids.size());
//m_p2p->drop_connection(context);
m_p2p->drop_connection(context);
m_p2p->add_ip_fail(context.m_remote_ip);
}
BOOST_FOREACH(auto& bl_details, arg.m_block_ids)

View file

@ -45,10 +45,19 @@
<true/>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>ZanoApp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>zano</string>
</array>
</dict>
</array>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 109 KiB

View file

@ -387,9 +387,9 @@ void MainWindow::changeEvent(QEvent *e)
bool MainWindow::store_app_config()
{
TRY_ENTRY();
std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG;
LOG_PRINT_L0("storing gui internal config from " << conf_path);
CHECK_AND_ASSERT_MES(tools::serialize_obj_to_file(m_config, conf_path), false, "failed to store gui internal config");
std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG2;
LOG_PRINT_L0("storing gui internal config to " << conf_path);
CHECK_AND_ASSERT_MES(epee::serialization::store_t_to_json_file(m_config, conf_path), false, "failed to store gui internal config");
return true;
CATCH_ENTRY2(false);
}
@ -397,9 +397,9 @@ bool MainWindow::store_app_config()
bool MainWindow::load_app_config()
{
TRY_ENTRY();
std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG;
std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG2;
LOG_PRINT_L0("loading gui internal config from " << conf_path);
bool r = tools::unserialize_obj_from_file(m_config, conf_path);
bool r = epee::serialization::load_t_from_json_file(m_config, conf_path);
LOG_PRINT_L0("gui internal config " << (r ? "loaded ok" : "was not loaded"));
return r;
CATCH_ENTRY2(false);
@ -548,15 +548,29 @@ void MainWindow::restore_pos(bool consider_showed)
}
else
{
QPoint pos;
QSize sz;
pos.setX(m_config.m_window_position.first);
pos.setY(m_config.m_window_position.second);
sz.setHeight(m_config.m_window_size.first);
sz.setWidth(m_config.m_window_size.second);
this->move(pos);
this->resize(sz);
QPoint point = QApplication::desktop()->screenGeometry().bottomRight();
if (m_config.m_window_position.first + m_config.m_window_size.second > point.x() ||
m_config.m_window_position.second + m_config.m_window_size.first > point.y()
)
{
QSize sz = AUTO_VAL_INIT(sz);
sz.setHeight(770);
sz.setWidth(1200);
this->resize(sz);
store_window_pos();
//reset position(screen changed or other reason)
}
else
{
QPoint pos = AUTO_VAL_INIT(pos);
QSize sz = AUTO_VAL_INIT(sz);
pos.setX(m_config.m_window_position.first);
pos.setY(m_config.m_window_position.second);
sz.setHeight(m_config.m_window_size.first);
sz.setWidth(m_config.m_window_size.second);
this->move(pos);
this->resize(sz);
}
}
if (consider_showed)
@ -643,14 +657,16 @@ bool MainWindow::show_inital()
restore_pos(true);
else
{
m_config = AUTO_VAL_INIT(m_config);
this->show();
QSize sz;
QSize sz = AUTO_VAL_INIT(sz);
sz.setHeight(770);
sz.setWidth(1200);
this->resize(sz);
store_window_pos();
m_config.is_maximazed = false;
m_config.is_showed = true;
m_config.disable_notifications = false;
}
return true;
CATCH_ENTRY2(false);
@ -727,14 +743,26 @@ void qt_log_message_handler(QtMsgType type, const QMessageLogContext &context, c
bool MainWindow::init_backend(int argc, char* argv[])
{
TRY_ENTRY();
if (!m_backend.init_command_line(argc, argv))
std::string command_line_fail_details;
if (!m_backend.init_command_line(argc, argv, command_line_fail_details))
{
this->show_msg_box(command_line_fail_details);
return false;
}
if (!init_window())
{
this->show_msg_box("Failed to main screen launch, check logs for the more detais.");
return false;
}
if (!m_backend.init(this))
{
this->show_msg_box("Failed to initialize backend, check debug logs for more details.");
return false;
}
if (m_backend.is_qt_logs_enabled())
{
@ -811,8 +839,25 @@ bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, l
CATCH_ENTRY2(false);
}
bool MainWindow::get_is_disabled_notifications()
{
return m_config.disable_notifications;
}
bool MainWindow::set_is_disabled_notifications(const bool& param)
{
m_config.disable_notifications = param;
return m_config.disable_notifications;
}
QString MainWindow::export_wallet_history(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::export_wallet_info, ewi);
PREPARE_RESPONSE(view::api_response, ar);
ar.error_code = m_backend.export_wallet_history(ewi);
return MAKE_RESPONSE(ar);
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
bool MainWindow::update_wallets_info(const view::wallets_summary_info& wsi)
{
TRY_ENTRY();
@ -834,6 +879,10 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
LOG_PRINT_L0(get_wallet_log_prefix(tei.wallet_id) + "SENDING SIGNAL -> [money_transfer]" << std::endl << json_str);
//this->money_transfer(json_str.c_str());
QMetaObject::invokeMethod(this, "money_transfer", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
if (m_config.disable_notifications)
return true;
if (!m_tray_icon)
return true;
if (!tei.ti.is_income)
@ -852,7 +901,7 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
return true;
}
auto amount_str = currency::print_money(tei.ti.amount);
auto amount_str = currency::print_money_brief(tei.ti.amount);
std::string title, msg;
if (tei.ti.height == 0) // unconfirmed trx
{
@ -869,6 +918,7 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
else if (tei.ti.unlock_time)
msg += m_localization[localization_id_locked];
show_notification(title, msg);
return true;

View file

@ -8,6 +8,7 @@
#include <QWebChannel>
#include "wallet/view_iface.h"
#include "serialization/keyvalue_helper_structs.h"
#ifndef Q_MOC_RUN
#include "wallet/wallets_manager.h"
@ -60,10 +61,20 @@ public:
struct app_config
{
std::pair<int64_t, int64_t> m_window_position;
std::pair<int64_t, int64_t> m_window_size;
epee::kvserializable_pair<int64_t, int64_t> m_window_position;
epee::kvserializable_pair<int64_t, int64_t> m_window_size;
bool is_maximazed;
bool is_showed;
bool disable_notifications;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_window_position)
KV_SERIALIZE(m_window_size)
KV_SERIALIZE(is_maximazed)
KV_SERIALIZE(is_showed)
KV_SERIALIZE(disable_notifications)
END_KV_SERIALIZE_MAP()
};
protected slots:
@ -150,6 +161,10 @@ public:
QString get_default_fee();
QString get_options();
void bool_toggle_icon(const QString& param);
bool get_is_disabled_notifications();
bool set_is_disabled_notifications(const bool& param);
QString export_wallet_history(const QString& param);
QString get_log_file();
QString check_available_sources(const QString& param);
QString open_url_in_browser(const QString& param);
@ -176,6 +191,7 @@ signals:
void do_dispatch(const QString status, const QString params); //general function
void on_core_event(const QString method_name); //general function
void set_options(const QString str); //general function
void get_wallet_name();
private:
//-------------------- i_core_event_handler --------------------
@ -254,7 +270,7 @@ private:
enum localization_string_indices
{
// order is surprizingly important here! (see also updateLocalisation in AppController.js)
// order is surprisingly important here! (see also updateLocalisation in AppController.js)
localization_id_quit = 0,
localization_id_is_received,
localization_id_is_confirmed,

View file

@ -0,0 +1,18 @@
#include "urleventfilter.h"
#include <QMessageBox>
bool URLEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent *fileEvent = static_cast<QFileOpenEvent*>(event);
if(!fileEvent->url().isEmpty())
{
QMessageBox msg;
msg.setText(fileEvent->url().toString());
msg.exec();
}
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
};

View file

@ -0,0 +1,12 @@
#include <QObject>
#include <QFileOpenEvent>
#include <QDebug>
class URLEventFilter : public QObject
{
Q_OBJECT
public:
URLEventFilter() : QObject(){};
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};

@ -1 +1 @@
Subproject commit b028252d30a32e80c12fa890c306d3c5842e937a
Subproject commit 93802cb8fe1c79daf320aa4b72ba454d27da31d7

View file

@ -12,7 +12,9 @@
//#include "qtlogger.h"
#include "include_base_utils.h"
#include "currency_core/currency_config.h"
#ifdef Q_OS_DARWIN
#include "application/urleventfilter.h"
#endif
int main(int argc, char *argv[])
{
@ -26,6 +28,9 @@ int main(int argc, char *argv[])
// See http://crbug.com/436603.
// _set_FMA3_enable(0);
//#endif // ARCH_CPU_X86_64 && _MSC_VER <= 1800
if(argc > 1)
std::cout << argv[1] << std::endl;
#ifdef _MSC_VER
#ifdef _WIN64
@ -61,12 +66,18 @@ int main(int argc, char *argv[])
QApplication app(argc, argv);
#ifdef Q_OS_DARWIN
URLEventFilter url_event_filter;
app.installEventFilter(&url_event_filter);
#endif
MainWindow viewer;
if (!viewer.init_backend(argc, argv))
{
static_cast<view::i_view*>(&viewer)->show_msg_box("Failed to initialize backend, check debug logs for more details.");
return 1;
}
app.installNativeEventFilter(&viewer);
viewer.setWindowTitle(CURRENCY_NAME_BASE);
viewer.show_inital();

View file

@ -81,7 +81,8 @@ namespace nodetool
m_last_stat_request_time{},
m_use_only_priority_peers(false),
m_peer_livetime{},
m_debug_requests_enabled(false)
m_debug_requests_enabled(false),
m_ip_auto_blocking_enabled(false)
{}
static void init_options(boost::program_options::options_description& desc);
@ -215,6 +216,8 @@ namespace nodetool
bool urgent_alert_worker();
bool critical_alert_worker();
bool remove_dead_connections();
bool is_ip_good_for_adding_to_peerlist(uint32_t adress);
bool is_ip_in_blacklist(uint32_t adress);
//debug functions
@ -245,6 +248,7 @@ namespace nodetool
bool m_hide_my_port;
bool m_offline_mode;
bool m_debug_requests_enabled;
bool m_ip_auto_blocking_enabled;
uint64_t m_startup_time;

View file

@ -26,18 +26,19 @@ namespace nodetool
namespace
{
const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"};
const command_line::arg_descriptor<std::string> arg_p2p_bind_port = {"p2p-bind-port", "Port for p2p network protocol", boost::to_string(P2P_DEFAULT_PORT)};
const command_line::arg_descriptor<uint32_t> arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0};
const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"};
const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"};
const command_line::arg_descriptor<std::string> arg_p2p_bind_port = {"p2p-bind-port", "Port for p2p network protocol", boost::to_string(P2P_DEFAULT_PORT)};
const command_line::arg_descriptor<uint32_t> arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0};
const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"};
const command_line::arg_descriptor<bool> arg_p2p_use_only_priority_nodes = {"use-only-priority-nodes", "Try to connect only to priority nodes"};
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
const command_line::arg_descriptor<bool> arg_p2p_offline_mode = { "offline-mode", "Don't connect to any node and reject any connections", false, true };
const command_line::arg_descriptor<bool> arg_p2p_disable_debug_reqs = { "disable-debug-p2p-requests", "Disable p2p debug requests", false, true };
}
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
const command_line::arg_descriptor<bool> arg_p2p_offline_mode = { "offline-mode", "Don't connect to any node and reject any connections", false, true };
const command_line::arg_descriptor<bool> arg_p2p_disable_debug_reqs = { "disable-debug-p2p-requests", "Disable p2p debug requests", false, true };
const command_line::arg_descriptor<uint32_t> arg_p2p_ip_auto_blocking = { "p2p-ip-auto-blocking", "Enable (1) or disable (0) peers auto-blocking by IP <0|1>. Default: 0", 0, false };
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@ -53,7 +54,8 @@ namespace nodetool
command_line::add_arg(desc, arg_p2p_hide_my_port);
command_line::add_arg(desc, arg_p2p_offline_mode);
command_line::add_arg(desc, arg_p2p_disable_debug_reqs);
command_line::add_arg(desc, arg_p2p_use_only_priority_nodes);
command_line::add_arg(desc, arg_p2p_use_only_priority_nodes);
command_line::add_arg(desc, arg_p2p_ip_auto_blocking);
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@ -65,7 +67,14 @@ namespace nodetool
CHECK_AND_ASSERT_MES(r, false, "Failed to parse P2P_MAINTAINERS_PUB_KEY = " << P2P_MAINTAINERS_PUB_KEY);
std::string state_file_path = m_config_folder + "/" + P2P_NET_DATA_FILENAME;
tools::unserialize_obj_from_file(*this, state_file_path);
boost::system::error_code ec = AUTO_VAL_INIT(ec);
std::time_t last_update_time = boost::filesystem::last_write_time(state_file_path, ec);
//let's assume that if p2p peer list file stored more then 2 weeks ago,
//then it outdated and we need to fetch peerlist from seed nodes
if (!ec && time(nullptr) - last_update_time < 86400 * 14)
{
tools::unserialize_obj_from_file(*this, state_file_path);
}
//always use new id, to be able differ cloned computers
m_config.m_peer_id = crypto::rand<uint64_t>();
@ -100,21 +109,39 @@ namespace nodetool
if (m_offline_mode)
return false;
//@#@ temporary workaround
return true;
#if 0
if (!m_ip_auto_blocking_enabled)
return true;
return !is_ip_in_blacklist(addr);
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_ip_good_for_adding_to_peerlist(uint32_t addr)
{
if (m_offline_mode)
return false;
// even if IP auto blocking is disabled, bad peers should not be added to peerlists and be shared with other nodes
return !is_ip_in_blacklist(addr);
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_ip_in_blacklist(uint32_t addr)
{
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
auto it = m_blocked_ips.find(addr);
if(it == m_blocked_ips.end())
return true;
if(time(nullptr) - it->second > P2P_IP_BLOCKTIME )
if (it == m_blocked_ips.end())
return false;
if (time(nullptr) - it->second > P2P_IP_BLOCKTIME)
{
m_blocked_ips.erase(it);
LOG_PRINT_CYAN("Ip " << string_tools::get_ip_string_from_int32(addr) << "is unblocked.", LOG_LEVEL_0);
return true;
LOG_PRINT_CYAN("IP " << string_tools::get_ip_string_from_int32(addr) << " is unblocked due to blocking expiration.", LOG_LEVEL_0);
return false;
}
return false;
#endif
return true;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
@ -122,7 +149,8 @@ namespace nodetool
{
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
m_blocked_ips[addr] = time(nullptr);
LOG_PRINT_CYAN("Ip " << string_tools::get_ip_string_from_int32(addr) << " blocked.", LOG_LEVEL_0);
m_peerlist.remove_peers_by_ip_from_all(addr);
LOG_PRINT_CYAN("IP " << string_tools::get_ip_string_from_int32(addr) << " blocked and removed from peerlist", LOG_LEVEL_0);
return true;
}
//-----------------------------------------------------------------------------------
@ -138,6 +166,10 @@ namespace nodetool
it->second = P2P_IP_FAILS_BEFOR_BLOCK/2;
block_ip(address);
}
else
{
LOG_PRINT_CYAN("IP " << string_tools::get_ip_string_from_int32(address) << ": fail recorded, total fails count: " << fails, LOG_LEVEL_2);
}
return true;
}
//-----------------------------------------------------------------------------------
@ -162,6 +194,9 @@ namespace nodetool
m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip);
m_offline_mode = command_line::get_arg(vm, arg_p2p_offline_mode);
m_debug_requests_enabled = !command_line::get_arg(vm, arg_p2p_disable_debug_reqs);
m_ip_auto_blocking_enabled = (command_line::get_arg(vm, arg_p2p_ip_auto_blocking) != 0);
LOG_PRINT_L0("p2p peers auto-blocking is " << (m_ip_auto_blocking_enabled ? "enabled" : "disabled"));
if (m_offline_mode)
{
@ -679,7 +714,6 @@ namespace nodetool
<< string_tools::get_ip_string_from_int32(na.ip)
<< ":" << string_tools::num_to_string_fast(na.port)
/*<< ", try " << try_count*/);
//m_peerlist.set_peer_unreachable(pe);
return false;
}
peerid_type pi = AUTO_VAL_INIT(pi);
@ -701,12 +735,15 @@ namespace nodetool
return true;
}
peerlist_entry pe_local = AUTO_VAL_INIT(pe_local);
pe_local.adr = na;
pe_local.id = pi;
time(&pe_local.last_seen);
m_peerlist.append_with_peer_white(pe_local);
//update last seen and push it to peerlist manager
if (is_ip_good_for_adding_to_peerlist(na.ip)) // additional check to avoid IP shown up in peers in the case of non-blocking incoming connections
{
//update last seen and push it to peerlist manager
peerlist_entry pe_local = AUTO_VAL_INIT(pe_local);
pe_local.adr = na;
pe_local.id = pi;
time(&pe_local.last_seen);
m_peerlist.append_with_peer_white(pe_local);
}
LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK with peer " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port), LOG_LEVEL_2);
return true;
@ -1373,7 +1410,8 @@ namespace nodetool
//associate peer_id with this connection
context.peer_id = arg.node_data.peer_id;
if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port)
if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port
&& is_ip_good_for_adding_to_peerlist(context.m_remote_ip))
{
peerid_type peer_id_l = arg.node_data.peer_id;
uint32_t port_l = arg.node_data.my_port;

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2021 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -11,8 +11,6 @@
#include <map>
#include <iterator>
#include <boost/foreach.hpp>
//#include <boost/bimap.hpp>
//#include <boost/bimap/multiset_of.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/version.hpp>
@ -55,10 +53,10 @@ namespace nodetool
bool append_with_peer_gray(const peerlist_entry& pr);
bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port);
bool set_peer_just_seen(peerid_type peer, const net_address& addr);
bool set_peer_unreachable(const peerlist_entry& pr);
bool is_ip_allowed(uint32_t ip);
void trim_white_peerlist();
void trim_gray_peerlist();
bool remove_peers_by_ip_from_all(const uint32_t ip);
private:
@ -110,17 +108,6 @@ namespace nodetool
>
> peers_indexed;
typedef boost::multi_index_container<
peerlist_entry,
boost::multi_index::indexed_by<
// access by peerlist_entry::id<
boost::multi_index::ordered_unique<boost::multi_index::tag<by_id>, boost::multi_index::member<peerlist_entry,uint64_t,&peerlist_entry::id> >,
// access by peerlist_entry::net_adress
boost::multi_index::ordered_unique<boost::multi_index::tag<by_addr>, boost::multi_index::member<peerlist_entry,net_address,&peerlist_entry::adr> >,
// sort by peerlist_entry::last_seen<
boost::multi_index::ordered_non_unique<boost::multi_index::tag<by_time>, boost::multi_index::member<peerlist_entry,time_t,&peerlist_entry::last_seen> >
>
> peers_indexed_old;
public:
template <class Archive, class t_version_type>
@ -134,9 +121,7 @@ namespace nodetool
ar & m_peers_gray;
}
private:
bool peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi);
private:
friend class boost::serialization::access;
epee::critical_section m_peerlist_lock;
std::string m_config_folder;
@ -188,21 +173,6 @@ namespace nodetool
return true;
}
//--------------------------------------------------------------------------------------------------
inline
bool peerlist_manager::peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi)
{
for(auto x: pio)
{
auto by_addr_it = pi.get<by_addr>().find(x.adr);
if(by_addr_it == pi.get<by_addr>().end())
{
pi.insert(x);
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
inline void peerlist_manager::trim_white_peerlist()
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
@ -393,6 +363,33 @@ namespace nodetool
return true;
}
//--------------------------------------------------------------------------------------------------
inline
bool peerlist_manager::remove_peers_by_ip_from_all(const uint32_t ip)
{
TRY_ENTRY();
CRITICAL_REGION_LOCAL(m_peerlist_lock);
for (auto it = m_peers_white.begin(); it != m_peers_white.end();)
{
if (it->adr.ip == ip)
it = m_peers_white.erase(it);
else
++it;
}
for (auto it = m_peers_gray.begin(); it != m_peers_gray.end();)
{
if (it->adr.ip == ip)
it = m_peers_gray.erase(it);
else
++it;
}
return true;
CATCH_ENTRY_L0("peerlist_manager::remove_peers_by_ip_from_all()", false);
}
//--------------------------------------------------------------------------------------------------
}
BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER)

View file

@ -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 <unsgined_tx_file> <signed_tx_file> - 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 <signed_tx_file> - 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<std::string>& 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,58 +807,37 @@ bool simple_wallet::export_recent_transfers(const std::vector<std::string>& 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<tools::wallet_public::wallet_transfer_info> unconfirmed;
std::vector<tools::wallet_public::wallet_transfer_info> 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";
}
}
ss << "Recent transfers: " << ENDL;
for (auto & wti : recent)
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();
}
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);
return true;
}
//----------------------------------------------------------------------------------------------------

View file

@ -4,10 +4,10 @@
#define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_MAJOR_VERSION "1"
#define PROJECT_MINOR_VERSION "3"
#define PROJECT_REVISION "2"
#define PROJECT_MINOR_VERSION "4"
#define PROJECT_REVISION "0"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 135
#define PROJECT_VERSION_BUILD_NO 138
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -201,7 +201,8 @@ namespace plain_wallet
args[1] = const_cast<char*>(argss_1.c_str());
args[2] = const_cast<char*>(argss_2.c_str());
args[3] = nullptr;
if (!(ptr->gwm.init_command_line(3, args) && ptr->gwm.init(nullptr)))
std::string command_line_fail_details;
if (!(ptr->gwm.init_command_line(3, args, command_line_fail_details) && ptr->gwm.init(nullptr)))
{
LOG_ERROR("Failed to init wallets_manager");
return GENERAL_INTERNAL_ERRROR_INIT;

View file

@ -284,6 +284,20 @@ public:
END_KV_SERIALIZE_MAP()
};
struct export_wallet_info
{
uint64_t wallet_id;
bool include_pos_transactions;
std::string path;
std::string format;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(wallet_id)
KV_SERIALIZE(include_pos_transactions)
KV_SERIALIZE(path)
KV_SERIALIZE(format)
END_KV_SERIALIZE_MAP()
};
struct response_mining_estimate
{

View file

@ -3254,6 +3254,87 @@ void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_tra
total = m_transfer_history.size();
}
void wallet2::wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) {
ss << index << ",";
ss << epee::misc_utils::get_time_str_v2(wti.timestamp) << ",";
ss << print_money(wti.amount) << ",";
ss << "\"" << wti.comment << "\",";
ss << "[";
std::copy(wti.remote_addresses.begin(), wti.remote_addresses.end(), std::ostream_iterator<std::string>(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<std::string>(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)

View file

@ -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 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<uint64_t>& 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<currency::extra_v>& 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

View file

@ -56,7 +56,11 @@ namespace tools
command_line::add_arg(desc, arg_deaf_mode);
}
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), m_do_mint(false), m_deaf(false)
wallet_rpc_server::wallet_rpc_server(wallet2& w)
: m_wallet(w)
, m_do_mint(false)
, m_deaf(false)
, m_last_wallet_store_height(0)
{}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address)
@ -309,7 +313,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<currency::tx_destination_entry>& dsts = ctp.dsts;
@ -397,7 +401,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())
{

View file

@ -152,7 +152,7 @@ bool wallets_manager::do_exception_safe_call(guarded_code_t guarded_code, error_
}
bool wallets_manager::init_command_line(int argc, char* argv[])
bool wallets_manager::init_command_line(int argc, char* argv[], std::string& fail_message)
{
TRY_ENTRY();
po::options_description desc_cmd_only("Command line options");
@ -197,9 +197,8 @@ bool wallets_manager::init_command_line(int argc, char* argv[])
po::options_description desc_options("Allowed options");
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
bool coomand_line_parsed = command_line::handle_error_helper(desc_options, [&]()
std::string err_str;
bool command_line_parsed = command_line::handle_error_helper(desc_options, err_str, [&]()
{
po::store(po::parse_command_line(argc, argv, desc_options), m_vm);
@ -230,23 +229,29 @@ bool wallets_manager::init_command_line(int argc, char* argv[])
return true;
});
if (!coomand_line_parsed)
if (!command_line_parsed)
{
std::stringstream ss;
ss << "Command line has wrong arguments: " << std::endl;
for (int i = 0; i != argc; i++)
ss << "[" << i << "] " << argv[i] << std::endl;
std::cerr << ss.str() << std::endl << std::flush;
fail_message = "Error parsing arguments.\n";
fail_message += err_str + "\n";
std::stringstream s;
desc_options.print(s);
fail_message += s.str();
return false;
}
m_qt_logs_enbaled = command_line::get_arg(m_vm, arg_enable_qt_logs);
m_qt_dev_tools = command_line::get_arg(m_vm, arg_qt_dev_tools);
return true;
CATCH_ENTRY2(false);
}
void terminate_handler_func()
{
LOG_ERROR("\n\nTERMINATE HANDLER\n"); // should print callstack
@ -798,6 +803,24 @@ std::string wallets_manager::get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INF
}
std::string wallets_manager::export_wallet_history(const view::export_wallet_info& ewi)
{
GET_WALLET_OPT_BY_ID(ewi.wallet_id, wo);
try {
boost::filesystem::ofstream fstream;
fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fstream.open(ewi.path, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
wo.w->get()->export_transaction_history(fstream, ewi.format, ewi.include_pos_transactions);
fstream.close();
}
catch (...)
{
return API_RETURN_CODE_FAIL;
}
return API_RETURN_CODE_OK;
}
uint64_t wallets_manager::get_default_fee()
{
return TX_DEFAULT_FEE;
@ -1802,7 +1825,10 @@ void wallets_manager::on_transfer2(size_t wallet_id, const tools::wallet_public:
GET_WALLET_OPTIONS_BY_ID_VOID_RET(wallet_id, w);
tei.is_wallet_in_sync_process = w.long_refresh_in_progress;
m_pview->money_transfer(tei);
if (!(w.w->get()->is_watch_only()))
{
m_pview->money_transfer(tei);
}
}
void wallets_manager::on_pos_block_found(size_t wallet_id, const currency::block& b)
{

View file

@ -89,7 +89,7 @@ public:
wallets_manager();
~wallets_manager();
bool init_command_line(int argc, char* argv[]);
bool init_command_line(int argc, char* argv[], std::string& fail_message);
bool init(view::i_view* pview_handler);
bool start();
bool stop();
@ -139,6 +139,7 @@ public:
std::string get_my_offers(const bc_services::core_offers_filter& filter, std::list<bc_services::offer_details_ex>& offers);
std::string get_fav_offers(const std::list<bc_services::offer_id>& hashes, const bc_services::core_offers_filter& filter, std::list<bc_services::offer_details_ex>& offers);
std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res);
std::string export_wallet_history(const view::export_wallet_info& ewi);
uint64_t get_default_fee();
std::string get_mining_estimate(uint64_t amuont_coins,
uint64_t time,

View file

@ -2053,6 +2053,25 @@ bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& event
return true;
}
bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c)
{
std::shared_ptr<const currency::transaction_chain_entry> ptce = c.get_blockchain_storage().get_tx_chain_entry(tx_id);
if (!ptce)
return false;
for (size_t i = 0; i < ptce->tx.vin.size(); ++i)
{
auto& input = ptce->tx.vin[i];
if (input.type() == typeid(txin_to_key))
{
auto& intk = boost::get<txin_to_key>(input);
CHECK_AND_ASSERT_MES(intk.key_offsets.size() == mixin + 1, false, "for input #" << i << " mixin count is " << intk.key_offsets.size() - 1 << ", expected is " << mixin);
}
}
return true;
}
//------------------------------------------------------------------------------
void test_chain_unit_base::register_callback(const std::string& cb_name, verify_callback cb)

View file

@ -679,6 +679,7 @@ bool generate_pos_block_with_given_coinstake(test_generator& generator, const st
bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& events, const crypto::hash& last_block_id, const currency::txin_to_key& in_t_k,
const crypto::hash& hash_for_sig, const std::vector<crypto::signature> &sig);
bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c);
//--------------------------------------------------------------------------
template<class t_test_class>

View file

@ -57,7 +57,7 @@ bool clean_data_directory()
{
std::string config_folder = command_line::get_arg(g_vm, command_line::arg_data_dir);
static const std::set<std::string> files = { CURRENCY_POOLDATA_FOLDERNAME_OLD, CURRENCY_BLOCKCHAINDATA_FOLDERNAME_OLD, P2P_NET_DATA_FILENAME, MINER_CONFIG_FILENAME, GUI_SECURE_CONFIG_FILENAME, GUI_CONFIG_FILENAME, GUI_INTERNAL_CONFIG };
static const std::set<std::string> files = { CURRENCY_POOLDATA_FOLDERNAME_OLD, CURRENCY_BLOCKCHAINDATA_FOLDERNAME_OLD, P2P_NET_DATA_FILENAME, MINER_CONFIG_FILENAME, GUI_SECURE_CONFIG_FILENAME, GUI_CONFIG_FILENAME, GUI_INTERNAL_CONFIG2 };
static const std::set<std::string> prefixes = { CURRENCY_POOLDATA_FOLDERNAME_PREFIX, CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX };
std::vector<boost::filesystem::path> entries_to_remove;
@ -743,6 +743,9 @@ int main(int argc, char* argv[])
#undef MARK_TEST_AS_POSTPONED
// TODO // GENERATE_AND_PLAY(wallet_spend_form_auditable_and_track);
GENERATE_AND_PLAY(pos_minting_tx_packing);
GENERATE_AND_PLAY(multisig_wallet_test);
@ -814,6 +817,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_checkpoints_reorganize);
GENERATE_AND_PLAY(gen_checkpoints_pos_validation_on_altchain);
GENERATE_AND_PLAY(gen_checkpoints_and_invalid_tx_to_pool);
GENERATE_AND_PLAY(gen_checkpoints_set_after_switching_to_altchain);
GENERATE_AND_PLAY(gen_no_attchments_in_coinbase);
GENERATE_AND_PLAY(gen_no_attchments_in_coinbase_gentime);
@ -867,6 +871,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer);
GENERATE_AND_PLAY(wallet_rpc_transfer);
GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki);
GENERATE_AND_PLAY(wallet_sending_to_integrated_address);

View file

@ -36,13 +36,18 @@ bool checkpoints_test::set_checkpoint(currency::core& c, size_t ev_index, const
{
if (pcp.hash != null_hash && pcp.hash != get_block_hash(b))
continue;
currency::checkpoints cp;
cp.add_checkpoint(currency::get_block_height(b), epee::string_tools::pod_to_hex(currency::get_block_hash(b)));
c.set_checkpoints(std::move(cp));
m_local_checkpoints.add_checkpoint(pcp.height, epee::string_tools::pod_to_hex(currency::get_block_hash(b)));
c.set_checkpoints(currency::checkpoints(m_local_checkpoints));
LOG_PRINT_YELLOW("CHECKPOINT set at height " << pcp.height, LOG_LEVEL_0);
//for(uint64_t h = 0; h <= pcp.height + 1; ++h)
// LOG_PRINT_MAGENTA("%% " << h << " : " << m_local_checkpoints.get_checkpoint_before_height(h), LOG_LEVEL_0);
return true;
}
}
LOG_ERROR("set_checkpoint failed trying to set checkpoint at height " << pcp.height);
return false;
}
@ -395,8 +400,13 @@ bool gen_checkpoints_prun_txs_after_blockchain_load::generate(std::vector<test_e
DO_CALLBACK(events, "check_not_being_in_cp_zone");
DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2));
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true)); // tx_0 goes with blk_1_bad
MAKE_TX(events, tx_0, miner_acc, alice, MK_TEST_COINS(1), blk_0r);
std::vector<attachment_v> attach;
attach.push_back(tx_comment{"jokes are funny"});
// tx pool won't accept the tx, because it cannot be verified in CP zone
// set kept_by_block flag, so tx_0 be accepted
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
MAKE_TX_ATTACH(events, tx_0, miner_acc, alice, MK_TEST_COINS(1), blk_0r, attach);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
@ -407,11 +417,12 @@ bool gen_checkpoints_prun_txs_after_blockchain_load::generate(std::vector<test_e
DO_CALLBACK(events, "check_not_being_in_cp_zone");
MAKE_TX(events, tx_1, miner_acc, alice, MK_TEST_COINS(1), blk_3);
MAKE_TX_ATTACH(events, tx_1, miner_acc, alice, MK_TEST_COINS(1), blk_3, attach);
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_1);
DO_CALLBACK(events, "check_not_being_in_cp_zone");
// BCS tx pruning (on interval 0 - CP1) should be triggered once the following checkpoint is set
DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 6));
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
@ -437,8 +448,8 @@ bool gen_checkpoints_prun_txs_after_blockchain_load::check_txs(currency::core& c
r = c.get_transaction(m_tx1_id, tx_1);
CHECK_AND_ASSERT_MES(r, false, "can't get transaction tx_1");
CHECK_AND_ASSERT_MES(tx_1.signatures.empty(), false, "tx_1 has non-empty sig");
CHECK_AND_ASSERT_MES(tx_1.attachment.empty(), false, "tx_1 has non-empty attachments");
CHECK_AND_ASSERT_MES(!tx_1.signatures.empty(), false, "tx_1 has empty sig");
CHECK_AND_ASSERT_MES(!tx_1.attachment.empty(), false, "tx_1 has empty attachments");
return true;
}
@ -895,3 +906,64 @@ bool gen_checkpoints_and_invalid_tx_to_pool::c1(currency::core& c, size_t ev_ind
return true;
}
//------------------------------------------------------------------------------
gen_checkpoints_set_after_switching_to_altchain::gen_checkpoints_set_after_switching_to_altchain()
{
}
bool gen_checkpoints_set_after_switching_to_altchain::generate(std::vector<test_event_entry>& events) const
{
// Test outline:
// 0) no checkpoints are set;
// 1) core is in a subchain, that will become alternative;
// 2) checkpoint is set (in the furute), transaction pruning is executed;
// 3) core continues to sync, chain switching occurs
// Make sure that chain switching is still possible after pruning.
// 0 ... N N+1 N+2 N+3 N+4 N+5 N+6 <- height (N = CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
// tx1
// (0 )- (0r)- (1 )- (2a)- (3a)- <- alt chain
// \
// \- (2 )- <- main chain
bool r = false;
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
DO_CALLBACK(events, "check_not_being_in_cp_zone");
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
MAKE_TX(events, tx1, miner_acc, alice_acc, MK_TEST_COINS(1), blk_1);
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1, miner_acc, tx1);
MAKE_NEXT_BLOCK(events, blk_3a, blk_2a, miner_acc);
DO_CALLBACK(events, "check_not_being_in_cp_zone");
// 0 ... N N+1 N+2 N+3 N+4 N+5 N+6 <- height (N = CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
// +-----------> CP <- checkpoint
// tx1 |
// (0 )- (0r)- (1 )- (2a)- (3a)- <- alt chain
// \ | <- when CP set up
// \- (2 )- (3 )- (4 )- (5 )- (6 )- <- main chain
DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5));
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc); // <-- this should trigger the switching
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_4), get_block_hash(blk_4)));
DO_CALLBACK(events, "check_being_in_cp_zone");
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc); // <-- CHECKPOINT
MAKE_NEXT_BLOCK(events, blk_6, blk_5, miner_acc);
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_6), get_block_hash(blk_6)));
DO_CALLBACK(events, "check_not_being_in_cp_zone");
return true;
}

View file

@ -23,6 +23,9 @@ protected:
uint64_t height;
crypto::hash hash;
};
private:
currency::checkpoints m_local_checkpoints;
};
struct gen_checkpoints_attachments_basic : public checkpoints_test
@ -109,3 +112,9 @@ struct gen_checkpoints_and_invalid_tx_to_pool : public checkpoints_test
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct gen_checkpoints_set_after_switching_to_altchain : public checkpoints_test
{
gen_checkpoints_set_after_switching_to_altchain();
bool generate(std::vector<test_event_entry>& events) const;
};

View file

@ -148,6 +148,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind
alice_wlt->get_payments(payment_id, payments);
CHECK_AND_ASSERT_MES(payments.size() == 1, false, "Invalid payments count: " << payments.size());
CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(3), false, "Invalid payment");
CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(0, payments.front().m_tx_hash, c), false, ""); // make sure number of decoys is correct
// 3. standard address + invalid external payment id => fail
@ -181,9 +182,127 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind
alice_wlt->get_payments(payment_id, payments);
CHECK_AND_ASSERT_MES(payments.size() == 1, false, "Invalid payments count: " << payments.size());
CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(7), false, "Invalid payment");
CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(0, payments.front().m_tx_hash, c), false, ""); // make sure number of decoys is correct
return true;
}
//------------------------------------------------------------------------------
wallet_rpc_transfer::wallet_rpc_transfer()
{
REGISTER_CALLBACK_METHOD(wallet_rpc_transfer, configure_core);
REGISTER_CALLBACK_METHOD(wallet_rpc_transfer, c1);
}
bool wallet_rpc_transfer::generate(std::vector<test_event_entry>& events) const
{
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core");
set_hard_fork_heights_to_generator(generator);
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 6);
DO_CALLBACK(events, "c1");
return true;
}
bool wallet_rpc_transfer::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
pc.hard_fork_01_starts_after_height = 1;
pc.hard_fork_02_starts_after_height = 1;
pc.hard_fork_03_starts_after_height = 1;
c.get_blockchain_storage().set_core_runtime_config(pc);
return true;
}
bool wallet_rpc_transfer::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
miner_wlt->refresh();
// wallet RPC server
tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt);
epee::json_rpc::error je;
tools::wallet_rpc_server::connection_context ctx;
// 1. Check non-zero mixin and default settings
tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req);
req.fee = TESTS_DEFAULT_FEE;
req.mixin = 2;
tools::wallet_public::transfer_destination tds = AUTO_VAL_INIT(tds);
tds.address = m_accounts[ALICE_ACC_IDX].get_public_address_str();
tds.amount = MK_TEST_COINS(3);
req.destinations.push_back(tds);
tools::wallet_public::COMMAND_RPC_TRANSFER::response res = AUTO_VAL_INIT(res);
r = miner_wlt_rpc.on_transfer(req, res, je, ctx);
CHECK_AND_ASSERT_MES(r, false, "RPC call failed, code: " << je.code << ", msg: " << je.message);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, tds.amount), false, "");
// check the transfer has been received
tools::wallet2::transfer_details td = AUTO_VAL_INIT(td);
CHECK_AND_ASSERT_MES(alice_wlt->get_transfer_info_by_index(0, td), false, "");
CHECK_AND_ASSERT_MES(td.amount() == MK_TEST_COINS(3), false, "Invalid payment");
CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(2, td.tx_hash(), c), false, "");
// make sure tx_received is set by default, but tx_payer is not
std::shared_ptr<const transaction_chain_entry> pche = c.get_blockchain_storage().get_tx_chain_entry(td.tx_hash());
CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container<tx_receiver>(pche->tx.extra) == 1, false, "tx_receiver: incorrect count of items");
CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container<tx_payer>(pche->tx.extra) == 0, false, "tx_payer: incorrect count of items");
// 2. check tx_receiver and tx_payer non-default
req.mixin = 1;
req.hide_receiver = true;
req.push_payer = true;
tds.amount = MK_TEST_COINS(5);
req.destinations.clear();
req.destinations.push_back(tds);
res = AUTO_VAL_INIT(res);
r = miner_wlt_rpc.on_transfer(req, res, je, ctx);
CHECK_AND_ASSERT_MES(r, false, "RPC call failed, code: " << je.code << ", msg: " << je.message);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count());
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(3 + 5)), false, "");
td = AUTO_VAL_INIT(td);
CHECK_AND_ASSERT_MES(alice_wlt->get_transfer_info_by_index(1, td), false, "");
CHECK_AND_ASSERT_MES(td.amount() == MK_TEST_COINS(5), false, "Invalid payment");
CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(1, td.tx_hash(), c), false, "");
// make sure tx_received is set by default, but tx_payer is not
pche = c.get_blockchain_storage().get_tx_chain_entry(td.tx_hash());
CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container<tx_receiver>(pche->tx.extra) == 0, false, "tx_receiver: incorrect count of items");
CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container<tx_payer>(pche->tx.extra) == 1, false, "tx_payer: incorrect count of items");
return true;
}

View file

@ -21,3 +21,11 @@ struct wallet_rpc_integrated_address_transfer : public wallet_test
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct wallet_rpc_transfer : public wallet_test
{
wallet_rpc_transfer();
bool generate(std::vector<test_event_entry>& events) const;
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};

View file

@ -3553,5 +3553,87 @@ bool wallet_watch_only_and_chain_switch::c1(currency::core& c, size_t ev_index,
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(7), false, UINT64_MAX, 0, 0, MK_TEST_COINS(7), 0), false, "");
return true;
}
//------------------------------------------------------------------------------
wallet_spend_form_auditable_and_track::wallet_spend_form_auditable_and_track()
{
REGISTER_CALLBACK_METHOD(wallet_spend_form_auditable_and_track, c1);
}
bool wallet_spend_form_auditable_and_track::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(true); // Alice has auditable wallet
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc = alice_acc; bob_acc.make_account_watch_only(); // Bob has Alice's tracking wallet
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_TX(events, tx_1, miner_acc, alice_acc, MK_TEST_COINS(5), blk_0r);
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
std::vector<attachment_v> attachments;
tx_comment comment_attachment = AUTO_VAL_INIT(comment_attachment);
m_comment = "Jokes are funny!";
comment_attachment.comment = m_comment;
attachments.push_back(comment_attachment);
MAKE_TX_ATTACH(events, tx_2, alice_acc, miner_acc, MK_TEST_COINS(1), blk_1r, attachments);
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_2);
DO_CALLBACK(events, "c1");
return true;
}
bool wallet_spend_form_auditable_and_track::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
// make sure Alice's wallet is autibale and not watch-only
CHECK_AND_ASSERT_MES(!alice_wlt->is_watch_only() && alice_wlt->is_auditable(), false, "incorrect type of Alice's wallet");
// make sure Bob's wallet is a tracking wallet
CHECK_AND_ASSERT_MES(bob_wlt->is_watch_only() && bob_wlt->is_auditable(), false, "incorrect type of Bob's wallet");
const account_public_address& bob_addr = bob_wlt->get_account().get_public_address();
const account_public_address& alice_addr = alice_wlt->get_account().get_public_address();
// make sure their addresses are linked indeed
CHECK_AND_ASSERT_MES(bob_addr.view_public_key == alice_addr.view_public_key && bob_addr.spend_public_key == alice_addr.spend_public_key, false,
"Bob's tracking wallet address is not linked with Alice's one");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
bob_wlt->refresh();
// check the balances
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(3), false, UINT64_MAX, 0, 0, 0, 0), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt, MK_TEST_COINS(3), false, UINT64_MAX, 0, 0, 0, 0), false, "");
r = false;
bool r_comment = false;
bob_wlt->enumerate_transfers_history([&](const tools::wallet_public::wallet_transfer_info& wti) {
if (wti.amount == MK_TEST_COINS(5))
{
r_comment = (wti.comment == m_comment);
if (!r_comment)
return false; // stop
}
return true; // continue
}, true);
CHECK_AND_ASSERT_MES(r, false, "cannot get comment from tx");
CHECK_AND_ASSERT_MES(r_comment, false, "wrong comment got from tx");
return true;
}

View file

@ -276,3 +276,12 @@ struct wallet_watch_only_and_chain_switch : public wallet_test
mutable crypto::hash m_split_point_block_id;
mutable uint64_t m_split_point_block_height;
};
struct wallet_spend_form_auditable_and_track : public wallet_test
{
wallet_spend_form_auditable_and_track();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable std::string m_comment;
};

View file

@ -39,3 +39,87 @@ TEST(checkpoints_test, test_checkpoints_for_alternative)
r = cp.is_height_passed_zone(11, 12);
ASSERT_FALSE(r);
}
TEST(checkpoints_test, get_checkpoint_before_height_1)
{
currency::checkpoints cp;
cp.add_checkpoint(15, "0000000000000000000000000000000000000000000000000000000000000000");
for (uint64_t h = 0; h <= 15; ++h)
ASSERT_TRUE(cp.get_checkpoint_before_height(h) == 0);
ASSERT_TRUE(cp.get_checkpoint_before_height(16) == 15);
for (uint64_t h = 17; h < 100; ++h)
ASSERT_TRUE(cp.get_checkpoint_before_height(h) == 15);
}
TEST(checkpoints_test, get_checkpoint_before_height_2)
{
currency::checkpoints cp;
cp.add_checkpoint(11, "0000000000000000000000000000000000000000000000000000000000000000");
cp.add_checkpoint(15, "0000000000000000000000000000000000000000000000000000000000000000");
for (uint64_t h = 0; h < 11; ++h)
ASSERT_TRUE(cp.get_checkpoint_before_height(h) == 0);
ASSERT_TRUE(cp.get_checkpoint_before_height(11) == 0);
ASSERT_TRUE(cp.get_checkpoint_before_height(12) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(13) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(14) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(15) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(16) == 15);
for (uint64_t h = 17; h < 100; ++h)
ASSERT_TRUE(cp.get_checkpoint_before_height(h) == 15);
}
TEST(checkpoints_test, get_checkpoint_before_height_3)
{
currency::checkpoints cp;
cp.add_checkpoint(11, "0000000000000000000000000000000000000000000000000000000000000000");
cp.add_checkpoint(15, "0000000000000000000000000000000000000000000000000000000000000000");
cp.add_checkpoint(21, "0000000000000000000000000000000000000000000000000000000000000000");
for (uint64_t h = 0; h < 11; ++h)
ASSERT_TRUE(cp.get_checkpoint_before_height(h) == 0);
ASSERT_TRUE(cp.get_checkpoint_before_height(11) == 0);
ASSERT_TRUE(cp.get_checkpoint_before_height(12) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(13) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(14) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(15) == 11);
ASSERT_TRUE(cp.get_checkpoint_before_height(16) == 15);
ASSERT_TRUE(cp.get_checkpoint_before_height(17) == 15);
ASSERT_TRUE(cp.get_checkpoint_before_height(18) == 15);
ASSERT_TRUE(cp.get_checkpoint_before_height(19) == 15);
ASSERT_TRUE(cp.get_checkpoint_before_height(20) == 15);
ASSERT_TRUE(cp.get_checkpoint_before_height(21) == 15);
ASSERT_TRUE(cp.get_checkpoint_before_height(22) == 21);
for (uint64_t h = 22; h < 100; ++h)
ASSERT_TRUE(cp.get_checkpoint_before_height(h) == 21);
}
TEST(checkpoints_test, is_in_checkpoint_zone)
{
currency::checkpoints cp;
cp.add_checkpoint(11, "0000000000000000000000000000000000000000000000000000000000000000");
cp.add_checkpoint(15, "0000000000000000000000000000000000000000000000000000000000000000");
cp.add_checkpoint(21, "0000000000000000000000000000000000000000000000000000000000000000");
for (uint64_t h = 0; h < 22; ++h)
ASSERT_TRUE(cp.is_in_checkpoint_zone(h));
for (uint64_t h = 22; h < 100; ++h)
ASSERT_FALSE(cp.is_in_checkpoint_zone(h));
}

View file

@ -12,7 +12,7 @@ out_file_name=~/.local/share/applications/Zano.desktop
call_app()
{
pushd $script_dir
./Zano
./Zano "$@"
popd
exit
}
@ -25,17 +25,20 @@ create_desktop_icon()
rm -f $target_file_name
echo [Desktop Entry] | tee -a $target_file_name > /dev/null
echo Version=1.0 | tee -a $target_file_name > /dev/null
echo Name=My Application | tee -a $target_file_name > /dev/null
echo GenericName=My Application | tee -a $target_file_name > /dev/null
echo Comment=Doing some funny stuff | tee -a $target_file_name > /dev/null
echo Name=Zano | tee -a $target_file_name > /dev/null
echo GenericName=Zano | tee -a $target_file_name > /dev/null
echo Comment=Privacy blockchain | tee -a $target_file_name > /dev/null
echo Icon=$script_dir/html/files/desktop_linux_icon.png | tee -a $target_file_name > /dev/null
echo Exec=$script_dir/Zano | tee -a $target_file_name > /dev/null
echo Exec=$script_dir/Zano.sh %u | tee -a $target_file_name > /dev/null
echo Terminal=true | tee -a $target_file_name > /dev/null
echo Type=Application | tee -a $target_file_name > /dev/null
echo "Categories=Qt;Utility;" | tee -a $target_file_name > /dev/null
echo "MimeType=x-scheme-handler/zano;" | tee -a $target_file_name > /dev/null
}
create_desktop_icon $out_file_name
call_app
xdg-mime default Zano.desktop x-scheme-handler/zano
call_app "$@"

View file

@ -46,25 +46,18 @@ if [ $? -ne 0 ]; then
exit 1
fi
make -j1 daemon Zano;
make -j2 daemon simplewallet connectivity_tool
if [ $? -ne 0 ]; then
echo "Failed to make!"
exit 1
fi
make -j1 simplewallet;
make -j1 Zano
if [ $? -ne 0 ]; then
echo "Failed to make!"
exit 1
fi
make -j1 connectivity_tool;
if [ $? -ne 0 ]; then
echo "Failed to make!"
exit 1
fi
read version_str <<< $(./src/zanod --version | awk '/^Zano/ { print $2 }')
version_str=${version_str}

View file

@ -51,6 +51,8 @@ Root: HKCR; Subkey: "ZanoWalletDataKyesFile"; ValueType: string; ValueName: "";
Root: HKCR; Subkey: "ZanoWalletDataFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\zano.exe,0"
Root: HKCR; Subkey: "ZanoWalletDataKyesFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\zano.exe,0"
Root: HKCR; Subkey: "Zano"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""
Root: HKCR; Subkey: "Zano\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\zano.exe %1"
[Files]

View file

@ -52,6 +52,9 @@ Root: HKCR; Subkey: "ZanoWalletDataKyesFile"; ValueType: string; ValueName: "";
Root: HKCR; Subkey: "ZanoWalletDataFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\Zano.exe,0"
Root: HKCR; Subkey: "ZanoWalletDataKyesFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\Zano.exe,0"
Root: HKCR; Subkey: "Zano"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""
Root: HKCR; Subkey: "Zano\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\Zano.exe %1"
[Files]