1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into release

This commit is contained in:
sowle 2019-10-31 16:34:12 +03:00
commit 7ba96b61ec
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
59 changed files with 1619 additions and 191 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "contrib/miniupnp"]
path = contrib/miniupnp
url = https://github.com/miniupnp/miniupnp
[submodule "contrib\\db\\libmdbx"]
path = contrib/db/libmdbx
url = https://github.com/leo-yuriev/libmdbx.git

View file

@ -37,7 +37,8 @@ endif()
set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers for MSVC")
include_directories(src contrib/eos_portable_archive contrib/db/liblmdb contrib contrib/epee/include "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib")
include_directories(src contrib/eos_portable_archive contrib contrib/epee/include "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib")
add_definitions(-DSTATICLIB)
set(TESTNET FALSE CACHE BOOL "Compile for testnet")
@ -213,7 +214,12 @@ else()
endif()
set(BUILD_TESTS FALSE CACHE BOOL "Build Zano tests")
set(DISABLE_MDBX FALSE CACHE BOOL "Exclude mdbx from build(need for a first time)")
if(NOT DISABLE_MDBX)
add_definitions(-DENABLED_ENGINE_MDBX)
endif()
add_subdirectory(contrib)
add_subdirectory(src)

View file

@ -7,13 +7,19 @@ add_subdirectory(db)
add_subdirectory(ethereum)
set_property(TARGET upnpc-static PROPERTY FOLDER "contrib/miniupnp")
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib")
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
set_property(TARGET mdbx PROPERTY FOLDER "contrib")
set_property(TARGET lmdb PROPERTY FOLDER "contrib")
set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat minigzip zlib example PROPERTY FOLDER "unused")
if(MSVC)
set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused")
endif()
if(MSVC)
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " /wd4244 /wd4267")
set_property(TARGET zlibstatic APPEND_STRING PROPERTY COMPILE_FLAGS " /wd4267 /wd4267")
else()
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value -Wno-implicit-fallthrough -Wno-discarded-qualifiers ")
set_property(TARGET zlibstatic APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value -Wno-implicit-fallthrough -Wno-discarded-qualifiers ")

View file

@ -1,7 +1,13 @@
add_subdirectory(liblmdb)
if(MSVC)
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
else()
# Warnings as used by LMDB itself (LMDB_0.9.23)
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
endif()
message("DB ENGINE: lmdb")
add_subdirectory(liblmdb)
if(MSVC)
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
else()
# Warnings as used by LMDB itself (LMDB_0.9.23)
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
endif()
if(NOT DISABLE_MDBX)
message("DB ENGINE: mdbx")
add_subdirectory(libmdbx)
endif()

1
contrib/db/libmdbx Submodule

@ -0,0 +1 @@
Subproject commit a0ec89e46833e61d9b93850e85157d4bc93db1b2

View file

@ -133,12 +133,12 @@ class connection
volatile uint32_t& m_ref_sockets_count;
i_connection_filter*& m_pfilter;
volatile bool m_is_multithreaded;
//this should be the last one, because it could be wait on destructor, while other activities possible on other threads
t_protocol_handler m_protocol_handler;
//typename t_protocol_handler::config_type m_dummy_config;
std::list<boost::shared_ptr<connection<t_protocol_handler>>> m_self_refs; // add_ref/release support
critical_section m_self_refs_lock;
t_protocol_handler m_protocol_handler;
//this should be the last line with m_protocol_handler, because it could be wait on destructor, while other activities possible on other threads
//DON'T ADD ANYTHING HERE!!!
};
/************************************************************************/

View file

@ -220,6 +220,11 @@ public:
bool add_invoke_response_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
{
CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock);
if (m_protocol_released)
{
LOG_PRINT_L0("ERROR: Adding response handler to a released object");
return false;
}
boost::shared_ptr<invoke_response_handler_base> handler(boost::make_shared<invoke_handler<callback_t>>(cb, timeout, con, command));
m_invoke_response_handlers.push_back(handler);
LOG_PRINT_L4("[LEVIN_PROTOCOL" << this << "] INVOKE_HANDLER_QUE: PUSH_BACK RESPONSE HANDLER");

View file

@ -117,34 +117,34 @@ namespace net_utils
//some helpers
inline
std::string print_connection_context(const connection_context_base& ctx)
inline std::string print_connection_context(const connection_context_base& ctx)
{
std::stringstream ss;
ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
inline
void print_connection_context_short(const connection_context_base& ctx, std::stringstream& ss)
inline std::ostream &operator <<(std::ostream &o, const connection_context_base& ctx)
{
ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT");
}
o << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC" : " OUT");
return o;
}
inline
std::string print_connection_context_short(const connection_context_base& ctx)
inline std::string print_connection_context_short(const connection_context_base& ctx)
{
std::stringstream ss;
print_connection_context_short(ctx, ss);
ss << ctx;
return ss.str();
}
inline std::string print_connection_context_list(const std::list<connection_context_base>& contexts)
inline std::string print_connection_context_list(const std::list<connection_context_base>& contexts, const std::string& delim = std::string("\n"))
{
std::stringstream ss;
for (auto& c : contexts)
{
ss << epee::string_tools::get_ip_string_from_int32(c.m_remote_ip) << ":" << c.m_remote_port << (c.m_is_income ? " INC" : " OUT") << ENDL;
if (ss.tellp())
ss << delim;
ss << c;
}
return ss.str();
}
@ -179,7 +179,7 @@ namespace net_utils
#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message)
}
}
} // namespace net_utils
} // namespace epee
#endif //_NET_UTILS_BASE_H_

View file

@ -116,7 +116,7 @@ add_library(wallet ${WALLET})
add_dependencies(wallet version ${PCH_LIB_NAME})
ENABLE_SHARED_PCH(WALLET)
target_link_libraries(currency_core lmdb)
target_link_libraries(currency_core lmdb mdbx)
add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL})
add_dependencies(daemon version)

View file

@ -30,4 +30,5 @@ namespace command_line
const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync = { "disable-stop-if-time-out-of-sync", "Do not stop the daemon if serious time synchronization problem is detected", false, true };
const arg_descriptor<bool> arg_disable_stop_on_low_free_space = { "disable-stop-on-low-free-space", "Do not stop the daemon if free space at data dir is critically low", false, true };
const arg_descriptor<bool> arg_enable_offers_service = { "enable-offers-service", "Enables marketplace feature", false, false};
const arg_descriptor<std::string> arg_db_engine = { "db-engine", "Specify database engine for storage. May be \"lmdb\"(default) or \"mdbx\"", ARG_DB_ENGINE_LMDB, false };
}

View file

@ -172,6 +172,9 @@ namespace command_line
return get_arg<bool, false>(vm, arg);
}
#define ARG_DB_ENGINE_LMDB "lmdb"
#define ARG_DB_ENGINE_MDBX "mdbx"
extern const arg_descriptor<bool> arg_help;
extern const arg_descriptor<bool> arg_version;
@ -188,4 +191,5 @@ namespace command_line
extern const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync;
extern const arg_descriptor<bool> arg_disable_stop_on_low_free_space;
extern const arg_descriptor<bool> arg_enable_offers_service;
extern const arg_descriptor<std::string> arg_db_engine;
}

View file

@ -95,7 +95,7 @@ namespace tools
{
close();
}
void reset_backend(std::shared_ptr<i_db_backend> backend) { m_backend = backend; }
performance_data& get_performance_data_for_handle(container_handle h) const { return m_performance_data_map[h]; }
performance_data& get_performance_data_global() const { return m_gperformance_data; }

View file

@ -45,6 +45,7 @@ namespace tools
virtual bool clear(container_handle h) = 0;
virtual bool enumerate(container_handle h, i_db_callback* pcb)=0;
virtual bool get_stat_info(stat_info& si) = 0;
virtual const char* name()=0;
virtual ~i_db_backend(){};
};
}

View file

@ -379,6 +379,10 @@ namespace tools
}
return true;
}
const char* lmdb_db_backend::name()
{
return "lmdb";
}
}
}

View file

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <thread>
#include "include_base_utils.h"
@ -53,6 +54,7 @@ namespace tools
bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs);
bool enumerate(container_handle h, i_db_callback* pcb);
bool get_stat_info(tools::db::stat_info& si);
const char* name();
//-------------------------------------------------------------------------------------
bool have_tx();
MDB_txn* get_current_tx();

View file

@ -0,0 +1,398 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifdef ENABLED_ENGINE_MDBX
#include "db_backend_mdbx.h"
#include "misc_language.h"
#include "string_coding.h"
#include "profile_tools.h"
#include "util.h"
#define BUF_SIZE 1024
#define CHECK_AND_ASSERT_MESS_MDBX_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(res == MDBX_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdbx_strerror(rc) << ", [message]: " << mess);
#define CHECK_AND_ASSERT_THROW_MESS_MDBX_DB(rc, mess) CHECK_AND_ASSERT_THROW_MES(res == MDBX_SUCCESS, "[DB ERROR]:(" << rc << ")" << mdbx_strerror(rc) << ", [message]: " << mess);
#define ASSERT_MES_AND_THROW_MDBX(rc, mess) ASSERT_MES_AND_THROW("[DB ERROR]:(" << rc << ")" << mdbx_strerror(rc) << ", [message]: " << mess);
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "mdbx"
// 'mdbx' channel is disabled by default
namespace tools
{
namespace db
{
mdbx_db_backend::mdbx_db_backend() : m_penv(AUTO_VAL_INIT(m_penv))
{
}
mdbx_db_backend::~mdbx_db_backend()
{
NESTED_TRY_ENTRY();
close();
NESTED_CATCH_ENTRY(__func__);
}
bool mdbx_db_backend::open(const std::string& path_, uint64_t cache_sz)
{
int res = 0;
res = mdbx_env_create(&m_penv);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_create");
res = mdbx_env_set_maxdbs(m_penv, 15);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_set_maxdbs");
intptr_t size_lower = 0;
intptr_t size_now = -1; //don't change current database size
intptr_t size_upper = 0x10000000000; //don't set db file size limit
intptr_t growth_step = 0x40000000; //increment step 1GB
intptr_t shrink_threshold = -1;
intptr_t pagesize = 0x00001000; //4kb
res = mdbx_env_set_geometry(m_penv, size_lower, size_now, size_upper, growth_step, shrink_threshold, pagesize);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_set_mapsize");
m_path = path_;
CHECK_AND_ASSERT_MES(tools::create_directories_if_necessary(m_path), false, "create_directories_if_necessary failed: " << m_path);
res = mdbx_env_open(m_penv, m_path.c_str(), MDBX_NORDAHEAD , 0644);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_env_open, m_path=" << m_path);
return true;
}
bool mdbx_db_backend::open_container(const std::string& name, container_handle& h)
{
MDBX_dbi dbi = AUTO_VAL_INIT(dbi);
begin_transaction();
int res = mdbx_dbi_open(get_current_tx(), name.c_str(), MDBX_CREATE, &dbi);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_dbi_open with container name: " << name);
commit_transaction();
h = static_cast<container_handle>(dbi);
return true;
}
bool mdbx_db_backend::close()
{
{
std::lock_guard<boost::recursive_mutex> lock(m_cs);
for (auto& tx_thread : m_txs)
{
for (auto txe : tx_thread.second)
{
int res = mdbx_txn_commit(txe.ptx);
if (res != MDBX_SUCCESS)
{
LOG_ERROR("[DB ERROR]: On close tranactions: " << mdbx_strerror(res));
}
}
}
m_txs.clear();
}
if (m_penv)
{
mdbx_env_close(m_penv);
m_penv = nullptr;
}
return true;
}
bool mdbx_db_backend::begin_transaction(bool read_only)
{
if (!read_only)
{
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED", LOG_LEVEL_3);
CRITICAL_SECTION_LOCK(m_write_exclusive_lock);
}
PROFILE_FUNC("mdbx_db_backend::begin_transaction");
{
std::lock_guard<boost::recursive_mutex> lock(m_cs);
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
transactions_list& rtxlist = m_txs[std::this_thread::get_id()];
MDBX_txn* pparent_tx = nullptr;
MDBX_txn* p_new_tx = nullptr;
bool parent_read_only = false;
if (rtxlist.size())
{
pparent_tx = rtxlist.back().ptx;
parent_read_only = rtxlist.back().read_only;
}
if (pparent_tx && read_only)
{
++rtxlist.back().count;
}
else
{
int res = 0;
unsigned int flags = 0;
if (read_only)
flags += MDBX_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"
if (pparent_tx && parent_read_only)
pparent_tx = nullptr;
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
res = mdbx_txn_begin(m_penv, pparent_tx, flags, &p_new_tx);
if(res != MDBX_SUCCESS)
{
//Important: if mdbx_txn_begin is failed need to unlock previously locked mutex
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
//throw exception to avoid regular code execution
ASSERT_MES_AND_THROW_MDBX(res, "Unable to mdbx_txn_begin");
}
rtxlist.push_back(tx_entry());
rtxlist.back().count = read_only ? 1 : 0;
rtxlist.back().ptx = p_new_tx;
rtxlist.back().read_only = read_only;
}
}
LOG_PRINT_L4("[DB] Transaction started");
return true;
}
MDBX_txn* mdbx_db_backend::get_current_tx()
{
std::lock_guard<boost::recursive_mutex> lock(m_cs);
auto& rtxlist = m_txs[std::this_thread::get_id()];
CHECK_AND_ASSERT_MES(rtxlist.size(), nullptr, "Unable to find active tx for thread " << std::this_thread::get_id());
return rtxlist.back().ptx;
}
bool mdbx_db_backend::pop_tx_entry(tx_entry& txe)
{
std::lock_guard<boost::recursive_mutex> lock(m_cs);
auto it = m_txs.find(std::this_thread::get_id());
CHECK_AND_ASSERT_MES(it != m_txs.end(), false, "[DB] Unable to find id cor current thread");
CHECK_AND_ASSERT_MES(it->second.size(), false, "[DB] No active tx for current thread");
txe = it->second.back();
if (it->second.back().read_only && it->second.back().count == 0)
{
LOG_ERROR("Internal db tx state error: read_only and count readers == 0");
}
if ((it->second.back().read_only && it->second.back().count < 2) || (!it->second.back().read_only && it->second.back().count < 1))
{
it->second.pop_back();
if (!it->second.size())
m_txs.erase(it);
}
else
{
--it->second.back().count;
}
return true;
}
bool mdbx_db_backend::commit_transaction()
{
PROFILE_FUNC("mdbx_db_backend::commit_transaction");
{
tx_entry txe = AUTO_VAL_INIT(txe);
bool r = pop_tx_entry(txe);
CHECK_AND_ASSERT_MES(r, false, "Unable to pop_tx_entry");
if (txe.count == 0 || (txe.read_only && txe.count == 1))
{
int res = 0;
res = mdbx_txn_commit(txe.ptx);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_txn_commit (error " << res << ")");
if (!txe.read_only && !txe.count)
{
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED", LOG_LEVEL_3);
}
}
}
LOG_PRINT_L4("[DB] Transaction committed");
return true;
}
void mdbx_db_backend::abort_transaction()
{
{
tx_entry txe = AUTO_VAL_INIT(txe);
bool r = pop_tx_entry(txe);
CHECK_AND_ASSERT_MES(r, void(), "Unable to pop_tx_entry");
if (txe.count == 0 || (txe.read_only && txe.count == 1))
{
mdbx_txn_abort(txe.ptx);
if (!txe.read_only && !txe.count)
{
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED(ABORTED)", LOG_LEVEL_3);
}
}
}
LOG_PRINT_L4("[DB] Transaction aborted");
}
bool mdbx_db_backend::erase(container_handle h, const char* k, size_t ks)
{
int res = 0;
MDBX_val key = AUTO_VAL_INIT(key);
key.iov_base = (void*)k;
key.iov_len = ks;
res = mdbx_del(get_current_tx(), static_cast<MDBX_dbi>(h), &key, nullptr);
if (res == MDBX_NOTFOUND)
return false;
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_del");
return true;
}
bool mdbx_db_backend::have_tx()
{
std::lock_guard<boost::recursive_mutex> lock(m_cs);
auto it = m_txs.find(std::this_thread::get_id());
if (it == m_txs.end())
return false;
return it->second.size() ? true : false;
}
bool mdbx_db_backend::get(container_handle h, const char* k, size_t ks, std::string& res_buff)
{
PROFILE_FUNC("mdbx_db_backend::get");
int res = 0;
MDBX_val key = AUTO_VAL_INIT(key);
MDBX_val data = AUTO_VAL_INIT(data);
key.iov_base = (void*)k;
key.iov_len = ks;
bool need_to_commit = false;
if (!have_tx())
{
need_to_commit = true;
begin_transaction(true);
}
res = mdbx_get(get_current_tx(), static_cast<MDBX_dbi>(h), &key, &data);
if (need_to_commit)
commit_transaction();
if (res == MDBX_NOTFOUND)
return false;
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_get, h: " << h << ", ks: " << ks);
res_buff.assign((const char*)data.iov_base, data.iov_len);
return true;
}
bool mdbx_db_backend::clear(container_handle h)
{
int res = mdbx_drop(get_current_tx(), static_cast<MDBX_dbi>(h), 0);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_drop");
return true;
}
uint64_t mdbx_db_backend::size(container_handle h)
{
PROFILE_FUNC("mdbx_db_backend::size");
MDBX_stat container_stat = AUTO_VAL_INIT(container_stat);
bool need_to_commit = false;
if (!have_tx())
{
need_to_commit = true;
begin_transaction(true);
}
int res = mdbx_dbi_stat(get_current_tx(), static_cast<MDBX_dbi>(h), &container_stat, sizeof(MDBX_stat));
if (need_to_commit)
commit_transaction();
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_stat");
return container_stat.ms_entries;
}
bool mdbx_db_backend::set(container_handle h, const char* k, size_t ks, const char* v, size_t vs)
{
PROFILE_FUNC("mdbx_db_backend::set");
int res = 0;
MDBX_val key = AUTO_VAL_INIT(key);
MDBX_val data = AUTO_VAL_INIT(data);
key.iov_base = (void*)k;
key.iov_len = ks;
data.iov_base = (void*)v;
data.iov_len = vs;
res = mdbx_put(get_current_tx(), static_cast<MDBX_dbi>(h), &key, &data, 0);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_put");
return true;
}
bool mdbx_db_backend::enumerate(container_handle h, i_db_callback* pcb)
{
CHECK_AND_ASSERT_MES(pcb, false, "null capback ptr passed to enumerate");
MDBX_val key = AUTO_VAL_INIT(key);
MDBX_val data = AUTO_VAL_INIT(data);
bool need_to_commit = false;
if (!have_tx())
{
need_to_commit = true;
begin_transaction(true);
}
MDBX_cursor* cursor_ptr = nullptr;
int res = mdbx_cursor_open(get_current_tx(), static_cast<MDBX_dbi>(h), &cursor_ptr);
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_cursor_open");
CHECK_AND_ASSERT_MES(cursor_ptr, false, "cursor_ptr is null after mdbx_cursor_open");
uint64_t count = 0;
do
{
int res = mdbx_cursor_get(cursor_ptr, &key, &data, MDBX_NEXT);
if (res == MDBX_NOTFOUND)
break;
if (!pcb->on_enum_item(count, key.iov_base, key.iov_len, data.iov_base, data.iov_len))
break;
count++;
} while (cursor_ptr);
mdbx_cursor_close(cursor_ptr);
if (need_to_commit)
commit_transaction();
return true;
}
bool mdbx_db_backend::get_stat_info(tools::db::stat_info& si)
{
si = AUTO_VAL_INIT_T(tools::db::stat_info);
MDBX_envinfo ei = AUTO_VAL_INIT(ei);
mdbx_env_info(m_penv, &ei, sizeof(MDBX_envinfo));
si.map_size = ei.mi_mapsize;
std::lock_guard<boost::recursive_mutex> lock(m_cs);
for (auto& e : m_txs)
{
for (auto& pr : e.second)
{
++si.tx_count;
if(!pr.read_only)
++si.write_tx_count;
}
}
return true;
}
const char* mdbx_db_backend::name()
{
return "mdbx";
}
}
}
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL NULL
#endif

View file

@ -0,0 +1,66 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#ifdef ENABLED_ENGINE_MDBX
#include <thread>
#include "include_base_utils.h"
#include "db_backend_base.h"
#include "db/libmdbx/mdbx.h"
namespace tools
{
namespace db
{
class mdbx_db_backend : public i_db_backend
{
struct tx_entry
{
MDBX_txn* ptx;
bool read_only; // needed for thread-top transaction, for figure out if we need to unlock exclusive access
size_t count; //count of read-only nested emulated transactions
};
typedef std::list<tx_entry> transactions_list;
std::string m_path;
MDBX_env *m_penv;
boost::recursive_mutex m_cs;
boost::recursive_mutex m_write_exclusive_lock;
std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
bool pop_tx_entry(tx_entry& txe);
public:
mdbx_db_backend();
~mdbx_db_backend();
//----------------- i_db_backend -----------------------------------------------------
bool close();
bool begin_transaction(bool read_only = false);
bool commit_transaction();
void abort_transaction();
bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE);
bool open_container(const std::string& name, container_handle& h);
bool erase(container_handle h, const char* k, size_t s);
bool get(container_handle h, const char* k, size_t s, std::string& res_buff);
bool clear(container_handle h);
uint64_t size(container_handle h);
bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs);
bool enumerate(container_handle h, i_db_callback* pcb);
bool get_stat_info(tools::db::stat_info& si);
const char* name();
//-------------------------------------------------------------------------------------
bool have_tx();
MDBX_txn* get_current_tx();
};
}
}
#endif

View file

@ -0,0 +1,41 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "db_backend_lmdb.h"
#include "db_backend_mdbx.h"
#include "common/command_line.h"
#include "common/db_abstract_accessor.h"
namespace tools
{
namespace db
{
inline
bool select_db_engine_from_arg(const boost::program_options::variables_map& vm, tools::db::basic_db_accessor& rdb)
{
if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_LMDB)
{
rdb.reset_backend(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend));
}
else if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_MDBX)
{
#ifdef ENABLED_ENGINE_MDBX
rdb.reset_backend(std::shared_ptr<tools::db::i_db_backend>(new tools::db::mdbx_db_backend));
#else
LOG_PRINT_L0(" DB ENGINE: " << ARG_DB_ENGINE_MDBX << " is not suported by this build(see DISABLE_MDBX cmake option), STOPPING");
return false;
#endif
}
else
{
LOG_PRINT_RED_L0(" UNKNOWN DB ENGINE: " << command_line::get_arg(vm, command_line::arg_db_engine) << ", STOPPING");
return false;
}
return true;
}
}
}

View file

@ -201,7 +201,7 @@ namespace tools
udp_blocking_client ubc(sender_endpoint, socket, io_service);
boost::system::error_code ec;
size_t len = ubc.receive(boost::asio::buffer(&packet_received, sizeof packet_received), boost::posix_time::seconds(timeout_sec), ec);
size_t len = ubc.receive(boost::asio::buffer(&packet_received, sizeof packet_received), boost::posix_time::seconds(static_cast<long>(timeout_sec)), ec);
if (ec)
{
LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): boost error: " << ec.message());

View file

@ -658,4 +658,41 @@ std::string get_nix_version_display_string()
return static_cast<uint64_t>(in.tellg());
}
bool check_remote_client_version(const std::string& client_ver)
{
std::string v = client_ver.substr(0, client_ver.find('[')); // remove commit id
v = v.substr(0, v.rfind('.')); // remove build number
int v_major = 0, v_minor = 0, v_revision = 0;
size_t dot_pos = v.find('.');
if (dot_pos == std::string::npos || !epee::string_tools::string_to_num_fast(v.substr(0, dot_pos), v_major))
return false;
v = v.substr(dot_pos + 1);
dot_pos = v.find('.');
if (!epee::string_tools::string_to_num_fast(v.substr(0, dot_pos), v_minor))
return false;
if (dot_pos != std::string::npos)
{
// revision
v = v.substr(dot_pos + 1);
if (!epee::string_tools::string_to_num_fast(v, v_revision))
return false;
}
// got v_major, v_minor, v_revision
// allow 1.1.x and greater
if (v_major < 1)
return false;
if (v_major == 1 && v_minor < 1)
return false;
return true;
}
} // namespace tools

View file

@ -30,6 +30,8 @@ namespace tools
std::string get_default_user_dir();
std::string get_current_username();
std::string get_os_version_string();
bool check_remote_client_version(const std::string& client_ver);
bool create_directories_if_necessary(const std::string& path);
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);

View file

@ -27,7 +27,7 @@ namespace currency
class bc_attachment_services_manager
{
public:
bc_attachment_services_manager(i_core_event_handler* pcore_event_handler) : m_pcore_event_handler(pcore_event_handler), m_core_runtime_config(get_default_core_runtime_config())
bc_attachment_services_manager(/* i_core_event_handler* pcore_event_handler*/) : /*m_pcore_event_handler(pcore_event_handler),*/ m_core_runtime_config(get_default_core_runtime_config())
{}
@ -43,7 +43,7 @@ namespace currency
private:
std::map<std::string, i_bc_service*> m_services;
i_core_event_handler* m_pcore_event_handler;
//i_core_event_handler* m_pcore_event_handler;
core_runtime_config m_core_runtime_config;
};

View file

@ -14,7 +14,7 @@
#include "include_base_utils.h"
#include "common/db_backend_lmdb.h"
#include "common/db_backend_selector.h"
#include "common/command_line.h"
#include "blockchain_storage.h"
@ -30,7 +30,6 @@
#include "crypto/hash.h"
#include "miner_common.h"
#include "storages/portable_storage_template_helper.h"
#include "common/db_backend_lmdb.h"
#include "basic_pow_helpers.h"
#include "version.h"
@ -70,7 +69,7 @@ using namespace currency;
#endif
#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1"
DISABLE_VS_WARNINGS(4267)
@ -81,7 +80,7 @@ namespace
}
//------------------------------------------------------------------
blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend), m_rw_lock),
blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m_rw_lock),
m_db_blocks(m_db),
m_db_blocks_index(m_db),
m_db_transactions(m_db),
@ -104,7 +103,6 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(std::share
m_core_runtime_config(get_default_core_runtime_config()),
//m_bei_stub(AUTO_VAL_INIT(m_bei_stub)),
m_event_handler(&m_event_handler_stub),
m_services_mgr(nullptr),
m_interprocess_locker_file(0),
m_current_fee_median(0),
m_current_fee_median_effective_index(0),
@ -207,7 +205,13 @@ bool blockchain_storage::validate_instance(const std::string& path)
bool blockchain_storage::init(const std::string& config_folder, const boost::program_options::variables_map& vm)
{
// CRITICAL_REGION_LOCAL(m_read_lock);
if (!select_db_engine_from_arg(vm, m_db))
{
LOG_PRINT_RED_L0("Failed to select db engine");
return false;
}
LOG_PRINT_L0("DB ENGINE USED BY CORE: " << m_db.get_backend()->name());
if (!validate_instance(config_folder))
{
LOG_ERROR("Failed to initialize instance");
@ -230,8 +234,8 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
LOG_PRINT_YELLOW("Removing old DB in " << old_db_folder_path << "...", LOG_LEVEL_0);
boost::filesystem::remove_all(epee::string_encoding::utf8_to_wstring(old_db_folder_path));
}
const std::string db_folder_path = m_config_folder + "/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME;
;
const std::string db_folder_path = m_config_folder + ("/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX) + m_db.get_backend()->name() + CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX;
LOG_PRINT_L0("Loading blockchain from " << db_folder_path);
bool db_opened_okay = false;

View file

@ -182,15 +182,18 @@
#define ALIAS_NAME_MAX_LEN 255
#define ALIAS_VALID_CHARS "0123456789abcdefghijklmnopqrstuvwxyz-."
#define ALIAS_COMMENT_MAX_SIZE_BYTES 400
#define ALIAS_COMMENT_MAX_SIZE_BYTES 400
#define CURRENCY_CORE_INSTANCE_LOCK_FILE "lock.lck"
#define CURRENCY_POOLDATA_FOLDERNAME_OLD "poolstate"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_OLD "blockchain"
#define CURRENCY_POOLDATA_FOLDERNAME "poolstate_lmdb_v1"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME "blockchain_lmdb_v1"
#define CURRENCY_POOLDATA_FOLDERNAME_PREFIX "poolstate_"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX "blockchain_"
#define P2P_NET_DATA_FILENAME "p2pstate.bin"
#define MINER_CONFIG_FILENAME "miner_conf.json"
#define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin"

View file

@ -142,7 +142,7 @@ namespace currency
uint64_t available_space = 0;
CHECK_AND_ASSERT_MES(!check_if_free_space_critically_low(&available_space), false, "free space in data folder is critically low: " << std::fixed << available_space / (1024 * 1024) << " MB");
r = m_mempool.init(m_config_folder);
r = m_mempool.init(m_config_folder, vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
r = m_blockchain_storage.init(m_config_folder, vm);

View file

@ -41,7 +41,7 @@ namespace currency
miner::miner(i_miner_handler* phandler, blockchain_storage& bc):m_stop(1),
m_bc(bc),
//m_bc(bc),
m_template(boost::value_initialized<block>()),
m_template_no(0),
m_diffic(0),

View file

@ -105,7 +105,7 @@ namespace currency
std::list<boost::thread> m_threads;
::critical_section m_threads_lock;
i_miner_handler* m_phandler;
blockchain_storage& m_bc;
//blockchain_storage& m_bc;
account_public_address m_mine_address;
math_helper::once_a_time_seconds<5> m_update_block_template_interval;
math_helper::once_a_time_seconds<2> m_update_merge_hr_interval;

View file

@ -9,7 +9,7 @@
#include <unordered_set>
#include <vector>
#include "common/db_backend_lmdb.h"
#include "common/db_backend_selector.h"
#include "tx_pool.h"
#include "currency_boost_serialization.h"
#include "currency_core/currency_config.h"
@ -32,6 +32,10 @@ DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated
#define TRANSACTION_POOL_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 92 // DON'T CHANGE THIS, if you need to resync db! Change TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION instead!
#define TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 1
#define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1"
#define CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL 50 // if there's a conflict in key images between tx in the pool and in the blockchain this much depth in required to remove correspongin tx from pool
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "tx_pool"
ENABLE_CHANNEL_BY_DEFAULT("tx_pool");
@ -42,7 +46,7 @@ namespace currency
tx_memory_pool::tx_memory_pool(blockchain_storage& bchs, i_currency_protocol* pprotocol) :
m_blockchain(bchs),
m_pprotocol(pprotocol),
m_db(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend), m_dummy_rw_lock),
m_db(nullptr, m_dummy_rw_lock),
m_db_transactions(m_db),
m_db_black_tx_list(m_db),
m_db_solo_options(m_db),
@ -427,18 +431,41 @@ namespace currency
int64_t tx_age = get_core_time() - tx_entry.receive_time;
if ((tx_age > CURRENCY_MEMPOOL_TX_LIVETIME ))
{
LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: outdated, age: " << tx_age);
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: outdated, age: " << tx_age << " = " << misc_utils::get_time_interval_string(tx_age));
to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block));
}
// expiration time check - remove expired
if (is_tx_expired(tx_entry.tx, tx_expiration_ts_median) )
{
LOG_PRINT_L0("Tx " << h << " removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median);
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: expired, expiration time: " << get_tx_expiration_time(tx_entry.tx) << ", blockchain median: " << tx_expiration_ts_median);
to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block));
}
// if a tx has at least one key image already used in blockchain (deep enough) -- remove such tx, as it cannot be added to any block
// although it will be removed by the age check above, we consider desireable
// to remove it from the pool faster in order to unblock related key images used in the same tx
uint64_t should_be_spent_before_height = m_blockchain.get_current_blockchain_size() - 1;
if (should_be_spent_before_height > CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL)
{
should_be_spent_before_height -= CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL;
for (auto& in : tx_entry.tx.vin)
{
if (in.type() == typeid(txin_to_key))
{
// if at least one key image is spent deep enought -- remove such tx
const crypto::key_image& ki = boost::get<txin_to_key>(in).k_image;
if (m_blockchain.have_tx_keyimg_as_spent(ki, should_be_spent_before_height))
{
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: ki was spent in the blockchain before height " << should_be_spent_before_height << ", tx age: " << misc_utils::get_time_interval_string(tx_age));
to_delete.push_back(tx_to_delete_entry(h, tx_entry.tx, tx_entry.kept_by_block));
return true;
}
}
}
}
return true;
});
@ -1116,8 +1143,15 @@ namespace currency
m_db.commit_transaction();
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::init(const std::string& config_folder)
bool tx_memory_pool::init(const std::string& config_folder, const boost::program_options::variables_map& vm)
{
if (!select_db_engine_from_arg(vm, m_db))
{
LOG_PRINT_RED_L0("Failed to select db engine");
return false;
}
LOG_PRINT_L0("DB ENGINE USED BY POOL: " << m_db.get_backend()->name());
m_config_folder = config_folder;
uint64_t cache_size_l1 = CACHE_SIZE;
@ -1131,7 +1165,8 @@ namespace currency
boost::filesystem::remove_all(epee::string_encoding::utf8_to_wstring(old_db_folder_path));
}
const std::string db_folder_path = m_config_folder + "/" CURRENCY_POOLDATA_FOLDERNAME;
const std::string db_folder_path = m_config_folder + ("/" CURRENCY_POOLDATA_FOLDERNAME_PREFIX) + m_db.get_backend()->name() + CURRENCY_POOLDATA_FOLDERNAME_SUFFIX;
LOG_PRINT_L0("Loading blockchain from " << db_folder_path << "...");
bool db_opened_okay = false;

View file

@ -20,6 +20,7 @@ using namespace epee;
#include "math_helper.h"
#include "common/db_abstract_accessor.h"
#include "common/command_line.h"
#include "currency_format_utils.h"
#include "verification_context.h"
@ -114,7 +115,7 @@ namespace currency
void clear();
// load/store operations
bool init(const std::string& config_folder);
bool init(const std::string& config_folder, const boost::program_options::variables_map& vm);
bool deinit();
bool fill_block_template(block &bl, bool pos, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height);
bool get_transactions(std::list<transaction>& txs) const;

View file

@ -22,7 +22,7 @@
PUSH_VS_WARNINGS
DISABLE_VS_WARNINGS(4355)
#define ASYNC_RELAY_MODE
#define ASYNC_RELAY_MODE // relay transactions asyncronously via m_relay_que
namespace currency
{
@ -117,25 +117,25 @@ namespace currency
int64_t m_last_ntp2local_time_difference;
template<class t_parametr>
bool post_notify(typename t_parametr::request& arg, currency_connection_context& context)
{
LOG_PRINT_L2("[POST]" << typeid(t_parametr).name());
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
}
bool post_notify(typename t_parametr::request& arg, currency_connection_context& context)
{
LOG_PRINT_L3("[POST]" << typeid(t_parametr).name() << " to " << context);
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
return m_p2p->invoke_notify_to_peer(t_parametr::ID, blob, context);
}
template<class t_parametr>
bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context)
{
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
std::list<epee::net_utils::connection_context_base> relayed_peers;
bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers);
template<class t_parametr>
bool relay_post_notify(typename t_parametr::request& arg, currency_connection_context& exlude_context)
{
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
std::list<epee::net_utils::connection_context_base> relayed_peers;
bool r = m_p2p->relay_notify_to_all(t_parametr::ID, arg_buff, exlude_context, relayed_peers);
LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " relayed contexts list: " << ENDL << print_connection_context_list(relayed_peers), LOG_LEVEL_2);
return r;
}
LOG_PRINT_GREEN("[POST RELAY] " << typeid(t_parametr).name() << " to (" << relayed_peers.size() << "): " << print_connection_context_list(relayed_peers, ", "), LOG_LEVEL_2);
return r;
}
};
}

View file

@ -94,22 +94,32 @@ namespace currency
<< std::setw(20) << "Peer id"
<< std::setw(25) << "Recv/Sent (idle,sec)"
<< std::setw(25) << "State"
<< std::setw(20) << "Livetime(seconds)"
<< std::setw(20) << "Livetime"
<< std::setw(20) << "Client version" << ENDL;
size_t incoming_count = 0, outgoing_count = 0;
std::multimap<time_t, std::string> conn_map;
m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id)
{
ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") +
std::stringstream conn_ss;
time_t livetime = time(NULL) - cntxt.m_started;
conn_ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") +
string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
<< std::setw(20) << std::hex << peer_id
<< std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
<< std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
<< std::setw(20) << epee::misc_utils::get_time_interval_string(livetime)
<< std::setw(20) << cntxt.m_remote_version
<< ENDL;
conn_map.insert(std::make_pair(livetime, conn_ss.str()));
(cntxt.m_is_income ? incoming_count : outgoing_count) += 1;
return true;
});
LOG_PRINT_L0("Connections: " << ENDL << ss.str());
for(auto it = conn_map.rbegin(); it != conn_map.rend(); ++it)
ss << it->second;
LOG_PRINT_L0("Connections (" << incoming_count << " in, " << outgoing_count << " out, " << incoming_count + outgoing_count << " total):" << ENDL << ss.str());
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
@ -174,7 +184,8 @@ namespace currency
"That means that current software is outdated, please updated it." <<
"Current heigh lay under checkpoints on remote host, so it is not possible validate this transactions on local host, disconnecting.", LOG_LEVEL_0);
return false;
}else if (m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() < hshd.last_checkpoint_height)
}
else if (m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() < hshd.last_checkpoint_height)
{
LOG_PRINT_MAGENTA("Remote node have longer checkpoints zone( " << hshd.last_checkpoint_height << ") " <<
"that local (" << m_core.get_blockchain_storage().get_checkpoints().get_top_checkpoint_height() << ")" <<
@ -234,7 +245,6 @@ namespace currency
if(context.m_state != currency_connection_context::state_normal)
return 1;
//check if block already exists
block b = AUTO_VAL_INIT(b);
block_verification_context bvc = AUTO_VAL_INIT(bvc);
@ -244,6 +254,7 @@ namespace currency
m_p2p->drop_connection(context);
return 1;
}
crypto::hash block_id = get_block_hash(b);
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK " << block_id << " HEIGHT " << get_block_height(b) << " (hop " << arg.hop << ")", LOG_LEVEL_2);
@ -313,11 +324,11 @@ namespace currency
m_p2p->drop_connection(context);
return 1;
}
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA: id: " << block_id
<< ",bvc.m_added_to_main_chain " << bvc.m_added_to_main_chain
//<< ",prevalidate_result " << prevalidate_relayed
<< ",bvc.added_to_altchain " << bvc.added_to_altchain
<< ",bvc.m_marked_as_orphaned " << bvc.m_marked_as_orphaned, LOG_LEVEL_2);
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA " << block_id
<< " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain
//<< ", prevalidate_result=" << prevalidate_relayed
<< ", bvc.added_to_altchain=" << bvc.added_to_altchain
<< ", bvc.m_marked_as_orphaned=" << bvc.m_marked_as_orphaned, LOG_LEVEL_2);
if (bvc.m_added_to_main_chain || (bvc.added_to_altchain && bvc.height_difference < 2))
{
@ -722,13 +733,14 @@ namespace currency
if (req.txs.size())
{
post_notify<NOTIFY_NEW_TRANSACTIONS>(req, cc);
print_connection_context_short(cc, debug_ss);
debug_ss << ": " << req.txs.size() << ENDL;
if (debug_ss.tellp())
debug_ss << ", ";
debug_ss << cc << ": " << req.txs.size();
}
}
TIME_MEASURE_FINISH_MS(ms);
LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms)contexts list: " << debug_ss.str(), LOG_LEVEL_2);
LOG_PRINT_GREEN("[POST RELAY] NOTIFY_NEW_TRANSACTIONS relayed (" << ms << "ms) to: " << debug_ss.str(), LOG_LEVEL_2);
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
@ -788,7 +800,7 @@ namespace currency
std::vector<int64_t> time_deltas_copy(m_time_deltas.begin(), m_time_deltas.end());
m_last_median2local_time_difference = epee::misc_utils::median(time_deltas_copy);
LOG_PRINT_MAGENTA("TIME: network time difference is " << m_last_median2local_time_difference << " (max is " << TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE << ")", LOG_LEVEL_2);
LOG_PRINT_MAGENTA("TIME: network time difference is " << m_last_median2local_time_difference << " (max is " << TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE << ")", ((m_last_median2local_time_difference >= 3) ? LOG_LEVEL_2 : LOG_LEVEL_3));
if (std::abs(m_last_median2local_time_difference) > TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE)
{
int64_t ntp_time = tools::get_ntp_time();

View file

@ -75,10 +75,16 @@ struct core_critical_error_handler_t : public currency::i_critical_error_handler
LOG_ERROR(ENDL << ENDL << "Free space at data directory is critically low (" << available / (1024 * 1024) << " MB, while " << required / (1024 * 1024) << " MB is required), daemon will stop immediately" << ENDL << ENDL);
/*
temporary disable daemon stop due to issue #133
*/
return false;
/*
// stop handling
dch.stop_handling();
p2psrv.send_stop_signal();
return true; // the caller must stop processing
*/
}
daemon_commands_handler& dch;
@ -106,7 +112,7 @@ int main(int argc, char* argv[])
//_CrtSetAllocHook(alloc_hook);
#endif
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0);
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet");
LOG_PRINT_L0("Starting...");
@ -141,6 +147,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, command_line::arg_disable_stop_if_time_out_of_sync);
command_line::add_arg(desc_cmd_sett, command_line::arg_disable_stop_on_low_free_space);
command_line::add_arg(desc_cmd_sett, command_line::arg_enable_offers_service);
command_line::add_arg(desc_cmd_sett, command_line::arg_db_engine);
arg_market_disable.default_value = true;
@ -220,7 +227,7 @@ int main(int argc, char* argv[])
//create objects and link them
bc_services::bc_offers_service offers_service(nullptr);
offers_service.set_disabled(true);
offers_service.set_disabled(true); //disable by default
currency::core ccore(NULL);
currency::t_currency_protocol_handler<currency::core> cprotocol(ccore, NULL );
p2psrv_t p2psrv(cprotocol);
@ -237,8 +244,10 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_enable_offers_service))
{
offers_service.set_disabled(false);
ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service);
}
std::shared_ptr<currency::stratum_server> stratum_server_ptr;
@ -270,9 +279,10 @@ int main(int argc, char* argv[])
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize p2p server.");
LOG_PRINT_L0("P2p server initialized OK on port: " << p2psrv.get_this_peer_port());
tools::miniupnp_helper upnp_helper;
if (!command_line::get_arg(vm, command_line::arg_disable_upnp))
{
tools::miniupnp_helper upnp_helper;
LOG_PRINT_L0("Starting UPnP");
upnp_helper.start_regular_mapping(p2psrv.get_this_peer_port(), p2psrv.get_this_peer_port(), 20*60*1000);
}

View file

@ -120,6 +120,7 @@ bool daemon_backend::init(int argc, char* argv[], view::i_view* pview_handler)
command_line::add_arg(desc_cmd_sett, command_line::arg_log_level);
command_line::add_arg(desc_cmd_sett, command_line::arg_console);
command_line::add_arg(desc_cmd_sett, command_line::arg_show_details);
command_line::add_arg(desc_cmd_sett, command_line::arg_db_engine);
command_line::add_arg(desc_cmd_sett, arg_alloc_win_console);
command_line::add_arg(desc_cmd_sett, arg_html_folder);
command_line::add_arg(desc_cmd_sett, arg_xcode_stub);

View file

@ -166,14 +166,14 @@
},
"MASTER_PASSWORD": {
"TITLE": "Update master password",
"OLD": "Old password",
"OLD": "Current password",
"NEW": "New password",
"CONFIRM": "New password confirmation",
"BUTTON": "Save"
},
"FORM_ERRORS": {
"PASS_REQUIRED": "Password is required",
"PASS_NOT_MATCH": "Old password not match",
"PASS_NOT_MATCH": "Incorrect password",
"CONFIRM_NOT_MATCH": "Confirm password not match"
},
"LAST_BUILD": "Current build: {{value}}",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -649,7 +649,7 @@ module.exports = function (NAME, wrapper, methods, common, IS_MAP, IS_WEAK) {
/*! no static exports found */
/***/ (function(module, exports) {
var core = module.exports = { version: '2.6.9' };
var core = module.exports = { version: '2.6.10' };
if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
@ -5800,8 +5800,8 @@ __webpack_require__.r(__webpack_exports__);
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(/*! D:\Projects\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
module.exports = __webpack_require__(/*! D:\Projects\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
__webpack_require__(/*! C:\Users\Admin\Desktop\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
module.exports = __webpack_require__(/*! C:\Users\Admin\Desktop\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
/***/ })

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -15,7 +15,8 @@ import {ModalService} from './_helpers/services/modal.service';
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
intervalUpdatePriceState;
intervalUpdateContractsState;
expMedTsEvent;
onQuitRequest = false;
@ -547,6 +548,10 @@ export class AppComponent implements OnInit, OnDestroy {
console.log(error);
});
this.getMoneyEquivalent();
this.intervalUpdatePriceState = setInterval(() => {
this.getMoneyEquivalent();
}, 30000);
}
getMoneyEquivalent() {
@ -565,7 +570,7 @@ export class AppComponent implements OnInit, OnDestroy {
console.warn('api.coingecko.com error: ', error);
setTimeout(() => {
this.getMoneyEquivalent();
}, 60000);
}, 30000);
}
)
}
@ -673,6 +678,9 @@ export class AppComponent implements OnInit, OnDestroy {
if (this.intervalUpdateContractsState) {
clearInterval(this.intervalUpdateContractsState);
}
if (this.intervalUpdatePriceState) {
clearInterval(this.intervalUpdatePriceState);
}
this.expMedTsEvent.unsubscribe();
}

View file

@ -166,14 +166,14 @@
},
"MASTER_PASSWORD": {
"TITLE": "Update master password",
"OLD": "Old password",
"OLD": "Current password",
"NEW": "New password",
"CONFIRM": "New password confirmation",
"BUTTON": "Save"
},
"FORM_ERRORS": {
"PASS_REQUIRED": "Password is required",
"PASS_NOT_MATCH": "Old password not match",
"PASS_NOT_MATCH": "Incorrect password",
"CONFIRM_NOT_MATCH": "Confirm password not match"
},
"LAST_BUILD": "Current build: {{value}}",

View file

@ -32,6 +32,7 @@ using namespace epee;
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "p2p"
ENABLE_CHANNEL_BY_DEFAULT(LOG_DEFAULT_CHANNEL);
#define CURRENT_P2P_STORAGE_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+13)
@ -198,6 +199,7 @@ namespace nodetool
bool make_new_connection_from_peerlist(bool use_white_list);
bool try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist = false, uint64_t last_seen_stamp = 0, bool white = true);
size_t get_random_index_with_fixed_probability(size_t max_index);
bool is_peer_id_used(const peerid_type id);
bool is_peer_used(const peerlist_entry& peer);
bool is_addr_connected(const net_address& peer);
template<class t_callback>

View file

@ -483,6 +483,12 @@ namespace nodetool
return;
}
if (!tools::check_remote_client_version(rsp.payload_data.client_version))
{
LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong client version: " << rsp.payload_data.client_version << ", closing connection.");
return;
}
if(!handle_maintainers_entry(rsp.maintrs_entry))
{
LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong maintainers entry!, closing connection.");
@ -505,6 +511,13 @@ namespace nodetool
return;
}
if (is_peer_id_used(rsp.node_data.peer_id))
{
LOG_PRINT_L0("It seems that peer " << std::hex << rsp.node_data.peer_id << " has already been connected, dropping connection");
hsh_result = false;
return;
}
pi = context.peer_id = rsp.node_data.peer_id;
m_peerlist.set_peer_just_seen(rsp.node_data.peer_id, context.m_remote_ip, context.m_remote_port);
@ -529,7 +542,7 @@ namespace nodetool
if(!hsh_result)
{
LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed");
LOG_PRINT_CC_L0(context_, "COMMAND_HANDSHAKE Failed, closing connection");
m_net_server.get_config_object().close(context_.m_connection_id);
}
@ -591,6 +604,26 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_peer_id_used(const peerid_type id)
{
if (id == m_config.m_peer_id)
return true; // ourself
bool used = false;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
if (id == cntxt.peer_id)
{
used = true;
return false; // stop enumerating
}
return true;
});
return used;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::is_peer_used(const peerlist_entry& peer)
{
@ -632,7 +665,7 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const net_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, bool white)
{
LOG_PRINT_L0("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")...");
LOG_PRINT_L1("Connecting to " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << "(white=" << white << ", last_seen: " << (last_seen_stamp?misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never" ) << ")...");
typename net_server::t_connection_context con = AUTO_VAL_INIT(con);
bool res = m_net_server.connect(string_tools::get_ip_string_from_int32(na.ip),
@ -641,7 +674,7 @@ namespace nodetool
con);
if(!res)
{
LOG_PRINT_L0("Connect failed to "
LOG_PRINT_L1("Connect failed to "
<< string_tools::get_ip_string_from_int32(na.ip)
<< ":" << string_tools::num_to_string_fast(na.port)
/*<< ", try " << try_count*/);
@ -655,9 +688,11 @@ namespace nodetool
LOG_PRINT_CC_L0(con, "Failed to HANDSHAKE with peer "
<< string_tools::get_ip_string_from_int32(na.ip)
<< ":" << string_tools::num_to_string_fast(na.port)
/*<< ", try " << try_count*/);
<< ", closing connection");
m_net_server.get_config_object().close(con.m_connection_id);
return false;
}
if(just_take_peerlist)
{
m_net_server.get_config_object().close(con.m_connection_id);
@ -801,7 +836,10 @@ namespace nodetool
if(is_addr_connected(na))
continue;
try_to_connect_and_handshake_with_new_peer(na);
if (!try_to_connect_and_handshake_with_new_peer(na))
{
LOG_PRINT_L0("connection to priority node " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) << " failed");
}
}
if(m_use_only_priority_peers)
return true;
@ -1304,6 +1342,21 @@ namespace nodetool
return 1;
}
if (is_peer_id_used(arg.node_data.peer_id))
{
LOG_PRINT_CCONTEXT_L1("COMMAND_HANDSHAKE came, but seems that peer " << std::hex << arg.node_data.peer_id << " has already been connected to this node, dropping connection");
drop_connection(context);
return 1;
}
if (!tools::check_remote_client_version(arg.payload_data.client_version))
{
LOG_PRINT_CCONTEXT_L2("COMMAND_HANDSHAKE: wrong client version: " << arg.payload_data.client_version << ", closing connection.");
drop_connection(context);
add_ip_fail(context.m_remote_ip);
return 1;
}
if(!handle_maintainers_entry(arg.maintrs_entry))
{
LOG_ERROR_CCONTEXT("COMMAND_HANDSHAKE Failed, wrong maintainers entry!, closing connection.");

View file

@ -1,12 +1,13 @@
#pragma once
#include "misc_language.h"
#define BUILD_COMMIT_ID "@VERSION@"
#define PROJECT_MAJOR_VERSION "1"
#define PROJECT_MINOR_VERSION "1"
#define PROJECT_REVISION "2"
#define PROJECT_REVISION "3"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 67
#define PROJECT_VERSION_BUILD_NO 70
#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

@ -28,6 +28,8 @@ using namespace epee;
#include "version.h"
using namespace currency;
#define MINIMUM_REQUIRED_WALLET_FREE_SPACE_BYTES (100*1024*1024) // 100 MB
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL "wallet"
ENABLE_CHANNEL_BY_DEFAULT("wallet")
@ -571,8 +573,8 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
//build transaction
finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
prepare_transaction(construct_param, ftp, tx);
finalize_transaction(ftp, tx, one_time_key, true);
mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">");
finalize_transaction(ftp, tx, one_time_key, true);
print_tx_sent_message(tx, "(contract <" + epee::string_tools::pod_to_hex(contract_id) + ">)", construct_param.fee);
if (p_acceptance_tx != nullptr)
@ -693,8 +695,8 @@ void wallet2::request_cancel_contract(const crypto::hash& contract_id, uint64_t
prepare_transaction(construct_param, ftp);
currency::transaction tx = AUTO_VAL_INIT(tx);
crypto::secret_key sk = AUTO_VAL_INIT(sk);
finalize_transaction(ftp, tx, sk, true);
mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been requested for cancellaton with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">");
finalize_transaction(ftp, tx, sk, true);
print_tx_sent_message(tx, "(transport for cancel proposal)", fee);
@ -1965,6 +1967,9 @@ void wallet2::generate(const std::wstring& path, const std::string& pass)
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(validate_password(pass), "new wallet generation failed: password contains forbidden characters")
clear();
prepare_file_names(path);
check_for_free_space_and_throw_if_it_lacks(m_wallet_file);
m_password = pass;
m_account.generate();
init_log_prefix();
@ -2000,6 +2005,9 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password)
{
clear();
prepare_file_names(wallet_);
check_for_free_space_and_throw_if_it_lacks(m_wallet_file);
m_password = password;
std::string keys_buff;
@ -2058,35 +2066,56 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor
{
LOG_PRINT_L0("(before storing: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")");
// check_for_free_space_and_throw_if_it_lacks(path_to_save); temporary disabled, wallet saving implemented in two-stage scheme to avoid data loss due to lack of space
std::string ascii_path_to_save = epee::string_encoding::convert_to_ansii(path_to_save);
//prepare data
std::string keys_buff;
bool r = store_keys(keys_buff, password);
CHECK_AND_ASSERT_THROW_MES(r, "failed to store_keys for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "failed to store_keys for wallet " << ascii_path_to_save);
//store data
wallet_file_binary_header wbh = AUTO_VAL_INIT(wbh);
wbh.m_signature = WALLET_FILE_SIGNATURE;
wbh.m_cb_keys = keys_buff.size();
//@#@ change it to proper
wbh.m_cb_body = 1000;
std::string header_buff((const char*)&wbh, sizeof(wbh));
uint64_t ts = m_core_runtime_config.get_core_time();
// save to tmp file, then rename
boost::filesystem::path tmp_file_path = boost::filesystem::path(path_to_save);
tmp_file_path += L".newtmp_" + std::to_wstring(ts);
//std::ofstream data_file;
boost::filesystem::ofstream data_file;
data_file.open(path_to_save, std::ios_base::binary | std::ios_base::out | std::ios::trunc);
CHECK_AND_ASSERT_THROW_MES(!data_file.fail(), "failed to open binary wallet file for saving: " << epee::string_encoding::convert_to_ansii(m_wallet_file));
data_file.open(tmp_file_path, std::ios_base::binary | std::ios_base::out | std::ios::trunc);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!data_file.fail(), "failed to open binary wallet file for saving: " << tmp_file_path.string());
data_file << header_buff << keys_buff;
WLT_LOG_L0("Storing to file...");
WLT_LOG_L0("Storing to " << tmp_file_path.string() << " ...");
r = tools::portble_serialize_obj_to_stream(*this, data_file);
CHECK_AND_ASSERT_THROW_MES(r, "failed to portble_serialize_obj_to_stream for wallet " << epee::string_encoding::convert_to_ansii(m_wallet_file));
if (!r)
{
data_file.close();
boost::filesystem::remove(tmp_file_path); // remove tmp file if smth went wrong
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "IO error while storing wallet to " << tmp_file_path.string() << " (portble_serialize_obj_to_stream failed)");
}
data_file.flush();
data_file.close();
// for the sake of safety perform a double-renaming: wallet file -> old tmp, new tmp -> wallet file, remove old tmp
boost::filesystem::path tmp_old_file_path = boost::filesystem::path(path_to_save);
tmp_old_file_path += L".oldtmp_" + std::to_wstring(ts);
if (boost::filesystem::is_regular_file(path_to_save))
boost::filesystem::rename(path_to_save, tmp_old_file_path);
boost::filesystem::rename(tmp_file_path, path_to_save);
boost::filesystem::remove(tmp_old_file_path);
}
//----------------------------------------------------------------------------------------------------
void wallet2::store_watch_only(const std::wstring& path_to_save, const std::string& password) const
@ -2134,6 +2163,49 @@ void wallet2::store_watch_only(const std::wstring& path_to_save, const std::stri
wo.store(path_to_save, password);
}
//----------------------------------------------------------------------------------------------------
void wallet2::check_for_free_space_and_throw_if_it_lacks(const std::wstring& wallet_filename, uint64_t exact_size_needed_if_known /* = UINT64_MAX */)
{
namespace fs = boost::filesystem;
try
{
fs::path wallet_file_path(wallet_filename);
fs::path base_path = wallet_file_path.parent_path();
if (base_path.empty())
base_path = fs::path(".");
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(fs::is_directory(base_path), "directory does not exist: " << base_path.string());
uint64_t min_free_size = exact_size_needed_if_known;
if (min_free_size == UINT64_MAX)
{
// if exact size needed is unknown -- determine it as
// twice the original wallet file size or MINIMUM_REQUIRED_WALLET_FREE_SPACE_BYTES, which one is bigger
min_free_size = MINIMUM_REQUIRED_WALLET_FREE_SPACE_BYTES;
if (fs::is_regular_file(wallet_file_path))
min_free_size = std::max(min_free_size, 2 * static_cast<uint64_t>(fs::file_size(wallet_file_path)));
}
else
{
min_free_size += 1024 * 1024 * 10; // add a little for FS overhead and so
}
fs::space_info si = fs::space(base_path);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(si.available > min_free_size, "free space at " << base_path.string() << " is too low: " << si.available << ", required minimum is: " << min_free_size);
}
catch (tools::error::wallet_common_error&)
{
throw;
}
catch (std::exception& e)
{
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "failed to determine free space: " << e.what());
}
catch (...)
{
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(false, "failed to determine free space: unknown exception");
}
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::unlocked_balance() const
{
uint64_t stub = 0;
@ -2158,7 +2230,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a
for(auto& td : m_transfers)
{
if (td.is_spendable() || td.is_reserved_for_escrow())
if (td.is_spendable() || (td.is_reserved_for_escrow() && !td.is_spent()))
{
balance_total += td.amount();
if (is_transfer_unlocked(td))
@ -3284,7 +3356,7 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details&
uint64_t expiration_time = m_core_runtime_config.get_core_time() + expiration_period;
std::vector<uint64_t> selected_transfers_for_template;
build_escrow_template(ecrow_details, fake_outputs_count, unlock_time, expiration_time, b_release_fee, payment_id, template_tx, selected_transfers_for_template, one_time_key);
crypto::hash ms_id = get_multisig_out_id(template_tx, 0);
crypto::hash ms_id = get_multisig_out_id(template_tx, get_multisig_out_index(template_tx.vout));
const uint32_t mask_to_mark_escrow_template_locked_transfers = WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION;
mark_transfers_with_flag(selected_transfers_for_template, mask_to_mark_escrow_template_locked_transfers, "preparing escrow template tx, contract: " + epee::string_tools::pod_to_hex(ms_id));
@ -4009,6 +4081,10 @@ void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_par
//----------------------------------------------------------------------------------------------------
void wallet2::finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx)
{
// NOTE: if broadcast_tx == true callback rise_on_transfer2() may be called at the end of this function.
// That callback may call balance(), so it's important to have all used/spending transfers
// to be correctly marked with corresponding flags PRIOR to calling finalize_transaction()
//TIME_MEASURE_START_MS(construct_tx_time);
bool r = currency::construct_tx(m_account.get_keys(),
ftp.sources,

View file

@ -47,22 +47,22 @@
ENABLE_CHANNEL_BY_DEFAULT("wallet");
// wallet-specific logging functions
#define WLT_LOG_L0(msg) LOG_PRINT_L0("[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_L1(msg) LOG_PRINT_L1("[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_L2(msg) LOG_PRINT_L2("[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_L3(msg) LOG_PRINT_L3("[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_L4(msg) LOG_PRINT_L4("[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_ERROR(msg) LOG_ERROR("[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_BLUE(msg, log_level) LOG_PRINT_BLUE("[W:" << m_log_prefix << "]" << msg, log_level)
#define WLT_LOG_CYAN(msg, log_level) LOG_PRINT_CYAN("[W:" << m_log_prefix << "]" << msg, log_level)
#define WLT_LOG_GREEN(msg, log_level) LOG_PRINT_GREEN("[W:" << m_log_prefix << "]" << msg, log_level)
#define WLT_LOG_MAGENTA(msg, log_level) LOG_PRINT_MAGENTA("[W:" << m_log_prefix << "]" << msg, log_level)
#define WLT_LOG_RED(msg, log_level) LOG_PRINT_RED("[W:" << m_log_prefix << "]" << msg, log_level)
#define WLT_LOG_YELLOW(msg, log_level) LOG_PRINT_YELLOW("[W:" << m_log_prefix << "]" << msg, log_level)
#define WLT_CHECK_AND_ASSERT_MES(expr, ret, msg) CHECK_AND_ASSERT_MES(expr, ret, "[W:" << m_log_prefix << "]" << msg)
#define WLT_CHECK_AND_ASSERT_MES_NO_RET(expr, msg) CHECK_AND_ASSERT_MES_NO_RET(expr, "[W:" << m_log_prefix << "]" << msg)
#define WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, "[W:" << m_log_prefix << "]" << msg)
#define WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, "[W:" << m_log_prefix << "]" << msg)
#define WLT_LOG_L0(msg) LOG_PRINT_L0("[W:" << m_log_prefix << "] " << msg)
#define WLT_LOG_L1(msg) LOG_PRINT_L1("[W:" << m_log_prefix << "] " << msg)
#define WLT_LOG_L2(msg) LOG_PRINT_L2("[W:" << m_log_prefix << "] " << msg)
#define WLT_LOG_L3(msg) LOG_PRINT_L3("[W:" << m_log_prefix << "] " << msg)
#define WLT_LOG_L4(msg) LOG_PRINT_L4("[W:" << m_log_prefix << "] " << msg)
#define WLT_LOG_ERROR(msg) LOG_ERROR("[W:" << m_log_prefix << "] " << msg)
#define WLT_LOG_BLUE(msg, log_level) LOG_PRINT_BLUE("[W:" << m_log_prefix << "] " << msg, log_level)
#define WLT_LOG_CYAN(msg, log_level) LOG_PRINT_CYAN("[W:" << m_log_prefix << "] " << msg, log_level)
#define WLT_LOG_GREEN(msg, log_level) LOG_PRINT_GREEN("[W:" << m_log_prefix << "] " << msg, log_level)
#define WLT_LOG_MAGENTA(msg, log_level) LOG_PRINT_MAGENTA("[W:" << m_log_prefix << "] " << msg, log_level)
#define WLT_LOG_RED(msg, log_level) LOG_PRINT_RED("[W:" << m_log_prefix << "] " << msg, log_level)
#define WLT_LOG_YELLOW(msg, log_level) LOG_PRINT_YELLOW("[W:" << m_log_prefix << "] " << msg, log_level)
#define WLT_CHECK_AND_ASSERT_MES(expr, ret, msg) CHECK_AND_ASSERT_MES(expr, ret, "[W:" << m_log_prefix << "] " << msg)
#define WLT_CHECK_AND_ASSERT_MES_NO_RET(expr, msg) CHECK_AND_ASSERT_MES_NO_RET(expr, "[W:" << m_log_prefix << "] " << msg)
#define WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_INT_ERR_EX(cond, "[W:" << m_log_prefix << "] " << msg)
#define WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, msg) THROW_IF_FALSE_WALLET_CMN_ERR_EX(cond, "[W:" << m_log_prefix << "] " << msg)
class test_generator;
@ -729,6 +729,7 @@ namespace tools
std::string get_log_prefix() const { return m_log_prefix; }
static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td);
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);
void remove_transfer_from_expiration_list(uint64_t transfer_index);
@ -840,7 +841,7 @@ private:
void exception_handler();
void exception_handler() const;
uint64_t get_minimum_allowed_fee_for_contract(const crypto::hash& ms_id);
void check_for_free_space_and_throw_if_it_lacks(const std::wstring& path, uint64_t exact_size_needed_if_known = UINT64_MAX);

View file

@ -2057,6 +2057,7 @@ test_chain_unit_enchanced::test_chain_unit_enchanced()
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_tx_pool_empty);
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_tx_pool_count);
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, print_tx_pool);
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, remove_stuck_txs);
REGISTER_CALLBACK_METHOD(test_chain_unit_enchanced, check_offers_count);
}
@ -2122,6 +2123,16 @@ bool test_chain_unit_enchanced::print_tx_pool(currency::core& c, size_t ev_index
return true;
}
bool test_chain_unit_enchanced::remove_stuck_txs(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
size_t tx_count_before = c.get_pool_transactions_count();
bool r = c.get_tx_pool().remove_stuck_transactions();
CHECK_AND_ASSERT_MES(r, false, "remove_stuck_transactions() failed");
LOG_PRINT_L0("stuck txs removed from the pool, pool tx count: " << tx_count_before << " -> " << c.get_pool_transactions_count());
return true;
}
std::string print_market(bc_services::bc_offers_service* offers_service)
{
std::stringstream ss;

View file

@ -297,6 +297,7 @@ public:
bool check_tx_pool_empty(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_tx_pool_count(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool print_tx_pool(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool remove_stuck_txs(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_offers_count(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
protected:

View file

@ -56,14 +56,46 @@ bool clean_data_directory()
{
std::string config_folder = command_line::get_arg(g_vm, command_line::arg_data_dir);
static const char* const files[] = { CURRENCY_BLOCKCHAINDATA_FOLDERNAME, CURRENCY_POOLDATA_FOLDERNAME, MINER_CONFIG_FILENAME };
for (size_t i = 0; i < sizeof files / sizeof files[0]; ++i)
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> prefixes = { CURRENCY_POOLDATA_FOLDERNAME_PREFIX, CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX };
std::vector<boost::filesystem::path> entries_to_remove;
for(auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(config_folder), {}))
{
boost::filesystem::path filename(config_folder + "/" + files[i]);
if (boost::filesystem::exists(filename))
CHECK_AND_ASSERT_MES(boost::filesystem::remove_all(filename), false, "boost::filesystem::remove failed to remove this: " << filename);
const std::string& fn_str = entry.path().filename().string();
if (files.count(fn_str) != 0)
{
entries_to_remove.push_back(entry.path());
continue;
}
for(auto& p : prefixes)
{
if (fn_str.find(p) == 0)
{
entries_to_remove.push_back(entry.path());
break;
}
}
}
for (auto& entry : entries_to_remove)
{
if (!boost::filesystem::exists(entry))
continue;
if (boost::filesystem::remove_all(entry))
{
LOG_PRINT_L1("coretests: clean_data_directory: " << entry.string() << " removed");
}
else
{
CHECK_AND_ASSERT_MES(false, false, "boost::filesystem::remove failed to remove this: " << entry.string());
}
}
return true;
}
@ -623,6 +655,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_options, arg_run_single_test);
command_line::add_arg(desc_options, arg_enable_debug_asserts);
command_line::add_arg(desc_options, command_line::arg_data_dir, std::string("."));
command_line::add_arg(desc_options, command_line::arg_db_engine);
bool r = command_line::handle_error_helper(desc_options, [&]()
{
@ -731,6 +764,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(escrow_cancellation_acceptance_expiration);
// GENERATE_AND_PLAY(escrow_proposal_acceptance_in_alt_chain); -- work in progress
GENERATE_AND_PLAY(escrow_zero_amounts);
GENERATE_AND_PLAY(escrow_acceptance_and_balance);
GENERATE_AND_PLAY(escrow_altchain_meta_test<0>);
GENERATE_AND_PLAY(escrow_altchain_meta_test<1>);
@ -919,6 +953,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(tx_expiration_time);
GENERATE_AND_PLAY(tx_expiration_time_and_block_template);
GENERATE_AND_PLAY(tx_expiration_time_and_chain_switching);
GENERATE_AND_PLAY(tx_key_image_pool_conflict);
// Double spend
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);

View file

@ -3095,3 +3095,200 @@ bool escrow_zero_amounts::c1(currency::core& c, size_t ev_index, const std::vect
return true;
}
//------------------------------------------------------------------------------
escrow_acceptance_and_balance::escrow_acceptance_and_balance()
: m_alice_bob_start_amount(0)
, m_alice_bob_start_chunk_amount(0)
, m_alice_fee_proposal(0)
, m_bob_fee_accept(0)
, m_bob_fee_release(0)
{
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_not_confirmed);
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_confirmed);
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_not_confirmed);
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_confirmed);
}
bool escrow_acceptance_and_balance::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());
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
m_alice_bob_start_amount = MK_TEST_COINS(200);
uint64_t amount_chunks = 10;
m_alice_bob_start_chunk_amount = m_alice_bob_start_amount / 10;
transaction tx_0 = AUTO_VAL_INIT(tx_0);
bool r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), alice_acc.get_public_address(), m_alice_bob_start_amount, 10, TESTS_DEFAULT_FEE, tx_0);
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
events.push_back(tx_0);
transaction tx_1 = AUTO_VAL_INIT(tx_1);
r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), bob_acc.get_public_address(), m_alice_bob_start_amount, 10, TESTS_DEFAULT_FEE, tx_1);
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
events.push_back(tx_1);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({tx_0, tx_1}));
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
// prepare contract details
m_cpd = AUTO_VAL_INIT(m_cpd);
m_cpd.amount_a_pledge = MK_TEST_COINS(7);
m_cpd.amount_b_pledge = MK_TEST_COINS(5);
m_cpd.amount_to_pay = MK_TEST_COINS(3);
m_cpd.a_addr = alice_acc.get_public_address();
m_cpd.b_addr = bob_acc.get_public_address();
m_alice_fee_proposal = MK_TEST_COINS(4);
m_bob_fee_accept = MK_TEST_COINS(2);
m_bob_fee_release = MK_TEST_COINS(9); // Alice states that Bob should pay this much money for upcoming contract release (which will be sent by Alice)
std::vector<tx_source_entry> used_sources;
// escrow proposal
bc_services::proposal_body prop = AUTO_VAL_INIT(prop);
transaction escrow_proposal_tx = AUTO_VAL_INIT(escrow_proposal_tx);
r = build_custom_escrow_proposal(events, blk_1r, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_1r.timestamp + 36000, 0, m_alice_fee_proposal, m_bob_fee_release, eccf_normal, escrow_proposal_tx, used_sources, &prop);
CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed");
events.push_back(escrow_proposal_tx);
DO_CALLBACK(events, "check_balance_after_proposal_not_confirmed");
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, escrow_proposal_tx);
DO_CALLBACK(events, "check_balance_after_proposal_confirmed");
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
DO_CALLBACK(events, "check_balance_after_proposal_confirmed");
// escrow proposal acceptance
transaction escrow_normal_acceptance_tx = prop.tx_template;
uint64_t normal_acceptance_mask = eccf_normal;
r = build_custom_escrow_accept_proposal(events, blk_2, 0, bob_acc.get_keys(), m_cpd, 0, 0, 0, 0, m_bob_fee_accept, m_bob_fee_release, normal_acceptance_mask, prop.tx_onetime_secret_key, escrow_normal_acceptance_tx, used_sources);
CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_accept_proposal failed");
events.push_back(escrow_normal_acceptance_tx);
DO_CALLBACK(events, "check_balance_after_acceptance_not_confirmed");
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, escrow_normal_acceptance_tx);
DO_CALLBACK(events, "check_balance_after_acceptance_confirmed");
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
DO_CALLBACK(events, "check_balance_after_acceptance_confirmed");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
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);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awainted out
), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount, // total
true, UINT64_MAX,
m_alice_bob_start_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
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);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount, // total
true, UINT64_MAX,
m_alice_bob_start_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
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);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
m_cpd.amount_a_pledge + m_cpd.amount_to_pay), // awaited out
false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
m_cpd.amount_b_pledge + m_bob_fee_release), // awaited out
false, "");
return true;
}
bool escrow_acceptance_and_balance::check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
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);
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total
true, UINT64_MAX,
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
0, // mined
MK_TEST_COINS(0), // awaited in
MK_TEST_COINS(0) // awaited out
), false, "");
return true;
}

View file

@ -141,3 +141,20 @@ struct escrow_zero_amounts : 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 escrow_acceptance_and_balance : public wallet_test
{
escrow_acceptance_and_balance();
bool generate(std::vector<test_event_entry>& events) const;
bool check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable uint64_t m_alice_bob_start_amount;
mutable uint64_t m_alice_bob_start_chunk_amount;
mutable uint64_t m_alice_fee_proposal;
mutable uint64_t m_bob_fee_release;
mutable uint64_t m_bob_fee_accept;
mutable bc_services::contract_private_details m_cpd;
};

View file

@ -1448,5 +1448,134 @@ bool tx_expiration_time_and_chain_switching::generate(std::vector<test_event_ent
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1))
return true;
}
//------------------------------------------------------------------
bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events) const
{
// Test idea: check tx that is stuck in tx pool because one on its key images is already spent in the blockchain
// 1) if it's linked to an alt block -- tx will not be removed as long as linked alt block exists (in order to be able to switch)
// 2) if it's not linked to an alt block -- it will be removed after CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL confirmations of conflicted tx
// or it will be removed once tx is old enough (CURRENCY_MEMPOOL_TX_LIVETIME)
bool r = false;
m_miner_acc.generate();
GENERATE_ACCOUNT(bob_acc);
MAKE_GENESIS_BLOCK(events, blk_0, m_miner_acc, test_core_time::get_time());
REWIND_BLOCKS_N(events, blk_0r, blk_0, m_miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
// make tx_0 : miner -> bob
std::vector<tx_source_entry> sources;
std::vector<tx_destination_entry> destinations;
r = fill_tx_sources_and_destinations(events, blk_0r, m_miner_acc.get_keys(), bob_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed");
transaction tx_0 = AUTO_VAL_INIT(tx_0);
r = construct_tx(m_miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, 0);
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
LOG_PRINT_YELLOW("tx_0 = " << get_transaction_hash(tx_0), LOG_LEVEL_0);
// do not push tx_0 into events yet
// tx_1 spends the same key image as tx_0
transaction tx_1 = tx_0;
keypair kp = keypair::generate();
// change tx pub key to end up with different tx hash
update_or_add_field_to_extra(tx_1.extra, kp.pub);
r = resign_tx(m_miner_acc.get_keys(), sources, tx_1);
CHECK_AND_ASSERT_MES(r, false, "resign_tx failed");
LOG_PRINT_YELLOW("tx_1 = " << get_transaction_hash(tx_1), LOG_LEVEL_0);
// tx_2 spends the same key image as tx_0
transaction tx_2 = tx_0;
kp = keypair::generate();
// change tx pub key to end up with different tx hash
update_or_add_field_to_extra(tx_2.extra, kp.pub);
r = resign_tx(m_miner_acc.get_keys(), sources, tx_2);
CHECK_AND_ASSERT_MES(r, false, "resign_tx failed");
LOG_PRINT_YELLOW("tx_2 = " << get_transaction_hash(tx_2), LOG_LEVEL_0);
events.push_back(tx_1);
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
// as long as tx_0 is using the same key image as tx_1, tx_0 and tx_2 can't be added to the pool atm
// make sure that it's true
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(tx_0);
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(tx_2);
// however, tx_0 and tx_2 can be added with kept_by_block flag (to simulate it's going with blk_1)
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
events.push_back(tx_0);
events.push_back(tx_2);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(3));
// make a block with tx_0 and put tx_0 to the blockchain
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, m_miner_acc, tx_0);
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// tx_1 and tx_2 is still in the pool
// it can never be added to any block as long as blk_1 is in the blockchain due to key image conflict
DO_CALLBACK(events, "mark_invalid_block");
MAKE_NEXT_BLOCK_TX1(events, blk_2_bad, blk_1, m_miner_acc, tx_1);
// add tx_1 to alt block, it should go well
MAKE_NEXT_BLOCK_TX1(events, blk_1a, blk_0r, m_miner_acc, tx_1);
// however, it does not remove tx from the pool
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
//
// make sure stuck tx will be removed from the pool when it's too old
//
MAKE_NEXT_BLOCK(events, blk_2, blk_1, m_miner_acc);
// remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// shift time by CURRENCY_MEMPOOL_TX_LIVETIME
events.push_back(event_core_time(CURRENCY_MEMPOOL_TX_LIVETIME + 1, true));
// remove_stuck_txs should have removed tx_2 because it's too old
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
//
// make sure stuck tx will be removed from the pool as soon as one of its key images is spent deep enough in the blockchain
// (even if it's not too old to be removed by age)
//
MAKE_NEXT_BLOCK(events, blk_3, blk_2, m_miner_acc);
// re-add tx_2 with kept_by_block flag
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
events.push_back(tx_2);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
// rewind 50 blocks so tx_0 spending its key image will be deep enough
REWIND_BLOCKS_N_WITH_TIME(events, blk_3r, blk_3, m_miner_acc, 50);
// remove_stuck_txs should remove only tx_2 and left tx_1 (linked to alt block)
DO_CALLBACK(events, "remove_stuck_txs");
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
DO_CALLBACK(events, "print_tx_pool");
return true;
}

View file

@ -147,3 +147,9 @@ struct tx_expiration_time_and_chain_switching : public test_chain_unit_enchanced
{
bool generate(std::vector<test_event_entry>& events) const;
};
struct tx_key_image_pool_conflict : public test_chain_unit_enchanced
{
bool generate(std::vector<test_event_entry>& events) const;
mutable currency::account_base m_miner_acc;
};

View file

@ -0,0 +1,158 @@
#pragma once
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
#include <boost/filesystem.hpp>
#include "misc_log_ex.h"
namespace fs = boost::filesystem;
std::string exec(const char* cmd)
{
std::array<char, 1024> buffer;
#if defined(WIN32)
std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(cmd, "r"), _pclose);
#else
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
#endif
if (!pipe)
throw std::runtime_error("popen() failed!");
std::string result;
while (fgets(buffer.data(), static_cast<int>(buffer.size()), pipe.get()) != nullptr)
result += buffer.data();
return result;
}
bool try_write_test_file(size_t size_bytes)
{
static const std::string filename = "test_out_file";
static const fs::path filename_p = filename;
try
{
fs::ofstream s;
s.open(filename, std::ios_base::binary | std::ios_base::out| std::ios::trunc);
if(s.fail())
return false;
uint8_t block[32 * 1024] = {};
crypto::generate_random_bytes(sizeof block, &block);
size_t size_total = 0;
for (size_t i = 0; i < size_bytes / (sizeof block); ++i)
{
s.write((const char*)&block, sizeof block);
size_total += sizeof block;
}
if (size_bytes > size_total)
s.write((const char*)&block, size_bytes - size_total);
s.close();
size_t size_actual = fs::file_size(filename_p);
CHECK_AND_ASSERT_MES(size_bytes == size_actual, false, "size_bytes = " << size_bytes << ", size_actual = " << size_actual);
CHECK_AND_ASSERT_MES(fs::remove(filename_p), false, "remove failed");
}
catch (std::exception& e)
{
LOG_PRINT_RED("caught: " << e.what(), LOG_LEVEL_0);
return false;
}
catch (...)
{
LOG_PRINT_RED("caught unknown exception", LOG_LEVEL_0);
return false;
}
return true;
}
void free_space_check()
{
static const size_t test_file_size = 1024 * 1024;
namespace fs = boost::filesystem;
std::string output;
bool r = false;
#ifdef WIN32
output = exec("dir");
#else
output = exec("df -h");
#endif
LOG_PRINT_L0("test command output:" << std::endl << output);
r = try_write_test_file(test_file_size);
LOG_PRINT_L0("test file write: " << (r ? "OK" : "fail"));
boost::filesystem::path current_path(".");
size_t counter = 0;
bool need_backspace = false;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds( 900 ));
try
{
fs::space_info si = fs::space(current_path);
if (si.available > 1024)
{
// free space is ok
counter = (counter + 1) % 4;
if (need_backspace)
std::cout << '\b';
std::cout << ( counter == 0 ? '*' : counter == 1 ? '\\' : counter == 2 ? '|' : '/' );
std::cout << std::flush;
need_backspace = true;
continue;
}
// free space is not ok!
LOG_PRINT_YELLOW("1) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0);
#ifdef WIN32
output = exec("dir");
#else
output = exec("df -h");
#endif
LOG_PRINT_YELLOW(output, LOG_LEVEL_0);
// try one again asap
si = fs::space(current_path);
LOG_PRINT_YELLOW("2) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0);
if (!try_write_test_file(test_file_size))
{
LOG_PRINT_YELLOW("try_write_test_file(" << test_file_size << ") failed", LOG_LEVEL_0);
}
need_backspace = false;
}
catch (std::exception& e)
{
LOG_ERROR("failed to determine free space: " << e.what());
need_backspace = false;
}
catch (...)
{
LOG_ERROR("failed to determine free space: unknown exception");
need_backspace = false;
}
}
}

View file

@ -20,6 +20,7 @@
#include "keccak_test.h"
#include "blake2_test.h"
#include "print_struct_to_json.h"
#include "free_space_check.h"
int main(int argc, char** argv)
{
@ -36,7 +37,9 @@ int main(int argc, char** argv)
//test_blake2();
print_struct_to_json();
free_space_check();
//print_struct_to_json();
//performance_timer timer;
//timer.start();

View file

@ -0,0 +1,53 @@
// Copyright (c) 2019 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "gtest/gtest.h"
#include "common/util.h"
TEST(p2p_client_version, test_1)
{
using namespace tools;
// good
ASSERT_TRUE(check_remote_client_version("10.101.999.28391[deadbeef31337-dirty]"));
ASSERT_TRUE(check_remote_client_version("1.1.9.237[aabcd]"));
ASSERT_TRUE(check_remote_client_version("3.0.2.7[aa00bcd]"));
ASSERT_TRUE(check_remote_client_version("1.4.2.7[aabcd]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[88f868c]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[88f868c]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[26c00a8]"));
ASSERT_TRUE(check_remote_client_version("1.1.2.67[26c00a8-dirty]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.65[40ba8cd]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.63[b0f376b]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.58[14bd668]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.58[9920eb7]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.58[e0d4ad8]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57[b77b915]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57[7dd61ae]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57[7dd61ae-dirty]"));
ASSERT_TRUE(check_remote_client_version("1.1.0.57"));
// bad
ASSERT_FALSE(check_remote_client_version(""));
ASSERT_FALSE(check_remote_client_version(" "));
ASSERT_FALSE(check_remote_client_version("1.0.999"));
ASSERT_FALSE(check_remote_client_version("1.0.40[f77f0d7]"));
ASSERT_FALSE(check_remote_client_version("1.0.40[734b726]"));
ASSERT_FALSE(check_remote_client_version("1.0.41[488e369]"));
ASSERT_FALSE(check_remote_client_version("1.0.40[469]"));
ASSERT_FALSE(check_remote_client_version("1.0.39[f77f0d7]"));
ASSERT_FALSE(check_remote_client_version("1.0.38[f77f0d7-dirty]"));
ASSERT_FALSE(check_remote_client_version("1.0.37[7dd61ae-dirty]"));
ASSERT_FALSE(check_remote_client_version("0.0.500[000]"));
}

View file

@ -0,0 +1,28 @@
{
"jsonrpc": "2.0",
"id": 0,
"method": "marketplace_global_get_offers_ex",
"params": {
"filter": {
"amount_low_limit": 0,
"amount_up_limit": 0,
"bonus": false,
"category": "",
"fake": false,
"keyword": "",
"limit": 100,
"location_city": "",
"location_country": "",
"offer_type_mask": 0,
"offset": 0,
"order_by": 0,
"primary": "",
"rate_low_limit": "0.000000",
"rate_up_limit": "0.000000",
"reverse": false,
"target": "",
"timestamp_start": 0,
"timestamp_stop": 0
}
}
}

View file

@ -17,7 +17,7 @@
"ot": 1,
"p": "USD",
"pt": "Credit cards, BTC, ZANO, ETH",
"t": "Mining farm built by Gigabyted"
"t": "Mining farm built by Gigabyted[2]"
}
}
}