forked from lthn/blockchain
Merge branch 'libmdbx' of github.com:hyle-team/zano into libmdbx
This commit is contained in:
commit
60f930b0be
101 changed files with 3627 additions and 1855 deletions
|
|
@ -11,10 +11,9 @@ set_property(TARGET upnpc-static PROPERTY FOLDER "contrib/miniupnp")
|
|||
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET ${DB_ENGINE} PROPERTY FOLDER "contrib")
|
||||
|
||||
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
|
||||
else()
|
||||
set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value")
|
||||
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 ")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ set (lmdb_sources mdb.c midl.c)
|
|||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers -Wno-missing-braces -Wno-aggregate-return")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers -Wno-missing-braces -Wno-aggregate-return -Wno-discarded-qualifiers -Wno-unused-but-set-variable -Wno-implicit-fallthrough -Wno-maybe-uninitialized ")
|
||||
endif()
|
||||
if(FREEBSD)
|
||||
add_definitions(-DMDB_DSYNC=O_SYNC)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
#endif
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "string_coding.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
@ -222,13 +223,23 @@ namespace file_io_utils
|
|||
return str_result;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline const std::wstring& convert_utf8_to_wstring_if_needed(const std::wstring& s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::wstring convert_utf8_to_wstring_if_needed(const std::string& s)
|
||||
{
|
||||
return epee::string_encoding::utf8_to_wstring(s);
|
||||
}
|
||||
|
||||
template<class t_string>
|
||||
bool is_file_exist(const t_string& path)
|
||||
{
|
||||
boost::filesystem::path p(path);
|
||||
return boost::filesystem::exists(p);
|
||||
}
|
||||
{
|
||||
boost::filesystem::path p(convert_utf8_to_wstring_if_needed(path));
|
||||
return boost::filesystem::exists(p);
|
||||
}
|
||||
|
||||
/*
|
||||
inline
|
||||
|
|
@ -261,19 +272,18 @@ namespace file_io_utils
|
|||
template<class t_string>
|
||||
bool save_string_to_file_throw(const t_string& path_to_file, const std::string& str)
|
||||
{
|
||||
//std::ofstream fstream;
|
||||
boost::filesystem::ofstream fstream;
|
||||
fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(path_to_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
fstream << str;
|
||||
fstream.close();
|
||||
return true;
|
||||
//std::ofstream fstream;
|
||||
boost::filesystem::ofstream fstream;
|
||||
fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(convert_utf8_to_wstring_if_needed(path_to_file), std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
fstream << str;
|
||||
fstream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class t_string>
|
||||
bool save_string_to_file(const t_string& path_to_file, const std::string& str)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
return save_string_to_file_throw(path_to_file, str);
|
||||
|
|
@ -290,13 +300,13 @@ namespace file_io_utils
|
|||
}
|
||||
|
||||
template<class t_string>
|
||||
bool load_file_to_string(const t_string& path_to_file, std::string& target_str)
|
||||
bool load_file_to_string(const t_string& path_to_file, std::string& target_str)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::filesystem::ifstream fstream;
|
||||
//fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate);
|
||||
fstream.open(convert_utf8_to_wstring_if_needed(path_to_file), std::ios_base::binary | std::ios_base::in | std::ios::ate);
|
||||
if (!fstream.good())
|
||||
return false;
|
||||
std::ifstream::pos_type file_size = fstream.tellg();
|
||||
|
|
@ -315,7 +325,6 @@ namespace file_io_utils
|
|||
fstream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -353,7 +362,7 @@ namespace file_io_utils
|
|||
bool get_file_time(const std::string& path_to_file, OUT time_t& ft)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec);
|
||||
ft = boost::filesystem::last_write_time(epee::string_encoding::utf8_to_wstring(path_to_file), ec);
|
||||
if(!ec)
|
||||
return true;
|
||||
else
|
||||
|
|
@ -364,7 +373,7 @@ namespace file_io_utils
|
|||
bool set_file_time(const std::string& path_to_file, const time_t& ft)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ft, ec);
|
||||
boost::filesystem::last_write_time(epee::string_encoding::utf8_to_wstring(path_to_file), ft, ec);
|
||||
if(!ec)
|
||||
return true;
|
||||
else
|
||||
|
|
@ -380,16 +389,18 @@ namespace file_io_utils
|
|||
typedef int native_filesystem_handle;
|
||||
#endif
|
||||
|
||||
// uses UTF-8 for unicode names for all systems
|
||||
inline bool open_and_lock_file(const std::string file_path, native_filesystem_handle& h_file)
|
||||
{
|
||||
#ifdef WIN32
|
||||
h_file = ::CreateFileA(file_path.c_str(), // name of the write
|
||||
GENERIC_WRITE, // open for writing
|
||||
0, // do not share
|
||||
NULL, // default security
|
||||
OPEN_ALWAYS, // create new file only
|
||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||
NULL); // no attr. template
|
||||
std::wstring file_path_w = epee::string_encoding::utf8_to_wstring(file_path);
|
||||
h_file = ::CreateFileW(file_path_w.c_str(), // name of the file
|
||||
GENERIC_WRITE, // open for writing
|
||||
0, // do not share
|
||||
NULL, // default security
|
||||
OPEN_ALWAYS, // create new file only
|
||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||
NULL); // no attr. template
|
||||
if (h_file == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
else
|
||||
|
|
@ -465,20 +476,21 @@ namespace file_io_utils
|
|||
bool copy_file(const std::string& source, const std::string& destination)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::copy_file(source, destination, ec);
|
||||
boost::filesystem::copy_file(epee::string_encoding::utf8_to_wstring(source), epee::string_encoding::utf8_to_wstring(destination), ec);
|
||||
if (ec)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool append_string_to_file(const std::string& path_to_file, const std::string& str)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ofstream fstream;
|
||||
boost::filesystem::ofstream fstream;
|
||||
fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(path_to_file.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::app);
|
||||
fstream.open(epee::string_encoding::utf8_to_wstring(path_to_file), std::ios_base::binary | std::ios_base::out | std::ios_base::app);
|
||||
fstream << str;
|
||||
fstream.close();
|
||||
return true;
|
||||
|
|
@ -550,7 +562,7 @@ namespace file_io_utils
|
|||
{
|
||||
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for ( boost::filesystem::directory_iterator itr( path ); itr != end_itr; ++itr )
|
||||
for ( boost::filesystem::directory_iterator itr( epee::string_encoding::utf8_to_wstring(path) ); itr != end_itr; ++itr )
|
||||
{
|
||||
if ( only_files && boost::filesystem::is_directory(itr->status()) )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ DISABLE_VS_WARNINGS(4100)
|
|||
|
||||
#include "syncobj.h"
|
||||
#include "sync_locked_object.h"
|
||||
#include "string_coding.h"
|
||||
|
||||
|
||||
#define LOG_LEVEL_SILENT -1
|
||||
|
|
@ -694,13 +695,13 @@ namespace log_space
|
|||
class file_output_stream : public ibase_log_stream
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, std::ofstream*> named_log_streams;
|
||||
typedef std::map<std::string, boost::filesystem::ofstream*> named_log_streams;
|
||||
|
||||
file_output_stream( std::string default_log_file_name, std::string log_path )
|
||||
file_output_stream( const std::string& default_log_file_name, const std::string& log_path )
|
||||
{
|
||||
m_default_log_filename = default_log_file_name;
|
||||
m_max_logfile_size = 0;
|
||||
m_default_log_path = log_path;
|
||||
m_default_log_path_w = epee::string_encoding::utf8_to_wstring(log_path);
|
||||
m_pdefault_file_stream = add_new_stream_and_open(default_log_file_name.c_str());
|
||||
}
|
||||
|
||||
|
|
@ -718,20 +719,22 @@ namespace log_space
|
|||
}
|
||||
private:
|
||||
named_log_streams m_log_file_names;
|
||||
std::string m_default_log_path;
|
||||
std::ofstream* m_pdefault_file_stream;
|
||||
std::wstring m_default_log_path_w;
|
||||
boost::filesystem::ofstream* m_pdefault_file_stream;
|
||||
std::string m_log_rotate_cmd;
|
||||
std::string m_default_log_filename;
|
||||
uint64_t m_max_logfile_size;
|
||||
|
||||
|
||||
std::ofstream* add_new_stream_and_open(const char* pstream_name)
|
||||
// gets utf-8 encoded string
|
||||
boost::filesystem::ofstream* add_new_stream_and_open(const char* pstream_name)
|
||||
{
|
||||
//log_space::rotate_log_file((m_default_log_path + "\\" + pstream_name).c_str());
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::create_directories(m_default_log_path, ec);
|
||||
std::ofstream* pstream = (m_log_file_names[pstream_name] = new std::ofstream);
|
||||
std::string target_path = m_default_log_path + "/" + pstream_name;
|
||||
boost::filesystem::create_directories(m_default_log_path_w, ec);
|
||||
boost::filesystem::ofstream* pstream = (m_log_file_names[pstream_name] = new boost::filesystem::ofstream);
|
||||
std::wstring target_path = m_default_log_path_w + L"/" + epee::string_encoding::utf8_to_wstring(pstream_name);
|
||||
|
||||
pstream->open( target_path.c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */);
|
||||
if(pstream->fail())
|
||||
return NULL;
|
||||
|
|
@ -754,7 +757,7 @@ namespace log_space
|
|||
|
||||
virtual bool out_buffer( const char* buffer, int buffer_len, int log_level, int color, const char* plog_name = NULL )
|
||||
{
|
||||
std::ofstream* m_target_file_stream = m_pdefault_file_stream;
|
||||
boost::filesystem::ofstream* m_target_file_stream = m_pdefault_file_stream;
|
||||
if(plog_name)
|
||||
{ //find named stream
|
||||
named_log_streams::iterator it = m_log_file_names.find(plog_name);
|
||||
|
|
@ -769,9 +772,10 @@ namespace log_space
|
|||
m_target_file_stream->write(buffer, buffer_len );
|
||||
m_target_file_stream->flush();
|
||||
|
||||
/*
|
||||
if(m_max_logfile_size)
|
||||
{
|
||||
std::ofstream::pos_type pt = m_target_file_stream->tellp();
|
||||
boost::filesystem::ofstream::pos_type pt = m_target_file_stream->tellp();
|
||||
uint64_t current_sz = pt;
|
||||
if(current_sz > m_max_logfile_size)
|
||||
{
|
||||
|
|
@ -818,12 +822,13 @@ namespace log_space
|
|||
misc_utils::call_sys_cmd(m_log_rotate_cmd_local_copy);
|
||||
}
|
||||
|
||||
m_target_file_stream->open( (m_default_log_path + "/" + log_file_name).c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */);
|
||||
|
||||
m_target_file_stream->open( (m_default_log_path + "/" + log_file_name).c_str(), std::ios_base::out | std::ios::app / * ios_base::trunc * /);
|
||||
if(m_target_file_stream->fail())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
int get_type(){return LOGGER_FILE;}
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const st
|
|||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
PUSH_WARNINGS
|
||||
DISABLE_GCC_WARNING(maybe - uninitialized)
|
||||
DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include <boost/filesystem.hpp>
|
||||
#include "warnings.h"
|
||||
#include "auto_val_init.h"
|
||||
#include "string_coding.h"
|
||||
|
||||
|
||||
#ifndef OUT
|
||||
|
|
@ -536,38 +537,15 @@ POP_WARNINGS
|
|||
return module_folder;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef _WIN32
|
||||
inline std::string get_current_module_path()
|
||||
inline bool set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
char pname [5000] = {0};
|
||||
GetModuleFileNameA( NULL, pname, sizeof(pname));
|
||||
pname[sizeof(pname)-1] = 0; //be happy ;)
|
||||
return pname;
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
std::string path_to_process = path_to_process_;
|
||||
boost::system::error_code ec;
|
||||
path_to_process = boost::filesystem::canonical(path_to_process, ec).string();
|
||||
#ifdef _WIN32
|
||||
path_to_process = get_current_module_path();
|
||||
#endif
|
||||
std::string::size_type a = path_to_process.rfind( '\\' );
|
||||
if(a == std::string::npos )
|
||||
{
|
||||
a = path_to_process.rfind( '/' );
|
||||
}
|
||||
if ( a != std::string::npos )
|
||||
{
|
||||
get_current_module_name() = path_to_process.substr(a+1, path_to_process.size());
|
||||
get_current_module_folder() = path_to_process.substr(0, a);
|
||||
return true;
|
||||
}else
|
||||
return false;
|
||||
boost::filesystem::path path(epee::string_encoding::utf8_to_wstring(path_to_process_));
|
||||
|
||||
}
|
||||
get_current_module_folder() = epee::string_encoding::wstring_to_utf8(path.parent_path().wstring());
|
||||
get_current_module_name() = epee::string_encoding::wstring_to_utf8(path.filename().wstring());
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool trim_left(std::string& str)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -145,7 +145,11 @@ epoch_context_full* create_epoch_context(
|
|||
|
||||
char* const alloc_data = static_cast<char*>(std::calloc(1, alloc_size));
|
||||
if (!alloc_data)
|
||||
return nullptr; // Signal out-of-memory by returning null pointer.
|
||||
{
|
||||
LOG_CUSTOM_WITH_CALLSTACK("CRITICAL: std::calloc(" << alloc_size << ") failed in create_epoch_context()", 0);
|
||||
return nullptr; // Signal out-of-memory by returning null pointer.
|
||||
}
|
||||
LOG_CUSTOM("context for epoch " << epoch_number << " allocated, size: " << alloc_size << " bytes", 0);
|
||||
|
||||
hash512* const light_cache = reinterpret_cast<hash512*>(alloc_data + context_alloc_size);
|
||||
const hash256 epoch_seed = calculate_epoch_seed(epoch_number);
|
||||
|
|
@ -373,6 +377,33 @@ search_result search(const epoch_context_full& context, const hash256& header_ha
|
|||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
custom_log_level_function*& access_custom_log_level_function()
|
||||
{
|
||||
static custom_log_level_function* p_custom_log_level_function = nullptr;
|
||||
return p_custom_log_level_function;
|
||||
}
|
||||
|
||||
custom_log_function*& access_custom_log_function()
|
||||
{
|
||||
static custom_log_function* p_custom_log_function = nullptr;
|
||||
return p_custom_log_function;
|
||||
}
|
||||
|
||||
int get_custom_log_level()
|
||||
{
|
||||
if (access_custom_log_level_function() != nullptr)
|
||||
return access_custom_log_level_function()();
|
||||
return -1;
|
||||
}
|
||||
|
||||
void custom_log(const std::string& m, bool add_callstack)
|
||||
{
|
||||
if (access_custom_log_function() != nullptr)
|
||||
access_custom_log_function()(m, add_callstack);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ethash
|
||||
|
||||
using namespace ethash;
|
||||
|
|
@ -434,6 +465,8 @@ void ethash_destroy_epoch_context_full(epoch_context_full* context) noexcept
|
|||
|
||||
void ethash_destroy_epoch_context(epoch_context* context) noexcept
|
||||
{
|
||||
LOG_CUSTOM("context for epoch " << context->epoch_number << " is about to be freed", 0);
|
||||
|
||||
context->~epoch_context();
|
||||
std::free(context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace ethash
|
||||
{
|
||||
|
|
@ -157,4 +159,33 @@ const epoch_context& get_global_epoch_context(int epoch_number);
|
|||
|
||||
/// Get global shared epoch context with full dataset initialized.
|
||||
std::shared_ptr<epoch_context_full> get_global_epoch_context_full(int epoch_number);
|
||||
|
||||
typedef int (custom_log_level_function)();
|
||||
typedef void (custom_log_function)(const std::string& m, bool add_callstack);
|
||||
|
||||
custom_log_level_function*& access_custom_log_level_function();
|
||||
custom_log_function*& access_custom_log_function();
|
||||
int get_custom_log_level();
|
||||
void custom_log(const std::string& m, bool add_callstack);
|
||||
|
||||
#define LOG_CUSTOM(msg, level) \
|
||||
{ \
|
||||
if (level <= ethash::get_custom_log_level()) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << msg << std::endl; \
|
||||
ethash::custom_log(ss.str(), false); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LOG_CUSTOM_WITH_CALLSTACK(msg, level) \
|
||||
{ \
|
||||
if (level <= ethash::get_custom_log_level()) \
|
||||
{ \
|
||||
std::stringstream ss; \
|
||||
ss << msg << std::endl; \
|
||||
ethash::custom_log(ss.str(), true); \
|
||||
} \
|
||||
}
|
||||
|
||||
} // namespace ethash
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ namespace tools
|
|||
bool serialize_obj_to_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
std::ofstream data_file;
|
||||
data_file.open( file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
|
||||
boost::filesystem::ofstream data_file;
|
||||
data_file.open( epee::string_encoding::utf8_to_wstring(file_path) , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
|
||||
|
|
@ -64,8 +64,8 @@ namespace tools
|
|||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
std::ifstream data_file;
|
||||
data_file.open( file_path, std::ios_base::binary | std::ios_base::in);
|
||||
boost::filesystem::ifstream data_file;
|
||||
data_file.open( epee::string_encoding::utf8_to_wstring(file_path), std::ios_base::binary | std::ios_base::in);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
boost::archive::binary_iarchive a(data_file);
|
||||
|
|
|
|||
|
|
@ -659,28 +659,27 @@ namespace tools
|
|||
{
|
||||
return bdb.size(m_h);
|
||||
}
|
||||
size_t clear()
|
||||
|
||||
bool clear()
|
||||
{
|
||||
bdb.clear(m_h);
|
||||
bool result = bdb.clear(m_h);
|
||||
m_isolation.isolated_write_access<bool>([&](){
|
||||
size_cache_valid = false;
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool erase_validate(const t_key& k)
|
||||
{
|
||||
auto res_ptr = this->get(k);
|
||||
bdb.erase(m_h, k);
|
||||
bool result = bdb.erase(m_h, k);
|
||||
m_isolation.isolated_write_access<bool>([&](){
|
||||
size_cache_valid = false;
|
||||
return true;
|
||||
});
|
||||
return static_cast<bool>(res_ptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void erase(const t_key& k)
|
||||
{
|
||||
bdb.erase(m_h, k);
|
||||
|
|
@ -861,13 +860,10 @@ namespace tools
|
|||
|
||||
operator t_value() const
|
||||
{
|
||||
static_assert(std::is_pod<t_value>::value, "t_value must be a POD type.");
|
||||
std::shared_ptr<const t_value> value_ptr = m_accessor.template explicit_get<t_key, t_value, access_strategy_selector<is_t_strategy> >(m_key);
|
||||
if (value_ptr.get())
|
||||
return *value_ptr.get();
|
||||
|
||||
std::shared_ptr<const t_value> vptr = m_accessor.template explicit_get<t_key, t_value, access_strategy_selector<false> >(m_key);
|
||||
if (vptr.get())
|
||||
{
|
||||
return *vptr.get();
|
||||
}
|
||||
return AUTO_VAL_INIT(t_value());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,10 +51,6 @@ namespace tools
|
|||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_mapsize");
|
||||
|
||||
m_path = path_;
|
||||
#ifdef WIN32
|
||||
m_path = epee::string_encoding::convert_ansii_to_utf8(m_path);
|
||||
#endif
|
||||
|
||||
CHECK_AND_ASSERT_MES(tools::create_directories_if_necessary(m_path), false, "create_directories_if_necessary failed: " << m_path);
|
||||
|
||||
res = mdb_env_open(m_penv, m_path.c_str(), MDB_NORDAHEAD , 0644);
|
||||
|
|
|
|||
265
src/common/ntp.cpp
Normal file
265
src/common/ntp.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
|
||||
// Note: class udp_blocking_client is a slightly modified version of an example
|
||||
// taken from https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_udp_client.cpp
|
||||
//
|
||||
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <epee/include/misc_log_ex.h>
|
||||
#include <chrono>
|
||||
#include "ntp.h"
|
||||
|
||||
using boost::asio::deadline_timer;
|
||||
using boost::asio::ip::udp;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// This class manages socket timeouts by applying the concept of a deadline.
|
||||
// Each asynchronous operation is given a deadline by which it must complete.
|
||||
// Deadlines are enforced by an "actor" that persists for the lifetime of the
|
||||
// client object:
|
||||
//
|
||||
// +----------------+
|
||||
// | |
|
||||
// | check_deadline |<---+
|
||||
// | | |
|
||||
// +----------------+ | async_wait()
|
||||
// | |
|
||||
// +---------+
|
||||
//
|
||||
// If the actor determines that the deadline has expired, any outstanding
|
||||
// socket operations are cancelled. The socket operations themselves are
|
||||
// implemented as transient actors:
|
||||
//
|
||||
// +---------------+
|
||||
// | |
|
||||
// | receive |
|
||||
// | |
|
||||
// +---------------+
|
||||
// |
|
||||
// async_- | +----------------+
|
||||
// receive() | | |
|
||||
// +--->| handle_receive |
|
||||
// | |
|
||||
// +----------------+
|
||||
//
|
||||
// The client object runs the io_service to block thread execution until the
|
||||
// actor completes.
|
||||
//
|
||||
namespace
|
||||
{
|
||||
class udp_blocking_client
|
||||
{
|
||||
public:
|
||||
udp_blocking_client(const udp::endpoint& listen_endpoint, udp::socket& socket, boost::asio::io_service& io_service)
|
||||
: socket_(socket),
|
||||
io_service_(io_service),
|
||||
deadline_(io_service)
|
||||
{
|
||||
// No deadline is required until the first socket operation is started. We
|
||||
// set the deadline to positive infinity so that the actor takes no action
|
||||
// until a specific deadline is set.
|
||||
deadline_.expires_at(boost::posix_time::pos_infin);
|
||||
|
||||
// Start the persistent actor that checks for deadline expiry.
|
||||
check_deadline();
|
||||
}
|
||||
|
||||
std::size_t receive(const boost::asio::mutable_buffer& buffer,
|
||||
boost::posix_time::time_duration timeout, boost::system::error_code& ec)
|
||||
{
|
||||
// Set a deadline for the asynchronous operation.
|
||||
deadline_.expires_from_now(timeout);
|
||||
|
||||
// Set up the variables that receive the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
// operation is incomplete. Asio guarantees that its asynchronous
|
||||
// operations will never fail with would_block, so any other value in
|
||||
// ec indicates completion.
|
||||
ec = boost::asio::error::would_block;
|
||||
std::size_t length = 0;
|
||||
|
||||
// Start the asynchronous operation itself. The handle_receive function
|
||||
// used as a callback will update the ec and length variables.
|
||||
socket_.async_receive(boost::asio::buffer(buffer),
|
||||
boost::bind(&udp_blocking_client::handle_receive, _1, _2, &ec, &length));
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
do io_service_.run_one(); while (ec == boost::asio::error::would_block);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
private:
|
||||
void check_deadline()
|
||||
{
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
|
||||
{
|
||||
// The deadline has passed. The outstanding asynchronous operation needs
|
||||
// to be cancelled so that the blocked receive() function will return.
|
||||
//
|
||||
// Please note that cancel() has portability issues on some versions of
|
||||
// Microsoft Windows, and it may be necessary to use close() instead.
|
||||
// Consult the documentation for cancel() for further information.
|
||||
socket_.cancel();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
deadline_.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
// Put the actor back to sleep.
|
||||
deadline_.async_wait(boost::bind(&udp_blocking_client::check_deadline, this));
|
||||
}
|
||||
|
||||
static void handle_receive(
|
||||
const boost::system::error_code& ec, std::size_t length,
|
||||
boost::system::error_code* out_ec, std::size_t* out_length)
|
||||
{
|
||||
*out_ec = ec;
|
||||
*out_length = length;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service& io_service_;
|
||||
udp::socket& socket_;
|
||||
deadline_timer deadline_;
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ntp_packet
|
||||
{
|
||||
|
||||
uint8_t li_vn_mode; // Eight bits. li, vn, and mode.
|
||||
// li. Two bits. Leap indicator.
|
||||
// vn. Three bits. Version number of the protocol.
|
||||
// mode. Three bits. Client will pick mode 3 for client.
|
||||
|
||||
uint8_t stratum; // Eight bits. Stratum level of the local clock.
|
||||
uint8_t poll; // Eight bits. Maximum interval between successive messages.
|
||||
uint8_t precision; // Eight bits. Precision of the local clock.
|
||||
|
||||
uint32_t rootDelay; // 32 bits. Total round trip delay time.
|
||||
uint32_t rootDispersion; // 32 bits. Max error aloud from primary clock source.
|
||||
uint32_t refId; // 32 bits. Reference clock identifier.
|
||||
|
||||
uint32_t refTm_s; // 32 bits. Reference time-stamp seconds.
|
||||
uint32_t refTm_f; // 32 bits. Reference time-stamp fraction of a second.
|
||||
|
||||
uint64_t orig_tm; // 64 bits. Originate time-stamp (set by client)
|
||||
|
||||
uint32_t rxTm_s; // 32 bits. Received time-stamp seconds.
|
||||
uint32_t rxTm_f; // 32 bits. Received time-stamp fraction of a second.
|
||||
|
||||
uint32_t txTm_s; // 32 bits and the most important field the client cares about. Transmit time-stamp seconds.
|
||||
uint32_t txTm_f; // 32 bits. Transmit time-stamp fraction of a second.
|
||||
|
||||
}; // Total: 384 bits or 48 bytes.
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(ntp_packet) == 48, "ntp_packet has invalid size");
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
int64_t get_ntp_time(const std::string& host_name, size_t timeout_sec)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::udp::resolver resolver(io_service);
|
||||
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), host_name, "ntp");
|
||||
boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
|
||||
boost::asio::ip::udp::socket socket(io_service);
|
||||
socket.open(boost::asio::ip::udp::v4());
|
||||
|
||||
ntp_packet packet_sent = AUTO_VAL_INIT(packet_sent);
|
||||
packet_sent.li_vn_mode = 0x1b;
|
||||
auto packet_sent_time = std::chrono::high_resolution_clock::now();
|
||||
socket.send_to(boost::asio::buffer(&packet_sent, sizeof packet_sent), receiver_endpoint);
|
||||
|
||||
ntp_packet packet_received = AUTO_VAL_INIT(packet_received);
|
||||
boost::asio::ip::udp::endpoint sender_endpoint;
|
||||
|
||||
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);
|
||||
if (ec)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): boost error: " << ec.message());
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto packet_received_time = std::chrono::high_resolution_clock::now();
|
||||
int64_t roundtrip_mcs = std::chrono::duration_cast<std::chrono::microseconds>(packet_received_time - packet_sent_time).count();
|
||||
uint64_t roundtrip_s = roundtrip_mcs > 2000000 ? roundtrip_mcs / 2000000 : 0;
|
||||
|
||||
time_t ntp_time = ntohl(packet_received.txTm_s);
|
||||
if (ntp_time <= 2208988800U)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): wrong txTm_s: " << packet_received.txTm_s);
|
||||
return 0;
|
||||
}
|
||||
// LOG_PRINT_L2("NTP: get_ntp_time(" << host_name << "): RAW time received: " << ntp_time << ", refTm_s: " << ntohl(packet_received.refTm_s) << ", stratum: " << packet_received.stratum << ", round: " << roundtrip_mcs);
|
||||
ntp_time -= 2208988800U; // Unix time starts from 01/01/1970 == 2208988800U
|
||||
ntp_time += roundtrip_s;
|
||||
return ntp_time;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L2("NTP: get_ntp_time(" << host_name << "): exception: " << e.what());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_PRINT_L2("NTP: get_ntp_time(" << host_name << "): unknown exception");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define TIME_SYNC_NTP_SERVERS "time1.google.com", "time2.google.com", "time3.google.com", "time4.google.com" /* , "pool.ntp.org" -- we need to request a vender zone before using this pool */
|
||||
#define TIME_SYNC_NTP_TIMEOUT_SEC 5
|
||||
#define TIME_SYNC_NTP_ATTEMPTS_COUNT 3 // max number of attempts when getting time from NTP server
|
||||
|
||||
int64_t get_ntp_time()
|
||||
{
|
||||
static const std::vector<std::string> ntp_servers { TIME_SYNC_NTP_SERVERS };
|
||||
|
||||
for (size_t att = 0; att < TIME_SYNC_NTP_ATTEMPTS_COUNT; ++att)
|
||||
{
|
||||
const std::string& ntp_server = ntp_servers[att % ntp_servers.size()];
|
||||
LOG_PRINT_L3("NTP: trying to get time from " << ntp_server);
|
||||
int64_t time = get_ntp_time(ntp_server, TIME_SYNC_NTP_TIMEOUT_SEC);
|
||||
if (time > 0)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: " << ntp_server << " responded with " << time << " (" << epee::misc_utils::get_time_str_v2(time) << ")");
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_PRINT_RED("NTP: unable to get time from NTP with " << TIME_SYNC_NTP_ATTEMPTS_COUNT << " trials", LOG_LEVEL_2);
|
||||
return 0; // smth went wrong
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace tools
|
||||
18
src/common/ntp.h
Normal file
18
src/common/ntp.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
// requests current time via NTP from 'host_hame' using 'timeout_sec'
|
||||
// may return zero -- means error
|
||||
int64_t get_ntp_time(const std::string& host_name, size_t timeout_sec = 5);
|
||||
|
||||
// request time via predefined NTP servers
|
||||
// may return zero -- mean error
|
||||
int64_t get_ntp_time();
|
||||
|
||||
} // namespace tools
|
||||
|
|
@ -24,6 +24,8 @@ using namespace epee;
|
|||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "string_coding.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
std::function<void(void)> signal_handler::m_handler;
|
||||
|
|
@ -450,18 +452,22 @@ std::string get_nix_version_display_string()
|
|||
|
||||
|
||||
#ifdef WIN32
|
||||
std::string get_special_folder_path(int nfolder, bool iscreate)
|
||||
std::wstring get_special_folder_path_w(int nfolder, bool iscreate)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
char psz_path[MAX_PATH] = "";
|
||||
wchar_t psz_path[MAX_PATH] = L"";
|
||||
|
||||
if(SHGetSpecialFolderPathA(NULL, psz_path, nfolder, iscreate))
|
||||
if (SHGetSpecialFolderPathW(NULL, psz_path, nfolder, iscreate))
|
||||
{
|
||||
return psz_path;
|
||||
}
|
||||
|
||||
LOG_ERROR("SHGetSpecialFolderPathA() failed, could not obtain requested path.");
|
||||
return "";
|
||||
LOG_ERROR("SHGetSpecialFolderPathW(" << nfolder << ", " << iscreate << ") failed, could not obtain requested path.");
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::string get_special_folder_path_utf8(int nfolder, bool iscreate)
|
||||
{
|
||||
return epee::string_encoding::wstring_to_utf8(get_special_folder_path_w(nfolder, iscreate));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -476,9 +482,9 @@ std::string get_nix_version_display_string()
|
|||
#ifdef WIN32
|
||||
// Windows
|
||||
#ifdef _M_X64
|
||||
config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT;
|
||||
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT;
|
||||
#else
|
||||
config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86";
|
||||
config_folder = get_special_folder_path_utf8(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86";
|
||||
#endif
|
||||
#else
|
||||
std::string pathRet;
|
||||
|
|
@ -518,7 +524,7 @@ std::string get_nix_version_display_string()
|
|||
std::string wallets_dir;
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
wallets_dir = get_special_folder_path(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE;
|
||||
wallets_dir = get_special_folder_path_utf8(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE;
|
||||
#else
|
||||
std::string pathRet;
|
||||
char* pszHome = getenv("HOME");
|
||||
|
|
@ -553,7 +559,7 @@ std::string get_nix_version_display_string()
|
|||
{
|
||||
namespace fs = boost::filesystem;
|
||||
boost::system::error_code ec;
|
||||
fs::path fs_path(path);
|
||||
fs::path fs_path = epee::string_encoding::utf8_to_wstring(path);
|
||||
if (fs::is_directory(fs_path, ec))
|
||||
{
|
||||
return true;
|
||||
|
|
@ -652,38 +658,4 @@ std::string get_nix_version_display_string()
|
|||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
int64_t get_ntp_time(const std::string& host_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::ip::udp::resolver resolver(io_service);
|
||||
boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), host_name, "ntp");
|
||||
boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query);
|
||||
boost::asio::ip::udp::socket socket(io_service);
|
||||
socket.open(boost::asio::ip::udp::v4());
|
||||
|
||||
boost::array<unsigned char, 48> send_buf = { { 010, 0, 0, 0, 0, 0, 0, 0, 0 } };
|
||||
socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
|
||||
|
||||
boost::array<unsigned long, 1024> recv_buf;
|
||||
boost::asio::ip::udp::endpoint sender_endpoint;
|
||||
size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
|
||||
|
||||
time_t time_recv = ntohl((time_t)recv_buf[4]);
|
||||
time_recv -= 2208988800U; //Unix time starts from 01/01/1970 == 2208988800U
|
||||
return time_recv;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L2("get_ntp_time(): exception: " << e.what());
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace tools
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
#include "ntp.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <dbghelp.h>
|
||||
|
|
@ -274,6 +275,4 @@ namespace tools
|
|||
static std::function<void(int, void*)> m_fatal_handler;
|
||||
};
|
||||
|
||||
|
||||
int64_t get_ntp_time(const std::string& host_name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
//#include "initializer.h"
|
||||
#include "random.h"
|
||||
|
||||
static void generate_system_random_bytes(size_t n, void *result);
|
||||
static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE");
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
static void generate_system_random_bytes(size_t n, void *result) {
|
||||
void generate_system_random_bytes(size_t n, void *result) {
|
||||
HCRYPTPROV prov;
|
||||
#define must_succeed(x) do if (!(x)) assert(0); while (0)
|
||||
if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
||||
|
|
@ -40,7 +40,7 @@ static void generate_system_random_bytes(size_t n, void *result) {
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void generate_system_random_bytes(size_t n, void *result) {
|
||||
void generate_system_random_bytes(size_t n, void *result) {
|
||||
int fd;
|
||||
if ((fd = open("/dev/urandom", O_RDONLY | O_NOCTTY | O_CLOEXEC)) < 0) {
|
||||
err(EXIT_FAILURE, "open /dev/urandom");
|
||||
|
|
@ -68,7 +68,7 @@ static void generate_system_random_bytes(size_t n, void *result) {
|
|||
|
||||
#endif
|
||||
|
||||
/* static */ union hash_state state; // NOTE: 'static' is commented out here to be able to store/load global random generator state in tests (see also random_helper.h)
|
||||
static union hash_state state;
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
static volatile int curstate; /* To catch thread safety problems. */
|
||||
|
|
@ -105,6 +105,57 @@ void grant_random_initialize(void)
|
|||
}
|
||||
}
|
||||
|
||||
void random_prng_initialize_with_seed(uint64_t seed)
|
||||
{
|
||||
grant_random_initialize();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 3;
|
||||
#endif
|
||||
memset(&state, 0, sizeof state);
|
||||
memcpy(&state, &seed, sizeof seed);
|
||||
for(size_t i = 0, count = seed & 31; i < count; ++i)
|
||||
hash_permutation(&state);
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 3);
|
||||
curstate = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void random_prng_get_state(void *state_buffer, const size_t buffer_size)
|
||||
{
|
||||
grant_random_initialize();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 4;
|
||||
#endif
|
||||
|
||||
assert(sizeof state == buffer_size);
|
||||
memcpy(state_buffer, &state, buffer_size);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 4);
|
||||
curstate = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void random_prng_set_state(const void *state_buffer, const size_t buffer_size)
|
||||
{
|
||||
grant_random_initialize();
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 1);
|
||||
curstate = 5;
|
||||
#endif
|
||||
|
||||
assert(sizeof state == buffer_size);
|
||||
memcpy(&state, state_buffer, buffer_size);
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
assert(curstate == 5);
|
||||
curstate = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void generate_random_bytes(size_t n, void *result) {
|
||||
grant_random_initialize();
|
||||
#if !defined(NDEBUG)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Copyright (c) 2014-2018 The Boolberry developers
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
|
@ -5,6 +7,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// use the cryptographically secure Pseudo-Random Number Generator provided by the operating system
|
||||
void generate_system_random_bytes(size_t n, void *result);
|
||||
|
||||
void generate_random_bytes(size_t n, void *result);
|
||||
void grant_random_initialize(void);
|
||||
|
||||
// checks if PRNG is initialized and initializes it if necessary
|
||||
void grant_random_initialize(void);
|
||||
|
||||
#define RANDOM_STATE_SIZE 200
|
||||
|
||||
// explicitly define USE_INSECURE_RANDOM_RPNG_ROUTINES for using random_initialize_with_seed
|
||||
#ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES
|
||||
// reinitializes PRNG with the given seed
|
||||
// !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH!
|
||||
// Use with care and ONLY for tests or debug purposes!
|
||||
void random_prng_initialize_with_seed(uint64_t seed);
|
||||
|
||||
// gets internal RPNG state (state_buffer should be 200 bytes long)
|
||||
void random_prng_get_state(void *state_buffer, const size_t buffer_size);
|
||||
|
||||
// sets internal RPNG state (state_buffer should be 200 bytes long)
|
||||
// !!!ATTENTION!!!! Improper use of this routine may lead to SECURITY BREACH!
|
||||
// Use with care and ONLY for tests or debug purposes!
|
||||
void random_prng_set_state(const void *state_buffer, const size_t buffer_size);
|
||||
|
||||
#endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES
|
||||
|
|
|
|||
|
|
@ -22,17 +22,31 @@ namespace currency
|
|||
{
|
||||
|
||||
//--------------------------------------------------------------
|
||||
//global object
|
||||
// crypto::ethash::cache_manager cache;
|
||||
// void ethash_set_use_dag(bool use_dag)
|
||||
// {
|
||||
// cache.set_use_dag(use_dag);
|
||||
// }
|
||||
// //------------------------------------------------------------------
|
||||
// const uint8_t* ethash_get_dag(uint64_t epoch, uint64_t& dag_size)
|
||||
// {
|
||||
// return cache.get_dag(epoch, dag_size);
|
||||
// }
|
||||
int ethash_custom_log_get_level()
|
||||
{
|
||||
return epee::log_space::get_set_log_detalisation_level();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
void ethash_custom_log(const std::string& m, bool add_callstack)
|
||||
{
|
||||
std::string msg = epee::log_space::log_singletone::get_prefix_entry() + "[ETHASH]" + m;
|
||||
if (add_callstack)
|
||||
msg = msg + "callstask: " + epee::misc_utils::get_callstack();
|
||||
|
||||
epee::log_space::log_singletone::do_log_message(msg, LOG_LEVEL_0, epee::log_space::console_color_default, true, LOG_DEFAULT_TARGET);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
void init_ethash_log_if_necessary()
|
||||
{
|
||||
static bool inited = false;
|
||||
if (inited)
|
||||
return;
|
||||
|
||||
ethash::access_custom_log_level_function() = ðash_custom_log_get_level;
|
||||
ethash::access_custom_log_function() = ðash_custom_log;
|
||||
|
||||
inited = true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
int ethash_height_to_epoch(uint64_t height)
|
||||
{
|
||||
|
|
@ -49,6 +63,7 @@ namespace currency
|
|||
//--------------------------------------------------------------
|
||||
crypto::hash get_block_longhash(uint64_t height, const crypto::hash& block_header_hash, uint64_t nonce)
|
||||
{
|
||||
init_ethash_log_if_necessary();
|
||||
int epoch = ethash_height_to_epoch(height);
|
||||
std::shared_ptr<ethash::epoch_context_full> p_context = progpow::get_global_epoch_context_full(static_cast<int>(epoch));
|
||||
CHECK_AND_ASSERT_THROW_MES(p_context, "progpow::get_global_epoch_context_full returned null");
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@ void blockchain_storage::init_options(boost::program_options::options_descriptio
|
|||
command_line::add_arg(desc, arg_db_cache_l2);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
||||
uint64_t blockchain_storage::get_block_h_older_then(uint64_t timestamp) const
|
||||
{
|
||||
// get avarage block position
|
||||
|
|
@ -223,12 +222,12 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
|
|||
|
||||
m_config_folder = config_folder;
|
||||
|
||||
// remove old incompartible DB
|
||||
// remove old incompatible DB
|
||||
const std::string old_db_folder_path = m_config_folder + "/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME_OLD;
|
||||
if (boost::filesystem::exists(old_db_folder_path))
|
||||
if (boost::filesystem::exists(epee::string_encoding::utf8_to_wstring(old_db_folder_path)))
|
||||
{
|
||||
LOG_PRINT_YELLOW("Removing old DB in " << old_db_folder_path << "...", LOG_LEVEL_0);
|
||||
boost::filesystem::remove_all(old_db_folder_path);
|
||||
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;
|
||||
|
|
@ -242,7 +241,7 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
|
|||
{
|
||||
// if DB could not be opened -- try to remove the whole folder and re-open DB
|
||||
LOG_PRINT_YELLOW("Failed to initialize database in folder: " << db_folder_path << ", first attempt", LOG_LEVEL_0);
|
||||
boost::filesystem::remove_all(db_folder_path);
|
||||
boost::filesystem::remove_all(epee::string_encoding::utf8_to_wstring(db_folder_path));
|
||||
res = m_db.open(db_folder_path, cache_size_l1);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to initialize database in folder: " << db_folder_path << ", second attempt");
|
||||
}
|
||||
|
|
@ -312,7 +311,7 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
|
|||
m_db_addr_to_alias.deinit();
|
||||
m_db_per_block_gindex_incs.deinit();
|
||||
m_db.close();
|
||||
size_t files_removed = boost::filesystem::remove_all(db_folder_path);
|
||||
size_t files_removed = boost::filesystem::remove_all(epee::string_encoding::utf8_to_wstring(db_folder_path));
|
||||
LOG_PRINT_L1(files_removed << " files at " << db_folder_path << " removed");
|
||||
|
||||
// try to re-create DB and re-init containers
|
||||
|
|
@ -1820,10 +1819,19 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_
|
|||
wide_difficulty_type main_pow_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height - 1, false);
|
||||
main_cumul_diff.pow_diff = main_pow_diff_end - main_pow_diff_begin;
|
||||
|
||||
//TODO: measurment of precise cumulative difficult
|
||||
//TODO: measurement of precise cumulative difficult
|
||||
wide_difficulty_type alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
|
||||
wide_difficulty_type main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
|
||||
|
||||
LOG_PRINT_L1("[FORK_CHOICE]: " << ENDL
|
||||
<< "difficulty_pow_at_split_point:" << difficulty_pow_at_split_point << ENDL
|
||||
<< "difficulty_pos_at_split_point:" << difficulty_pos_at_split_point << ENDL
|
||||
<< "alt_cumul_diff.pow_diff:" << alt_cumul_diff.pow_diff << ENDL
|
||||
<< "alt_cumul_diff.pos_diff:" << alt_cumul_diff.pos_diff << ENDL
|
||||
<< "main_cumul_diff.pow_diff:" << main_cumul_diff.pow_diff << ENDL
|
||||
<< "main_cumul_diff.pos_diff:" << main_cumul_diff.pos_diff << ENDL
|
||||
<< "alt:" << alt << ENDL
|
||||
<< "main:" << main << ENDL
|
||||
);
|
||||
if (main < alt)
|
||||
return true;
|
||||
else if (main > alt)
|
||||
|
|
@ -1838,7 +1846,7 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_
|
|||
if (std::memcmp(&main_chain_bei.stake_hash, &proof_alt, sizeof(main_chain_bei.stake_hash)) >= 0)
|
||||
return false;
|
||||
|
||||
LOG_PRINT_L2("[is_reorganize_required]:TRUE, \"by order of memcmp\" main_stake_hash:" << &main_chain_bei.stake_hash << ", alt_stake_hash" << proof_alt);
|
||||
LOG_PRINT_L1("[is_reorganize_required]:TRUE, \"by order of memcmp\" main_stake_hash:" << &main_chain_bei.stake_hash << ", alt_stake_hash" << proof_alt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2635,7 +2643,8 @@ void blockchain_storage::print_blockchain_with_tx(uint64_t start_index, uint64_t
|
|||
{
|
||||
boost::filesystem::ofstream ss;
|
||||
ss.exceptions(/*std::ifstream::failbit |*/ std::ifstream::badbit);
|
||||
ss.open(log_space::log_singletone::get_default_log_folder() + "/blockchain_with_tx.txt", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
ss.open(epee::string_encoding::utf8_to_wstring(log_space::log_singletone::get_default_log_folder() + "/blockchain_with_tx.txt"),
|
||||
std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
|
@ -2714,7 +2723,6 @@ void blockchain_storage::print_db_cache_perfeormance_data() const
|
|||
void blockchain_storage::get_last_n_x_blocks(uint64_t n, bool pos_blocks, std::list<std::shared_ptr<const block_extended_info>>& blocks) const
|
||||
{
|
||||
uint64_t count = 0;
|
||||
bool looking_for_a_pos = true;
|
||||
for (uint64_t i = m_db_blocks.size() - 1; i != 0; --i)
|
||||
{
|
||||
auto block_ptr = m_db_blocks[i];
|
||||
|
|
@ -3909,14 +3917,14 @@ bool blockchain_storage::is_tx_spendtime_unlocked(uint64_t unlock_time) const
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& max_unlock_time) const
|
||||
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
//TIME_MEASURE_START_PD(tx_check_inputs_loop_ch_in_get_keys_loop);
|
||||
|
||||
std::vector<crypto::public_key> output_keys;
|
||||
if(!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, max_unlock_time))
|
||||
if(!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")");
|
||||
return false;
|
||||
|
|
@ -3935,7 +3943,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
|
|||
// 1) source tx unlock time validity
|
||||
// 2) mixin restrictions
|
||||
// 3) general gindex/ref_by_id corectness
|
||||
bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction& tx, const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& max_unlock_time) const
|
||||
bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction& tx, const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
|
|
@ -3943,10 +3951,13 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
|
|||
{
|
||||
std::vector<crypto::public_key >& m_results_collector;
|
||||
const blockchain_storage& m_bch;
|
||||
uint64_t& m_max_unlock_time;
|
||||
uint64_t& m_source_max_unlock_time_for_pos_coinbase;
|
||||
outputs_visitor(std::vector<crypto::public_key>& results_collector,
|
||||
const blockchain_storage& bch,
|
||||
uint64_t& max_unlock_time) :m_results_collector(results_collector), m_bch(bch), m_max_unlock_time(max_unlock_time)
|
||||
uint64_t& source_max_unlock_time_for_pos_coinbase)
|
||||
: m_results_collector(results_collector)
|
||||
, m_bch(bch)
|
||||
, m_source_max_unlock_time_for_pos_coinbase(source_max_unlock_time_for_pos_coinbase)
|
||||
{}
|
||||
bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out& out, uint64_t out_i)
|
||||
{
|
||||
|
|
@ -3955,8 +3966,9 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
|
|||
//let coinbase sources for PoS block to have locked inputs, the outputs supposed to be locked same way, except the reward
|
||||
if (is_coinbase(validated_tx) && is_pos_block(validated_tx))
|
||||
{
|
||||
if (source_out_unlock_time > m_max_unlock_time)
|
||||
m_max_unlock_time = source_out_unlock_time;
|
||||
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(source_out_unlock_time), false, "source output #" << out_i << " is locked by time, not by height, which is not allowed for PoS coinbase");
|
||||
if (source_out_unlock_time > m_source_max_unlock_time_for_pos_coinbase)
|
||||
m_source_max_unlock_time_for_pos_coinbase = source_out_unlock_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3967,7 +3979,6 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if(out.target.type() != typeid(txout_to_key))
|
||||
{
|
||||
LOG_PRINT_L0("Output have wrong type id, which=" << out.target.which());
|
||||
|
|
@ -3979,7 +3990,7 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction
|
|||
}
|
||||
};
|
||||
|
||||
outputs_visitor vi(output_keys, *this, max_unlock_time);
|
||||
outputs_visitor vi(output_keys, *this, source_max_unlock_time_for_pos_coinbase);
|
||||
return scan_outputkeys_for_indexes(tx, txin, vi, max_related_block_height);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -4437,13 +4448,13 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t max_unlock_time)const
|
||||
bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const
|
||||
{
|
||||
uint64_t major_unlock_time = get_tx_x_detail<etc_tx_details_unlock_time>(miner_tx);
|
||||
if (major_unlock_time)
|
||||
{
|
||||
//if there was etc_tx_details_unlock_time present in tx, then ignore etc_tx_details_unlock_time2
|
||||
if (major_unlock_time < max_unlock_time)
|
||||
if (major_unlock_time < source_max_unlock_time)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
|
@ -4457,11 +4468,13 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio
|
|||
CHECK_AND_ASSERT_MES(ut2.unlock_time_array.size() == miner_tx.vout.size(), false, "ut2.unlock_time_array.size()<" << ut2.unlock_time_array.size()
|
||||
<< "> != miner_tx.vout.size()<" << miner_tx.vout.size() << ">");
|
||||
|
||||
uint64_t amount_of_coins_in_unlock_in_range = 0;
|
||||
uint64_t amount_of_coins_in_unlock_in_range = 0; // amount of outputs locked for at least the same time
|
||||
|
||||
for (uint64_t i = 0; i != miner_tx.vout.size(); i++)
|
||||
{
|
||||
if (ut2.unlock_time_array[i] >= max_unlock_time)
|
||||
uint64_t unlock_value = ut2.unlock_time_array[i];
|
||||
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(unlock_value), false, "output #" << i << " is locked by time, not buy height, which is not allowed for PoS coinbase");
|
||||
if (unlock_value >= source_max_unlock_time)
|
||||
amount_of_coins_in_unlock_in_range += miner_tx.vout[i].amount;
|
||||
}
|
||||
|
||||
|
|
@ -4548,22 +4561,22 @@ bool blockchain_storage::validate_pos_block(const block& b,
|
|||
{
|
||||
// Do coinstake input validation for main chain only.
|
||||
// Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs()
|
||||
uint64_t max_unlock_time = 0;
|
||||
r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], max_related_block_height, max_unlock_time);
|
||||
uint64_t source_max_unlock_time_for_pos_coinbase = 0;
|
||||
r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], max_related_block_height, source_max_unlock_time_for_pos_coinbase);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b));
|
||||
|
||||
if (get_block_height(b) > m_core_runtime_config.hard_fork1_starts_after_height)
|
||||
{
|
||||
uint64_t last_pow_h = get_last_x_block_height(false);
|
||||
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to failed to validate coinbase in pos block, condition failed: max_related_block_height(" << max_related_block_height << ") < last_pow_h(" << last_pow_h << ")");
|
||||
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to validate coinbase in PoS block, condition failed: max_related_block_height(" << max_related_block_height << ") <= last_pow_h(" << last_pow_h << ")");
|
||||
//let's check that coinbase amount and unlock time
|
||||
r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, max_unlock_time);
|
||||
r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b)
|
||||
<< "max_unlock_time=" << max_unlock_time);
|
||||
<< "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(max_unlock_time), false, "Failed to failed to validate coinbase in pos block, condition failed: is_tx_spendtime_unlocked(max_unlock_time)(" << max_unlock_time << ")");
|
||||
CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase), false, "Failed to validate coinbase in PoS block, condition failed: is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase)(" << source_max_unlock_time_for_pos_coinbase << ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4856,7 +4869,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool");
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
add_block_as_invalid(bl, id);
|
||||
LOG_PRINT_L0("Block with id " << id << " added as invalid becouse of wrong inputs in transactions");
|
||||
LOG_PRINT_L0("Block with id " << id << " added as invalid because of wrong inputs in transactions");
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -5356,7 +5369,7 @@ bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt
|
|||
else
|
||||
{
|
||||
bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_MODFIFIER");
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_KERNEL_HASH");
|
||||
}
|
||||
|
||||
sm.last_pow_id = get_block_hash(pbei_last_pow->bl);
|
||||
|
|
|
|||
|
|
@ -267,14 +267,14 @@ namespace currency
|
|||
uint64_t get_aliases_count()const;
|
||||
uint64_t get_block_h_older_then(uint64_t timestamp) const;
|
||||
bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& max_unlock_time)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const;
|
||||
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const;
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const;
|
||||
bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const transaction& source_tx, size_t out_n) const;
|
||||
bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const;
|
||||
bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& max_unlock_time) const;
|
||||
bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_to_key& txin, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const;
|
||||
bool check_tokey_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const std::vector<const crypto::public_key*>& output_keys_ptrs) const;
|
||||
uint64_t get_current_comulative_blocksize_limit()const;
|
||||
uint64_t get_current_hashrate(size_t aprox_count)const;
|
||||
|
|
@ -312,7 +312,7 @@ namespace currency
|
|||
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash *p_last_block_hash = nullptr) const;
|
||||
|
||||
bool scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp)const;
|
||||
bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t max_unlock_time)const;
|
||||
bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const;
|
||||
bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const;
|
||||
bool validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain)const;
|
||||
bool validate_pos_block(const block& b,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ namespace currency
|
|||
FIELD(block_cumulative_size)
|
||||
FIELD(cumulative_diff_adjusted)
|
||||
FIELD(cumulative_diff_precise)
|
||||
FIELD(cumulative_diff_precise_adjusted)
|
||||
FIELD(difficulty)
|
||||
FIELD(already_generated_coins)
|
||||
FIELD(stake_hash)
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@
|
|||
#define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3
|
||||
#define CURRENT_BLOCK_EXTENDED_INFO_ARCHIVE_VER 1
|
||||
|
||||
#define BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION CURRENCY_FORMATION_VERSION + 8
|
||||
#define BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION CURRENCY_FORMATION_VERSION + 9
|
||||
#define BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION 1
|
||||
|
||||
|
||||
|
|
@ -227,13 +227,12 @@
|
|||
#define BLOCK_MINOR_VERSION_GENESIS 0
|
||||
#define BLOCK_MAJOR_VERSION_INITAL 0
|
||||
#ifndef TESTNET
|
||||
#define ZANO_HARDFORK_1_AFTER_HEIGHT 172200
|
||||
#define ZANO_HARDFORK_1_AFTER_HEIGHT 194624
|
||||
#else
|
||||
#define ZANO_HARDFORK_1_AFTER_HEIGHT 1440
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit");
|
||||
static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs");
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using namespace epee;
|
|||
#include "currency_core/currency_config.h"
|
||||
#include "currency_format_utils.h"
|
||||
#include "misc_language.h"
|
||||
#include "string_coding.h"
|
||||
|
||||
#define MINIMUM_REQUIRED_FREE_SPACE_BYTES (1024 * 1024 * 100)
|
||||
|
||||
|
|
@ -717,10 +718,27 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_if_free_space_critically_low(uint64_t* p_available_space /* = nullptr */)
|
||||
{
|
||||
boost::filesystem::space_info si = boost::filesystem::space(m_config_folder);
|
||||
if (p_available_space != nullptr)
|
||||
*p_available_space = si.available;
|
||||
return si.available < MINIMUM_REQUIRED_FREE_SPACE_BYTES;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
try
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(tools::create_directories_if_necessary(m_config_folder), false, "create_directories_if_necessary failed: " << m_config_folder);
|
||||
std::wstring config_folder_w = epee::string_encoding::utf8_to_wstring(m_config_folder);
|
||||
fs::space_info si = fs::space(config_folder_w);
|
||||
if (p_available_space != nullptr)
|
||||
*p_available_space = si.available;
|
||||
return si.available < MINIMUM_REQUIRED_FREE_SPACE_BYTES;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LOG_ERROR("failed to determine free space: " << e.what());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_ERROR("failed to determine free space: unknown exception");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void core::check_free_space()
|
||||
|
|
|
|||
|
|
@ -2715,7 +2715,7 @@ namespace currency
|
|||
|
||||
boost::multiprecision::uint1024_t basic_sum = boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty) + (boost::multiprecision::uint1024_t(a_pos_cumulative_difficulty)*difficulty_pow_at_split_point) / difficulty_pos_at_split_point;
|
||||
boost::multiprecision::uint1024_t res =
|
||||
(basic_sum * a_pow_cumulative_difficulty * a_pos_cumulative_difficulty) / (boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty)*a_pos_cumulative_difficulty);
|
||||
(basic_sum * a_pow_cumulative_difficulty * a_pos_cumulative_difficulty) / (boost::multiprecision::uint1024_t(b_pow_cumulative_difficulty)*b_pos_cumulative_difficulty);
|
||||
|
||||
if (res > boost::math::tools::max_value<wide_difficulty_type>())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace currency
|
|||
return 0;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(ut2.unlock_time_array.size() > o_i, "unlock_time_array.size=" << ut2.unlock_time_array.size()
|
||||
<< " is less then o_i=" << o_i << " in tx: " << get_transaction_hash(tx));
|
||||
<< " is less or equal to o_i=" << o_i << " in tx: " << get_transaction_hash(tx));
|
||||
|
||||
return ut2.unlock_time_array[o_i];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ namespace currency
|
|||
uint64_t get_tx_unlock_time(const transaction& tx, uint64_t o_i);
|
||||
uint64_t get_tx_max_unlock_time(const transaction& tx);
|
||||
bool get_tx_max_min_unlock_time(const transaction& tx, uint64_t& max_unlock_time, uint64_t& min_unlock_time);
|
||||
inline bool should_unlock_value_be_treated_as_block_height(uint64_t v) { return v < CURRENCY_MAX_BLOCK_NUMBER; }
|
||||
inline uint64_t get_tx_flags(const transaction& tx) { return get_tx_x_detail<etc_tx_details_flags>(tx); }
|
||||
inline uint64_t get_tx_expiration_time(const transaction& tx) {return get_tx_x_detail<etc_tx_details_expiration_time>(tx); }
|
||||
inline void set_tx_unlock_time(transaction& tx, uint64_t v) { set_tx_x_detail<etc_tx_details_unlock_time>(tx, v); }
|
||||
|
|
@ -106,4 +107,4 @@ namespace currency
|
|||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size);
|
||||
blobdata tx_to_blob(const transaction& b);
|
||||
bool tx_to_blob(const transaction& b, blobdata& b_blob);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ namespace currency
|
|||
else
|
||||
{
|
||||
// this tx has no fee
|
||||
LOG_ERROR("Transaction with id= " << id << " has too small fee: " << tx_fee << ", expected fee: " << m_blockchain.get_core_runtime_config().tx_pool_min_fee);
|
||||
LOG_PRINT_RED_L0("Transaction with id= " << id << " has too small fee: " << tx_fee << ", expected fee: " << m_blockchain.get_core_runtime_config().tx_pool_min_fee);
|
||||
tvc.m_verification_failed = false;
|
||||
tvc.m_should_be_relayed = false;
|
||||
tvc.m_added_to_pool = false;
|
||||
|
|
@ -1125,10 +1125,10 @@ namespace currency
|
|||
|
||||
// remove old incompartible DB
|
||||
const std::string old_db_folder_path = m_config_folder + "/" CURRENCY_POOLDATA_FOLDERNAME_OLD;
|
||||
if (boost::filesystem::exists(old_db_folder_path))
|
||||
if (boost::filesystem::exists(epee::string_encoding::utf8_to_wstring(old_db_folder_path)))
|
||||
{
|
||||
LOG_PRINT_YELLOW("Removing old DB in " << old_db_folder_path << "...", LOG_LEVEL_0);
|
||||
boost::filesystem::remove_all(old_db_folder_path);
|
||||
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;
|
||||
|
|
@ -1142,7 +1142,7 @@ namespace currency
|
|||
{
|
||||
// if DB could not be opened -- try to remove the whole folder and re-open DB
|
||||
LOG_PRINT_YELLOW("Failed to initialize database in folder: " << db_folder_path << ", first attempt", LOG_LEVEL_0);
|
||||
boost::filesystem::remove_all(db_folder_path);
|
||||
boost::filesystem::remove_all(epee::string_encoding::utf8_to_wstring(db_folder_path));
|
||||
res = m_db.open(db_folder_path, cache_size_l1);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Failed to initialize database in folder: " << db_folder_path << ", second attempt");
|
||||
}
|
||||
|
|
@ -1182,7 +1182,7 @@ namespace currency
|
|||
m_db_alias_addresses.deinit();
|
||||
m_db_solo_options.deinit();
|
||||
m_db.close();
|
||||
size_t files_removed = boost::filesystem::remove_all(db_folder_path);
|
||||
size_t files_removed = boost::filesystem::remove_all(epee::string_encoding::utf8_to_wstring(db_folder_path));
|
||||
LOG_PRINT_L1(files_removed << " files at " << db_folder_path << " removed");
|
||||
|
||||
// try to re-create DB and re-init containers
|
||||
|
|
|
|||
|
|
@ -770,36 +770,14 @@ namespace currency
|
|||
#define TIME_SYNC_DELTA_RING_BUFFER_SIZE 8
|
||||
#define TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE (60 * 5) // max acceptable difference between time delta median among peers and local time (seconds)
|
||||
#define TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE (60 * 5) // max acceptable difference between NTP time and local time (seconds)
|
||||
#define TIME_SYNC_NTP_SERVERS { "time.google.com", "0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org" }
|
||||
#define TIME_SYNC_NTP_ATTEMPTS_COUNT 3 // max number of attempts when getting time from NTP server
|
||||
|
||||
static int64_t get_ntp_time()
|
||||
{
|
||||
static const std::vector<std::string> ntp_servers TIME_SYNC_NTP_SERVERS;
|
||||
|
||||
for (size_t att = 0; att < TIME_SYNC_NTP_ATTEMPTS_COUNT; ++att)
|
||||
{
|
||||
size_t i = 0;
|
||||
crypto::generate_random_bytes(sizeof(i), &i);
|
||||
const std::string& ntp_server = ntp_servers[i % ntp_servers.size()];
|
||||
LOG_PRINT_L3("NTP: trying to get time from " << ntp_server);
|
||||
int64_t time = tools::get_ntp_time(ntp_server);
|
||||
if (time > 0)
|
||||
{
|
||||
LOG_PRINT_L2("NTP: " << ntp_server << " responded with " << time << " (" << epee::misc_utils::get_time_str_v2(time) << ")");
|
||||
return time;
|
||||
}
|
||||
LOG_PRINT_L2("NTP: cannot get time from " << ntp_server);
|
||||
}
|
||||
|
||||
return 0; // smth went wrong
|
||||
}
|
||||
|
||||
template<class t_core>
|
||||
bool t_currency_protocol_handler<t_core>::add_time_delta_and_check_time_sync(int64_t time_delta)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_time_deltas_lock);
|
||||
|
||||
auto get_core_time = [this] { return m_core.get_blockchain_storage().get_core_runtime_config().get_core_time(); };
|
||||
|
||||
m_time_deltas.push_back(time_delta);
|
||||
while (m_time_deltas.size() > TIME_SYNC_DELTA_RING_BUFFER_SIZE)
|
||||
m_time_deltas.pop_front();
|
||||
|
|
@ -813,7 +791,8 @@ namespace currency
|
|||
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);
|
||||
if (std::abs(m_last_median2local_time_difference) > TIME_SYNC_DELTA_TO_LOCAL_MAX_DIFFERENCE)
|
||||
{
|
||||
int64_t ntp_time = get_ntp_time();
|
||||
int64_t ntp_time = tools::get_ntp_time();
|
||||
LOG_PRINT_L2("NTP: received time " << ntp_time << " (" << epee::misc_utils::get_time_str_v2(ntp_time) << "), diff: " << std::showpos << get_core_time() - ntp_time);
|
||||
if (ntp_time == 0)
|
||||
{
|
||||
// error geting ntp time
|
||||
|
|
@ -823,7 +802,7 @@ namespace currency
|
|||
|
||||
// got ntp time correctly
|
||||
// update local time, because getting ntp time could be time consuming
|
||||
uint64_t local_time_2 = m_core.get_blockchain_storage().get_core_runtime_config().get_core_time();
|
||||
uint64_t local_time_2 = get_core_time();
|
||||
m_last_ntp2local_time_difference = local_time_2 - ntp_time;
|
||||
if (std::abs(m_last_ntp2local_time_difference) > TIME_SYNC_NTP_TO_LOCAL_MAX_DIFFERENCE)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,6 +87,13 @@ struct core_critical_error_handler_t : public currency::i_critical_error_handler
|
|||
bool dont_stop_on_low_space;
|
||||
};
|
||||
|
||||
void terminate_handler_func()
|
||||
{
|
||||
LOG_ERROR("\n\nTERMINATE HANDLER\n"); // should print callstack
|
||||
std::fflush(nullptr); // all open output streams are flushed
|
||||
std::abort(); // default terminate handler's behavior
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
try
|
||||
|
|
@ -112,6 +119,9 @@ int main(int argc, char* argv[])
|
|||
// setup custom callstack retrieving function
|
||||
epee::misc_utils::get_callstack(tools::get_callstack);
|
||||
|
||||
// setup custom terminate functions
|
||||
std::set_terminate(&terminate_handler_func);
|
||||
|
||||
po::options_description desc_cmd_only("Command line options");
|
||||
po::options_description desc_cmd_sett("Command line options and settings options", 130, 83);
|
||||
|
||||
|
|
@ -162,8 +172,8 @@ int main(int argc, char* argv[])
|
|||
std::string data_dir = command_line::get_arg(vm, command_line::arg_data_dir);
|
||||
std::string config = command_line::get_arg(vm, command_line::arg_config_file);
|
||||
|
||||
boost::filesystem::path data_dir_path(data_dir);
|
||||
boost::filesystem::path config_path(config);
|
||||
boost::filesystem::path data_dir_path(epee::string_encoding::utf8_to_wstring(data_dir));
|
||||
boost::filesystem::path config_path(epee::string_encoding::utf8_to_wstring(config));
|
||||
if (!config_path.has_parent_path())
|
||||
{
|
||||
config_path = data_dir_path / config_path;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ public:
|
|||
m_cmd_binder.set_handler("print_tx_outputs_usage", boost::bind(&daemon_commands_handler::print_tx_outputs_usage, this, _1), "Analyse if tx outputs for involved in subsequent transactions");
|
||||
m_cmd_binder.set_handler("print_difficulties_of_last_n_blocks", boost::bind(&daemon_commands_handler::print_difficulties_of_last_n_blocks, this, _1), "Print difficulties of last n blocks");
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_cmd_binder.set_handler("debug_set_time_adj", boost::bind(&daemon_commands_handler::debug_set_time_adj, this, _1), "DEBUG: set core time adjustment");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool start_handling()
|
||||
|
|
@ -499,8 +502,15 @@ private:
|
|||
bool r = m_srv.get_payload_object().get_core().get_blockchain_storage().get_main_blocks_rpc_details(height, 1, false, blocks);
|
||||
if (r && blocks.size())
|
||||
{
|
||||
currency::block b = AUTO_VAL_INIT(b);
|
||||
m_srv.get_payload_object().get_core().get_blockchain_storage().get_block_by_height(height, b);
|
||||
currency::blobdata blob = block_to_blob(b);
|
||||
std::string block_hex = epee::string_tools::buff_to_hex_nodelimer(blob);
|
||||
|
||||
currency::block_rpc_extended_info& rbei = blocks.back();
|
||||
LOG_PRINT_GREEN("------------------ block_id: " << rbei.id << " ------------------" << ENDL << epee::serialization::store_t_to_json(rbei), LOG_LEVEL_0);
|
||||
LOG_PRINT_GREEN("------------------ block_id: " << rbei.id << " ------------------" <<
|
||||
ENDL << epee::serialization::store_t_to_json(rbei) << ENDL
|
||||
<< " ------------------ hex_blob: " << ENDL << block_hex, LOG_LEVEL_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -523,8 +533,14 @@ private:
|
|||
|
||||
if (r)
|
||||
{
|
||||
currency::block b = AUTO_VAL_INIT(b);
|
||||
m_srv.get_payload_object().get_core().get_blockchain_storage().get_block_by_hash(block_hash, b);
|
||||
currency::blobdata blob = block_to_blob(b);
|
||||
std::string block_hex = epee::string_tools::buff_to_hex_nodelimer(blob);
|
||||
// currency::block& block = bei.bl;
|
||||
LOG_PRINT_GREEN("------------------ block_id: " << bei.id << " ------------------" << ENDL << epee::serialization::store_t_to_json(bei), LOG_LEVEL_0);
|
||||
LOG_PRINT_GREEN("------------------ block_id: " << bei.id << " ------------------" << ENDL
|
||||
<< epee::serialization::store_t_to_json(bei) << ENDL
|
||||
<< " ------------------ hex_blob: " << ENDL << block_hex, LOG_LEVEL_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -811,7 +827,49 @@ private:
|
|||
LOG_PRINT_L0(ENDL << epee::deadlock_guard_singleton::get_dlg_state());
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
#ifdef _DEBUG
|
||||
static std::atomic<int64_t>& debug_core_time_shift_accessor()
|
||||
{
|
||||
static std::atomic<int64_t> time_shift(0);
|
||||
return time_shift;
|
||||
}
|
||||
|
||||
static uint64_t debug_core_time_function()
|
||||
{
|
||||
return (int64_t)time(NULL) + debug_core_time_shift_accessor().load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool debug_set_time_adj(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.size() != 1)
|
||||
{
|
||||
LOG_PRINT_RED("one arg required: signed time shift in seconds", LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t time_shift = 0;
|
||||
if (!epee::string_tools::string_to_num_fast(args[0], time_shift))
|
||||
{
|
||||
LOG_PRINT_RED("could not parse: " << args[0], LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t time_before = debug_core_time_function();
|
||||
debug_core_time_shift_accessor().store(time_shift);
|
||||
uint64_t time_after = debug_core_time_function();
|
||||
|
||||
currency::blockchain_storage& bcs = m_srv.get_payload_object().get_core().get_blockchain_storage();
|
||||
|
||||
currency::core_runtime_config crc = bcs.get_core_runtime_config();
|
||||
crc.get_core_time = &debug_core_time_function;
|
||||
bcs.set_core_runtime_config(crc);
|
||||
|
||||
LOG_PRINT_L0("debug time shift set to " << time_shift << " : time before: " << time_before << ", time_after: " << time_after);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,13 @@ daemon_backend::~daemon_backend()
|
|||
stop();
|
||||
}
|
||||
|
||||
void terminate_handler_func()
|
||||
{
|
||||
LOG_ERROR("\n\nTERMINATE HANDLER\n"); // should print callstack
|
||||
std::fflush(nullptr); // all open output streams are flushed
|
||||
std::abort(); // default terminate handler's behavior
|
||||
}
|
||||
|
||||
bool daemon_backend::init(int argc, char* argv[], view::i_view* pview_handler)
|
||||
{
|
||||
m_stop_singal_sent = false;
|
||||
|
|
@ -88,6 +95,9 @@ bool daemon_backend::init(int argc, char* argv[], view::i_view* pview_handler)
|
|||
// setup custom callstack retrieving function
|
||||
epee::misc_utils::get_callstack(tools::get_callstack);
|
||||
|
||||
// setup custom terminate functions
|
||||
std::set_terminate(&terminate_handler_func);
|
||||
|
||||
//#if !defined(NDEBUG)
|
||||
// log_space::log_singletone::add_logger(LOGGER_DEBUGGER, nullptr, nullptr);
|
||||
//#endif
|
||||
|
|
@ -144,8 +154,8 @@ bool daemon_backend::init(int argc, char* argv[], view::i_view* pview_handler)
|
|||
m_data_dir = command_line::get_arg(m_vm, command_line::arg_data_dir);
|
||||
std::string config = command_line::get_arg(m_vm, command_line::arg_config_file);
|
||||
|
||||
boost::filesystem::path data_dir_path(m_data_dir);
|
||||
boost::filesystem::path config_path(config);
|
||||
boost::filesystem::path data_dir_path(epee::string_encoding::utf8_to_wstring(m_data_dir));
|
||||
boost::filesystem::path config_path(epee::string_encoding::utf8_to_wstring(config));
|
||||
if (!config_path.has_parent_path())
|
||||
{
|
||||
config_path = data_dir_path / config_path;
|
||||
|
|
@ -383,6 +393,7 @@ bool daemon_backend::deinit_local_daemon()
|
|||
LOG_PRINT_L0("Deinitializing p2p...");
|
||||
//dsi.text_state = "Deinitializing p2p";
|
||||
m_pview->update_daemon_status(dsi);
|
||||
m_p2psrv.deinit();
|
||||
|
||||
m_ccore.set_currency_protocol(NULL);
|
||||
m_cprotocol.set_p2p_endpoint(NULL);
|
||||
|
|
@ -429,7 +440,8 @@ void daemon_backend::main_worker(const po::variables_map& m_vm)
|
|||
//m_pview->update_daemon_status(dsi);
|
||||
try
|
||||
{
|
||||
wo.second.stop = true;
|
||||
wo.second.major_stop = true;
|
||||
wo.second.stop_for_refresh = true;
|
||||
wo.second.w.unlocked_get()->stop();
|
||||
|
||||
wo.second.w->get()->store();
|
||||
|
|
@ -543,7 +555,8 @@ void daemon_backend::init_wallet_entry(wallet_vs_options& wo, uint64_t id)
|
|||
{
|
||||
wo.wallet_id = id;
|
||||
wo.do_mining = false;
|
||||
wo.stop = false;
|
||||
wo.major_stop = false;
|
||||
wo.stop_for_refresh = false;
|
||||
wo.plast_daemon_height = &m_last_daemon_height;
|
||||
wo.plast_daemon_network_state = &m_last_daemon_network_state;
|
||||
wo.plast_daemon_is_disconnected = &m_last_daemon_is_disconnected;
|
||||
|
|
@ -837,7 +850,8 @@ std::string daemon_backend::close_wallet(size_t wallet_id)
|
|||
|
||||
try
|
||||
{
|
||||
it->second.stop = true;
|
||||
it->second.major_stop = true;
|
||||
it->second.stop_for_refresh = true;
|
||||
it->second.w.unlocked_get()->stop();
|
||||
|
||||
it->second.w->get()->store();
|
||||
|
|
@ -1488,8 +1502,9 @@ void daemon_backend::wallet_vs_options::worker_func()
|
|||
epee::math_helper::once_a_time_seconds<1> scan_pool_interval;
|
||||
epee::math_helper::once_a_time_seconds<POS_WALLET_MINING_SCAN_INTERVAL> pos_minin_interval;
|
||||
view::wallet_status_info wsi = AUTO_VAL_INIT(wsi);
|
||||
while (!stop)
|
||||
while (!major_stop)
|
||||
{
|
||||
stop_for_refresh = false;
|
||||
try
|
||||
{
|
||||
wsi.wallet_state = view::wallet_status_info::wallet_state_ready;
|
||||
|
|
@ -1516,7 +1531,7 @@ void daemon_backend::wallet_vs_options::worker_func()
|
|||
prepare_wallet_status_info(*this, wsi);
|
||||
pview->update_wallet_status(wsi);
|
||||
}
|
||||
w->get()->refresh(stop);
|
||||
w->get()->refresh(stop_for_refresh);
|
||||
w->get()->resend_unconfirmed();
|
||||
{
|
||||
auto w_ptr = *w; // get locked exclusive access to the wallet first (it's more likely that wallet is locked for a long time than 'offers')
|
||||
|
|
@ -1548,11 +1563,11 @@ void daemon_backend::wallet_vs_options::worker_func()
|
|||
});
|
||||
}
|
||||
|
||||
if (stop)
|
||||
if (major_stop || stop_for_refresh)
|
||||
break;
|
||||
//******************************************************************************************
|
||||
//mining zone
|
||||
if (do_mining)
|
||||
if (do_mining && *plast_daemon_network_state == currency::COMMAND_RPC_GET_INFO::daemon_network_state_online)
|
||||
{
|
||||
pos_minin_interval.do_call([this](){
|
||||
tools::wallet2::mining_context ctx = AUTO_VAL_INIT(ctx);
|
||||
|
|
@ -1614,7 +1629,8 @@ void daemon_backend::wallet_vs_options::worker_func()
|
|||
daemon_backend::wallet_vs_options::~wallet_vs_options()
|
||||
{
|
||||
do_mining = false;
|
||||
stop = true;
|
||||
major_stop = true;
|
||||
stop_for_refresh = true;
|
||||
break_mining_loop = true;
|
||||
if (miner_thread.joinable())
|
||||
miner_thread.join();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@ public:
|
|||
currency::core_runtime_config core_conf;
|
||||
epee::locked_object<std::shared_ptr<tools::wallet2>, wallet_lock_time_watching_policy> w;
|
||||
std::atomic<bool> do_mining;
|
||||
std::atomic<bool> stop;
|
||||
std::atomic<bool> major_stop;
|
||||
std::atomic<bool> stop_for_refresh; //use separate var for passing to "refresh" member function,
|
||||
//because it can be changed there due to internal interruption logis
|
||||
|
||||
std::atomic<bool> break_mining_loop;
|
||||
std::atomic<uint64_t> wallet_state;
|
||||
std::atomic<uint64_t> last_wallet_synch_height;
|
||||
|
|
|
|||
|
|
@ -75,14 +75,14 @@ namespace gui_tools
|
|||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
char pszPath[MAX_PATH] = "";
|
||||
wchar_t pszPath[MAX_PATH] = L"";
|
||||
|
||||
if (SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
|
||||
if (SHGetSpecialFolderPathW(NULL, pszPath, nFolder, fCreate))
|
||||
{
|
||||
return fs::path(pszPath);
|
||||
}
|
||||
|
||||
//LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
|
||||
//LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
|
||||
return fs::path("");
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -316,12 +316,12 @@ bool MainWindow::load_app_config()
|
|||
CATCH_ENTRY2(false);
|
||||
}
|
||||
|
||||
bool MainWindow::init(const std::string& htmlPath)
|
||||
bool MainWindow::init(const std::string& html_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
//QtWebEngine::initialize();
|
||||
init_tray_icon(htmlPath);
|
||||
set_html_path(htmlPath);
|
||||
init_tray_icon(html_path);
|
||||
set_html_path(html_path);
|
||||
|
||||
m_backend.subscribe_to_core_events(this);
|
||||
|
||||
|
|
@ -354,7 +354,7 @@ void MainWindow::on_menu_show()
|
|||
CATCH_ENTRY2(void());
|
||||
}
|
||||
|
||||
void MainWindow::init_tray_icon(const std::string& htmlPath)
|
||||
void MainWindow::init_tray_icon(const std::string& html_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
if (!QSystemTrayIcon::isSystemTrayAvailable())
|
||||
|
|
@ -384,14 +384,14 @@ void MainWindow::init_tray_icon(const std::string& htmlPath)
|
|||
|
||||
//setup icon
|
||||
#ifdef TARGET_OS_MAC
|
||||
m_normal_icon_path = htmlPath + "/files/app22macos.png"; // X11 tray icon size is 22x22
|
||||
m_blocked_icon_path = htmlPath + "/files/app22macos_blocked.png"; // X11 tray icon size is 22x22
|
||||
m_normal_icon_path = html_path + "/files/app22macos.png"; // X11 tray icon size is 22x22
|
||||
m_blocked_icon_path = html_path + "/files/app22macos_blocked.png"; // X11 tray icon size is 22x22
|
||||
#else
|
||||
m_normal_icon_path = htmlPath + "/files/app22windows.png"; // X11 tray icon size is 22x22
|
||||
m_blocked_icon_path = htmlPath + "/files/app22windows_blocked.png"; // X11 tray icon size
|
||||
m_normal_icon_path = html_path + "/files/app22windows.png"; // X11 tray icon size is 22x22
|
||||
m_blocked_icon_path = html_path + "/files/app22windows_blocked.png"; // X11 tray icon size
|
||||
#endif
|
||||
//setWindowIcon(QIcon(iconPath.c_str()));
|
||||
QIcon qi(m_normal_icon_path.c_str());
|
||||
QIcon qi( QString::fromWCharArray(epee::string_encoding::utf8_to_wstring(m_normal_icon_path).c_str()) );
|
||||
qi.setIsMask(true);
|
||||
m_tray_icon->setIcon(qi);
|
||||
m_tray_icon->setToolTip(CURRENCY_NAME_BASE);
|
||||
|
|
@ -411,7 +411,7 @@ void MainWindow::bool_toggle_icon(const QString& param)
|
|||
else
|
||||
path = m_normal_icon_path;
|
||||
|
||||
QIcon qi(path.c_str());
|
||||
QIcon qi( QString::fromWCharArray(epee::string_encoding::utf8_to_wstring(path).c_str()) );
|
||||
qi.setIsMask(true);
|
||||
m_tray_icon->setIcon(qi);
|
||||
CATCH_ENTRY2(void());
|
||||
|
|
@ -771,7 +771,7 @@ bool MainWindow::set_html_path(const std::string& path)
|
|||
TRY_ENTRY();
|
||||
//init_tray_icon(path);
|
||||
#ifdef _MSC_VER
|
||||
QString url = QString::fromUtf8(epee::string_encoding::convert_ansii_to_utf8(path).c_str()) + "/index.html";
|
||||
QString url = QString::fromUtf8(path.c_str()) + "/index.html";
|
||||
load_file(url);
|
||||
#else
|
||||
// load_file(QString((std::string("file://") + path + "/index.html").c_str()));
|
||||
|
|
@ -1037,7 +1037,7 @@ QString MainWindow::get_secure_app_data(const QString& param)
|
|||
const app_data_file_binary_header* phdr = reinterpret_cast<const app_data_file_binary_header*>(app_data_buff.data());
|
||||
if (phdr->m_signature != APP_DATA_FILE_BINARY_SIGNATURE)
|
||||
{
|
||||
LOG_ERROR("password missmatch: provided pass: " << pwd.pass);
|
||||
LOG_ERROR("password missmatch");
|
||||
view::api_response ar;
|
||||
ar.error_code = API_RETURN_CODE_WRONG_PASSWORD;
|
||||
return MAKE_RESPONSE(ar);
|
||||
|
|
@ -1232,7 +1232,7 @@ QString MainWindow::have_secure_app_data()
|
|||
view::api_response ar = AUTO_VAL_INIT(ar);
|
||||
|
||||
boost::system::error_code ec;
|
||||
if (boost::filesystem::exists(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, ec))
|
||||
if (boost::filesystem::exists(epee::string_encoding::utf8_to_wstring(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME), ec))
|
||||
ar.error_code = API_RETURN_CODE_TRUE;
|
||||
else
|
||||
ar.error_code = API_RETURN_CODE_FALSE;
|
||||
|
|
@ -1240,6 +1240,7 @@ QString MainWindow::have_secure_app_data()
|
|||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
||||
QString MainWindow::drop_secure_app_data()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
|
@ -1247,13 +1248,14 @@ QString MainWindow::drop_secure_app_data()
|
|||
view::api_response ar = AUTO_VAL_INIT(ar);
|
||||
|
||||
boost::system::error_code ec;
|
||||
if (boost::filesystem::remove(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME, ec))
|
||||
if (boost::filesystem::remove(epee::string_encoding::utf8_to_wstring(m_backend.get_config_folder() + "/" + GUI_SECURE_CONFIG_FILENAME), ec))
|
||||
ar.error_code = API_RETURN_CODE_TRUE;
|
||||
else
|
||||
ar.error_code = API_RETURN_CODE_FALSE;
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
||||
QString MainWindow::get_all_aliases()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"FORM_ERRORS": {
|
||||
"PASS_REQUIRED": "Passwort ist erforderlich",
|
||||
"CONFIRM_REQUIRED": "Bestätigung ist erforderlich",
|
||||
"MISMATCH": "Mismatch"
|
||||
"MISMATCH": "Fehlanpassung"
|
||||
}
|
||||
},
|
||||
"COMMON": {
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
"TITLE": "Wallets",
|
||||
"ADD_NEW": "+ Hinzufügen",
|
||||
"ACCOUNT": {
|
||||
"STAKING": "Staking (Anlegen)",
|
||||
"STAKING": "Staking",
|
||||
"MESSAGES": "Neue Angebote/Nachrichten",
|
||||
"SYNCING": "Wallet synchronisieren"
|
||||
},
|
||||
|
|
@ -159,15 +159,15 @@
|
|||
"PASS_NOT_MATCH": "Old password not match",
|
||||
"CONFIRM_NOT_MATCH": "Confirm password not match"
|
||||
},
|
||||
"LAST_BUILD": "Current build: {{value}}",
|
||||
"APP_LOG_TITLE": "Log level:"
|
||||
"LAST_BUILD": "Aktueller Build: {{value}}",
|
||||
"APP_LOG_TITLE": "Log-Level:"
|
||||
},
|
||||
"WALLET": {
|
||||
"REGISTER_ALIAS": "Alias registrieren",
|
||||
"DETAILS": "Details",
|
||||
"LOCK": "Verschlüsseln",
|
||||
"AVAILABLE_BALANCE": "Verfügbar <b>{{verfügbar}} {{Währung}}<b/>",
|
||||
"LOCKED_BALANCE": "Gesperrt <b>{{gesperrt}} {{Währung}}<b/>",
|
||||
"AVAILABLE_BALANCE": "Verfügbar <b>{{available}} {{currency}}<b/>",
|
||||
"LOCKED_BALANCE": "Gesperrt <b>{{locked}} {{currency}}<b/>",
|
||||
"LOCKED_BALANCE_LINK": "Was bedeutet das?",
|
||||
"TABS": {
|
||||
"SEND": "Senden",
|
||||
|
|
@ -175,7 +175,7 @@
|
|||
"HISTORY": "Verlauf",
|
||||
"CONTRACTS": "Verträge",
|
||||
"MESSAGES": "Nachrichten",
|
||||
"STAKING": "Staking (Anlegen)"
|
||||
"STAKING": "Staking"
|
||||
}
|
||||
},
|
||||
"WALLET_DETAILS": {
|
||||
|
|
@ -195,14 +195,14 @@
|
|||
"NAME": {
|
||||
"LABEL": "Alias",
|
||||
"PLACEHOLDER": "@ Alias eingeben",
|
||||
"TOOLTIP": "An alias is a shortened form or your account. An alias can only include Latin letters, numbers and characters “.” and “-”. It must start with “@”."
|
||||
"TOOLTIP": "Ein Alias ist eine verkürzte Form Ihres Kontos. Ein Alias kann nur lateinische Buchstaben, Zahlen und die Zeichen „.“ und “-” enthalten. Es muss mit “@” beginnen."
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Kommentar",
|
||||
"PLACEHOLDER": "",
|
||||
"TOOLTIP": "The comment will be visible to anyone who wants to make a payment to your alias. You can provide details about your business, contacts, or include any text. Comments can be edited later."
|
||||
"TOOLTIP": "Der Kommentar wird für jeden sichtbar sein, der eine Zahlung an Ihren Alias vornehmen möchte. Sie können Details über Ihre Geschäfte, Kontakte oder Text angeben. Kommentare können später bearbeitet werden."
|
||||
},
|
||||
"COST": "Alias fee {{value}} {{currency}}",
|
||||
"COST": "Alias-Gebühr {{value}} {{currency}}",
|
||||
"BUTTON_ASSIGN": "Zuweisen",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name ist erforderlich",
|
||||
|
|
@ -228,7 +228,7 @@
|
|||
"NO_MONEY": "Sie haben nicht genügend Geldmittel, um den Kommentar zu diesem Alias zu ändern",
|
||||
"MAX_LENGTH": "Maximale Kommentarlänge erreicht"
|
||||
},
|
||||
"COST": "Gebühr {{Wert}} {{Währung}}",
|
||||
"COST": "Gebühr {{value}} {{currency}}",
|
||||
"BUTTON_EDIT": "Bearbeiten"
|
||||
},
|
||||
"TRANSFER_ALIAS": {
|
||||
|
|
@ -249,7 +249,7 @@
|
|||
"ALIAS_EXISTS": "Dieses Konto hat bereits einen Alias",
|
||||
"NO_MONEY": "Du hast nicht genug Geldmittel, um diesen Alias zu transferieren"
|
||||
},
|
||||
"COST": "Transfer fee {{value}} {{currency}}",
|
||||
"COST": "Überweisungsgebühr {{value}} {{currency}}",
|
||||
"BUTTON_TRANSFER": "Transfer",
|
||||
"BUTTON_CANCEL": "Abbrechen",
|
||||
"REQUEST_SEND_REG": "Der Alias wird innerhalb von 10 Minuten übertragen"
|
||||
|
|
@ -271,14 +271,14 @@
|
|||
"AMOUNT_REQUIRED": "Betrag ist erforderlich",
|
||||
"AMOUNT_ZERO": "Betrag ist Null",
|
||||
"FEE_REQUIRED": "Gebühr ist erforderlich",
|
||||
"FEE_MINIMUM": "Mindestgebühr: {{Gebühr}}",
|
||||
"FEE_MINIMUM": "Mindestgebühr: {{fee}}",
|
||||
"MAX_LENGTH": "Maximale Kommentarlänge erreicht"
|
||||
}
|
||||
},
|
||||
"HISTORY": {
|
||||
"STATUS": "Status",
|
||||
"STATUS_TOOLTIP": "Confirmations {{current}}/{{total}}",
|
||||
"LOCK_TOOLTIP": "Gesperrt bis {{Datum}}",
|
||||
"STATUS_TOOLTIP": "Bestätigungen {{current}}/{{total}}",
|
||||
"LOCK_TOOLTIP": "Gesperrt bis {{date}}",
|
||||
"SEND": "Gesendet",
|
||||
"RECEIVED": "Empfangen",
|
||||
"DATE": "Datum",
|
||||
|
|
@ -289,7 +289,7 @@
|
|||
"PAYMENT_ID": "Zahlungs-ID",
|
||||
"ID": "Transaktions-ID",
|
||||
"SIZE": "Transaktionsgröße",
|
||||
"SIZE_VALUE": "{{Wert}} Bytes",
|
||||
"SIZE_VALUE": "{{value}} Bytes",
|
||||
"HEIGHT": "Höhe",
|
||||
"CONFIRMATION": "Bestätigung",
|
||||
"INPUTS": "Inputs",
|
||||
|
|
@ -306,10 +306,10 @@
|
|||
"POW_REWARD": "POW-Belohnung",
|
||||
"POS_REWARD": "POS-Belohnung",
|
||||
"CREATE_CONTRACT": "Vertragsvorschlag",
|
||||
"PLEDGE_CONTRACT": "Contract deposit",
|
||||
"PLEDGE_CONTRACT": "Vertrag-Einzahlung",
|
||||
"NULLIFY_CONTRACT": "Einzahlungen verbrennen",
|
||||
"PROPOSAL_CANCEL_CONTRACT": "Stornierungsanfrage",
|
||||
"CANCEL_CONTRACT": "Cancel and return deposits"
|
||||
"CANCEL_CONTRACT": "Abbrechen und Einzahlungen zurückzahlen"
|
||||
}
|
||||
},
|
||||
"CONTRACTS": {
|
||||
|
|
@ -322,17 +322,17 @@
|
|||
"STATUS": "Status",
|
||||
"COMMENTS": "Kommentare",
|
||||
"PURCHASE_BUTTON": "Neuer Kauf",
|
||||
"LISTING_BUTTON": "Create listing",
|
||||
"LISTING_BUTTON": "Auflistung erstellen",
|
||||
"TIME_LEFT": {
|
||||
"REMAINING_LESS_ONE": "Weniger als eine Stunde, um zu antworten",
|
||||
"REMAINING_ONE": "{{Zeit}} verbleibende Stunde",
|
||||
"REMAINING_MANY": "{{Zeit}} verbleibende Stunden",
|
||||
"REMAINING_MANY_ALT": "{{Zeit}} verbleibende Stunden",
|
||||
"REMAINING_ONE_RESPONSE": "{{Zeit}} verbleibende Stunde",
|
||||
"REMAINING_MANY_RESPONSE": "{{Zeit}} verbleibende Stunde",
|
||||
"REMAINING_MANY_ALT_RESPONSE": "{{Zeit}} verbleibende Stunden",
|
||||
"REMAINING_ONE_WAITING": "Warte für {{Zeit}} Stunde",
|
||||
"REMAINING_MANY_WAITING": "Warte für {{Zeit}} Stunden",
|
||||
"REMAINING_ONE": "{{time}} verbleibende Stunde",
|
||||
"REMAINING_MANY": "{{time}} verbleibende Stunden",
|
||||
"REMAINING_MANY_ALT": "{{time}} verbleibende Stunden",
|
||||
"REMAINING_ONE_RESPONSE": "{{time}} verbleibende Stunde",
|
||||
"REMAINING_MANY_RESPONSE": "{{time}} verbleibende Stunde",
|
||||
"REMAINING_MANY_ALT_RESPONSE": "{{time}} verbleibende Stunden",
|
||||
"REMAINING_ONE_WAITING": "Warte für {{time}} Stunde",
|
||||
"REMAINING_MANY_WAITING": "Warte für {{time}} Stunden",
|
||||
"REMAINING_MANY_ALT_WAITING": "Warte für {{Zeit}} Stunden"
|
||||
},
|
||||
"STATUS_MESSAGES": {
|
||||
|
|
@ -354,7 +354,7 @@
|
|||
"BUYER": {
|
||||
"WAITING": "Warte auf Antwort",
|
||||
"IGNORED": "Verkäufer ignorierte Ihren Vertragsvorschlag",
|
||||
"ACCEPTED": "Seller accepted your contract proposal",
|
||||
"ACCEPTED": "Verkäufer hat Ihren Vertragsvorschlag akzeptiert",
|
||||
"WAIT": "Warten auf die Bestätigung der Einzahlungen",
|
||||
"WAITING_SELLER": "Warte auf Sendung",
|
||||
"COMPLETED": "Vertrag abgeschlossen",
|
||||
|
|
@ -381,7 +381,7 @@
|
|||
"SEND_BUTTON": "Senden",
|
||||
"FORM_ERRORS": {
|
||||
"DESC_REQUIRED": "Beschreibung erforderlich",
|
||||
"DESC_MAXIMUM": "Maximum field length reached",
|
||||
"DESC_MAXIMUM": "Maximale Feldlänge erreicht",
|
||||
"SELLER_REQUIRED": "Adresse benötigt",
|
||||
"SELLER_NOT_VALID": "Ungültige Adresse",
|
||||
"ALIAS_NOT_VALID": "Ungültiger Alias",
|
||||
|
|
@ -390,7 +390,7 @@
|
|||
"YOUR_DEPOSIT_REQUIRED": "Einzahlung erforderlich",
|
||||
"SELLER_DEPOSIT_REQUIRED": "Verkäufer-Einzahlung erforderlich",
|
||||
"SELLER_SAME": "Anderes Konto verwenden",
|
||||
"COMMENT_MAXIMUM": "Maximum field length reached"
|
||||
"COMMENT_MAXIMUM": "Maximale Feldlänge erreicht"
|
||||
},
|
||||
"PROGRESS_NEW": "Neuer Kauf",
|
||||
"PROGRESS_WAIT": "Warte auf Antwort",
|
||||
|
|
@ -428,7 +428,7 @@
|
|||
"NEED_MONEY": "Unzureichendes Guthaben",
|
||||
"BUTTON_MAKE_PLEDGE": "Akzeptieren und Einzahlung tätigen",
|
||||
"BUTTON_IGNORE": "Angebot ignorieren und ausblenden",
|
||||
"BUTTON_NULLIFY": "Terminate and burn deposits",
|
||||
"BUTTON_NULLIFY": "Beenden und Einzahlungen verbrennen",
|
||||
"BUTTON_RECEIVED": "Einzahlungen abschließen und freigeben",
|
||||
"BUTTON_CANCEL_BUYER": "Einzahlungen abbrechen und zurückzahlen",
|
||||
"BUTTON_NOT_CANCEL": "Anfrage ignorieren",
|
||||
|
|
@ -464,7 +464,7 @@
|
|||
}
|
||||
},
|
||||
"STAKING": {
|
||||
"TITLE": "Staking (Anlegen)",
|
||||
"TITLE": "Staking",
|
||||
"TITLE_PENDING": "Ausstehend",
|
||||
"TITLE_TOTAL": "Gesamt",
|
||||
"TITLE_PERIOD": "Zeitspanne:",
|
||||
|
|
@ -518,7 +518,7 @@
|
|||
"ADDRESS_NOT_VALID": "Adresse ungültig",
|
||||
"SET_MASTER_PASSWORD": "Master-Passwort festlegen",
|
||||
"ADDRESS_DUBLICATED": "Adresse existiert bereits",
|
||||
"MAX_LENGTH": "Maximum notes length reached",
|
||||
"MAX_LENGTH": "Maximale Länge der Notiz erreicht",
|
||||
"NAME_LENGTH": "Der Name muss 4-25 Zeichen lang sein"
|
||||
},
|
||||
"BUTTON": {
|
||||
|
|
@ -532,19 +532,21 @@
|
|||
},
|
||||
"SUCCESS_SENT": "Kontakt hinzugefügt",
|
||||
"SUCCESS_SAVE": "Kontakt wurde bearbeitet",
|
||||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"SUCCESS_IMPORT": "Kontakte wurden importiert",
|
||||
"SUCCESS_EXPORT": "Kontakte wurden exportiert",
|
||||
"ERROR_IMPORT": "Fehler beim Lesen der Datei!",
|
||||
"ERROR_TYPE_FILE": "Bitte importieren Sie eine gültige .csv Datei.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Ungültiger Dateityp. Datei als .csv speichern",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Nicht genügend Geld",
|
||||
"NOT_ENOUGH_MONEY": "Unzureichendes Guthaben im Konto",
|
||||
"CORE_BUSY": "Interner Fehler: Kern ist beschäftigt",
|
||||
"DAEMON_BUSY": "Interner Fehler: Daemon ist beschäftigt",
|
||||
"NO_MONEY_REMOVE_OFFER": "There is no fee for deleting an offer, but in order to protect the network against flood transactions you need to have at least {{fee}} {{currency}} in your wallet",
|
||||
"NOT_ENOUGH_OUTPUTS_TO_MIX": "Mix-in number is too big for current blockchain state. There are not enough unspent outputs to mix with",
|
||||
"NO_MONEY_REMOVE_OFFER": "Es gibt keine Gebühr für das Löschen eines Angebots, aber um das Netzwerk vor Spam-Transaktionen zu schützen, müssen Sie mindestens {{fee}} {{currency}} in Ihrer Wallet haben",
|
||||
"NOT_ENOUGH_OUTPUTS_TO_MIX": "Mix-in-Nummer ist zu groß für den aktuellen Blockchain-Status. Nicht genügend unverbrauchte outputs zum Mischen",
|
||||
"TRANSACTION_IS_TO_BIG": "Transaktion überschreitet das Netzwerk-Limit. Sendet benötigten Betrag mit mehreren Transaktionen.",
|
||||
"TRANSFER_ATTEMPT": "Keine Verbindung zum Zano-Netzwerk",
|
||||
"ACCESS_DENIED": "Zugriff verweigert",
|
||||
|
|
@ -561,7 +563,7 @@
|
|||
"TX_TYPE_NORMAL_END": "wurde nicht abgeschlossen.",
|
||||
"TX_TYPE_NEW_ALIAS": "Fehler. Fehler beim Registrieren des Alias zum Speichern",
|
||||
"TX_TYPE_NEW_ALIAS_END": "Bitte nochmals versuchen.",
|
||||
"TX_TYPE_UPDATE_ALIAS": "Error. Failed to change comment to alias in safe",
|
||||
"TX_TYPE_UPDATE_ALIAS": "Fehler. Fehlgeschlagen Kommentar von gespeichertem Alias zu ändern",
|
||||
"TX_TYPE_COIN_BASE": "Fehler. Die Zahlung wurde nicht abgeschlossen."
|
||||
},
|
||||
"CONTEXT_MENU": {
|
||||
|
|
@ -577,8 +579,8 @@
|
|||
"INCOME_TRANSFER_CONFIRMED": "Zahlung erhalten",
|
||||
"MINED": "Mined",
|
||||
"LOCKED": "Blockiert",
|
||||
"IS_MINIMIZE": "Zano application is minimized to the system tray",
|
||||
"RESTORE": "You can recover it by clicking or using the context menu",
|
||||
"IS_MINIMIZE": "Zano-Anwendung wird auf die Systemleiste minimiert",
|
||||
"RESTORE": "Sie können es wiederherstellen, indem Sie auf das Kontextmenü benutzen oder anklicken ",
|
||||
"TRAY_MENU_SHOW": "Größe ändern",
|
||||
"TRAY_MENU_MINIMIZE": "Minimieren"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -39,15 +39,18 @@
|
|||
"SYNCING": "Syncing wallet"
|
||||
},
|
||||
"CONTACTS": "Contacts",
|
||||
"CONTACTS_TOOLTIP": "Contacts option available only with Master Password enabled",
|
||||
"SETTINGS": "Settings",
|
||||
"LOG_OUT": "Log out",
|
||||
"LOG_OUT_TOOLTIP": "Logout option available only with Master Password enabled",
|
||||
"SYNCHRONIZATION": {
|
||||
"OFFLINE": "Offline",
|
||||
"ONLINE": "Online",
|
||||
"ERROR": "System error",
|
||||
"COMPLETE": "Completion",
|
||||
"SYNCING": "Syncing blockchain",
|
||||
"LOADING": "Loading blockchain data"
|
||||
"SYNCING": "Syncing block",
|
||||
"LOADING": "Loading blockchain data",
|
||||
"SLASH": "/"
|
||||
},
|
||||
"UPDATE": {
|
||||
"STANDARD": "Update available",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Erreur lors de la lecture du fichier !",
|
||||
"ERROR_TYPE_FILE": "Veuillez importer un fichier .csv valide.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Pas assez de fonds",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Si è verificato un errore durante la lettura del file!",
|
||||
"ERROR_TYPE_FILE": "Importa un file .csv valido.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Non abbastanza denaro",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
|
|
@ -535,8 +535,10 @@
|
|||
"SUCCESS_IMPORT": "Contacts are imported",
|
||||
"SUCCESS_EXPORT": "Contacts are exported",
|
||||
"ERROR_IMPORT": "Error is occured while reading file!",
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file.",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv"
|
||||
"ERROR_TYPE_FILE": "Please import valid .csv file",
|
||||
"ERROR_EXPORT": "Invalid file type. Save file as .csv",
|
||||
"ERROR_EMPTY_LIST": "Contact list is empty",
|
||||
"ERROR_IMPORT_EMPTY": "File is empty"
|
||||
},
|
||||
"ERRORS": {
|
||||
"NO_MONEY": "Not enough money",
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -5800,8 +5800,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
__webpack_require__(/*! C:\Users\butsd\Documents\Projects\Projects now\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! C:\Users\butsd\Documents\Projects\Projects now\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__(/*! 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");
|
||||
|
||||
|
||||
/***/ })
|
||||
|
|
|
|||
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 it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -22,6 +22,7 @@ export class VariablesService {
|
|||
public exp_med_ts = 0;
|
||||
public net_time_delta_median = 0;
|
||||
public height_app = 0;
|
||||
public height_max = 0;
|
||||
public last_build_available = '';
|
||||
public last_build_displaymode = 0;
|
||||
public daemon_state = 3;
|
||||
|
|
@ -59,18 +60,23 @@ export class VariablesService {
|
|||
|
||||
getExpMedTsEvent = new BehaviorSubject(null);
|
||||
getHeightAppEvent = new BehaviorSubject(null);
|
||||
getHeightMaxEvent = new BehaviorSubject(null);
|
||||
getRefreshStackingEvent = new BehaviorSubject(null);
|
||||
getAliasChangedEvent = new BehaviorSubject(null);
|
||||
|
||||
public idle = new Idle()
|
||||
.whenNotInteractive()
|
||||
.do(() => {
|
||||
this.ngZone.run(() => {
|
||||
if (this.appPass == '') {
|
||||
this.restartCountdown();
|
||||
} else {
|
||||
this.ngZone.run(() => {
|
||||
this.idle.stop();
|
||||
this.appPass = '';
|
||||
this.appLogin = false;
|
||||
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
public allContextMenu: ContextMenuComponent;
|
||||
|
|
@ -94,6 +100,13 @@ export class VariablesService {
|
|||
}
|
||||
}
|
||||
|
||||
setHeightMax(height: number) {
|
||||
if (height !== this.height_max) {
|
||||
this.height_max = height;
|
||||
this.getHeightMaxEvent.next(height);
|
||||
}
|
||||
}
|
||||
|
||||
setRefreshStacking(wallet_id: number) {
|
||||
this.getHeightAppEvent.next(wallet_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
this.variablesService.last_build_available = data.last_build_available;
|
||||
this.variablesService.last_build_displaymode = data.last_build_displaymode;
|
||||
this.variablesService.setHeightApp(data.height);
|
||||
this.variablesService.setHeightMax(data.max_net_seen_height);
|
||||
|
||||
this.ngZone.run(() => {
|
||||
this.variablesService.daemon_state = data['daemon_network_state'];
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ export class ExportImportComponent implements OnInit {
|
|||
header: true
|
||||
};
|
||||
const elements = this.papa.parse(data, options);
|
||||
|
||||
if (elements.data && !elements.errors.length) {
|
||||
const isArray = Array.isArray(elements.data);
|
||||
if (isArray && elements.data.length !== 0 && !elements.errors.length) {
|
||||
if (!this.variablesService.contacts.length) {
|
||||
elements.data.forEach(element => {
|
||||
this.variablesService.contacts.push(element);
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
this.variablesService.dataIsLoaded = true;
|
||||
this.variablesService.startCountdown();
|
||||
this.variablesService.appPass = appPass;
|
||||
const isEmptyObject = Object.keys(data).length === 0 && data.constructor === Object;
|
||||
|
||||
if (this.variablesService.wallets.length) {
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.variablesService.wallets[0].wallet_id]);
|
||||
|
|
@ -131,7 +133,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
if (!data.hasOwnProperty('wallets') && !data.hasOwnProperty('contacts')) {
|
||||
if (data.length !== 0) {
|
||||
if (data.length !== 0 && !isEmptyObject) {
|
||||
this.getWalletData(data);
|
||||
} else {
|
||||
this.ngZone.run(() => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
background-position: center;
|
||||
background-size: 200%;
|
||||
padding: 2rem;
|
||||
width: 34rem;
|
||||
min-width: 34rem;
|
||||
max-width: 64rem;
|
||||
|
||||
.title {
|
||||
font-size: 1.8rem;
|
||||
|
|
@ -28,6 +29,8 @@
|
|||
.wallet-path {
|
||||
font-size: 1.3rem;
|
||||
margin: 5rem 0 2rem;
|
||||
word-wrap: break-word;
|
||||
line-height: 2rem;
|
||||
}
|
||||
|
||||
.wrap-button {
|
||||
|
|
|
|||
|
|
@ -38,32 +38,48 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="sidebar-settings">
|
||||
<div class="wrap-button" routerLinkActive="active">
|
||||
<button (click)="contactsRoute()" [class.disabled]="variablesService.daemon_state !== 2" [disabled]="variablesService.daemon_state !== 2">
|
||||
<div class="wrap-button" routerLinkActive="active" *ngIf="variablesService.appPass === ''; else contactsShow" tooltip="{{ 'SIDEBAR.CONTACTS_TOOLTIP' | translate }}" placement="top" tooltipClass="table-tooltip account-tooltip" [delay]="500">
|
||||
<button (click)="contactsRoute()" [class.disabled]="variablesService.daemon_state !== 2 || variablesService.appPass === ''" [disabled]="variablesService.daemon_state !== 2 || variablesService.appPass === ''">
|
||||
<i class="icon contacts"></i>
|
||||
<span>{{ 'SIDEBAR.CONTACTS' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<ng-template #contactsShow>
|
||||
<div class="wrap-button" routerLinkActive="active">
|
||||
<button (click)="contactsRoute()">
|
||||
<i class="icon contacts"></i>
|
||||
<span>{{ 'SIDEBAR.CONTACTS' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="wrap-button" routerLinkActive="active">
|
||||
<button [routerLink]="['/settings']">
|
||||
<i class="icon settings"></i>
|
||||
<span>{{ 'SIDEBAR.SETTINGS' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="wrap-button">
|
||||
<button (click)="logOut()">
|
||||
<div class="wrap-button" *ngIf="variablesService.appPass === ''; else masterPass" tooltip="{{ 'SIDEBAR.LOG_OUT_TOOLTIP' | translate }}" placement="bottom" tooltipClass="table-tooltip account-tooltip" [delay]="500">
|
||||
<button (click)="logOut()" [class.disabled]="variablesService.appPass === ''" [disabled]="variablesService.appPass === ''">
|
||||
<i class="icon logout"></i>
|
||||
<span>{{ 'SIDEBAR.LOG_OUT' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<ng-template #masterPass>
|
||||
<div class="wrap-button">
|
||||
<button (click)="logOut()">
|
||||
<i class="icon logout"></i>
|
||||
<span>{{ 'SIDEBAR.LOG_OUT' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="sidebar-synchronization-status">
|
||||
<div class="sidebar-synchronization-status" [ngStyle]="{'align-items': variablesService.daemon_state === 1 ? 'flex-start' : 'center'}">
|
||||
<div class="status-container">
|
||||
<span class="offline" *ngIf="variablesService.daemon_state === 0">
|
||||
{{ 'SIDEBAR.SYNCHRONIZATION.OFFLINE' | translate }}
|
||||
</span>
|
||||
<span class="syncing" *ngIf="variablesService.daemon_state === 1">
|
||||
{{ 'SIDEBAR.SYNCHRONIZATION.SYNCING' | translate }}
|
||||
{{ 'SIDEBAR.SYNCHRONIZATION.SYNCING' | translate }} {{ variablesService.height_app }}{{ 'SIDEBAR.SYNCHRONIZATION.SLASH' | translate }}{{ variablesService.height_max }}
|
||||
</span>
|
||||
<span class="online" *ngIf="variablesService.daemon_state === 2">
|
||||
{{ 'SIDEBAR.SYNCHRONIZATION.ONLINE' | translate }}
|
||||
|
|
@ -118,3 +134,4 @@
|
|||
<i class="icon time" tooltip="{{ 'SIDEBAR.UPDATE.TIME_TOOLTIP' | translate }}" placement="right-bottom" tooltipClass="update-tooltip important" [delay]="500"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@
|
|||
}
|
||||
|
||||
.syncing, .loading {
|
||||
line-height: 4rem;
|
||||
line-height: 5rem;
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
|
|
@ -279,7 +279,7 @@
|
|||
font-size: 1.3rem;
|
||||
line-height: 0.7rem;
|
||||
padding-left: 0.7rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
|
|
|
|||
|
|
@ -39,15 +39,18 @@
|
|||
"SYNCING": "Syncing wallet"
|
||||
},
|
||||
"CONTACTS": "Contacts",
|
||||
"CONTACTS_TOOLTIP": "Contacts option available only with Master Password enabled",
|
||||
"SETTINGS": "Settings",
|
||||
"LOG_OUT": "Log out",
|
||||
"LOG_OUT_TOOLTIP": "Logout option available only with Master Password enabled",
|
||||
"SYNCHRONIZATION": {
|
||||
"OFFLINE": "Offline",
|
||||
"ONLINE": "Online",
|
||||
"ERROR": "System error",
|
||||
"COMPLETE": "Completion",
|
||||
"SYNCING": "Syncing blockchain",
|
||||
"LOADING": "Loading blockchain data"
|
||||
"SYNCING": "Syncing block",
|
||||
"LOADING": "Loading blockchain data",
|
||||
"SLASH": "/"
|
||||
},
|
||||
"UPDATE": {
|
||||
"STANDARD": "Update available",
|
||||
|
|
|
|||
|
|
@ -42,25 +42,37 @@ int main(int argc, char *argv[])
|
|||
#endif
|
||||
|
||||
|
||||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#ifdef WIN32
|
||||
WCHAR sz_file_name[MAX_PATH + 1] = L"";
|
||||
::GetModuleFileNameW(NULL, sz_file_name, MAX_PATH + 1);
|
||||
std::string path_to_process_utf8 = epee::string_encoding::wstring_to_utf8(sz_file_name);
|
||||
#else
|
||||
std::string path_to_process_utf8 = argv[0];
|
||||
#endif
|
||||
|
||||
TRY_ENTRY();
|
||||
epee::string_tools::set_module_name_and_folder(path_to_process_utf8);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1910
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
|
||||
qputenv("QT_SCALE_FACTOR", "0.75");
|
||||
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
|
||||
qputenv("QT_SCALE_FACTOR", "0.75");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
MainWindow viewer;
|
||||
if (!viewer.init_backend(argc, argv))
|
||||
{
|
||||
static_cast<view::i_view*>(&viewer)->show_msg_box("Failed to initialize backend, check debug logs for more details.");
|
||||
return 1;
|
||||
}
|
||||
app.installNativeEventFilter(&viewer);
|
||||
viewer.setWindowTitle(CURRENCY_NAME_BASE);
|
||||
viewer.show_inital();
|
||||
|
||||
return app.exec();
|
||||
QApplication app(argc, argv);
|
||||
MainWindow viewer;
|
||||
if (!viewer.init_backend(argc, argv))
|
||||
{
|
||||
static_cast<view::i_view*>(&viewer)->show_msg_box("Failed to initialize backend, check debug logs for more details.");
|
||||
return 1;
|
||||
}
|
||||
app.installNativeEventFilter(&viewer);
|
||||
viewer.setWindowTitle(CURRENCY_NAME_BASE);
|
||||
viewer.show_inital();
|
||||
|
||||
int res = app.exec();
|
||||
LOG_PRINT_L0("Process exit with code: " << res);
|
||||
return res;
|
||||
CATCH_ENTRY2(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,11 +131,14 @@ namespace nodetool
|
|||
HANDLE_INVOKE_T2(COMMAND_TIMED_SYNC, &node_server::handle_timed_sync)
|
||||
HANDLE_INVOKE_T2(COMMAND_PING, &node_server::handle_ping)
|
||||
#ifdef ALLOW_DEBUG_COMMANDS
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_LOG, &node_server::handle_request_log)
|
||||
HANDLE_INVOKE_T2(COMMAND_SET_LOG_LEVEL, &node_server::handle_set_log_level)
|
||||
if (m_debug_requests_enabled)
|
||||
{
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_LOG, &node_server::handle_request_log)
|
||||
HANDLE_INVOKE_T2(COMMAND_SET_LOG_LEVEL, &node_server::handle_set_log_level)
|
||||
}
|
||||
#endif
|
||||
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
|
||||
END_INVOKE_MAP2()
|
||||
|
|
@ -239,6 +242,7 @@ namespace nodetool
|
|||
bool m_allow_local_ip;
|
||||
bool m_hide_my_port;
|
||||
bool m_offline_mode;
|
||||
bool m_debug_requests_enabled;
|
||||
uint64_t m_startup_time;
|
||||
|
||||
//critical_section m_connections_lock;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ namespace nodetool
|
|||
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_offline_mode = { "offline-mode", "Don't connect to any node and reject any connections", false, true };
|
||||
const command_line::arg_descriptor<bool> arg_p2p_disable_debug_reqs = { "disable-debug-p2p-requests", "Disable p2p debug requests", false, true };
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
|
@ -51,6 +52,7 @@ namespace nodetool
|
|||
command_line::add_arg(desc, arg_p2p_seed_node);
|
||||
command_line::add_arg(desc, arg_p2p_hide_my_port);
|
||||
command_line::add_arg(desc, arg_p2p_offline_mode);
|
||||
command_line::add_arg(desc, arg_p2p_disable_debug_reqs);
|
||||
command_line::add_arg(desc, arg_p2p_use_only_priority_nodes);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
|
@ -158,6 +160,7 @@ namespace nodetool
|
|||
m_external_port = command_line::get_arg(vm, arg_p2p_external_port);
|
||||
m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip);
|
||||
m_offline_mode = command_line::get_arg(vm, arg_p2p_offline_mode);
|
||||
m_debug_requests_enabled = !command_line::get_arg(vm, arg_p2p_disable_debug_reqs);
|
||||
|
||||
if (m_offline_mode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -154,11 +154,6 @@ namespace
|
|||
return message_writer(color ? epee::log_space::console_color_green : epee::log_space::console_color_default, false, std::string(), LOG_LEVEL_2);
|
||||
}
|
||||
|
||||
message_writer success_msg_writer(epee::log_space::console_colors color)
|
||||
{
|
||||
return message_writer(color, true, std::string(), LOG_LEVEL_2);
|
||||
}
|
||||
|
||||
message_writer fail_msg_writer()
|
||||
{
|
||||
return message_writer(epee::log_space::console_color_red, true, "Error: ", LOG_LEVEL_0);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
#include "misc_language.h"
|
||||
|
||||
#define BUILD_COMMIT_ID "@VERSION@"
|
||||
#define PROJECT_VERSION "1.0"
|
||||
#define PROJECT_VERSION_BUILD_NO 49
|
||||
|
||||
#define PROJECT_MAJOR_VERSION "1"
|
||||
#define PROJECT_MINOR_VERSION "1"
|
||||
#define PROJECT_REVISION "0"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 59
|
||||
#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 "]"
|
||||
|
|
|
|||
|
|
@ -1890,7 +1890,7 @@ void wallet2::load_keys2ki(bool create_if_not_exist, bool& need_to_resync)
|
|||
m_pending_key_images.clear();
|
||||
for (size_t i = 0, size = m_pending_key_images_file_container.size(); i < size; ++i)
|
||||
{
|
||||
out_key_to_ki item = AUTO_VAL_INIT(item);
|
||||
out_key_to_ki item = AUTO_VAL_INIT_T(out_key_to_ki);
|
||||
ok = m_pending_key_images_file_container.get_item(i, item);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(ok, "m_pending_key_images_file_container.get_item() failed for index " << i << ", size: " << m_pending_key_images_file_container.size());
|
||||
ok = m_pending_key_images.insert(std::make_pair(item.out_key, item.key_image)).second;
|
||||
|
|
@ -4002,7 +4002,7 @@ 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)
|
||||
{
|
||||
TIME_MEASURE_START_MS(construct_tx_time);
|
||||
//TIME_MEASURE_START_MS(construct_tx_time);
|
||||
bool r = currency::construct_tx(m_account.get_keys(),
|
||||
ftp.sources,
|
||||
ftp.prepared_destinations,
|
||||
|
|
@ -4016,10 +4016,10 @@ void wallet2::finalize_transaction(const finalize_tx_param& ftp, currency::trans
|
|||
ftp.tx_outs_attr,
|
||||
ftp.shuffle,
|
||||
ftp.flags);
|
||||
TIME_MEASURE_FINISH_MS(construct_tx_time);
|
||||
//TIME_MEASURE_FINISH_MS(construct_tx_time);
|
||||
THROW_IF_FALSE_WALLET_EX(r, error::tx_not_constructed, ftp.sources, ftp.prepared_destinations, ftp.unlock_time);
|
||||
|
||||
TIME_MEASURE_START_MS(sign_ms_input_time);
|
||||
//TIME_MEASURE_START_MS(sign_ms_input_time);
|
||||
if (ftp.multisig_id != currency::null_hash)
|
||||
{
|
||||
// In case there's multisig input is used -- sign it partially with this wallet's keys (we don't have any others here).
|
||||
|
|
@ -4031,21 +4031,21 @@ void wallet2::finalize_transaction(const finalize_tx_param& ftp, currency::trans
|
|||
r = sign_multisig_input_in_tx(tx, 0, m_account.get_keys(), ms_source_tx, &is_tx_input_fully_signed); // it's assumed that ms input is the first one (index 0)
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(r && !is_tx_input_fully_signed, "sign_multisig_input_in_tx failed: r = " << r << ", is_tx_input_fully_signed = " << is_tx_input_fully_signed);
|
||||
}
|
||||
TIME_MEASURE_FINISH_MS(sign_ms_input_time);
|
||||
//TIME_MEASURE_FINISH_MS(sign_ms_input_time);
|
||||
|
||||
m_tx_keys.insert(std::make_pair(get_transaction_hash(tx), tx_key));
|
||||
|
||||
THROW_IF_FALSE_WALLET_EX(get_object_blobsize(tx) < CURRENCY_MAX_TRANSACTION_BLOB_SIZE, error::tx_too_big, tx, m_upper_transaction_size_limit);
|
||||
|
||||
TIME_MEASURE_START(send_transaction_to_network_time);
|
||||
//TIME_MEASURE_START(send_transaction_to_network_time);
|
||||
if (broadcast_tx)
|
||||
send_transaction_to_network(tx);
|
||||
TIME_MEASURE_FINISH(send_transaction_to_network_time);
|
||||
//TIME_MEASURE_FINISH(send_transaction_to_network_time);
|
||||
|
||||
TIME_MEASURE_START(add_sent_tx_detailed_info_time);
|
||||
//TIME_MEASURE_START(add_sent_tx_detailed_info_time);
|
||||
if (broadcast_tx)
|
||||
add_sent_tx_detailed_info(tx, ftp.prepared_destinations, ftp.selected_transfers);
|
||||
TIME_MEASURE_FINISH(add_sent_tx_detailed_info_time);
|
||||
//TIME_MEASURE_FINISH(add_sent_tx_detailed_info_time);
|
||||
|
||||
/* TODO
|
||||
WLT_LOG_GREEN("[prepare_transaction]: get_needed_money_time: " << get_needed_money_time << " ms"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on pseudorandom number generator manupulations for tests
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
|
@ -176,7 +178,7 @@ bool test_generator::add_block_info(const currency::block& b, const std::list<cu
|
|||
sk.stake_modifier.last_pos_kernel_id = chain[pos_idx]->ks_hash;
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sk.stake_modifier.last_pos_kernel_id), false, "Failed to parse POS_STARTER_MODFIFIER");
|
||||
CHECK_AND_ASSERT_MES(string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sk.stake_modifier.last_pos_kernel_id), false, "Failed to parse POS_STARTER_KERNEL_HASH");
|
||||
}
|
||||
uint64_t pow_idx = get_last_block_of_type(false, chain);
|
||||
sk.stake_modifier.last_pow_id = get_block_hash(chain[pow_idx]->b);
|
||||
|
|
@ -686,7 +688,7 @@ bool test_generator::build_stake_modifier(stake_modifier_type& sm, const test_ge
|
|||
else
|
||||
{
|
||||
bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, sm.last_pos_kernel_id);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_MODFIFIER");
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse POS_STARTER_KERNEL_HASH");
|
||||
}
|
||||
|
||||
sm.last_pow_id = get_block_hash(blck_chain[last_pow_i]->b);
|
||||
|
|
@ -1030,44 +1032,46 @@ namespace
|
|||
|
||||
bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, const currency::account_keys& acc_keys)
|
||||
{
|
||||
for(const block& blk : blockchain)
|
||||
for (const block& blk : blockchain)
|
||||
{
|
||||
volatile uint64_t height = get_block_height(blk);
|
||||
|
||||
std::vector<const transaction*> vtx;
|
||||
vtx.push_back(&blk.miner_tx);
|
||||
|
||||
for (const crypto::hash &h : blk.tx_hashes)
|
||||
{
|
||||
std::vector<const transaction*> vtx;
|
||||
vtx.push_back(&blk.miner_tx);
|
||||
|
||||
for(const crypto::hash &h : blk.tx_hashes)
|
||||
{
|
||||
const map_hash2tx_t::const_iterator cit = mtx.find(h);
|
||||
CHECK_AND_ASSERT_MES(cit != mtx.end(), false, "block at height " << get_block_height(blk) << " contains a reference to unknown tx " << h);
|
||||
vtx.push_back(cit->second);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < vtx.size(); i++)
|
||||
{
|
||||
const transaction &tx = *vtx[i];
|
||||
crypto::key_derivation derivation;
|
||||
bool r = generate_key_derivation(get_tx_pub_key_from_extra(tx), acc_keys.m_view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed");
|
||||
|
||||
for (size_t j = 0; j < tx.vout.size(); ++j)
|
||||
{
|
||||
const tx_out &out = tx.vout[j];
|
||||
output_index oi(out.target, out.amount, boost::get<txin_gen>(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]);
|
||||
|
||||
if (out.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
outs[out.amount].push_back(oi);
|
||||
size_t tx_global_idx = outs[out.amount].size() - 1;
|
||||
outs[out.amount][tx_global_idx].idx = tx_global_idx;
|
||||
// Is out to me?
|
||||
if (is_out_to_acc(acc_keys, boost::get<txout_to_key>(out.target), derivation, j))
|
||||
outs_mine[out.amount].push_back(tx_global_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
const map_hash2tx_t::const_iterator cit = mtx.find(h);
|
||||
CHECK_AND_ASSERT_MES(cit != mtx.end(), false, "block at height " << get_block_height(blk) << " contains a reference to unknown tx " << h);
|
||||
vtx.push_back(cit->second);
|
||||
}
|
||||
|
||||
return true;
|
||||
for (size_t i = 0; i < vtx.size(); i++)
|
||||
{
|
||||
const transaction &tx = *vtx[i];
|
||||
crypto::key_derivation derivation;
|
||||
bool r = generate_key_derivation(get_tx_pub_key_from_extra(tx), acc_keys.m_view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "generate_key_derivation failed");
|
||||
|
||||
for (size_t j = 0; j < tx.vout.size(); ++j)
|
||||
{
|
||||
const tx_out &out = tx.vout[j];
|
||||
output_index oi(out.target, out.amount, boost::get<txin_gen>(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]);
|
||||
|
||||
if (out.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
outs[out.amount].push_back(oi);
|
||||
size_t tx_global_idx = outs[out.amount].size() - 1;
|
||||
outs[out.amount][tx_global_idx].idx = tx_global_idx;
|
||||
// Is out to me?
|
||||
if (is_out_to_acc(acc_keys, boost::get<txout_to_key>(out.target), derivation, j))
|
||||
outs_mine[out.amount].push_back(tx_global_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, const currency::account_keys& from)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on pseudorandom number generator manupulations for tests
|
||||
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "currency_core/currency_core.h"
|
||||
#include "wallet/wallet2.h"
|
||||
|
|
@ -1124,13 +1126,13 @@ void append_vector_by_another_vector(U& dst, const V& src)
|
|||
|
||||
#define MAKE_TX_ATTACH(EVENTS, TX_VAR, FROM, TO, AMOUNT, HEAD, ATTACH) MAKE_TX_ATTACH_FEE(EVENTS, TX_VAR, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, HEAD, ATTACH)
|
||||
|
||||
#define MAKE_MINER_TX_AND_KEY_MANUALLY(TX, BLK, KEY) \
|
||||
transaction TX; \
|
||||
if (!construct_miner_tx_manually(get_block_height(BLK) + 1, generator.get_already_generated_coins(BLK), \
|
||||
miner_account.get_keys().m_account_address, TX, 0, KEY)) \
|
||||
#define MAKE_MINER_TX_AND_KEY_MANUALLY(TX, PREV_BLOCK, P_KEYPAIR) \
|
||||
transaction TX; \
|
||||
if (!construct_miner_tx_manually(get_block_height(PREV_BLOCK) + 1, generator.get_already_generated_coins(PREV_BLOCK), \
|
||||
miner_account.get_keys().m_account_address, TX, 0, P_KEYPAIR)) \
|
||||
return false;
|
||||
|
||||
#define MAKE_MINER_TX_MANUALLY(TX, BLK) MAKE_MINER_TX_AND_KEY_MANUALLY(TX, BLK, 0)
|
||||
#define MAKE_MINER_TX_MANUALLY(TX, PREV_BLOCK) MAKE_MINER_TX_AND_KEY_MANUALLY(TX, PREV_BLOCK, nullptr)
|
||||
|
||||
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT, VAL) VEC_EVENTS.push_back(event_visitor_settings(SETT, VAL));
|
||||
|
||||
|
|
|
|||
|
|
@ -947,6 +947,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(hard_fork_1_unlock_time_2_in_coinbase);
|
||||
GENERATE_AND_PLAY(hard_fork_1_chain_switch_pow_only);
|
||||
GENERATE_AND_PLAY(hard_fork_1_checkpoint_basic_test);
|
||||
GENERATE_AND_PLAY(hard_fork_1_pos_locked_height_vs_time);
|
||||
//GENERATE_AND_PLAY(gen_block_reward); */
|
||||
|
||||
|
||||
|
|
@ -1023,3 +1024,11 @@ void tx2log(const currency::transaction& tx)
|
|||
currency::transaction ltx = tx;
|
||||
LOG_PRINT("!dbg transaction: " << currency::get_transaction_hash(ltx) << ENDL << currency::obj_to_json_str(ltx), LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
const char* amount2log(const uint64_t amount)
|
||||
{
|
||||
static std::string s;
|
||||
s = currency::print_money_brief(amount);
|
||||
LOG_PRINT("!dbg amount: " << s, LOG_LEVEL_0);
|
||||
return s.c_str();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,20 @@
|
|||
|
||||
using namespace currency;
|
||||
|
||||
template<typename extra_t>
|
||||
void remove_unlock_v1_entries_from_extra(extra_t& extra)
|
||||
{
|
||||
extra.erase(std::remove_if(extra.begin(), extra.end(), [](extra_v& extra_element) { return extra_element.type() == typeid(etc_tx_details_unlock_time); }), extra.end());
|
||||
}
|
||||
|
||||
template<typename extra_t>
|
||||
void remove_unlock_v2_entries_from_extra(extra_t& extra)
|
||||
{
|
||||
extra.erase(std::remove_if(extra.begin(), extra.end(), [](extra_v& extra_element) { return extra_element.type() == typeid(etc_tx_details_unlock_time2); }), extra.end());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
hard_fork_1_base_test::hard_fork_1_base_test(size_t hardfork_height)
|
||||
: m_hardfork_height(hardfork_height)
|
||||
{
|
||||
|
|
@ -28,7 +42,6 @@ bool hard_fork_1_base_test::configure_core(currency::core& c, size_t ev_index, c
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
hard_fork_1_unlock_time_2_in_normal_tx::hard_fork_1_unlock_time_2_in_normal_tx()
|
||||
: hard_fork_1_base_test(12)
|
||||
{
|
||||
|
|
@ -299,22 +312,28 @@ bool hard_fork_1_checkpoint_basic_test::generate(std::vector<test_event_entry>&
|
|||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2));
|
||||
DO_CALLBACK_PARAMS(events, "set_checkpoint", params_checkpoint(2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 7));
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
DO_CALLBACK(events, "check_being_in_cp_zone"); // make sure CP was has passed
|
||||
|
||||
//
|
||||
// before hardfork 1
|
||||
//
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), MK_TEST_COINS(90) + TESTS_DEFAULT_FEE, 0), false, "");
|
||||
|
||||
uint64_t stake_lock_time = 100; // locked till block 100
|
||||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
CHECK_AND_ASSERT_MES(fill_tx_sources_and_destinations(events, blk_0r, miner_acc, alice_acc, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations), false, "");
|
||||
destinations.push_back(tx_destination_entry(MK_TEST_COINS(90), alice_acc.get_public_address()));
|
||||
|
||||
// set unlock_time_2, should be rejected before hardfork 1
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.resize(destinations.size());
|
||||
ut2.unlock_time_array[0] = 1; // not zero, unlocked from block 1
|
||||
ut2.unlock_time_array[0] = stake_lock_time;
|
||||
extra.push_back(ut2);
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
crypto::secret_key tx_sec_key;
|
||||
|
|
@ -329,21 +348,120 @@ bool hard_fork_1_checkpoint_basic_test::generate(std::vector<test_event_entry>&
|
|||
DO_CALLBACK(events, "clear_tx_pool");
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); // <-- checkpoint
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc);
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc); // <-- hard fork
|
||||
MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_acc);
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_3.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_4.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
//
|
||||
// after hardfork 1
|
||||
//
|
||||
|
||||
// now tx_0 is okay and can be added to the blockchain
|
||||
events.push_back(tx_0);
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_5, blk_4, miner_acc, tx_0);
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_5r, blk_5, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
|
||||
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_5r, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5);
|
||||
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(90));
|
||||
|
||||
// try to mine a PoS block using locked coins
|
||||
block blk_6;
|
||||
{
|
||||
const block& prev_block = blk_5r;
|
||||
const transaction& stake = tx_0;
|
||||
const account_base& stakeholder = alice_acc;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(stakeholder.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address());
|
||||
|
||||
// set etc_tx_details_unlock_time2
|
||||
remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock
|
||||
for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i)
|
||||
ut2.unlock_time_array.push_back(stake_lock_time); // using the same lock time as stake input
|
||||
extra.push_back(ut2);
|
||||
pb.m_block.miner_tx.extra.push_back(ut2);
|
||||
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder);
|
||||
blk_6 = pb.m_block;
|
||||
}
|
||||
events.push_back(blk_6);
|
||||
generator.add_block_info(blk_6, std::list<transaction>()); // add modified block info
|
||||
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_7, blk_6, miner_acc); // <-- checkpoint
|
||||
MAKE_NEXT_BLOCK(events, blk_8, blk_7, miner_acc);
|
||||
|
||||
DO_CALLBACK(events, "check_not_being_in_cp_zone"); // make sure CP was has passed
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_8r, blk_8, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// make sure locked Alice's coins still can't be spent
|
||||
sources.clear();
|
||||
r = fill_tx_sources(sources, events, blk_8r, alice_acc.get_keys(), MK_TEST_COINS(90), 0 /* nmix */, true /* check for spends */, false /* check for unlock time */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx(alice_acc.get_keys(), sources, std::vector<tx_destination_entry>{ tx_destination_entry(MK_TEST_COINS(90) - TESTS_DEFAULT_FEE, miner_acc.get_public_address()) },
|
||||
empty_attachment, tx_1, stake_lock_time /* try to use stake unlock time -- should not work as it is not a coinbase */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
events.push_back(tx_1);
|
||||
|
||||
// mine another PoS block using the same stake after a checkpoint
|
||||
std::list<currency::account_base> pos_stakeing_accounts{alice_acc};
|
||||
MAKE_NEXT_POS_BLOCK(events, blk_9, blk_8r, miner_acc, pos_stakeing_accounts);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
struct unique_amount_params
|
||||
{
|
||||
unique_amount_params(uint64_t amount, uint64_t count) : amount(amount), count(count) {}
|
||||
uint64_t amount;
|
||||
uint64_t count;
|
||||
};
|
||||
|
||||
// check that the given amount has only one non-zero gidit
|
||||
// 3000 => true
|
||||
// 11000 => false
|
||||
bool does_amount_have_one_non_zero_digit(uint64_t amount)
|
||||
{
|
||||
size_t count = 0;
|
||||
auto f = [&count](uint64_t){ ++count; };
|
||||
decompose_amount_into_digits(amount, DEFAULT_DUST_THRESHOLD, f, f);
|
||||
return count == 1;
|
||||
}
|
||||
|
||||
|
||||
hard_fork_1_pos_and_locked_coins::hard_fork_1_pos_and_locked_coins()
|
||||
: hard_fork_1_base_test(13) // hardfork height
|
||||
, m_unique_amount(TESTS_DEFAULT_FEE * 9)
|
||||
: hard_fork_1_base_test(25) // hardfork height
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(hard_fork_1_pos_and_locked_coins, check_outputs_with_unique_amount);
|
||||
}
|
||||
|
|
@ -353,14 +471,24 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
|
|||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
GENERATE_ACCOUNT(bob_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", static_cast<size_t>(0));
|
||||
const uint64_t unique_amount_alice = TESTS_DEFAULT_FEE * 9;
|
||||
const uint64_t unique_amount_bob = TESTS_DEFAULT_FEE * 3;
|
||||
|
||||
CHECK_AND_ASSERT_MES(does_amount_have_one_non_zero_digit(unique_amount_alice), false, "does_amount_have_one_non_zero_digit failed for Alice");
|
||||
CHECK_AND_ASSERT_MES(does_amount_have_one_non_zero_digit(unique_amount_bob), false, "does_amount_have_one_non_zero_digit failed for Bob");
|
||||
|
||||
// make sure no outputs have such unique amounts
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", unique_amount_params(unique_amount_alice, 0) );
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", unique_amount_params(unique_amount_bob, 0) );
|
||||
|
||||
// create few locked outputs in the blockchain with unique amount
|
||||
// tx_0 : miner -> Alice
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time ut = AUTO_VAL_INIT(ut);
|
||||
ut.v = 100; // locked until block 100
|
||||
|
|
@ -368,56 +496,379 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector<test_event_entry>& e
|
|||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
destinations.push_back(tx_destination_entry(m_unique_amount, alice_acc.get_public_address()));
|
||||
destinations.push_back(tx_destination_entry(unique_amount_alice, alice_acc.get_public_address()));
|
||||
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
r = construct_tx_to_key(events, tx_0, blk_0r, miner_acc, destinations, TESTS_DEFAULT_FEE, 0, 0, extra);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_0);
|
||||
|
||||
// tx_1 : miner -> Bob
|
||||
extra.clear();
|
||||
uint64_t ut2_unlock_time = 100; // locked until block 100
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
destinations.clear();
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
destinations.push_back(tx_destination_entry(unique_amount_bob, bob_acc.get_public_address()));
|
||||
ut2.unlock_time_array.push_back(ut2_unlock_time);
|
||||
}
|
||||
ut2.unlock_time_array.push_back(ut2_unlock_time);
|
||||
extra.push_back(ut2);
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx_to_key(events, tx_1, blk_0r, miner_acc, destinations, TESTS_DEFAULT_FEE, 0, 0, extra);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_1);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", static_cast<size_t>(5));
|
||||
// block with tx_1 should be rejected because etc_tx_details_unlock_time2 is not allowed prior to hardfork 1
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1b, blk_1, miner_acc, tx_1);
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
block blk_0a;
|
||||
DO_CALLBACK_PARAMS(events, "check_outputs_with_unique_amount", unique_amount_params(unique_amount_alice, 5) );
|
||||
|
||||
// make sure outputs with m_unique_amount are still locked
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
crypto::hash prev_id = get_block_hash(blk_0);
|
||||
size_t height = get_block_height(blk_0) + 1;
|
||||
MAKE_TX(events, tx_1_bad, alice_acc, miner_acc, unique_amount_alice - TESTS_DEFAULT_FEE, blk_1r);
|
||||
}
|
||||
catch (std::runtime_error&)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(r, false, "exception was not cought as expected");
|
||||
|
||||
// try to make a PoS block with locked stake before the hardfork
|
||||
|
||||
block blk_2b;
|
||||
{
|
||||
const block& prev_block = blk_1r;
|
||||
const transaction& stake = tx_0;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
const transaction& stake = blk_0.miner_tx;
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(miner_acc.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
generate_key_image_helper(alice_acc.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, blk_0r.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(blk_0r), miner_acc.get_public_address());
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, miner_acc);
|
||||
blk_0a = pb.m_block;
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, alice_acc);
|
||||
blk_2b = pb.m_block;
|
||||
}
|
||||
|
||||
// it should not be accepted, because stake coins is still locked
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
events.push_back(blk_2b);
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_2.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_3.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
|
||||
// try to make a PoS block with locked stake after the hardfork
|
||||
|
||||
block blk_4b;
|
||||
{
|
||||
const block& prev_block = blk_3;
|
||||
const transaction& stake = tx_0;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(alice_acc.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, alice_acc);
|
||||
blk_4b = pb.m_block;
|
||||
}
|
||||
|
||||
// it should not be accepted, because stake coins is still locked
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
events.push_back(blk_4b);
|
||||
|
||||
// blk_4 with tx_1 (etc_tx_details_unlock_time2) should be accepted after hardfork 1
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_1);
|
||||
|
||||
block prev = blk_4;
|
||||
for(size_t i = 0; i < CURRENCY_MINED_MONEY_UNLOCK_WINDOW; ++i)
|
||||
{
|
||||
MAKE_NEXT_POS_BLOCK(events, b, prev, miner_acc, std::list<currency::account_base>{miner_acc});
|
||||
prev = b;
|
||||
}
|
||||
|
||||
|
||||
//REWIND_BLOCKS_N_WITH_TIME(events, blk_4r, blk_4, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
block blk_5;
|
||||
{
|
||||
const block& prev_block = prev;
|
||||
const transaction& stake = tx_1;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(bob_acc.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address());
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, bob_acc);
|
||||
blk_5 = pb.m_block;
|
||||
}
|
||||
|
||||
// it should not be accepted, because stake coins is still locked
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
events.push_back(blk_5);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hard_fork_1_pos_and_locked_coins::check_outputs_with_unique_amount(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
size_t expected_outputs_count = 0;
|
||||
unique_amount_params p(0, 0);
|
||||
const std::string& params = boost::get<callback_entry>(events[ev_index]).callback_params;
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(params, expected_outputs_count), false, "hex_to_pod failed, params = " << params);
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(params, p), false, "hex_to_pod failed, params = " << params);
|
||||
|
||||
std::list<crypto::public_key> pub_keys;
|
||||
bool r = c.get_outs(m_unique_amount, pub_keys);
|
||||
bool r = c.get_outs(p.amount, pub_keys);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r && pub_keys.size() == expected_outputs_count, false, "amount " << print_money_brief(m_unique_amount) << ": " << pub_keys.size() << " != " << expected_outputs_count);
|
||||
CHECK_AND_ASSERT_MES(r && pub_keys.size() == p.count, false, "amount " << print_money_brief(p.amount) << ": " << pub_keys.size() << " != " << p.count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
hard_fork_1_pos_locked_height_vs_time::hard_fork_1_pos_locked_height_vs_time()
|
||||
: hard_fork_1_base_test(11)
|
||||
{
|
||||
}
|
||||
|
||||
bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: make sure it's impossible to use height-locked coins as PoS stake IF they are ts-locked (not height-locked) in some outputs
|
||||
// (because it could possibly be used to unlock coins eralier)
|
||||
|
||||
bool r = false;
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
GENERATE_ACCOUNT(alice_acc);
|
||||
GENERATE_ACCOUNT(bob_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
generator.set_hardfork_height(m_hardfork_height);
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
|
||||
// create few locked outputs in the blockchain with unique amount
|
||||
// tx_0 : miner -> Alice, miner -> Bob
|
||||
uint64_t stake_unlock_time = 100; // locked until block 100
|
||||
uint64_t stake_amount = MK_TEST_COINS(10);
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time ut = AUTO_VAL_INIT(ut);
|
||||
ut.v = stake_unlock_time;
|
||||
extra.push_back(ut);
|
||||
|
||||
std::vector<tx_destination_entry> destinations;
|
||||
destinations.push_back(tx_destination_entry(stake_amount, alice_acc.get_public_address()));
|
||||
destinations.push_back(tx_destination_entry(stake_amount, bob_acc.get_public_address()));
|
||||
|
||||
transaction tx_0 = AUTO_VAL_INIT(tx_0);
|
||||
r = construct_tx_to_key(events, tx_0, blk_0r, miner_acc, destinations, TESTS_DEFAULT_FEE, 0, 0, extra);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_0);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); // first block after hardfork
|
||||
|
||||
// make sure hardfork went okay
|
||||
CHECK_AND_ASSERT_MES(blk_0r.major_version != CURRENT_BLOCK_MAJOR_VERSION && blk_1.major_version == CURRENT_BLOCK_MAJOR_VERSION, false, "hardfork did not happen as expected");
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
|
||||
|
||||
block blk_b1;
|
||||
{
|
||||
const block& prev_block = blk_1r;
|
||||
const transaction& stake = tx_0;
|
||||
const account_base& stakeholder = alice_acc;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(stakeholder.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address());
|
||||
|
||||
// set etc_tx_details_unlock_time2
|
||||
remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock
|
||||
for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i)
|
||||
ut2.unlock_time_array.push_back(test_core_time::get_time() - 1000); // stake locked by time and it's already passed
|
||||
extra.push_back(ut2);
|
||||
pb.m_block.miner_tx.extra.push_back(ut2);
|
||||
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder);
|
||||
blk_b1 = pb.m_block;
|
||||
}
|
||||
|
||||
// should not pass as using time-locking in outputs
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
events.push_back(blk_b1);
|
||||
|
||||
|
||||
block blk_b2;
|
||||
{
|
||||
const block& prev_block = blk_1r;
|
||||
const transaction& stake = tx_0;
|
||||
const account_base& stakeholder = alice_acc;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(stakeholder.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address());
|
||||
|
||||
// set etc_tx_details_unlock_time2
|
||||
remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock
|
||||
for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i)
|
||||
ut2.unlock_time_array.push_back(stake_unlock_time - 1); // stake locked by 1 less height that stake_unlock_time, that is incorrect as lock time of this coin is decreased
|
||||
extra.push_back(ut2);
|
||||
pb.m_block.miner_tx.extra.push_back(ut2);
|
||||
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder);
|
||||
blk_b2 = pb.m_block;
|
||||
}
|
||||
|
||||
// should no pass because stake output has less lock time than stake input
|
||||
DO_CALLBACK(events, "mark_invalid_block");
|
||||
events.push_back(blk_b2);
|
||||
|
||||
block blk_good;
|
||||
{
|
||||
const block& prev_block = blk_1r;
|
||||
const transaction& stake = tx_0;
|
||||
const account_base& stakeholder = alice_acc;
|
||||
|
||||
crypto::hash prev_id = get_block_hash(prev_block);
|
||||
size_t height = get_block_height(prev_block) + 1;
|
||||
currency::wide_difficulty_type diff = generator.get_difficulty_for_next_block(prev_id, false);
|
||||
|
||||
crypto::public_key stake_tx_pub_key = get_tx_pub_key_from_extra(stake);
|
||||
size_t stake_output_idx = 0;
|
||||
size_t stake_output_gidx = 0;
|
||||
uint64_t stake_output_amount = stake.vout[stake_output_idx].amount;
|
||||
crypto::key_image stake_output_key_image;
|
||||
keypair kp;
|
||||
generate_key_image_helper(stakeholder.get_keys(), stake_tx_pub_key, stake_output_idx, kp, stake_output_key_image);
|
||||
crypto::public_key stake_output_pubkey = boost::get<txout_to_key>(stake.vout[stake_output_idx].target).key;
|
||||
|
||||
pos_block_builder pb;
|
||||
pb.step1_init_header(height, prev_id);
|
||||
pb.m_block.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
pb.step2_set_txs(std::vector<transaction>());
|
||||
pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, diff, prev_id, null_hash, prev_block.timestamp);
|
||||
pb.step4_generate_coinbase_tx(generator.get_timestamps_median(prev_id), generator.get_already_generated_coins(prev_block), miner_acc.get_public_address(), stakeholder.get_public_address());
|
||||
|
||||
// set etc_tx_details_unlock_time2
|
||||
remove_unlock_v1_entries_from_extra(pb.m_block.miner_tx.extra); // clear already set unlock
|
||||
std::vector<extra_v> extra;
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
ut2.unlock_time_array.push_back(height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // reward lock
|
||||
for(size_t i = 0; i < pb.m_block.miner_tx.vout.size() - 1; ++i)
|
||||
ut2.unlock_time_array.push_back(stake_unlock_time); // using the same lock time as stake input
|
||||
extra.push_back(ut2);
|
||||
pb.m_block.miner_tx.extra.push_back(ut2);
|
||||
|
||||
pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, stakeholder);
|
||||
blk_good = pb.m_block;
|
||||
}
|
||||
|
||||
// should pass okay
|
||||
events.push_back(blk_good);
|
||||
generator.add_block_info(blk_good, std::list<transaction>()); // add modified block info
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_2, blk_good, miner_acc);
|
||||
|
||||
std::vector<tx_source_entry> sources;
|
||||
r = fill_tx_sources(sources, events, blk_2, alice_acc.get_keys(), stake_amount / 2 + TESTS_DEFAULT_FEE, 0 /* nmix */, true /* check for spends */, false /* check for unlock time */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx(alice_acc.get_keys(), sources, std::vector<tx_destination_entry>{ tx_destination_entry(stake_amount / 2, miner_acc.get_public_address()) },
|
||||
empty_attachment, tx_1, stake_unlock_time /* try to use stake unlock time -- should not work as it is not a coinbase */);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
|
||||
DO_CALLBACK(events, "mark_invalid_tx");
|
||||
events.push_back(tx_1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ struct hard_fork_1_pos_and_locked_coins : public hard_fork_1_base_test
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
|
||||
bool check_outputs_with_unique_amount(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
uint64_t m_unique_amount;
|
||||
};
|
||||
|
||||
struct hard_fork_1_pos_locked_height_vs_time : public hard_fork_1_base_test
|
||||
{
|
||||
hard_fork_1_pos_locked_height_vs_time();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ hard_fork_1_locked_mining_test::hard_fork_1_locked_mining_test()
|
|||
|
||||
bool hard_fork_1_locked_mining_test::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
random_state_test_restorer::reset_random();
|
||||
// Test idea: make sure PoS mining on locked coins is possible
|
||||
|
||||
GENERATE_ACCOUNT(preminer_acc);
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
|
|
@ -36,20 +36,30 @@ bool hard_fork_1_locked_mining_test::generate(std::vector<test_event_entry>& eve
|
|||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
|
||||
|
||||
//construc tx that locks transaction for some period of time
|
||||
// make a couple of huge txs
|
||||
//construct tx that locks coins for some period of time
|
||||
//make a couple of huge txs
|
||||
bool r = false;
|
||||
std::vector<extra_v> extra;
|
||||
|
||||
std::vector<tx_source_entry> sources_1;
|
||||
r = fill_tx_sources(sources_1, events, blk_0r, miner_acc.get_keys(), 2000000000000+TESTS_DEFAULT_FEE, 0);
|
||||
r = fill_tx_sources(sources_1, events, blk_0r, miner_acc.get_keys(), CURRENCY_BLOCK_REWARD + TESTS_DEFAULT_FEE, 0);
|
||||
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
|
||||
std::vector<tx_destination_entry> destinations({ tx_destination_entry(2010000000000, pos_miner_acc.get_public_address()) });
|
||||
std::vector<tx_destination_entry> destinations({ tx_destination_entry(CURRENCY_BLOCK_REWARD, pos_miner_acc.get_public_address()) });
|
||||
crypto::secret_key stub;
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx(miner_acc.get_keys(), sources_1, destinations, extra, empty_attachment, tx_1, stub, get_block_height(blk_0r)+2000);
|
||||
uint64_t unlock_time = get_block_height(blk_0r) + 2000;
|
||||
r = construct_tx(miner_acc.get_keys(), sources_1, destinations, extra, empty_attachment, tx_1, stub, unlock_time);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
|
||||
events.push_back(tx_1); // push it to the pool
|
||||
|
||||
uint64_t ut1 = get_tx_x_detail<etc_tx_details_unlock_time>(tx_1);
|
||||
etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2);
|
||||
get_type_in_variant_container(tx_1.extra, ut2);
|
||||
std::stringstream ss;
|
||||
for (auto v : ut2.unlock_time_array)
|
||||
ss << v << " ";
|
||||
LOG_PRINT_YELLOW("tx1: ut1: " << ut1 << ", ut2: " << ss.str(), LOG_LEVEL_0);
|
||||
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_0r_tx, blk_0r, miner_acc, tx_1);
|
||||
|
||||
|
|
@ -61,13 +71,30 @@ bool hard_fork_1_locked_mining_test::generate(std::vector<test_event_entry>& eve
|
|||
events.push_back(event_core_time(next_blk_pow.timestamp - 10));
|
||||
last_block = next_blk_pow;
|
||||
}
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_1, last_block, miner_acc);
|
||||
MAKE_NEXT_POS_BLOCK(events, blk_2, blk_1, miner_acc, miner_acc_lst);
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
|
||||
|
||||
std::list<currency::account_base> accounts_2;
|
||||
accounts_2.push_back(pos_miner_acc);
|
||||
//let's try to mint PoS block from locked account
|
||||
//mint PoS block from locked account into an altchain
|
||||
MAKE_NEXT_POS_BLOCK(events, next_blk_pos, last_block, pos_miner_acc, accounts_2);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
// switch chains
|
||||
MAKE_NEXT_BLOCK(events, blk_2a, next_blk_pos, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_3a, blk_2a, miner_acc);
|
||||
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
|
||||
|
||||
// make sure switch happened
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_4a));
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_4ar, blk_4a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
// mint another PoS block from locked account
|
||||
MAKE_NEXT_POS_BLOCK(events, blk_5a, blk_4ar, pos_miner_acc, accounts_2);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void pos_block_builder::step3_build_stake_kernel(
|
|||
if (last_pos_block_kernel_hash == null_hash)
|
||||
{
|
||||
bool r = string_tools::parse_tpod_from_hex_string(POS_STARTER_KERNEL_HASH, m_stake_kernel.stake_modifier.last_pos_kernel_id);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse POS_STARTER_MODFIFIER");
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse POS_STARTER_KERNEL_HASH");
|
||||
}
|
||||
|
||||
wide_difficulty_type stake_difficulty = difficulty / stake_output_amount;
|
||||
|
|
@ -105,9 +105,21 @@ void pos_block_builder::step3_build_stake_kernel(
|
|||
m_step = 3;
|
||||
}
|
||||
|
||||
void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const account_public_address &reward_and_stake_receiver_address,
|
||||
const blobdata& extra_nonce,
|
||||
size_t max_outs,
|
||||
const extra_alias_entry& alias,
|
||||
keypair tx_one_time_key)
|
||||
{
|
||||
step4_generate_coinbase_tx(median_size, already_generated_coins, reward_and_stake_receiver_address, reward_and_stake_receiver_address, extra_nonce, max_outs, alias, tx_one_time_key);
|
||||
}
|
||||
|
||||
void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const account_public_address &reward_receiver_address,
|
||||
const account_public_address &stakeholder_address,
|
||||
const blobdata& extra_nonce,
|
||||
size_t max_outs,
|
||||
const extra_alias_entry& alias,
|
||||
|
|
@ -118,7 +130,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
|||
// generate miner tx using incorrect current_block_size only for size estimation
|
||||
size_t estimated_block_size = m_txs_total_size;
|
||||
bool r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage,
|
||||
m_pos_stake_output_gindex, reward_receiver_address, m_block.miner_tx, extra_nonce, max_outs, alias, tx_one_time_key);
|
||||
m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
|
||||
|
||||
estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
|
||||
|
|
@ -126,7 +138,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
|
|||
for (size_t try_count = 0; try_count != 10; ++try_count)
|
||||
{
|
||||
r = construct_homemade_pos_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, m_pos_stake_amount, m_stake_kernel.kimage,
|
||||
m_pos_stake_output_gindex, reward_receiver_address, m_block.miner_tx, extra_nonce, max_outs, alias, tx_one_time_key);
|
||||
m_pos_stake_output_gindex, reward_receiver_address, stakeholder_address, m_block.miner_tx, extra_nonce, max_outs, tx_one_time_key);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
|
||||
|
||||
cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
|
||||
|
|
@ -171,11 +183,11 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
uint64_t pos_stake_amount,
|
||||
crypto::key_image pos_stake_keyimage,
|
||||
size_t pos_stake_gindex,
|
||||
const account_public_address &miner_address,
|
||||
const account_public_address &reward_receiving_address,
|
||||
const account_public_address &stakeholder_address,
|
||||
transaction& tx,
|
||||
const blobdata& extra_nonce /*= blobdata()*/,
|
||||
size_t max_outs /*= CURRENCY_MINER_TX_MAX_OUTS*/,
|
||||
const extra_alias_entry& alias /*= alias_info()*/,
|
||||
keypair tx_one_time_key /*= keypair::generate()*/)
|
||||
{
|
||||
boost::value_initialized<transaction> new_tx;
|
||||
|
|
@ -189,12 +201,6 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
bool r = get_block_reward(true, median_size, current_block_size, already_generated_coins, block_reward, height);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Block is too big");
|
||||
block_reward += fee;
|
||||
block_reward += pos_stake_amount;
|
||||
|
||||
uint64_t alias_reward = 0;
|
||||
if (!alias.m_alias.empty())
|
||||
alias_reward = currency::get_alias_coast_from_fee(alias.m_alias, TESTS_DEFAULT_FEE);
|
||||
block_reward -= alias_reward;
|
||||
|
||||
// decompose reward into outputs and populate tx.vout
|
||||
std::vector<size_t> out_amounts;
|
||||
|
|
@ -202,14 +208,15 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
[&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
|
||||
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
|
||||
|
||||
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
|
||||
while (max_outs < out_amounts.size())
|
||||
CHECK_AND_ASSERT_MES(2 <= max_outs, false, "max_out must be greather than 1");
|
||||
while (out_amounts.size() + 1 > max_outs)
|
||||
{
|
||||
out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
||||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
|
||||
bool burn_money = miner_address.m_spend_public_key == null_pkey && miner_address.m_view_public_key == null_pkey; // if true, burn money, so no one on Earth can spend them
|
||||
// reward
|
||||
bool burn_money = reward_receiving_address.m_spend_public_key == null_pkey && reward_receiving_address.m_view_public_key == null_pkey; // if true, burn reward, so no one on Earth can spend them
|
||||
for (size_t output_index = 0; output_index < out_amounts.size(); ++output_index)
|
||||
{
|
||||
txout_to_key tk;
|
||||
|
|
@ -218,7 +225,7 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
|
||||
if (!burn_money)
|
||||
{
|
||||
r = currency::derive_public_key_from_target_address(miner_address, tx_one_time_key.sec, output_index, tk.key); // derivation(view_pub; tx_sec).derive(output_index, spend_pub) => output pub key
|
||||
r = currency::derive_public_key_from_target_address(reward_receiving_address, tx_one_time_key.sec, output_index, tk.key); // derivation(view_pub; tx_sec).derive(output_index, spend_pub) => output pub key
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address");
|
||||
}
|
||||
|
||||
|
|
@ -228,36 +235,31 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
// stake
|
||||
burn_money = stakeholder_address.m_spend_public_key == null_pkey && stakeholder_address.m_view_public_key == null_pkey; // if true, burn stake
|
||||
{
|
||||
txout_to_key tk;
|
||||
tk.key = null_pkey; // null means burn money
|
||||
tk.mix_attr = 0;
|
||||
|
||||
if (!burn_money)
|
||||
{
|
||||
r = currency::derive_public_key_from_target_address(stakeholder_address, tx_one_time_key.sec, tx.vout.size(), tk.key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address");
|
||||
}
|
||||
|
||||
tx_out out;
|
||||
out.amount = pos_stake_amount;
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
// take care about extra
|
||||
add_tx_pub_key_to_extra(tx, tx_one_time_key.pub);
|
||||
if (extra_nonce.size())
|
||||
if (!add_tx_extra_userdata(tx, extra_nonce))
|
||||
return false;
|
||||
if (alias.m_alias.size())
|
||||
{
|
||||
if (!add_tx_extra_alias(tx, alias))
|
||||
return false;
|
||||
|
||||
// decompose alias reward into digits and create additional outputs
|
||||
out_amounts.clear();
|
||||
decompose_amount_into_digits(alias_reward, DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
|
||||
while (out_amounts.size() > max_outs)
|
||||
{
|
||||
out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
||||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
for (size_t output_index = 0; output_index < out_amounts.size(); ++output_index)
|
||||
{
|
||||
txout_to_key tk;
|
||||
tk.key = null_pkey; // burn money for the sake of alias!
|
||||
tk.mix_attr = 0;
|
||||
tx_out out;
|
||||
out.amount = out_amounts[output_index];
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// populate ins with 1) money-generating and 2) PoS
|
||||
txin_gen in;
|
||||
in.height = height;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,20 @@ struct pos_block_builder
|
|||
void step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const currency::account_public_address &reward_receiver_address,
|
||||
const currency::account_public_address &stakeholder_address,
|
||||
const currency::blobdata& extra_nonce = currency::blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
const currency::extra_alias_entry& alias = currency::extra_alias_entry(),
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate());
|
||||
|
||||
|
||||
void step4_generate_coinbase_tx(size_t median_size,
|
||||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
const currency::account_public_address &reward_and_stake_receiver_address,
|
||||
const currency::blobdata& extra_nonce = currency::blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
const currency::extra_alias_entry& alias = currency::extra_alias_entry(),
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate());
|
||||
|
||||
void step5_sign(const crypto::public_key& stake_tx_pub_key, size_t stake_tx_out_index, const crypto::public_key& stake_tx_out_pub_key, const currency::account_base& stakeholder_account);
|
||||
|
||||
currency::block m_block;
|
||||
|
|
@ -50,11 +59,11 @@ bool construct_homemade_pos_miner_tx(size_t height, size_t median_size, const bo
|
|||
uint64_t pos_stake_amount,
|
||||
crypto::key_image pos_stake_keyimage,
|
||||
size_t pos_stake_gindex,
|
||||
const currency::account_public_address &miner_address,
|
||||
const currency::account_public_address &reward_receiving_address,
|
||||
const currency::account_public_address &stakeholder_address,
|
||||
currency::transaction& tx,
|
||||
const currency::blobdata& extra_nonce = currency::blobdata(),
|
||||
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
|
||||
const currency::extra_alias_entry& alias = currency::extra_alias_entry(),
|
||||
currency::keypair tx_one_time_key = currency::keypair::generate());
|
||||
|
||||
bool mine_next_pos_block_in_playtime_sign_cb(currency::core& c, const currency::block& prev_block, const currency::block& coinstake_scr_block, const currency::account_base& acc,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,21 @@
|
|||
#include "chaingen.h"
|
||||
#include "random_helper.h"
|
||||
|
||||
random_state_test_restorer::random_state_test_restorer()
|
||||
{
|
||||
crypto::random_prng_get_state(&m_state, sizeof m_state);
|
||||
}
|
||||
|
||||
random_state_test_restorer::~random_state_test_restorer()
|
||||
{
|
||||
crypto::random_prng_set_state(&m_state, sizeof m_state);
|
||||
}
|
||||
|
||||
void random_state_test_restorer::reset_random(uint64_t seed /* = 0 */)
|
||||
{
|
||||
crypto::random_prng_initialize_with_seed(seed);
|
||||
}
|
||||
|
||||
std::string get_random_text(size_t len)
|
||||
{
|
||||
static const char text_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "~!@#$%^&*()-=_+\\/?,.<>|{}[]`';:\" ";
|
||||
|
|
@ -45,7 +60,7 @@ bool random_state_manupulation_test()
|
|||
// NOTE: If the test fails, it's most likely that random state permutation procedure was changed OR the state can't be correctly stored/loaded.
|
||||
|
||||
static const uint64_t my_own_random_seed = 4669201609102990671;
|
||||
static const char* my_random_str = "18b79ebb56744e9bafa462631c6f7d760af2b788";
|
||||
static const char* my_random_str = "760af2b78894c6a441731e2b354011da6ac98ddc";
|
||||
static const size_t rnd_buf_len = 20;
|
||||
|
||||
uint64_t first_random_after_state_saved = 0;
|
||||
|
|
|
|||
|
|
@ -1,40 +1,28 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// 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
|
||||
|
||||
#define RANDOM_STATE_SIZE 200
|
||||
extern "C" volatile union hash_state state; // field defined in random.c
|
||||
static_assert(RANDOM_STATE_SIZE >= HASH_DATA_AREA, "Invalid RANDOM_STATE_SIZE");
|
||||
|
||||
// DISCLAIMER: designed for tests puposes ONLY!
|
||||
// This class is not intended to be used neither in multi-threaded environment nor in production.
|
||||
|
||||
#ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES
|
||||
|
||||
// Remebers random state at ctor, restores it at dtor
|
||||
struct random_state_test_restorer
|
||||
{
|
||||
random_state_test_restorer()
|
||||
{
|
||||
memcpy(m_state, const_cast<hash_state*>(&::state), RANDOM_STATE_SIZE);
|
||||
}
|
||||
|
||||
~random_state_test_restorer()
|
||||
{
|
||||
memcpy(const_cast<hash_state*>(&::state), m_state, RANDOM_STATE_SIZE);
|
||||
}
|
||||
|
||||
static void reset_random(uint64_t seed = 0)
|
||||
{
|
||||
memset(const_cast<hash_state*>(&::state), 0, RANDOM_STATE_SIZE);
|
||||
memcpy(const_cast<hash_state*>(&::state), &seed, sizeof seed);
|
||||
}
|
||||
random_state_test_restorer();
|
||||
~random_state_test_restorer();
|
||||
static void reset_random(uint64_t seed = 0);
|
||||
|
||||
private:
|
||||
uint8_t m_state[RANDOM_STATE_SIZE];
|
||||
};
|
||||
|
||||
#endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES
|
||||
|
||||
std::string get_random_text(size_t len);
|
||||
|
||||
bool random_state_manupulation_test();
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ bool generate_events(currency::core& c, cct_events_t& events, const cct_wallets_
|
|||
{
|
||||
const transaction& tx = boost::get<const currency::transaction>(*it);
|
||||
uint64_t max_used_block_height = 0;
|
||||
r = bcs.check_tx_inputs(tx, get_transaction_hash(tx), &max_used_block_height);
|
||||
r = bcs.check_tx_inputs(tx, get_transaction_hash(tx), max_used_block_height);
|
||||
if (r && max_used_block_height <= prev_block.height)
|
||||
txs.push_back(&tx); // filter out tx that are using too recent outputs -- yep, some txs will be dropped forever
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,15 +9,35 @@
|
|||
|
||||
#include "single_tx_test_base.h"
|
||||
|
||||
uint64_t g_antioptimisation = 0;
|
||||
|
||||
class test_generate_key_derivation : public single_tx_test_base
|
||||
{
|
||||
public:
|
||||
static const size_t loop_count = 1000;
|
||||
static const size_t loop_count = 1;
|
||||
std::list<currency::account_base> accounts;
|
||||
|
||||
bool init()
|
||||
{
|
||||
|
||||
for (size_t i = 0; i != 10000; i++)
|
||||
{
|
||||
accounts.push_back(currency::account_base());
|
||||
accounts.back().generate();
|
||||
}
|
||||
|
||||
return single_tx_test_base::init();
|
||||
}
|
||||
|
||||
bool test()
|
||||
{
|
||||
crypto::key_derivation recv_derivation;
|
||||
crypto::generate_key_derivation(m_tx_pub_key, m_bob.get_keys().m_view_secret_key, recv_derivation);
|
||||
for (auto &a : accounts)
|
||||
{
|
||||
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
|
||||
crypto::generate_key_derivation(m_tx_pub_key, a.get_keys().m_view_secret_key, recv_derivation);
|
||||
g_antioptimisation ^= *(uint64_t*)(&recv_derivation);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ int main(int argc, char** argv)
|
|||
*/
|
||||
//TEST_PERFORMANCE0(test_is_out_to_acc);
|
||||
//TEST_PERFORMANCE0(test_generate_key_image_helper);
|
||||
//TEST_PERFORMANCE0(test_generate_key_derivation);
|
||||
TEST_PERFORMANCE0(test_generate_key_derivation);
|
||||
//TEST_PERFORMANCE0(test_generate_key_image);
|
||||
//TEST_PERFORMANCE0(test_derive_public_key);
|
||||
//TEST_PERFORMANCE0(test_derive_secret_key);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
// 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 <algorithm>
|
||||
|
||||
#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on random manupulation for tests
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
#include "common/db_abstract_accessor.h"
|
||||
|
|
@ -8,7 +13,6 @@
|
|||
#include "common/util.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "../core_tests/random_helper.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "file_io_utils.h"
|
||||
|
||||
|
|
@ -311,7 +315,7 @@ struct bcs_stub_t
|
|||
|
||||
TEST(db_accessor_tests, median_db_cache_test)
|
||||
{
|
||||
random_state_test_restorer::reset_random(); // make this test deterministic (the same crypto::rand() sequence)
|
||||
crypto::random_prng_initialize_with_seed(0); // make this test deterministic (the same crypto::rand() sequence)
|
||||
|
||||
epee::shared_recursive_mutex m_rw_lock;
|
||||
tools::db::basic_db_accessor m_db(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend), m_rw_lock);
|
||||
|
|
|
|||
76
tests/unit_tests/fork_choice_rule.cpp
Normal file
76
tests/unit_tests/fork_choice_rule.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// 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 "include_base_utils.h"
|
||||
#include "currency_core/currency_format_utils.h"
|
||||
|
||||
bool if_alt_chain_stronger(const currency::wide_difficulty_type& pos, const currency::wide_difficulty_type& pow)
|
||||
{
|
||||
currency::difficulties main_cumul_diff;
|
||||
main_cumul_diff.pos_diff = 400000;
|
||||
main_cumul_diff.pow_diff = 4000;
|
||||
currency::difficulties alt_cumul_diff;
|
||||
alt_cumul_diff.pow_diff = pow;
|
||||
alt_cumul_diff.pos_diff = pos;
|
||||
static currency::wide_difficulty_type difficulty_pos_at_split_point = 400000;
|
||||
static currency::wide_difficulty_type difficulty_pow_at_split_point = 4000;
|
||||
currency::wide_difficulty_type main = currency::get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
|
||||
currency::wide_difficulty_type alt = currency::get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
|
||||
if (alt > main)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST(fork_choice_rule_test, fork_choice_rule_test_1)
|
||||
{
|
||||
// std::stringstream ss;
|
||||
// for (uint64_t pos = 100000; pos < 1000001; pos += 10000)
|
||||
// {
|
||||
// for (uint64_t pow = 100; pow < 18000; pow += 100)
|
||||
// {
|
||||
// bool r = if_alt_chain_stronger(pos, pow);
|
||||
// if(r)
|
||||
// ss << pos << "\t" << pow << std::endl;
|
||||
// //ss << pos << "\t" << pow << "\t" << (r ? "1" : "0") << std::endl;
|
||||
//
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// bool r = epee::file_io_utils::save_string_to_file("stat.txt", ss.str());
|
||||
bool res = false;
|
||||
res = if_alt_chain_stronger(1000000, 1000);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(1000000, 1500);
|
||||
ASSERT_TRUE(res);
|
||||
res = if_alt_chain_stronger(800000, 1700);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(800000, 2000);
|
||||
ASSERT_TRUE(res);
|
||||
res = if_alt_chain_stronger(600000, 2200);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(600000, 2800);
|
||||
ASSERT_TRUE(res);
|
||||
res = if_alt_chain_stronger(400000, 3999);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(400000, 4001);
|
||||
ASSERT_TRUE(res);
|
||||
res = if_alt_chain_stronger(200000, 7000);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(200000, 7700);
|
||||
ASSERT_TRUE(res);
|
||||
res = if_alt_chain_stronger(200000, 7000);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(200000, 7700);
|
||||
ASSERT_TRUE(res);
|
||||
res = if_alt_chain_stronger(100000, 10000);
|
||||
ASSERT_FALSE(res);
|
||||
res = if_alt_chain_stronger(200000, 14000);
|
||||
ASSERT_TRUE(res);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,17 +1,895 @@
|
|||
// Copyright (c) 2019 Zano Project
|
||||
// Copyright (c) 2018 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include "epee/include/include_base_utils.h"
|
||||
|
||||
#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on random manupulation for tests
|
||||
#include "crypto/crypto.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "common/db_backend_lmdb.h"
|
||||
#include "common/db_abstract_accessor.h"
|
||||
#include "common/db_backend_lmdb.h"
|
||||
#include "serialization/serialization.h"
|
||||
|
||||
using namespace tools;
|
||||
|
||||
namespace lmdb_test
|
||||
{
|
||||
|
||||
crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
|
||||
|
||||
template<typename T>
|
||||
T random_t_from_range(T from, T to)
|
||||
{
|
||||
if (from >= to)
|
||||
return from;
|
||||
T result;
|
||||
crypto::generate_random_bytes(sizeof result, &result);
|
||||
return from + result % (to - from + 1);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// basic_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TEST(lmdb, basic_test)
|
||||
{
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
epee::shared_recursive_mutex db_lock;
|
||||
db::basic_db_accessor dbb(lmdb_ptr, db_lock);
|
||||
|
||||
bool r = false;
|
||||
|
||||
r = dbb.open("test_lmdb");
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
db::container_handle tid_decapod;
|
||||
r = lmdb_ptr->open_container("decapod", tid_decapod);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->begin_transaction());
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->clear(tid_decapod));
|
||||
|
||||
uint64_t key = 10;
|
||||
std::string buf = "nxjdu47flrp20soam19e7nfhxbcy48owks03of92sbf31n1oqkanmdb47";
|
||||
|
||||
r = lmdb_ptr->set(tid_decapod, (char*)&key, sizeof key, buf.c_str(), buf.size());
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->commit_transaction());
|
||||
|
||||
r = dbb.close();
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
|
||||
r = dbb.open("test_lmdb");
|
||||
ASSERT_TRUE(r);
|
||||
r = lmdb_ptr->open_container("decapod", tid_decapod);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->begin_transaction());
|
||||
|
||||
std::string out_buffer;
|
||||
r = lmdb_ptr->get(tid_decapod, (char*)&key, sizeof key, out_buffer);
|
||||
ASSERT_TRUE(r);
|
||||
ASSERT_EQ(buf, out_buffer);
|
||||
|
||||
ASSERT_TRUE(lmdb_ptr->commit_transaction());
|
||||
|
||||
r = dbb.close();
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// multithread_test_1
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
struct multithread_test_1_t : public db::i_db_callback
|
||||
{
|
||||
enum { c_keys_count = 128 };
|
||||
crypto::hash m_keys[c_keys_count];
|
||||
size_t m_randomly_mixed_indexes_1[c_keys_count];
|
||||
size_t m_randomly_mixed_indexes_2[c_keys_count];
|
||||
epee::shared_recursive_mutex m_db_lock;
|
||||
std::shared_ptr<db::lmdb_db_backend> m_lmdb_adapter;
|
||||
db::basic_db_accessor m_dbb;
|
||||
db::container_handle m_table_id;
|
||||
size_t m_counter;
|
||||
|
||||
multithread_test_1_t()
|
||||
: m_lmdb_adapter(std::make_shared<db::lmdb_db_backend>())
|
||||
, m_dbb(m_lmdb_adapter, m_db_lock)
|
||||
, m_table_id(0)
|
||||
, m_counter(0)
|
||||
{
|
||||
for (size_t i = 0; i < c_keys_count; ++i)
|
||||
{
|
||||
m_keys[i] = i == 0 ? null_hash : crypto::cn_fast_hash(&m_keys[i - 1], sizeof(crypto::hash));
|
||||
m_randomly_mixed_indexes_1[i] = i;
|
||||
m_randomly_mixed_indexes_2[i] = i;
|
||||
}
|
||||
|
||||
// prepare m_randomly_mixed_indexes_1 and m_randomly_mixed_indexes_2
|
||||
for (size_t i = 0; i < c_keys_count * 100; ++i)
|
||||
{
|
||||
size_t a = random_t_from_range<size_t>(0, c_keys_count - 1);
|
||||
size_t b = random_t_from_range<size_t>(0, c_keys_count - 1);
|
||||
size_t c = random_t_from_range<size_t>(0, c_keys_count - 1);
|
||||
size_t d = random_t_from_range<size_t>(0, c_keys_count - 1);
|
||||
|
||||
size_t tmp = m_randomly_mixed_indexes_1[a];
|
||||
m_randomly_mixed_indexes_1[a] = m_randomly_mixed_indexes_1[b];
|
||||
m_randomly_mixed_indexes_1[b] = tmp;
|
||||
|
||||
tmp = m_randomly_mixed_indexes_2[c];
|
||||
m_randomly_mixed_indexes_2[c] = m_randomly_mixed_indexes_2[d];
|
||||
m_randomly_mixed_indexes_2[d] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void adder_thread(std::atomic<bool>& stop_flag)
|
||||
{
|
||||
epee::log_space::log_singletone::set_thread_log_prefix("[ adder ] ");
|
||||
//epee::misc_utils::sleep_no_w(1000);
|
||||
|
||||
size_t i = 0;
|
||||
for(size_t n = 0; n < 1000; ++n)
|
||||
{
|
||||
// get pseudorandom key index
|
||||
size_t key_index = m_randomly_mixed_indexes_1[i];
|
||||
i = (i + 1) % c_keys_count;
|
||||
const crypto::hash& key = m_keys[key_index];
|
||||
|
||||
bool r = m_lmdb_adapter->begin_transaction();
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "begin_transaction");
|
||||
|
||||
// get a value by the given key
|
||||
std::string value;
|
||||
if (!m_lmdb_adapter->get(m_table_id, (const char*)&key, sizeof key, value))
|
||||
{
|
||||
// if such key does not exist -- add it
|
||||
char buffer[128];
|
||||
crypto::generate_random_bytes(sizeof buffer, buffer);
|
||||
r = m_lmdb_adapter->set(m_table_id, (const char*)&key, sizeof key, buffer, sizeof buffer);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "set");
|
||||
|
||||
size_t table_size = m_lmdb_adapter->size(m_table_id);
|
||||
|
||||
r = m_lmdb_adapter->commit_transaction();
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "commit_transaction");
|
||||
|
||||
LOG_PRINT_L1("added key index " << key_index << ", table size: " << table_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if key exists in the table - do nothing
|
||||
m_lmdb_adapter->abort_transaction();
|
||||
}
|
||||
epee::misc_utils::sleep_no_w(1);
|
||||
}
|
||||
LOG_PRINT_L0("adder_thread stopped");
|
||||
}
|
||||
|
||||
void deleter_thread(std::atomic<bool>& stop_flag)
|
||||
{
|
||||
epee::log_space::log_singletone::set_thread_log_prefix("[deleter] ");
|
||||
epee::misc_utils::sleep_no_w(1000);
|
||||
|
||||
// get pseudorandom key index
|
||||
size_t i = 0;
|
||||
|
||||
while(!stop_flag)
|
||||
{
|
||||
size_t key_index = m_randomly_mixed_indexes_2[i];
|
||||
i = (i + 1) % c_keys_count;
|
||||
const crypto::hash& key = m_keys[key_index];
|
||||
bool r = m_lmdb_adapter->begin_transaction();
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "begin_transaction");
|
||||
|
||||
// get a value by the given key
|
||||
std::string value;
|
||||
if (m_lmdb_adapter->get(m_table_id, (const char*)&key, sizeof key, value))
|
||||
{
|
||||
// if key exists in the table -- remove it
|
||||
r = m_lmdb_adapter->erase(m_table_id, (const char*)&key, sizeof key);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "erase");
|
||||
|
||||
size_t table_size = m_lmdb_adapter->size(m_table_id);
|
||||
|
||||
r = m_lmdb_adapter->commit_transaction();
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "commit_transaction");
|
||||
|
||||
LOG_PRINT_L1("erased key index " << key_index << ", table size: " << table_size);
|
||||
if (table_size == 2)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no such key exists in the table - do nothing
|
||||
m_lmdb_adapter->abort_transaction();
|
||||
}
|
||||
epee::misc_utils::sleep_no_w(1);
|
||||
}
|
||||
LOG_PRINT_L0("deleter_thread stopped");
|
||||
}
|
||||
|
||||
void reader_thread()
|
||||
{
|
||||
epee::log_space::log_singletone::set_thread_log_prefix("[reader ] ");
|
||||
epee::misc_utils::sleep_no_w(1000);
|
||||
|
||||
// get pseudorandom key index
|
||||
size_t i = 17;
|
||||
uint64_t sum = 0; // just for fun
|
||||
|
||||
for(;;)
|
||||
{
|
||||
size_t key_index = m_randomly_mixed_indexes_2[i];
|
||||
i = (i + 1) % c_keys_count;
|
||||
const crypto::hash& key = m_keys[key_index];
|
||||
bool r = m_lmdb_adapter->begin_transaction(true); // request Read-Only transaction
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "begin_transaction(RO=true)");
|
||||
|
||||
// get a value by the given key
|
||||
std::string value;
|
||||
if (m_lmdb_adapter->get(m_table_id, (const char*)&key, sizeof key, value))
|
||||
{
|
||||
sum += *reinterpret_cast<const uint64_t*>(value.data());
|
||||
|
||||
size_t table_size = m_lmdb_adapter->size(m_table_id);
|
||||
|
||||
r = m_lmdb_adapter->commit_transaction();
|
||||
CHECK_AND_ASSERT_MES_NO_RET(r, "commit_transaction");
|
||||
|
||||
if (table_size == 2)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if no such key exists in the table - do nothing
|
||||
m_lmdb_adapter->abort_transaction();
|
||||
}
|
||||
epee::misc_utils::sleep_no_w(1);
|
||||
}
|
||||
LOG_PRINT_L0("reader_thread stopped, sum = " << sum);
|
||||
}
|
||||
|
||||
bool check()
|
||||
{
|
||||
size_t table_size = m_lmdb_adapter->size(m_table_id);
|
||||
CHECK_AND_ASSERT_MES(table_size == 2, false, "2 elements are expected to left");
|
||||
|
||||
m_counter = 0;
|
||||
bool r = m_lmdb_adapter->begin_transaction();
|
||||
CHECK_AND_ASSERT_MES(r, false, "begin_transaction");
|
||||
|
||||
m_lmdb_adapter->enumerate(m_table_id, this);
|
||||
|
||||
r = m_lmdb_adapter->commit_transaction();
|
||||
CHECK_AND_ASSERT_MES(r, false, "commit_transaction");
|
||||
|
||||
return m_counter == 2;
|
||||
}
|
||||
|
||||
// class i_db_visitor
|
||||
virtual bool on_enum_item(size_t i, const void* key_data, size_t key_size, const void* value_data, size_t value_size) override
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(key_size == sizeof(crypto::hash), false, "invalid key size: " << key_size);
|
||||
const crypto::hash *p_key = reinterpret_cast<const crypto::hash*>(key_data);
|
||||
|
||||
size_t key_index = SIZE_MAX;
|
||||
for(size_t j = 0; j < c_keys_count && key_index == SIZE_MAX; ++j)
|
||||
if (m_keys[j] == *p_key)
|
||||
key_index = j;
|
||||
|
||||
CHECK_AND_ASSERT_MES(key_index != SIZE_MAX, false, "visitor gets a non-existing key");
|
||||
|
||||
LOG_PRINT_L1("visitor: #" << i << ", key index: " << key_index);
|
||||
if (i != m_counter)
|
||||
{
|
||||
LOG_ERROR("invalid visitor index i: " << i << ", m_counter: " << m_counter);
|
||||
m_counter = SIZE_MAX;
|
||||
return false;
|
||||
}
|
||||
++m_counter;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
bool run()
|
||||
{
|
||||
bool r = m_dbb.open("multithread_test_1_t");
|
||||
CHECK_AND_ASSERT_MES(r, false, "m_dbb.open");
|
||||
r = m_lmdb_adapter->open_container("table1_", m_table_id);
|
||||
CHECK_AND_ASSERT_MES(r, false, "open_table");
|
||||
r = m_lmdb_adapter->begin_transaction();
|
||||
CHECK_AND_ASSERT_MES(r, false, "begin_transaction");
|
||||
r = m_lmdb_adapter->clear(m_table_id);
|
||||
CHECK_AND_ASSERT_MES(r, false, "clear_table");
|
||||
r = m_lmdb_adapter->commit_transaction();
|
||||
CHECK_AND_ASSERT_MES(r, false, "commit_transaction");
|
||||
|
||||
std::atomic<bool> stop_adder(false), stop_deleter(false);
|
||||
std::thread adder_t(&multithread_test_1_t::adder_thread, this, std::ref(stop_adder));
|
||||
std::thread deleter_t(&multithread_test_1_t::deleter_thread, this, std::ref(stop_deleter));
|
||||
|
||||
std::vector<std::thread> readers_t;
|
||||
const size_t reader_threads_count = 2;
|
||||
for (size_t i = 0; i < reader_threads_count; ++i)
|
||||
readers_t.emplace_back(std::thread(&multithread_test_1_t::reader_thread, this));
|
||||
|
||||
for (auto& t : readers_t)
|
||||
t.join();
|
||||
|
||||
adder_t.join();
|
||||
//stop_deleter = true;
|
||||
deleter_t.join();
|
||||
r = check();
|
||||
m_dbb.close();
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(lmdb, multithread_test_1)
|
||||
{
|
||||
char prng_state[200] = {};
|
||||
crypto::random_prng_get_state(prng_state, sizeof prng_state); // store current RPNG state
|
||||
crypto::random_prng_initialize_with_seed(0); // this mades this test deterministic
|
||||
|
||||
bool result = false;
|
||||
try
|
||||
{
|
||||
multithread_test_1_t t;
|
||||
result = t.run();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LOG_ERROR("Caught exception: " << e.what());
|
||||
}
|
||||
|
||||
// restore PRNG state to keep other tests unaffected
|
||||
crypto::random_prng_get_state(prng_state, sizeof prng_state);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// bridge_basic_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
struct simple_serializable_t
|
||||
{
|
||||
std::string name;
|
||||
uint64_t number;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(name)
|
||||
FIELD(number)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline bool operator==(const simple_serializable_t &lhs, const simple_serializable_t &rhs)
|
||||
{
|
||||
return lhs.name == rhs.name &&
|
||||
lhs.number == rhs.number;
|
||||
}
|
||||
|
||||
struct simple_pod_t
|
||||
{
|
||||
char c;
|
||||
uint64_t u;
|
||||
float f;
|
||||
};
|
||||
|
||||
inline bool operator==(const simple_pod_t &_v1, const simple_pod_t &_v2)
|
||||
{
|
||||
return std::memcmp(&_v1, &_v2, sizeof _v1) == 0;
|
||||
}
|
||||
|
||||
TEST(lmdb, bridge_basic_test)
|
||||
{
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
epee::shared_recursive_mutex db_lock;
|
||||
db::basic_db_accessor dbb(lmdb_ptr, db_lock);
|
||||
|
||||
bool r = false;
|
||||
|
||||
r = dbb.open("bridge_basic_test");
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
db::container_handle tid_decapod;
|
||||
r = lmdb_ptr->open_container("decapod", tid_decapod);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
|
||||
ASSERT_TRUE(dbb.clear(tid_decapod));
|
||||
|
||||
const char key[] = "nxjdu47flrp20soam19e7nfhxbcy48owks03of92sbf31n1oqkanmdb47";
|
||||
simple_serializable_t s_object;
|
||||
s_object.number = 1001100102;
|
||||
s_object.name = "bender";
|
||||
|
||||
r = dbb.set_t_object(tid_decapod, key, s_object);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
|
||||
simple_serializable_t s_object2;
|
||||
r = dbb.get_t_object(tid_decapod, key, s_object2);
|
||||
ASSERT_TRUE(r);
|
||||
ASSERT_EQ(s_object, s_object2);
|
||||
|
||||
// del object by key and make sure it does not exist anymore
|
||||
r = dbb.erase(tid_decapod, key);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
r = dbb.get_t_object(tid_decapod, key, s_object2);
|
||||
ASSERT_FALSE(r);
|
||||
|
||||
// second erase shoud also fail
|
||||
r = dbb.erase(tid_decapod, key);
|
||||
ASSERT_FALSE(r);
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
// POD type
|
||||
const char key_pod[] = "alqocyfu7sbxhaoo5kdnrt77tgwderhjs9a9sdjf324nfjksd9f0s90f2";
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
simple_pod_t p_object1 = {' ', 0xf7f7f7f7d3d3d3d3ull, 2.002319f};
|
||||
r = dbb.set_pod_object(tid_decapod, key_pod, p_object1);
|
||||
ASSERT_TRUE(r);
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
simple_pod_t p_object2;
|
||||
r = dbb.get_pod_object(tid_decapod, key_pod, p_object2);
|
||||
ASSERT_TRUE(r);
|
||||
ASSERT_EQ(p_object1, p_object2);
|
||||
|
||||
// del object by key and make sure it does not exist anymore
|
||||
r = dbb.erase(tid_decapod, key_pod);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
r = dbb.get_pod_object(tid_decapod, key_pod, p_object2);
|
||||
ASSERT_FALSE(r);
|
||||
|
||||
// second erase shoud also fail
|
||||
r = dbb.erase(tid_decapod, key_pod);
|
||||
ASSERT_FALSE(r);
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
r = dbb.close();
|
||||
ASSERT_TRUE(r);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// single_value_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
struct serializable_string
|
||||
{
|
||||
serializable_string() {}
|
||||
explicit serializable_string(const std::string& v) : v(v) {}
|
||||
|
||||
std::string v;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(v)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
TEST(lmdb, single_value_test)
|
||||
{
|
||||
const std::string options_table_name("options");
|
||||
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
epee::shared_recursive_mutex db_lock;
|
||||
db::basic_db_accessor dbb(lmdb_ptr, db_lock);
|
||||
db::basic_key_value_accessor<uint64_t, uint64_t /* does not matter */, false /* does not matter */ > options_container(dbb);
|
||||
|
||||
db::solo_db_value<uint64_t, uint64_t, decltype(options_container), false> option_uint64(0, options_container);
|
||||
db::solo_db_value<uint64_t, serializable_string, decltype(options_container), true> option_serializable_obj(1, options_container);
|
||||
db::solo_db_value<uint64_t, crypto::hash, decltype(options_container), false> option_hash(2, options_container);
|
||||
|
||||
ASSERT_TRUE(dbb.open("single_value_test"));
|
||||
|
||||
// clear table
|
||||
db::container_handle options_tid;
|
||||
ASSERT_TRUE(lmdb_ptr->open_container(options_table_name, options_tid));
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
ASSERT_TRUE(dbb.clear(options_tid));
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(options_container.init(options_table_name));
|
||||
|
||||
// check defaults
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
uint64_t v = option_uint64;
|
||||
ASSERT_EQ(v, 0);
|
||||
|
||||
serializable_string ss = option_serializable_obj;
|
||||
ASSERT_EQ(ss.v, std::string(""));
|
||||
|
||||
crypto::hash h = option_hash;
|
||||
ASSERT_EQ(h, null_hash);
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
// set single values
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
option_uint64 = 97;
|
||||
option_serializable_obj = serializable_string("New York advertising men");
|
||||
option_hash = crypto::cn_fast_hash(options_table_name.c_str(), options_table_name.size());
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(dbb.close());
|
||||
|
||||
|
||||
// reopen DB
|
||||
ASSERT_TRUE(dbb.open("single_value_test"));
|
||||
ASSERT_TRUE(options_container.init(options_table_name));
|
||||
|
||||
|
||||
// get single value
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
|
||||
v = option_uint64;
|
||||
ASSERT_EQ(v, 97);
|
||||
|
||||
ss = option_serializable_obj;
|
||||
ASSERT_EQ(ss.v, "New York advertising men");
|
||||
|
||||
h = option_hash;
|
||||
ASSERT_EQ(h, crypto::cn_fast_hash(options_table_name.c_str(), options_table_name.size()));
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
ASSERT_TRUE(dbb.close());
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// array_basic_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TEST(lmdb, array_basic_test)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
const std::string array_table_name("test_array");
|
||||
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
epee::shared_recursive_mutex db_lock;
|
||||
db::basic_db_accessor dbb(lmdb_ptr, db_lock);
|
||||
|
||||
db::basic_key_to_array_accessor<uint64_t, serializable_string, true> db_array(dbb);
|
||||
|
||||
ASSERT_TRUE(dbb.open("array_basic_test"));
|
||||
|
||||
// clear table
|
||||
db::container_handle tid;
|
||||
ASSERT_TRUE(lmdb_ptr->open_container(array_table_name, tid));
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
ASSERT_TRUE(dbb.clear(tid));
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(db_array.init(array_table_name));
|
||||
|
||||
// check defaults
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
|
||||
size_t count = db_array.get_item_size(97);
|
||||
ASSERT_EQ(count, 0);
|
||||
|
||||
std::shared_ptr<const serializable_string> ptr;
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
ptr = db_array.get_subitem(97, 0);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
|
||||
// write
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
db_array.push_back_item(97, serializable_string("507507507507507507507507"));
|
||||
db_array.push_back_item(97, serializable_string("787878787878787878787878"));
|
||||
db_array.push_back_item(97, serializable_string("ringing phone"));
|
||||
|
||||
count = db_array.get_item_size(97);
|
||||
ASSERT_EQ(count, 3);
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
db_array.push_back_item(97, serializable_string("ring"));
|
||||
db_array.push_back_item(97, serializable_string("ring"));
|
||||
db_array.push_back_item(97, serializable_string("ring"));
|
||||
|
||||
count = db_array.get_item_size(97);
|
||||
ASSERT_EQ(count, 6);
|
||||
dbb.abort_transaction();
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
count = db_array.get_item_size(97);
|
||||
ASSERT_EQ(count, 3);
|
||||
dbb.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(dbb.close());
|
||||
|
||||
|
||||
// reopen DB
|
||||
ASSERT_TRUE(dbb.open("array_basic_test"));
|
||||
ASSERT_TRUE(db_array.init(array_table_name));
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
count = db_array.get_item_size(97);
|
||||
ASSERT_EQ(count, 3);
|
||||
|
||||
ptr = db_array.get_subitem(97, 0);
|
||||
ASSERT_TRUE((bool)ptr);
|
||||
ASSERT_EQ(ptr->v, "507507507507507507507507");
|
||||
|
||||
ptr = db_array.get_subitem(97, 1);
|
||||
ASSERT_TRUE((bool)ptr);
|
||||
ASSERT_EQ(ptr->v, "787878787878787878787878");
|
||||
|
||||
ptr = db_array.get_subitem(97, 2);
|
||||
ASSERT_TRUE((bool)ptr);
|
||||
ASSERT_EQ(ptr->v, "ringing phone");
|
||||
|
||||
ASSERT_EQ(db_array.get_item_size(555), 0);
|
||||
db_array.pop_back_item(555);
|
||||
ASSERT_EQ(db_array.get_item_size(555), 0);
|
||||
|
||||
db_array.pop_back_item(97);
|
||||
db_array.pop_back_item(97);
|
||||
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
count = db_array.get_item_size(97);
|
||||
ASSERT_EQ(count, 1);
|
||||
|
||||
ptr = db_array.get_subitem(97, 0);
|
||||
ASSERT_TRUE((bool)ptr);
|
||||
ASSERT_EQ(ptr->v, "507507507507507507507507");
|
||||
dbb.commit_transaction();
|
||||
|
||||
|
||||
ASSERT_TRUE(dbb.close());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// array_accessor_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TEST(lmdb, array_accessor_test)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
const std::string array_table_name("array");
|
||||
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
epee::shared_recursive_mutex db_lock;
|
||||
db::basic_db_accessor dbb(lmdb_ptr, db_lock);
|
||||
|
||||
db::array_accessor<serializable_string, true> db_array(dbb);
|
||||
|
||||
ASSERT_TRUE(dbb.open("array_accessor_test"));
|
||||
|
||||
// clear table
|
||||
db::container_handle tid;
|
||||
ASSERT_TRUE(lmdb_ptr->open_container(array_table_name, tid));
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
ASSERT_TRUE(dbb.clear(tid));
|
||||
dbb.commit_transaction();
|
||||
|
||||
// check defaults
|
||||
ASSERT_TRUE(db_array.init(array_table_name));
|
||||
ASSERT_TRUE(db_array.begin_transaction(true));
|
||||
|
||||
size_t count = db_array.size();
|
||||
ASSERT_EQ(count, 0);
|
||||
count = db_array.size_no_cache();
|
||||
ASSERT_EQ(count, 0);
|
||||
|
||||
std::shared_ptr<const serializable_string> ptr;
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
ptr = db_array.back();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ASSERT_FALSE(db_array.clear()); // clear() should fail on read-only transaction
|
||||
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
ptr = db_array[0];
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
db_array.commit_transaction();
|
||||
|
||||
|
||||
|
||||
ASSERT_TRUE(db_array.begin_transaction());
|
||||
db_array.push_back(serializable_string("A"));
|
||||
db_array.push_back(serializable_string("B"));
|
||||
db_array.push_back(serializable_string("C"));
|
||||
db_array.push_back(serializable_string("D"));
|
||||
db_array.push_back(serializable_string("E"));
|
||||
db_array.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(db_array.begin_transaction());
|
||||
ptr = db_array[4];
|
||||
ASSERT_EQ(ptr->v, "E");
|
||||
db_array.pop_back();
|
||||
ASSERT_EQ(db_array.size(), 4);
|
||||
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
ptr = db_array[4];
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ptr = db_array[3];
|
||||
ASSERT_EQ(ptr->v, "D");
|
||||
|
||||
db_array.push_back(serializable_string("X"));
|
||||
|
||||
ptr = db_array[4];
|
||||
ASSERT_EQ(ptr->v, "X");
|
||||
|
||||
ASSERT_TRUE(db_array.clear());
|
||||
|
||||
db_array.commit_transaction();
|
||||
|
||||
|
||||
ASSERT_TRUE(db_array.begin_transaction(true));
|
||||
count = db_array.size();
|
||||
ASSERT_EQ(count, 0);
|
||||
db_array.commit_transaction();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// key_value_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TEST(lmdb, key_value_test)
|
||||
{
|
||||
bool r = false;
|
||||
|
||||
const std::string array_table_name("key-value");
|
||||
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
epee::shared_recursive_mutex db_lock;
|
||||
db::basic_db_accessor dbb(lmdb_ptr, db_lock);
|
||||
|
||||
db::basic_key_value_accessor<uint64_t, serializable_string, true> db_key_value_map(dbb);
|
||||
|
||||
ASSERT_TRUE(dbb.open("key-value_test"));
|
||||
|
||||
// clear table
|
||||
db::container_handle tid;
|
||||
ASSERT_TRUE(lmdb_ptr->open_container(array_table_name, tid));
|
||||
ASSERT_TRUE(dbb.begin_transaction());
|
||||
ASSERT_TRUE(dbb.clear(tid));
|
||||
dbb.commit_transaction();
|
||||
|
||||
// check defaults
|
||||
ASSERT_TRUE(db_key_value_map.init(array_table_name));
|
||||
ASSERT_TRUE(db_key_value_map.begin_transaction(true));
|
||||
|
||||
size_t count = db_key_value_map.size();
|
||||
ASSERT_EQ(count, 0);
|
||||
count = db_key_value_map.size_no_cache();
|
||||
ASSERT_EQ(count, 0);
|
||||
|
||||
std::shared_ptr<const serializable_string> ptr;
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
ptr = db_key_value_map[99];
|
||||
}
|
||||
catch (std::out_of_range&)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ptr = db_key_value_map.get(99);
|
||||
ASSERT_TRUE(!ptr);
|
||||
|
||||
ASSERT_FALSE(db_key_value_map.clear()); // clear() should fail on read-only transaction
|
||||
|
||||
db_key_value_map.commit_transaction();
|
||||
|
||||
|
||||
|
||||
ASSERT_TRUE(db_key_value_map.begin_transaction());
|
||||
db_key_value_map.set(99, serializable_string("A"));
|
||||
db_key_value_map.set(100, serializable_string("B"));
|
||||
db_key_value_map.set(101, serializable_string("C"));
|
||||
db_key_value_map.set(102, serializable_string("D"));
|
||||
db_key_value_map.commit_transaction();
|
||||
|
||||
ASSERT_TRUE(db_key_value_map.begin_transaction());
|
||||
ASSERT_EQ(db_key_value_map.size(), 4);
|
||||
ptr = db_key_value_map[102];
|
||||
ASSERT_EQ(ptr->v, "D");
|
||||
ASSERT_TRUE(db_key_value_map.erase_validate(102));
|
||||
ASSERT_EQ(db_key_value_map.size(), 3);
|
||||
db_key_value_map.erase(102);
|
||||
ASSERT_EQ(db_key_value_map.size(), 3);
|
||||
ASSERT_FALSE(db_key_value_map.erase_validate(102));
|
||||
ASSERT_EQ(db_key_value_map.size(), 3);
|
||||
|
||||
r = false;
|
||||
try
|
||||
{
|
||||
ptr = db_key_value_map[0];
|
||||
}
|
||||
catch (std::out_of_range&)
|
||||
{
|
||||
r = true;
|
||||
}
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
ptr = db_key_value_map[99];
|
||||
ASSERT_EQ(ptr->v, "A");
|
||||
|
||||
db_key_value_map.set(102, serializable_string("W"));
|
||||
ASSERT_EQ(db_key_value_map.size(), 4);
|
||||
|
||||
ptr = db_key_value_map[102];
|
||||
ASSERT_EQ(ptr->v, "W");
|
||||
|
||||
ASSERT_TRUE(db_key_value_map.clear());
|
||||
|
||||
db_key_value_map.commit_transaction();
|
||||
|
||||
|
||||
ASSERT_TRUE(db_key_value_map.begin_transaction(true));
|
||||
ASSERT_EQ(db_key_value_map.size(), 0);
|
||||
db_key_value_map.commit_transaction();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 2gb_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TEST(lmdb, 2gb_test)
|
||||
{
|
||||
bool r = false;
|
||||
|
|
@ -54,7 +932,7 @@ namespace lmdb_test
|
|||
if (key % 1024 == 0)
|
||||
{
|
||||
ASSERT_TRUE(lmdb_ptr->commit_transaction());
|
||||
ASSERT_TRUE(lmdb_ptr->resize_if_needed());
|
||||
//ASSERT_TRUE(lmdb_ptr->resize_if_needed());
|
||||
ASSERT_TRUE(lmdb_ptr->begin_transaction());
|
||||
std::cout << total_data / 1024 / 1024 << " MB written to DB" << ENDL;
|
||||
}
|
||||
|
|
@ -101,4 +979,4 @@ namespace lmdb_test
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace lmdb_test
|
||||
|
|
|
|||
|
|
@ -40,19 +40,19 @@ if [ $? -ne 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
make -j daemon Zano;
|
||||
make -j1 daemon Zano;
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to make!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
make -j simplewallet;
|
||||
make -j1 simplewallet;
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to make!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
make -j connectivity_tool;
|
||||
make -j1 connectivity_tool;
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to make!"
|
||||
exit 1
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue