Multi-signatures added
This commit is contained in:
parent
ce6a3be646
commit
4363a9f100
197 changed files with 17996 additions and 5974 deletions
|
@ -19,7 +19,7 @@ if(MSVC)
|
|||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760")
|
||||
if(STATIC)
|
||||
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE)
|
||||
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
@ -122,6 +122,7 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(contrib)
|
||||
add_subdirectory(external)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(tests)
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
Release notes 1.0.0
|
||||
|
||||
- Multi-signatures
|
||||
- Updated block reward scheme
|
||||
- Further optimization in daemon RAM consumption
|
||||
- Faster wallet refresh
|
||||
- Transaction priority based on tx fee
|
||||
- Transactions are returned from tx pools after 24 hours
|
||||
- Dynamic maximum block size limit
|
||||
- Reduced default transaction fee
|
||||
- Various network health updates
|
||||
|
||||
Release notes 0.8.11
|
||||
|
||||
- Increased minimum transaction fee
|
||||
|
|
7
contrib/CMakeLists.txt
Normal file
7
contrib/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
file(GLOB_RECURSE EPEE epee/include/*)
|
||||
|
||||
source_group(epee FILES ${EPEE})
|
||||
|
||||
add_library(epee ${EPEE})
|
||||
|
||||
set_property(TARGET epee PROPERTY FOLDER "external")
|
|
@ -35,7 +35,4 @@
|
|||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define ENABLE_RELEASE_LOGGING
|
||||
#include "log_opt_defs.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
#include "string_tools.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class async_stdin_reader
|
||||
|
@ -294,7 +299,7 @@ namespace epee
|
|||
bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
std::shared_ptr<async_console_handler> console_handler = std::make_shared<async_console_handler>();
|
||||
boost::thread([=](){console_handler->run<t_server, t_handler>(ptsrv, handlr, prompt, usage);}).detach();
|
||||
std::thread([=](){console_handler->run<t_server, t_handler>(ptsrv, handlr, prompt, usage);}).detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -314,46 +319,24 @@ namespace epee
|
|||
bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
async_console_handler console_handler;
|
||||
return console_handler.run(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), prompt, usage);
|
||||
return console_handler.run(ptsrv, std::bind<bool>(no_srv_param_adapter<t_server, t_handler>, std::placeholders::_1, std::placeholders::_2, handlr), prompt, usage);
|
||||
}
|
||||
|
||||
template<class t_server, class t_handler>
|
||||
bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
||||
{
|
||||
boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
|
||||
std::thread( std::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*template<class a>
|
||||
bool f(int i, a l)
|
||||
{
|
||||
return true;
|
||||
}*/
|
||||
/*
|
||||
template<class chain_handler>
|
||||
bool default_console_handler2(chain_handler ch_handler, const std::string usage)
|
||||
*/
|
||||
|
||||
|
||||
/*template<class t_handler>
|
||||
bool start_default_console2(t_handler handlr, const std::string& usage = "")
|
||||
{
|
||||
//std::string usage_local = usage;
|
||||
boost::thread( boost::bind(default_console_handler2<t_handler>, handlr, usage) );
|
||||
//boost::function<bool ()> p__ = boost::bind(f<t_handler>, 1, handlr);
|
||||
//boost::function<bool ()> p__ = boost::bind(default_console_handler2<t_handler>, handlr, usage);
|
||||
//boost::thread tr(p__);
|
||||
return true;
|
||||
}*/
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class console_handlers_binder
|
||||
{
|
||||
typedef boost::function<bool (const std::vector<std::string> &)> console_command_handler;
|
||||
typedef std::function<bool (const std::vector<std::string> &)> console_command_handler;
|
||||
typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
|
||||
std::unique_ptr<boost::thread> m_console_thread;
|
||||
std::unique_ptr<std::thread> m_console_thread;
|
||||
command_handlers_map m_command_handlers;
|
||||
async_console_handler m_console_handler;
|
||||
public:
|
||||
|
@ -396,16 +379,9 @@ namespace epee
|
|||
return process_command_vec(cmd_v);
|
||||
}
|
||||
|
||||
/*template<class t_srv>
|
||||
bool start_handling(t_srv& srv, const std::string& usage_string = "")
|
||||
{
|
||||
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
|
||||
return true;
|
||||
}*/
|
||||
|
||||
bool start_handling(const std::string& prompt, const std::string& usage_string = "")
|
||||
{
|
||||
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string)));
|
||||
m_console_thread.reset(new std::thread(std::bind(&console_handlers_binder::run_handling, this, prompt, usage_string)));
|
||||
m_console_thread->detach();
|
||||
return true;
|
||||
}
|
||||
|
@ -417,14 +393,8 @@ namespace epee
|
|||
|
||||
bool run_handling(const std::string& prompt, const std::string& usage_string)
|
||||
{
|
||||
return m_console_handler.run(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string);
|
||||
return m_console_handler.run(std::bind(&console_handlers_binder::process_command_str, this, std::placeholders::_1), prompt, usage_string);
|
||||
}
|
||||
|
||||
/*template<class t_srv>
|
||||
bool run_handling(t_srv& srv, const std::string& usage_string)
|
||||
{
|
||||
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
|
||||
}*/
|
||||
};
|
||||
|
||||
/* work around because of broken boost bind */
|
||||
|
@ -438,13 +408,14 @@ namespace epee
|
|||
public:
|
||||
bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "")
|
||||
{
|
||||
boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
|
||||
std::thread(std::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string)
|
||||
{
|
||||
return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
|
||||
return m_console_handler.run(psrv, std::bind(&srv_console_handlers_binder<t_server>::process_command_str, this,
|
||||
std::placeholders::_1, std::placeholders::_2), prompt, usage_string);
|
||||
}
|
||||
|
||||
void stop_handling()
|
||||
|
|
|
@ -28,10 +28,7 @@
|
|||
#ifndef _FILE_IO_UTILS_H_
|
||||
#define _FILE_IO_UTILS_H_
|
||||
|
||||
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
@ -75,7 +72,7 @@ namespace file_io_utils
|
|||
|
||||
#ifdef BOOST_LEXICAL_CAST_INCLUDED
|
||||
inline
|
||||
bool get_not_used_filename(const std::string& folder, OUT std::string& result_name)
|
||||
bool get_not_used_filename(const std::string& folder, std::string& result_name)
|
||||
{
|
||||
DWORD folder_attr = ::GetFileAttributesA(folder.c_str());
|
||||
if(folder_attr == INVALID_FILE_ATTRIBUTES)
|
||||
|
@ -302,7 +299,7 @@ namespace file_io_utils
|
|||
}
|
||||
*/
|
||||
inline
|
||||
bool get_file_time(const std::string& path_to_file, OUT time_t& ft)
|
||||
bool get_file_time(const std::string& path_to_file, time_t& ft)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec);
|
||||
|
@ -408,7 +405,7 @@ namespace file_io_utils
|
|||
}
|
||||
*/
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline bool get_folder_content(const std::string& path, std::list<WIN32_FIND_DATAA>& OUT target_list)
|
||||
inline bool get_folder_content(const std::string& path, std::list<WIN32_FIND_DATAA>& target_list)
|
||||
{
|
||||
WIN32_FIND_DATAA find_data = {0};
|
||||
HANDLE hfind = ::FindFirstFileA((path + "\\*.*").c_str(), &find_data);
|
||||
|
@ -426,7 +423,7 @@ namespace file_io_utils
|
|||
return true;
|
||||
}
|
||||
#endif
|
||||
inline bool get_folder_content(const std::string& path, std::list<std::string>& OUT target_list, bool only_files = false)
|
||||
inline bool get_folder_content(const std::string& path, std::list<std::string>& target_list, bool only_files = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <boost/uuid/random_generator.hpp>
|
||||
|
||||
#include "misc_os_dependent.h"
|
||||
#include "pragma_comp_defs.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
1029
contrib/epee/include/misc_log_ex.cpp
Normal file
1029
contrib/epee/include/misc_log_ex.cpp
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
97
contrib/epee/include/misc_os_dependent.cpp
Normal file
97
contrib/epee/include/misc_os_dependent.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "misc_os_dependent.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace misc_utils
|
||||
{
|
||||
|
||||
uint64_t get_tick_count()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return ::GetTickCount64();
|
||||
#elif defined(__MACH__)
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
|
||||
return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
|
||||
#else
|
||||
struct timespec ts;
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
int call_sys_cmd(const std::string& cmd)
|
||||
{
|
||||
std::cout << "# " << cmd << std::endl;
|
||||
|
||||
FILE * fp ;
|
||||
//char tstCommand[] ="ls *";
|
||||
char path[1000] = {0};
|
||||
#if !defined(__GNUC__)
|
||||
fp = _popen(cmd.c_str(), "r");
|
||||
#else
|
||||
fp = popen(cmd.c_str(), "r");
|
||||
#endif
|
||||
while ( fgets( path, 1000, fp ) != NULL )
|
||||
std::cout << path;
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
_pclose(fp);
|
||||
#else
|
||||
pclose(fp);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string get_thread_string_id()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return boost::lexical_cast<std::string>(GetCurrentThreadId());
|
||||
#elif defined(__GNUC__)
|
||||
return boost::lexical_cast<std::string>(pthread_self());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,86 +23,30 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
//#ifdef _WIN32_WINNT
|
||||
// #undef _WIN32_WINNT
|
||||
// #define _WIN32_WINNT 0x0600
|
||||
//#endif
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX 1
|
||||
#endif // !defined(NOMINMAX)
|
||||
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
namespace epee
|
||||
{
|
||||
namespace misc_utils
|
||||
{
|
||||
|
||||
inline uint64_t get_tick_count()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return ::GetTickCount64();
|
||||
#elif defined(__MACH__)
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
|
||||
return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
|
||||
#else
|
||||
struct timespec ts;
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline int call_sys_cmd(const std::string& cmd)
|
||||
{
|
||||
std::cout << "# " << cmd << std::endl;
|
||||
|
||||
FILE * fp ;
|
||||
//char tstCommand[] ="ls *";
|
||||
char path[1000] = {0};
|
||||
#if !defined(__GNUC__)
|
||||
fp = _popen(cmd.c_str(), "r");
|
||||
#else
|
||||
fp = popen(cmd.c_str(), "r");
|
||||
#endif
|
||||
while ( fgets( path, 1000, fp ) != NULL )
|
||||
std::cout << path;
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
_pclose(fp);
|
||||
#else
|
||||
pclose(fp);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline std::string get_thread_string_id()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return boost::lexical_cast<std::string>(GetCurrentThreadId());
|
||||
#elif defined(__GNUC__)
|
||||
return boost::lexical_cast<std::string>(pthread_self());
|
||||
#endif
|
||||
}
|
||||
uint64_t get_tick_count();
|
||||
int call_sys_cmd(const std::string& cmd);
|
||||
std::string get_thread_string_id();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
#include <boost/lambda/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "misc_language.h"
|
||||
#include "pragma_comp_defs.h"
|
||||
|
||||
|
@ -304,7 +306,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
|||
if(m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)
|
||||
{
|
||||
send_guard.unlock();
|
||||
// LOG_ERROR("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
|
||||
LOG_WARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection", LOG_LEVEL_2);
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define _HTTP_SERVER_H_
|
||||
|
||||
#include <string>
|
||||
#include "include_base_utils.h"
|
||||
#include "net_utils_base.h"
|
||||
#include "to_nonconst_iterator.h"
|
||||
#include "http_base.h"
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
#include <boost/regex.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "http_protocol_handler.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "reg_exp_definer.h"
|
||||
#include "string_tools.h"
|
||||
#include "time_helper.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "net_parse_helpers.h"
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#pragma once
|
||||
#include "http_base.h"
|
||||
#include "jsonrpc_structs.h"
|
||||
#include "misc_os_dependent.h"
|
||||
#include "storages/portable_storage.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
|
||||
|
@ -59,7 +60,7 @@
|
|||
else if(query_info.m_URI == s_pattern) \
|
||||
{ \
|
||||
handled = true; \
|
||||
uint64_t ticks = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::request> req; \
|
||||
bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
|
||||
CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse json: \r\n" << query_info.m_body); \
|
||||
|
@ -84,11 +85,11 @@
|
|||
else if(query_info.m_URI == s_pattern) \
|
||||
{ \
|
||||
handled = true; \
|
||||
uint64_t ticks = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::request> req; \
|
||||
bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \
|
||||
CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \
|
||||
uint64_t ticks1 = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::response> resp;\
|
||||
if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context)) \
|
||||
{ \
|
||||
|
@ -97,7 +98,7 @@
|
|||
response_info.m_response_comment = "Internal Server Error"; \
|
||||
return true; \
|
||||
} \
|
||||
uint64_t ticks2 = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
|
||||
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), response_info.m_body); \
|
||||
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
|
||||
response_info.m_mime_tipe = " application/octet-stream"; \
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
//
|
||||
|
||||
#pragma once
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#pragma once
|
||||
#include "http_base.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "reg_exp_definer.h"
|
||||
|
||||
|
||||
|
|
|
@ -36,6 +36,11 @@
|
|||
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
class io_service;
|
||||
}
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#ifndef _PROFILE_TOOLS_H_
|
||||
#define _PROFILE_TOOLS_H_
|
||||
|
||||
#include <boost/date_time/posix_time/ptime.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/mpl/contains.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
|
|
|
@ -44,38 +44,11 @@ public:
|
|||
initializer()
|
||||
{
|
||||
to_initialize::init();
|
||||
//get_set_is_initialized(true, true);
|
||||
}
|
||||
~initializer()
|
||||
{
|
||||
to_initialize::un_init();
|
||||
//get_set_is_uninitialized(true, true);
|
||||
}
|
||||
|
||||
/*static inline bool is_initialized()
|
||||
{
|
||||
return get_set_is_initialized();
|
||||
}
|
||||
static inline bool is_uninitialized()
|
||||
{
|
||||
return get_set_is_uninitialized();
|
||||
}
|
||||
|
||||
private:
|
||||
static inline bool get_set_is_initialized(bool need_to_set = false, bool val_to_set= false)
|
||||
{
|
||||
static bool val_is_initialized = false;
|
||||
if(need_to_set)
|
||||
val_is_initialized = val_to_set;
|
||||
return val_is_initialized;
|
||||
}
|
||||
static inline bool get_set_is_uninitialized(bool need_to_set = false, bool val_to_set = false)
|
||||
{
|
||||
static bool val_is_uninitialized = false;
|
||||
if(need_to_set)
|
||||
val_is_uninitialized = val_to_set;
|
||||
return val_is_uninitialized;
|
||||
}*/
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -150,7 +150,8 @@ namespace epee
|
|||
m_root.m_entries.clear();
|
||||
if(source.size() < sizeof(storage_block_header))
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)=" << sizeof(storage_block_header));
|
||||
LOG_WARNING("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)="
|
||||
<< sizeof(storage_block_header), LOG_LEVEL_2)
|
||||
return false;
|
||||
}
|
||||
storage_block_header* pbuff = (storage_block_header*)source.data();
|
||||
|
@ -158,12 +159,12 @@ namespace epee
|
|||
pbuff->m_signature_b != PORTABLE_STORAGE_SIGNATUREB
|
||||
)
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format - signature missmatch");
|
||||
LOG_WARNING("portable_storage: wrong binary format - signature missmatch", LOG_LEVEL_2);
|
||||
return false;
|
||||
}
|
||||
if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER)
|
||||
{
|
||||
LOG_ERROR("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver);
|
||||
LOG_WARNING("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver, LOG_LEVEL_2);
|
||||
return false;
|
||||
}
|
||||
TRY_ENTRY();
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include "parserse_base_utils.h"
|
||||
#include "file_io_utils.h"
|
||||
|
||||
|
@ -365,6 +368,7 @@ namespace epee
|
|||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
(void)(ex);
|
||||
LOG_PRINT_RED_L0("Failed to parse json, what: " << ex.what());
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "pragma_comp_defs.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "warnings.h"
|
||||
|
|
487
contrib/epee/include/string_tools.cpp
Normal file
487
contrib/epee/include/string_tools.cpp
Normal file
|
@ -0,0 +1,487 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "string_tools.h"
|
||||
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
#pragma comment (lib, "Rpcrt4.lib")
|
||||
#endif
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace string_tools
|
||||
{
|
||||
std::wstring get_str_from_guid(const boost::uuids::uuid& rid)
|
||||
{
|
||||
return boost::lexical_cast<std::wstring>(rid);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string get_str_from_guid_a(const boost::uuids::uuid& rid)
|
||||
{
|
||||
return boost::lexical_cast<std::string>(rid);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool get_guid_from_string( boost::uuids::uuid& inetifer, std::wstring str_id)
|
||||
{
|
||||
if(str_id.size() < 36)
|
||||
return false;
|
||||
|
||||
if('{' == *str_id.begin())
|
||||
str_id.erase(0, 1);
|
||||
|
||||
if('}' == *(--str_id.end()))
|
||||
str_id.erase(--str_id.end());
|
||||
|
||||
try
|
||||
{
|
||||
inetifer = boost::lexical_cast<boost::uuids::uuid>(str_id);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id)
|
||||
{
|
||||
std::string local_str_id = str_id;
|
||||
if(local_str_id.size() < 36)
|
||||
return false;
|
||||
|
||||
if('{' == *local_str_id.begin())
|
||||
local_str_id.erase(0, 1);
|
||||
|
||||
if('}' == *(--local_str_id.end()))
|
||||
local_str_id.erase(--local_str_id.end());
|
||||
|
||||
try
|
||||
{
|
||||
inetifer = boost::lexical_cast<boost::uuids::uuid>(local_str_id);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
//#ifdef _WINSOCK2API_
|
||||
std::string get_ip_string_from_int32(uint32_t ip)
|
||||
{
|
||||
in_addr adr;
|
||||
adr.s_addr = ip;
|
||||
const char* pbuf = inet_ntoa(adr);
|
||||
if(pbuf)
|
||||
return pbuf;
|
||||
else
|
||||
return "[failed]";
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str)
|
||||
{
|
||||
ip = inet_addr(ip_str.c_str());
|
||||
if(INADDR_NONE == ip)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres)
|
||||
{
|
||||
//parse ip and address
|
||||
std::string::size_type p = addres.find(':');
|
||||
if(p == std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::string ip_str = addres.substr(0, p);
|
||||
std::string port_str = addres.substr(p+1, addres.size());
|
||||
|
||||
if(!get_ip_int32_from_string(ip, ip_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_xtype_from_string(port, port_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string num_to_string_fast(int64_t val)
|
||||
{
|
||||
/*
|
||||
char buff[30] = {0};
|
||||
i64toa_s(val, buff, sizeof(buff)-1, 10);
|
||||
return buff;*/
|
||||
return boost::lexical_cast<std::string>(val);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool string_to_num_fast(const std::string& buff, int64_t& val)
|
||||
{
|
||||
//return get_xtype_from_string(val, buff);
|
||||
#if (defined _MSC_VER)
|
||||
val = _atoi64(buff.c_str());
|
||||
#else
|
||||
val = atoll(buff.c_str());
|
||||
#endif
|
||||
/*
|
||||
* val = atoi64(buff.c_str());
|
||||
*/
|
||||
if(buff != "0" && val == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool string_to_num_fast(const std::string& buff, int& val)
|
||||
{
|
||||
val = atoi(buff.c_str());
|
||||
if(buff != "0" && val == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
std::string system_time_to_string(const SYSTEMTIME& st)
|
||||
{
|
||||
|
||||
/*
|
||||
TIME_ZONE_INFORMATION tzi;
|
||||
GetTimeZoneInformation(&tzi);
|
||||
SystemTimeToTzSpecificLocalTime(&tzi, &stUTC, &stLocal);
|
||||
*/
|
||||
|
||||
char szTime[25], szDate[25];
|
||||
::GetTimeFormatA(
|
||||
LOCALE_USER_DEFAULT, // locale
|
||||
TIME_FORCE24HOURFORMAT, // options
|
||||
&st, // time
|
||||
NULL, // time format string
|
||||
szTime, // formatted string buffer
|
||||
25 // size of string buffer
|
||||
);
|
||||
|
||||
::GetDateFormatA(
|
||||
LOCALE_USER_DEFAULT, // locale
|
||||
NULL, // options
|
||||
&st, // date
|
||||
NULL, // date format
|
||||
szDate, // formatted string buffer
|
||||
25 // size of buffer
|
||||
);
|
||||
szTime[24] = szDate[24] = 0; //be happy :)
|
||||
|
||||
std::string res = szDate;
|
||||
(res += " " )+= szTime;
|
||||
return res;
|
||||
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool compare_no_case(const std::string& str1, const std::string& str2)
|
||||
{
|
||||
|
||||
return !boost::iequals(str1, str2);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool compare_no_case(const std::wstring& str1, const std::wstring& str2)
|
||||
{
|
||||
return !boost::iequals(str1, str2);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool is_match_prefix(const std::wstring& str1, const std::wstring& prefix)
|
||||
{
|
||||
if(prefix.size()>str1.size())
|
||||
return false;
|
||||
|
||||
if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool is_match_prefix(const std::string& str1, const std::string& prefix)
|
||||
{
|
||||
if(prefix.size()>str1.size())
|
||||
return false;
|
||||
|
||||
if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string& get_current_module_name()
|
||||
{
|
||||
static std::string module_name;
|
||||
return module_name;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string& get_current_module_folder()
|
||||
{
|
||||
static std::string module_folder;
|
||||
return module_folder;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef _WIN32
|
||||
std::string get_current_module_path()
|
||||
{
|
||||
char pname [5000] = {0};
|
||||
GetModuleFileNameA( NULL, pname, sizeof(pname));
|
||||
pname[sizeof(pname)-1] = 0; //be happy ;)
|
||||
return pname;
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
bool set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
std::string path_to_process = path_to_process_;
|
||||
#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;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool trim_left(std::string& str)
|
||||
{
|
||||
for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase(str.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool trim_right(std::string& str)
|
||||
{
|
||||
|
||||
for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase( --((it++).base()));
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string& trim(std::string& str)
|
||||
{
|
||||
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string trim(const std::string& str_)
|
||||
{
|
||||
std::string str = str_;
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string get_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return res;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string get_filename_from_path(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('\\');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
|
||||
res = str.substr(0, pos);
|
||||
return res;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef _WININET_
|
||||
std::string get_string_from_systemtime(const SYSTEMTIME& sys_time)
|
||||
{
|
||||
std::string result_string;
|
||||
|
||||
char buff[100] = {0};
|
||||
BOOL res = ::InternetTimeFromSystemTimeA(&sys_time, INTERNET_RFC1123_FORMAT, buff, 99);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to load SytemTime to string");
|
||||
}
|
||||
|
||||
result_string = buff;
|
||||
return result_string;
|
||||
|
||||
}
|
||||
//-------------------------------------------------------------------------------------
|
||||
SYSTEMTIME get_systemtime_from_string(const std::string& buff)
|
||||
{
|
||||
SYSTEMTIME result_time = {0};
|
||||
|
||||
BOOL res = ::InternetTimeToSystemTimeA(buff.c_str(), &result_time, NULL);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to load SytemTime from string " << buff << "interval set to 15 minutes");
|
||||
}
|
||||
|
||||
return result_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
const wchar_t* get_pc_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = INFO_BUFFER_SIZE;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
if (!GetComputerNameW( info, &bufCharCount ))
|
||||
info[0] = 0;
|
||||
else
|
||||
init = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
const wchar_t* get_user_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = INFO_BUFFER_SIZE;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
if (!GetUserNameW( info, &bufCharCount ))
|
||||
info[0] = 0;
|
||||
else
|
||||
init = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LM_
|
||||
const wchar_t* get_domain_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = 0;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
LPWSTR domain( NULL );
|
||||
NETSETUP_JOIN_STATUS status;
|
||||
info[0] = 0;
|
||||
|
||||
if (NET_API_STATUS result = NetGetJoinInformation( NULL, &domain, &status ))
|
||||
{
|
||||
LOG_ERROR("get_domain_name error: " << log_space::get_win32_err_descr(result));
|
||||
} else
|
||||
{
|
||||
StringCchCopyW( info, sizeof(info)/sizeof( info[0] ), domain );
|
||||
NetApiBufferFree((void*)domain);
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline
|
||||
std::string load_resource_string_a(int id, const char* pmodule_name = NULL)
|
||||
{
|
||||
//slow realization
|
||||
HMODULE h = ::GetModuleHandleA( pmodule_name );
|
||||
|
||||
char buff[2000] = {0};
|
||||
|
||||
::LoadStringA( h, id, buff, sizeof(buff));
|
||||
buff[sizeof(buff)-1] = 0; //be happy :)
|
||||
return buff;
|
||||
}
|
||||
inline
|
||||
std::wstring load_resource_string_w(int id, const char* pmodule_name = NULL)
|
||||
{
|
||||
//slow realization
|
||||
HMODULE h = ::GetModuleHandleA( pmodule_name );
|
||||
|
||||
wchar_t buff[2000] = {0};
|
||||
|
||||
::LoadStringW( h, id, buff, sizeof(buff) / sizeof( buff[0] ) );
|
||||
buff[(sizeof(buff)/sizeof(buff[0]))-1] = 0; //be happy :)
|
||||
return buff;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -24,24 +24,21 @@
|
|||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _STRING_TOOLS_H_
|
||||
#define _STRING_TOOLS_H_
|
||||
|
||||
//#include <objbase.h>
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
//#include <strsafe.h>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string/compare.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "warnings.h"
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "warnings.h"
|
||||
|
||||
#ifndef OUT
|
||||
#define OUT
|
||||
|
@ -51,71 +48,32 @@
|
|||
#pragma comment (lib, "Rpcrt4.lib")
|
||||
#endif
|
||||
|
||||
// Don't include lexical_cast.hpp, to reduce compilation time
|
||||
//#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace uuids {
|
||||
struct uuid;
|
||||
}
|
||||
|
||||
template <typename Target, typename Source>
|
||||
inline Target lexical_cast(const Source &arg);
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace string_tools
|
||||
{
|
||||
inline std::wstring get_str_from_guid(const boost::uuids::uuid& rid)
|
||||
{
|
||||
return boost::lexical_cast<std::wstring>(rid);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_str_from_guid_a(const boost::uuids::uuid& rid)
|
||||
{
|
||||
return boost::lexical_cast<std::string>(rid);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool get_guid_from_string( boost::uuids::uuid& inetifer, std::wstring str_id)
|
||||
{
|
||||
if(str_id.size() < 36)
|
||||
return false;
|
||||
|
||||
if('{' == *str_id.begin())
|
||||
str_id.erase(0, 1);
|
||||
|
||||
if('}' == *(--str_id.end()))
|
||||
str_id.erase(--str_id.end());
|
||||
|
||||
try
|
||||
{
|
||||
inetifer = boost::lexical_cast<boost::uuids::uuid>(str_id);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id)
|
||||
{
|
||||
std::string local_str_id = str_id;
|
||||
if(local_str_id.size() < 36)
|
||||
return false;
|
||||
|
||||
if('{' == *local_str_id.begin())
|
||||
local_str_id.erase(0, 1);
|
||||
|
||||
if('}' == *(--local_str_id.end()))
|
||||
local_str_id.erase(--local_str_id.end());
|
||||
|
||||
try
|
||||
{
|
||||
inetifer = boost::lexical_cast<boost::uuids::uuid>(local_str_id);
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::wstring get_str_from_guid(const boost::uuids::uuid& rid);
|
||||
std::string get_str_from_guid_a(const boost::uuids::uuid& rid);
|
||||
bool get_guid_from_string( boost::uuids::uuid& inetifer, std::wstring str_id);
|
||||
bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id);
|
||||
//----------------------------------------------------------------------------
|
||||
template<class CharT>
|
||||
std::basic_string<CharT> buff_to_hex(const std::basic_string<CharT>& s)
|
||||
{
|
||||
using namespace std;
|
||||
basic_stringstream<CharT> hexStream;
|
||||
hexStream << hex << noshowbase << setw(2);
|
||||
std::basic_stringstream<CharT> hexStream;
|
||||
hexStream << std::hex << std::noshowbase << std::setw(2);
|
||||
|
||||
for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
|
||||
{
|
||||
|
@ -127,13 +85,12 @@ namespace string_tools
|
|||
template<class CharT>
|
||||
std::basic_string<CharT> buff_to_hex_nodelimer(const std::basic_string<CharT>& s)
|
||||
{
|
||||
using namespace std;
|
||||
basic_stringstream<CharT> hexStream;
|
||||
hexStream << hex << noshowbase;
|
||||
std::basic_stringstream<CharT> hexStream;
|
||||
hexStream << std::hex << std::noshowbase;
|
||||
|
||||
for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
|
||||
{
|
||||
hexStream << setw(2) << setfill('0') << static_cast<unsigned int>(static_cast<unsigned char>(*it));
|
||||
hexStream << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(static_cast<unsigned char>(*it));
|
||||
}
|
||||
return hexStream.str();
|
||||
}
|
||||
|
@ -273,13 +230,6 @@ POP_WARNINGS
|
|||
return true;
|
||||
}
|
||||
|
||||
/* template<typename t_type>
|
||||
bool get_xparam_from_command_line(const std::map<std::string, std::string>& res, const std::basic_string<typename t_string::value_type> & key, t_type& val)
|
||||
{
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
template<class t_string, typename t_type>
|
||||
bool get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, t_type& val)
|
||||
{
|
||||
|
@ -295,22 +245,22 @@ POP_WARNINGS
|
|||
return true;
|
||||
}
|
||||
|
||||
template<class t_string, typename t_type>
|
||||
t_type get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, const t_type& default_value)
|
||||
{
|
||||
typename std::map<t_string, t_string>::const_iterator it = res.find(key);
|
||||
if(it == res.end())
|
||||
return default_value;
|
||||
template<class t_string, typename t_type>
|
||||
t_type get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, const t_type& default_value)
|
||||
{
|
||||
typename std::map<t_string, t_string>::const_iterator it = res.find(key);
|
||||
if(it == res.end())
|
||||
return default_value;
|
||||
|
||||
if(it->second.size())
|
||||
{
|
||||
t_type s;
|
||||
get_xtype_from_string(s, it->second);
|
||||
return s;
|
||||
}
|
||||
if(it->second.size())
|
||||
{
|
||||
t_type s;
|
||||
get_xtype_from_string(s, it->second);
|
||||
return s;
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
template<class t_string>
|
||||
bool have_in_command_line(const std::map<t_string, t_string>& res, const std::basic_string<typename t_string::value_type>& key)
|
||||
|
@ -322,243 +272,40 @@ POP_WARNINGS
|
|||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//#ifdef _WINSOCK2API_
|
||||
inline std::string get_ip_string_from_int32(uint32_t ip)
|
||||
{
|
||||
in_addr adr;
|
||||
adr.s_addr = ip;
|
||||
const char* pbuf = inet_ntoa(adr);
|
||||
if(pbuf)
|
||||
return pbuf;
|
||||
else
|
||||
return "[failed]";
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str)
|
||||
{
|
||||
ip = inet_addr(ip_str.c_str());
|
||||
if(INADDR_NONE == ip)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres)
|
||||
{
|
||||
//parse ip and address
|
||||
std::string::size_type p = addres.find(':');
|
||||
if(p == std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::string ip_str = addres.substr(0, p);
|
||||
std::string port_str = addres.substr(p+1, addres.size());
|
||||
|
||||
if(!get_ip_int32_from_string(ip, ip_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_xtype_from_string(port, port_str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//#endif
|
||||
//----------------------------------------------------------------------------
|
||||
std::string get_ip_string_from_int32(uint32_t ip);
|
||||
bool get_ip_int32_from_string(uint32_t& ip, const std::string& ip_str);
|
||||
bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres);
|
||||
//----------------------------------------------------------------------------
|
||||
template<typename t>
|
||||
inline std::string get_t_as_hex_nwidth(const t& v, std::streamsize w = 8)
|
||||
inline std::string get_t_as_hex_nwidth(const t& v, std::streamsize w = 8)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setfill ('0') << std::setw (w) << std::hex << std::noshowbase;
|
||||
ss << v;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline std::string num_to_string_fast(int64_t val)
|
||||
{
|
||||
/*
|
||||
char buff[30] = {0};
|
||||
i64toa_s(val, buff, sizeof(buff)-1, 10);
|
||||
return buff;*/
|
||||
return boost::lexical_cast<std::string>(val);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool string_to_num_fast(const std::string& buff, int64_t& val)
|
||||
{
|
||||
//return get_xtype_from_string(val, buff);
|
||||
#if (defined _MSC_VER)
|
||||
val = _atoi64(buff.c_str());
|
||||
#else
|
||||
val = atoll(buff.c_str());
|
||||
#endif
|
||||
/*
|
||||
* val = atoi64(buff.c_str());
|
||||
*/
|
||||
if(buff != "0" && val == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool string_to_num_fast(const std::string& buff, int& val)
|
||||
{
|
||||
val = atoi(buff.c_str());
|
||||
if(buff != "0" && val == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
std::string num_to_string_fast(int64_t val);
|
||||
bool string_to_num_fast(const std::string& buff, int64_t& val);
|
||||
bool string_to_num_fast(const std::string& buff, int& val);
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline std::string system_time_to_string(const SYSTEMTIME& st)
|
||||
{
|
||||
|
||||
/*
|
||||
TIME_ZONE_INFORMATION tzi;
|
||||
GetTimeZoneInformation(&tzi);
|
||||
SystemTimeToTzSpecificLocalTime(&tzi, &stUTC, &stLocal);
|
||||
*/
|
||||
|
||||
char szTime[25], szDate[25];
|
||||
::GetTimeFormatA(
|
||||
LOCALE_USER_DEFAULT, // locale
|
||||
TIME_FORCE24HOURFORMAT, // options
|
||||
&st, // time
|
||||
NULL, // time format string
|
||||
szTime, // formatted string buffer
|
||||
25 // size of string buffer
|
||||
);
|
||||
|
||||
::GetDateFormatA(
|
||||
LOCALE_USER_DEFAULT, // locale
|
||||
NULL, // options
|
||||
&st, // date
|
||||
NULL, // date format
|
||||
szDate, // formatted string buffer
|
||||
25 // size of buffer
|
||||
);
|
||||
szTime[24] = szDate[24] = 0; //be happy :)
|
||||
|
||||
std::string res = szDate;
|
||||
(res += " " )+= szTime;
|
||||
return res;
|
||||
|
||||
}
|
||||
std::string system_time_to_string(const SYSTEMTIME& st);
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
inline bool compare_no_case(const std::string& str1, const std::string& str2)
|
||||
{
|
||||
|
||||
return !boost::iequals(str1, str2);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool compare_no_case(const std::wstring& str1, const std::wstring& str2)
|
||||
{
|
||||
return !boost::iequals(str1, str2);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool is_match_prefix(const std::wstring& str1, const std::wstring& prefix)
|
||||
{
|
||||
if(prefix.size()>str1.size())
|
||||
return false;
|
||||
|
||||
if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool is_match_prefix(const std::string& str1, const std::string& prefix)
|
||||
{
|
||||
if(prefix.size()>str1.size())
|
||||
return false;
|
||||
|
||||
if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string& get_current_module_name()
|
||||
{
|
||||
static std::string module_name;
|
||||
return module_name;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string& get_current_module_folder()
|
||||
{
|
||||
static std::string module_folder;
|
||||
return module_folder;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool compare_no_case(const std::string& str1, const std::string& str2);
|
||||
bool compare_no_case(const std::wstring& str1, const std::wstring& str2);
|
||||
bool is_match_prefix(const std::wstring& str1, const std::wstring& prefix);
|
||||
bool is_match_prefix(const std::string& str1, const std::string& prefix);
|
||||
std::string& get_current_module_name();
|
||||
std::string& get_current_module_folder();
|
||||
#ifdef _WIN32
|
||||
inline std::string get_current_module_path()
|
||||
{
|
||||
char pname [5000] = {0};
|
||||
GetModuleFileNameA( NULL, pname, sizeof(pname));
|
||||
pname[sizeof(pname)-1] = 0; //be happy ;)
|
||||
return pname;
|
||||
}
|
||||
std::string get_current_module_path();
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
std::string path_to_process = path_to_process_;
|
||||
#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;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool trim_left(std::string& str)
|
||||
{
|
||||
for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase(str.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline bool trim_right(std::string& str)
|
||||
{
|
||||
|
||||
for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase( --((it++).base()));
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string& trim(std::string& str)
|
||||
{
|
||||
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string trim(const std::string& str_)
|
||||
{
|
||||
std::string str = str_;
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
return str;
|
||||
}
|
||||
bool set_module_name_and_folder(const std::string& path_to_process_);
|
||||
bool trim_left(std::string& str);
|
||||
bool trim_right(std::string& str);
|
||||
std::string& trim(std::string& str);
|
||||
std::string trim(const std::string& str_);
|
||||
//----------------------------------------------------------------------------
|
||||
template<class t_pod_type>
|
||||
std::string pod_to_hex(const t_pod_type& s)
|
||||
|
@ -584,161 +331,27 @@ POP_WARNINGS
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return res;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_filename_from_path(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('\\');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
inline std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
|
||||
res = str.substr(0, pos);
|
||||
return res;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string get_extension(const std::string& str);
|
||||
std::string get_filename_from_path(const std::string& str);
|
||||
std::string cut_off_extension(const std::string& str);
|
||||
#ifdef _WININET_
|
||||
inline std::string get_string_from_systemtime(const SYSTEMTIME& sys_time)
|
||||
{
|
||||
std::string result_string;
|
||||
|
||||
char buff[100] = {0};
|
||||
BOOL res = ::InternetTimeFromSystemTimeA(&sys_time, INTERNET_RFC1123_FORMAT, buff, 99);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to load SytemTime to string");
|
||||
}
|
||||
|
||||
result_string = buff;
|
||||
return result_string;
|
||||
|
||||
}
|
||||
//-------------------------------------------------------------------------------------
|
||||
inline SYSTEMTIME get_systemtime_from_string(const std::string& buff)
|
||||
{
|
||||
SYSTEMTIME result_time = {0};
|
||||
|
||||
BOOL res = ::InternetTimeToSystemTimeA(buff.c_str(), &result_time, NULL);
|
||||
if(!res)
|
||||
{
|
||||
LOG_ERROR("Failed to load SytemTime from string " << buff << "interval set to 15 minutes");
|
||||
}
|
||||
|
||||
return result_time;
|
||||
}
|
||||
std::string get_string_from_systemtime(const SYSTEMTIME& sys_time);
|
||||
SYSTEMTIME get_systemtime_from_string(const std::string& buff);
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
static const DWORD INFO_BUFFER_SIZE = 10000;
|
||||
const DWORD INFO_BUFFER_SIZE = 10000;
|
||||
|
||||
static const wchar_t* get_pc_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = INFO_BUFFER_SIZE;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
if (!GetComputerNameW( info, &bufCharCount ))
|
||||
info[0] = 0;
|
||||
else
|
||||
init = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static const wchar_t* get_user_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = INFO_BUFFER_SIZE;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
if (!GetUserNameW( info, &bufCharCount ))
|
||||
info[0] = 0;
|
||||
else
|
||||
init = true;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
const wchar_t* get_pc_name();
|
||||
const wchar_t* get_user_name();
|
||||
#endif
|
||||
|
||||
#ifdef _LM_
|
||||
static const wchar_t* get_domain_name()
|
||||
{
|
||||
static wchar_t info[INFO_BUFFER_SIZE];
|
||||
static DWORD bufCharCount = 0;
|
||||
static bool init = false;
|
||||
|
||||
if (!init) {
|
||||
LPWSTR domain( NULL );
|
||||
NETSETUP_JOIN_STATUS status;
|
||||
info[0] = 0;
|
||||
|
||||
if (NET_API_STATUS result = NetGetJoinInformation( NULL, &domain, &status ))
|
||||
{
|
||||
LOG_ERROR("get_domain_name error: " << log_space::get_win32_err_descr(result));
|
||||
} else
|
||||
{
|
||||
StringCchCopyW( info, sizeof(info)/sizeof( info[0] ), domain );
|
||||
NetApiBufferFree((void*)domain);
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
const wchar_t* get_domain_name();
|
||||
#endif
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline
|
||||
std::string load_resource_string_a(int id, const char* pmodule_name = NULL)
|
||||
{
|
||||
//slow realization
|
||||
HMODULE h = ::GetModuleHandleA( pmodule_name );
|
||||
|
||||
char buff[2000] = {0};
|
||||
|
||||
::LoadStringA( h, id, buff, sizeof(buff));
|
||||
buff[sizeof(buff)-1] = 0; //be happy :)
|
||||
return buff;
|
||||
}
|
||||
inline
|
||||
std::wstring load_resource_string_w(int id, const char* pmodule_name = NULL)
|
||||
{
|
||||
//slow realization
|
||||
HMODULE h = ::GetModuleHandleA( pmodule_name );
|
||||
|
||||
wchar_t buff[2000] = {0};
|
||||
|
||||
::LoadStringW( h, id, buff, sizeof(buff) / sizeof( buff[0] ) );
|
||||
buff[(sizeof(buff)/sizeof(buff[0]))-1] = 0; //be happy :)
|
||||
return buff;
|
||||
}
|
||||
std::string load_resource_string_a(int id, const char* pmodule_name = NULL);
|
||||
std::wstring load_resource_string_w(int id, const char* pmodule_name = NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,13 +32,9 @@
|
|||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
struct simple_event
|
||||
{
|
||||
simple_event() : m_rised(false)
|
||||
|
@ -70,7 +66,7 @@ namespace epee
|
|||
|
||||
class critical_section
|
||||
{
|
||||
boost::recursive_mutex m_section;
|
||||
std::recursive_mutex m_section;
|
||||
|
||||
public:
|
||||
//to make copy fake!
|
||||
|
@ -89,7 +85,6 @@ namespace epee
|
|||
void lock()
|
||||
{
|
||||
m_section.lock();
|
||||
//EnterCriticalSection( &m_section );
|
||||
}
|
||||
|
||||
void unlock()
|
||||
|
|
333
external/google/dense_hash_map
vendored
Normal file
333
external/google/dense_hash_map
vendored
Normal file
|
@ -0,0 +1,333 @@
|
|||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This is just a very thin wrapper over densehashtable.h, just
|
||||
// like sgi stl's stl_hash_map is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// NOTE: this is exactly like sparse_hash_map.h, with the word
|
||||
// "sparse" replaced by "dense", except for the addition of
|
||||
// set_empty_key().
|
||||
//
|
||||
// YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
|
||||
//
|
||||
// Otherwise your program will die in mysterious ways. (Note if you
|
||||
// use the constructor that takes an InputIterator range, you pass in
|
||||
// the empty key in the constructor, rather than after. As a result,
|
||||
// this constructor differs from the standard STL version.)
|
||||
//
|
||||
// In other respects, we adhere mostly to the STL semantics for
|
||||
// hash-map. One important exception is that insert() may invalidate
|
||||
// iterators entirely -- STL semantics are that insert() may reorder
|
||||
// iterators, but they all still refer to something valid in the
|
||||
// hashtable. Not so for us. Likewise, insert() may invalidate
|
||||
// pointers into the hashtable. (Whether insert invalidates iterators
|
||||
// and pointers depends on whether it results in a hashtable resize).
|
||||
// On the plus side, delete() doesn't invalidate iterators or pointers
|
||||
// at all, or even change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// If you want to use erase() you *must* call set_deleted_key(),
|
||||
// in addition to set_empty_key(), after construction.
|
||||
// The deleted and empty keys must differ.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This allows you to iterate over a hashtable,
|
||||
// and call erase(), without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_map: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_map: slowest, uses the least memory
|
||||
// (3) hash_map / unordered_map (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_map when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_map otherwise. I
|
||||
// don't personally use dense_hash_set ever; some people use it for
|
||||
// small sets with lots of lookups.
|
||||
//
|
||||
// - dense_hash_map has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_map uses .78X more bytes in overhead).
|
||||
// - sparse_hash_map has about 4 bits overhead per entry.
|
||||
// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/dense_hash_map.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _DENSE_HASH_MAP_H_
|
||||
#define _DENSE_HASH_MAP_H_
|
||||
|
||||
#include <google/sparsehash/sparseconfig.h>
|
||||
#include <stdio.h> // for FILE * in read()/write()
|
||||
#include <algorithm> // for the default template args
|
||||
#include <functional> // for equal_to
|
||||
#include <memory> // for alloc<>
|
||||
#include <utility> // for pair<>
|
||||
#include HASH_FUN_H // defined in config.h
|
||||
#include <google/sparsehash/libc_allocator_with_realloc.h>
|
||||
#include <google/sparsehash/densehashtable.h>
|
||||
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
using STL_NAMESPACE::pair;
|
||||
|
||||
template <class Key, class T,
|
||||
class HashFcn = SPARSEHASH_HASH<Key>, // defined in sparseconfig.h
|
||||
class EqualKey = STL_NAMESPACE::equal_to<Key>,
|
||||
class Alloc = libc_allocator_with_realloc<pair<const Key, T> > >
|
||||
class dense_hash_map {
|
||||
private:
|
||||
// Apparently select1st is not stl-standard, so we define our own
|
||||
struct SelectKey {
|
||||
typedef const Key& result_type;
|
||||
const Key& operator()(const pair<const Key, T>& p) const {
|
||||
return p.first;
|
||||
}
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(pair<const Key, T>* value, const Key& new_key) const {
|
||||
*const_cast<Key*>(&value->first) = new_key;
|
||||
// It would be nice to clear the rest of value here as well, in
|
||||
// case it's taking up a lot of memory. We do this by clearing
|
||||
// the value. This assumes T has a zero-arg constructor!
|
||||
value->second = T();
|
||||
}
|
||||
};
|
||||
// For operator[].
|
||||
struct DefaultValue {
|
||||
STL_NAMESPACE::pair<const Key, T> operator()(const Key& key) {
|
||||
return STL_NAMESPACE::make_pair(key, T());
|
||||
}
|
||||
};
|
||||
|
||||
// The actual data
|
||||
typedef dense_hashtable<pair<const Key, T>, Key, HashFcn, SelectKey,
|
||||
SetKey, EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef T data_type;
|
||||
typedef T mapped_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
// Iterator functions
|
||||
iterator begin() { return rep.begin(); }
|
||||
iterator end() { return rep.end(); }
|
||||
const_iterator begin() const { return rep.begin(); }
|
||||
const_iterator end() const { return rep.end(); }
|
||||
|
||||
|
||||
// These come from tr1's unordered_map. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) { return rep.begin(i); }
|
||||
local_iterator end(size_type i) { return rep.end(i); }
|
||||
const_local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
const_local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); }
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit dense_hash_map(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
dense_hash_map(InputIterator f, InputIterator l,
|
||||
const key_type& empty_key_val,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
set_empty_key(empty_key_val);
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
// This clears the hash map without resizing it down to the minimum
|
||||
// bucket count, but rather keeps the number of buckets constant
|
||||
void clear_no_resize() { rep.clear_no_resize(); }
|
||||
void swap(dense_hash_map& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) { return rep.find(key); }
|
||||
const_iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
data_type& operator[](const key_type& key) { // This is our value-add!
|
||||
// If key is in the hashtable, returns find(key)->second,
|
||||
// otherwise returns insert(value_type(key, T()).first->second.
|
||||
// Note it does not create an empty T unless the find fails.
|
||||
return rep.template find_or_insert<DefaultValue>(key).second;
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
// Insertion routines
|
||||
pair<iterator, bool> insert(const value_type& obj) { return rep.insert(obj); }
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator f, InputIterator l) { rep.insert(f, l); }
|
||||
void insert(const_iterator f, const_iterator l) { rep.insert(f, l); }
|
||||
// required for std::insert_iterator; the passed-in iterator is ignored
|
||||
iterator insert(iterator, const value_type& obj) { return insert(obj).first; }
|
||||
|
||||
|
||||
// Deletion and empty routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted and empty buckets. You can change the
|
||||
// deleted key as time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_empty_key(const key_type& key) { // YOU MUST CALL THIS!
|
||||
rep.set_empty_key(value_type(key, data_type())); // rep wants a value
|
||||
}
|
||||
key_type empty_key() const {
|
||||
return rep.empty_key().first; // rep returns a value
|
||||
}
|
||||
|
||||
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const dense_hash_map& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const dense_hash_map& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
bool write_metadata(FILE *fp) { return rep.write_metadata(fp); }
|
||||
bool read_metadata(FILE *fp) { return rep.read_metadata(fp); }
|
||||
bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
|
||||
bool read_nopointer_data(FILE *fp) { return rep.read_nopointer_data(fp); }
|
||||
};
|
||||
|
||||
// We need a global swap as well
|
||||
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
|
||||
dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
|
||||
hm1.swap(hm2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _DENSE_HASH_MAP_H_ */
|
308
external/google/dense_hash_set
vendored
Normal file
308
external/google/dense_hash_set
vendored
Normal file
|
@ -0,0 +1,308 @@
|
|||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This is just a very thin wrapper over densehashtable.h, just
|
||||
// like sgi stl's stl_hash_set is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// This is more different from dense_hash_map than you might think,
|
||||
// because all iterators for sets are const (you obviously can't
|
||||
// change the key, and for sets there is no value).
|
||||
//
|
||||
// NOTE: this is exactly like sparse_hash_set.h, with the word
|
||||
// "sparse" replaced by "dense", except for the addition of
|
||||
// set_empty_key().
|
||||
//
|
||||
// YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
|
||||
//
|
||||
// Otherwise your program will die in mysterious ways. (Note if you
|
||||
// use the constructor that takes an InputIterator range, you pass in
|
||||
// the empty key in the constructor, rather than after. As a result,
|
||||
// this constructor differs from the standard STL version.)
|
||||
//
|
||||
// In other respects, we adhere mostly to the STL semantics for
|
||||
// hash-map. One important exception is that insert() may invalidate
|
||||
// iterators entirely -- STL semantics are that insert() may reorder
|
||||
// iterators, but they all still refer to something valid in the
|
||||
// hashtable. Not so for us. Likewise, insert() may invalidate
|
||||
// pointers into the hashtable. (Whether insert invalidates iterators
|
||||
// and pointers depends on whether it results in a hashtable resize).
|
||||
// On the plus side, delete() doesn't invalidate iterators or pointers
|
||||
// at all, or even change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// If you want to use erase() you must call set_deleted_key(),
|
||||
// in addition to set_empty_key(), after construction.
|
||||
// The deleted and empty keys must differ.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This allows you to iterate over a hashtable,
|
||||
// and call erase(), without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_set: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_set: slowest, uses the least memory
|
||||
// (3) hash_set / unordered_set (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_set when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_set otherwise. I
|
||||
// don't personally use dense_hash_set ever; some people use it for
|
||||
// small sets with lots of lookups.
|
||||
//
|
||||
// - dense_hash_set has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_set uses .78X more bytes in overhead).
|
||||
// - sparse_hash_set has about 4 bits overhead per entry.
|
||||
// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/dense_hash_set.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _DENSE_HASH_SET_H_
|
||||
#define _DENSE_HASH_SET_H_
|
||||
|
||||
#include <google/sparsehash/sparseconfig.h>
|
||||
#include <stdio.h> // for FILE * in read()/write()
|
||||
#include <algorithm> // for the default template args
|
||||
#include <functional> // for equal_to
|
||||
#include <memory> // for alloc<>
|
||||
#include <utility> // for pair<>
|
||||
#include HASH_FUN_H // defined in config.h
|
||||
#include <google/sparsehash/libc_allocator_with_realloc.h>
|
||||
#include <google/sparsehash/densehashtable.h>
|
||||
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
using STL_NAMESPACE::pair;
|
||||
|
||||
template <class Value,
|
||||
class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
|
||||
class EqualKey = STL_NAMESPACE::equal_to<Value>,
|
||||
class Alloc = libc_allocator_with_realloc<Value> >
|
||||
class dense_hash_set {
|
||||
private:
|
||||
// Apparently identity is not stl-standard, so we define our own
|
||||
struct Identity {
|
||||
typedef const Value& result_type;
|
||||
const Value& operator()(const Value& v) const { return v; }
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(Value* value, const Value& new_key) const {
|
||||
*value = new_key;
|
||||
}
|
||||
};
|
||||
|
||||
// The actual data
|
||||
typedef dense_hashtable<Value, Value, HashFcn, Identity, SetKey,
|
||||
EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::const_pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::const_reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::const_iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::const_local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
|
||||
// Iterator functions -- recall all iterators are const
|
||||
iterator begin() const { return rep.begin(); }
|
||||
iterator end() const { return rep.end(); }
|
||||
|
||||
// These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); } // tr1 name
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit dense_hash_set(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
dense_hash_set(InputIterator f, InputIterator l,
|
||||
const key_type& empty_key_val,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
set_empty_key(empty_key_val);
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
// This clears the hash set without resizing it down to the minimum
|
||||
// bucket count, but rather keeps the number of buckets constant
|
||||
void clear_no_resize() { rep.clear_no_resize(); }
|
||||
void swap(dense_hash_set& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
pair<iterator, iterator> equal_range(const key_type& key) const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
|
||||
// Insertion routines
|
||||
pair<iterator, bool> insert(const value_type& obj) {
|
||||
pair<typename ht::iterator, bool> p = rep.insert(obj);
|
||||
return pair<iterator, bool>(p.first, p.second); // const to non-const
|
||||
}
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator f, InputIterator l) { rep.insert(f, l); }
|
||||
void insert(const_iterator f, const_iterator l) { rep.insert(f, l); }
|
||||
// required for std::insert_iterator; the passed-in iterator is ignored
|
||||
iterator insert(iterator, const value_type& obj) { return insert(obj).first; }
|
||||
|
||||
|
||||
// Deletion and empty routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted and empty buckets. You can change the
|
||||
// deleted key as time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_empty_key(const key_type& key) { rep.set_empty_key(key); }
|
||||
key_type empty_key() const { return rep.empty_key(); }
|
||||
|
||||
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const dense_hash_set& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const dense_hash_set& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
bool write_metadata(FILE *fp) { return rep.write_metadata(fp); }
|
||||
bool read_metadata(FILE *fp) { return rep.read_metadata(fp); }
|
||||
bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
|
||||
bool read_nopointer_data(FILE *fp) { return rep.read_nopointer_data(fp); }
|
||||
};
|
||||
|
||||
template <class Val, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
|
||||
dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
|
||||
hs1.swap(hs2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _DENSE_HASH_SET_H_ */
|
310
external/google/sparse_hash_map
vendored
Normal file
310
external/google/sparse_hash_map
vendored
Normal file
|
@ -0,0 +1,310 @@
|
|||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This is just a very thin wrapper over sparsehashtable.h, just
|
||||
// like sgi stl's stl_hash_map is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// We adhere mostly to the STL semantics for hash-map. One important
|
||||
// exception is that insert() may invalidate iterators entirely -- STL
|
||||
// semantics are that insert() may reorder iterators, but they all
|
||||
// still refer to something valid in the hashtable. Not so for us.
|
||||
// Likewise, insert() may invalidate pointers into the hashtable.
|
||||
// (Whether insert invalidates iterators and pointers depends on
|
||||
// whether it results in a hashtable resize). On the plus side,
|
||||
// delete() doesn't invalidate iterators or pointers at all, or even
|
||||
// change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// Unlike STL's hash_map, if you want to use erase() you
|
||||
// *must* call set_deleted_key() after construction.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This is what allows you to iterate over a hashtable
|
||||
// and call erase() without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_map: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_map: slowest, uses the least memory
|
||||
// (3) hash_map / unordered_map (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_map when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_map otherwise. I
|
||||
// don't personally use dense_hash_map ever; some people use it for
|
||||
// small maps with lots of lookups.
|
||||
//
|
||||
// - dense_hash_map has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_map uses .78X more bytes in overhead).
|
||||
// - sparse_hash_map has about 4 bits overhead per entry.
|
||||
// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/sparse_hash_map.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _SPARSE_HASH_MAP_H_
|
||||
#define _SPARSE_HASH_MAP_H_
|
||||
|
||||
#include <google/sparsehash/sparseconfig.h>
|
||||
#include <stdio.h> // for FILE * in read()/write()
|
||||
#include <algorithm> // for the default template args
|
||||
#include <functional> // for equal_to
|
||||
#include <memory> // for alloc<>
|
||||
#include <utility> // for pair<>
|
||||
#include HASH_FUN_H // defined in config.h
|
||||
#include <google/sparsehash/libc_allocator_with_realloc.h>
|
||||
#include <google/sparsehash/sparsehashtable.h>
|
||||
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
using STL_NAMESPACE::pair;
|
||||
|
||||
template <class Key, class T,
|
||||
class HashFcn = SPARSEHASH_HASH<Key>, // defined in sparseconfig.h
|
||||
class EqualKey = STL_NAMESPACE::equal_to<Key>,
|
||||
class Alloc = libc_allocator_with_realloc<pair<const Key, T> > >
|
||||
class sparse_hash_map {
|
||||
private:
|
||||
// Apparently select1st is not stl-standard, so we define our own
|
||||
struct SelectKey {
|
||||
typedef const Key& result_type;
|
||||
const Key& operator()(const pair<const Key, T>& p) const {
|
||||
return p.first;
|
||||
}
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(pair<const Key, T>* value, const Key& new_key) const {
|
||||
*const_cast<Key*>(&value->first) = new_key;
|
||||
// It would be nice to clear the rest of value here as well, in
|
||||
// case it's taking up a lot of memory. We do this by clearing
|
||||
// the value. This assumes T has a zero-arg constructor!
|
||||
value->second = T();
|
||||
}
|
||||
};
|
||||
// For operator[].
|
||||
struct DefaultValue {
|
||||
STL_NAMESPACE::pair<const Key, T> operator()(const Key& key) {
|
||||
return STL_NAMESPACE::make_pair(key, T());
|
||||
}
|
||||
};
|
||||
|
||||
// The actual data
|
||||
typedef sparse_hashtable<pair<const Key, T>, Key, HashFcn, SelectKey,
|
||||
SetKey, EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef T data_type;
|
||||
typedef T mapped_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
// Iterator functions
|
||||
iterator begin() { return rep.begin(); }
|
||||
iterator end() { return rep.end(); }
|
||||
const_iterator begin() const { return rep.begin(); }
|
||||
const_iterator end() const { return rep.end(); }
|
||||
|
||||
// These come from tr1's unordered_map. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) { return rep.begin(i); }
|
||||
local_iterator end(size_type i) { return rep.end(i); }
|
||||
const_local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
const_local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); }
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit sparse_hash_map(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
sparse_hash_map(InputIterator f, InputIterator l,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
void swap(sparse_hash_map& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) { return rep.find(key); }
|
||||
const_iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
data_type& operator[](const key_type& key) { // This is our value-add!
|
||||
// If key is in the hashtable, returns find(key)->second,
|
||||
// otherwise returns insert(value_type(key, T()).first->second.
|
||||
// Note it does not create an empty T unless the find fails.
|
||||
return rep.template find_or_insert<DefaultValue>(key).second;
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
// Insertion routines
|
||||
pair<iterator, bool> insert(const value_type& obj) { return rep.insert(obj); }
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator f, InputIterator l) { rep.insert(f, l); }
|
||||
void insert(const_iterator f, const_iterator l) { rep.insert(f, l); }
|
||||
// required for std::insert_iterator; the passed-in iterator is ignored
|
||||
iterator insert(iterator, const value_type& obj) { return insert(obj).first; }
|
||||
|
||||
|
||||
// Deletion routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted buckets. You can change the key as
|
||||
// time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_deleted_key(const key_type& key) {
|
||||
rep.set_deleted_key(key);
|
||||
}
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const sparse_hash_map& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const sparse_hash_map& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
bool write_metadata(FILE *fp) { return rep.write_metadata(fp); }
|
||||
bool read_metadata(FILE *fp) { return rep.read_metadata(fp); }
|
||||
bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
|
||||
bool read_nopointer_data(FILE *fp) { return rep.read_nopointer_data(fp); }
|
||||
};
|
||||
|
||||
// We need a global swap as well
|
||||
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
|
||||
sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
|
||||
hm1.swap(hm2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _SPARSE_HASH_MAP_H_ */
|
285
external/google/sparse_hash_set
vendored
Normal file
285
external/google/sparse_hash_set
vendored
Normal file
|
@ -0,0 +1,285 @@
|
|||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Craig Silverstein
|
||||
//
|
||||
// This is just a very thin wrapper over sparsehashtable.h, just
|
||||
// like sgi stl's stl_hash_set is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// This is more different from sparse_hash_map than you might think,
|
||||
// because all iterators for sets are const (you obviously can't
|
||||
// change the key, and for sets there is no value).
|
||||
//
|
||||
// We adhere mostly to the STL semantics for hash-map. One important
|
||||
// exception is that insert() may invalidate iterators entirely -- STL
|
||||
// semantics are that insert() may reorder iterators, but they all
|
||||
// still refer to something valid in the hashtable. Not so for us.
|
||||
// Likewise, insert() may invalidate pointers into the hashtable.
|
||||
// (Whether insert invalidates iterators and pointers depends on
|
||||
// whether it results in a hashtable resize). On the plus side,
|
||||
// delete() doesn't invalidate iterators or pointers at all, or even
|
||||
// change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// Unlike STL's hash_map, if you want to use erase() you
|
||||
// *must* call set_deleted_key() after construction.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This allows you to iterate over a hashtable,
|
||||
// and call erase(), without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_set: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_set: slowest, uses the least memory
|
||||
// (3) hash_set / unordered_set (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_set when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_set otherwise. I
|
||||
// don't personally use dense_hash_set ever; some people use it for
|
||||
// small sets with lots of lookups.
|
||||
//
|
||||
// - dense_hash_set has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_set uses .78X more bytes in overhead).
|
||||
// - sparse_hash_set has about 4 bits overhead per entry.
|
||||
// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/sparse_hash_set.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _SPARSE_HASH_SET_H_
|
||||
#define _SPARSE_HASH_SET_H_
|
||||
|
||||
#include <google/sparsehash/sparseconfig.h>
|
||||
#include <stdio.h> // for FILE * in read()/write()
|
||||
#include <algorithm> // for the default template args
|
||||
#include <functional> // for equal_to
|
||||
#include <memory> // for alloc<>
|
||||
#include <utility> // for pair<>
|
||||
#include HASH_FUN_H // defined in config.h
|
||||
#include <google/sparsehash/libc_allocator_with_realloc.h>
|
||||
#include <google/sparsehash/sparsehashtable.h>
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
using STL_NAMESPACE::pair;
|
||||
|
||||
template <class Value,
|
||||
class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
|
||||
class EqualKey = STL_NAMESPACE::equal_to<Value>,
|
||||
class Alloc = libc_allocator_with_realloc<Value> >
|
||||
class sparse_hash_set {
|
||||
private:
|
||||
// Apparently identity is not stl-standard, so we define our own
|
||||
struct Identity {
|
||||
typedef const Value& result_type;
|
||||
const Value& operator()(const Value& v) const { return v; }
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(Value* value, const Value& new_key) const {
|
||||
*value = new_key;
|
||||
}
|
||||
};
|
||||
|
||||
typedef sparse_hashtable<Value, Value, HashFcn, Identity, SetKey,
|
||||
EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::const_pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::const_reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::const_iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::const_local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
|
||||
// Iterator functions -- recall all iterators are const
|
||||
iterator begin() const { return rep.begin(); }
|
||||
iterator end() const { return rep.end(); }
|
||||
|
||||
// These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); } // tr1 name
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit sparse_hash_set(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
sparse_hash_set(InputIterator f, InputIterator l,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
void swap(sparse_hash_set& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
pair<iterator, iterator> equal_range(const key_type& key) const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
// Insertion routines
|
||||
pair<iterator, bool> insert(const value_type& obj) {
|
||||
pair<typename ht::iterator, bool> p = rep.insert(obj);
|
||||
return pair<iterator, bool>(p.first, p.second); // const to non-const
|
||||
}
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator f, InputIterator l) { rep.insert(f, l); }
|
||||
void insert(const_iterator f, const_iterator l) { rep.insert(f, l); }
|
||||
// required for std::insert_iterator; the passed-in iterator is ignored
|
||||
iterator insert(iterator, const value_type& obj) { return insert(obj).first; }
|
||||
|
||||
|
||||
// Deletion routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted buckets. You can change the key as
|
||||
// time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const sparse_hash_set& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const sparse_hash_set& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
bool write_metadata(FILE *fp) { return rep.write_metadata(fp); }
|
||||
bool read_metadata(FILE *fp) { return rep.read_metadata(fp); }
|
||||
bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
|
||||
bool read_nopointer_data(FILE *fp) { return rep.read_nopointer_data(fp); }
|
||||
};
|
||||
|
||||
template <class Val, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
|
||||
sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
|
||||
hs1.swap(hs2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _SPARSE_HASH_SET_H_ */
|
1268
external/google/sparsehash/densehashtable.h
vendored
Normal file
1268
external/google/sparsehash/densehashtable.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
178
external/google/sparsehash/hashtable-common.h
vendored
Normal file
178
external/google/sparsehash/hashtable-common.h
vendored
Normal file
|
@ -0,0 +1,178 @@
|
|||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Giao Nguyen
|
||||
|
||||
#ifndef UTIL_GTL_HASHTABLE_COMMON_H_
|
||||
#define UTIL_GTL_HASHTABLE_COMMON_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// Settings contains parameters for growing and shrinking the table.
|
||||
// It also packages zero-size functor (ie. hasher).
|
||||
|
||||
template<typename Key, typename HashFunc,
|
||||
typename SizeType, int HT_MIN_BUCKETS>
|
||||
class sh_hashtable_settings : public HashFunc {
|
||||
public:
|
||||
typedef Key key_type;
|
||||
typedef HashFunc hasher;
|
||||
typedef SizeType size_type;
|
||||
|
||||
public:
|
||||
sh_hashtable_settings(const hasher& hf,
|
||||
const float ht_occupancy_flt,
|
||||
const float ht_empty_flt)
|
||||
: hasher(hf),
|
||||
enlarge_threshold_(0),
|
||||
shrink_threshold_(0),
|
||||
consider_shrink_(false),
|
||||
use_empty_(false),
|
||||
use_deleted_(false),
|
||||
num_ht_copies_(0) {
|
||||
set_enlarge_factor(ht_occupancy_flt);
|
||||
set_shrink_factor(ht_empty_flt);
|
||||
}
|
||||
|
||||
size_type hash(const key_type& v) const {
|
||||
return hasher::operator()(v);
|
||||
}
|
||||
|
||||
float enlarge_factor() const {
|
||||
return enlarge_factor_;
|
||||
}
|
||||
void set_enlarge_factor(float f) {
|
||||
enlarge_factor_ = f;
|
||||
}
|
||||
float shrink_factor() const {
|
||||
return shrink_factor_;
|
||||
}
|
||||
void set_shrink_factor(float f) {
|
||||
shrink_factor_ = f;
|
||||
}
|
||||
|
||||
size_type enlarge_threshold() const {
|
||||
return enlarge_threshold_;
|
||||
}
|
||||
void set_enlarge_threshold(size_type t) {
|
||||
enlarge_threshold_ = t;
|
||||
}
|
||||
size_type shrink_threshold() const {
|
||||
return shrink_threshold_;
|
||||
}
|
||||
void set_shrink_threshold(size_type t) {
|
||||
shrink_threshold_ = t;
|
||||
}
|
||||
|
||||
size_type enlarge_size(size_type x) const {
|
||||
return static_cast<size_type>(x * enlarge_factor_);
|
||||
}
|
||||
size_type shrink_size(size_type x) const {
|
||||
return static_cast<size_type>(x * shrink_factor_);
|
||||
}
|
||||
|
||||
bool consider_shrink() const {
|
||||
return consider_shrink_;
|
||||
}
|
||||
void set_consider_shrink(bool t) {
|
||||
consider_shrink_ = t;
|
||||
}
|
||||
|
||||
bool use_empty() const {
|
||||
return use_empty_;
|
||||
}
|
||||
void set_use_empty(bool t) {
|
||||
use_empty_ = t;
|
||||
}
|
||||
|
||||
bool use_deleted() const {
|
||||
return use_deleted_;
|
||||
}
|
||||
void set_use_deleted(bool t) {
|
||||
use_deleted_ = t;
|
||||
}
|
||||
|
||||
size_type num_ht_copies() const {
|
||||
return static_cast<size_type>(num_ht_copies_);
|
||||
}
|
||||
void inc_num_ht_copies() {
|
||||
++num_ht_copies_;
|
||||
}
|
||||
|
||||
// Reset the enlarge and shrink thresholds
|
||||
void reset_thresholds(size_type num_buckets) {
|
||||
set_enlarge_threshold(enlarge_size(num_buckets));
|
||||
set_shrink_threshold(shrink_size(num_buckets));
|
||||
// whatever caused us to reset already considered
|
||||
set_consider_shrink(false);
|
||||
}
|
||||
|
||||
// Caller is resposible for calling reset_threshold right after
|
||||
// set_resizing_parameters.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
assert(shrink >= 0.0);
|
||||
assert(grow <= 1.0);
|
||||
if (shrink > grow/2.0f)
|
||||
shrink = grow / 2.0f; // otherwise we thrash hashtable size
|
||||
set_shrink_factor(shrink);
|
||||
set_enlarge_factor(grow);
|
||||
}
|
||||
|
||||
// This is the smallest size a hashtable can be without being too crowded
|
||||
// If you like, you can give a min #buckets as well as a min #elts
|
||||
size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) {
|
||||
float enlarge = enlarge_factor();
|
||||
size_type sz = HT_MIN_BUCKETS; // min buckets allowed
|
||||
while ( sz < min_buckets_wanted ||
|
||||
num_elts >= static_cast<size_type>(sz * enlarge) ) {
|
||||
// This just prevents overflowing size_type, since sz can exceed
|
||||
// max_size() here.
|
||||
if (static_cast<size_type>(sz * 2) < sz) {
|
||||
throw std::length_error("resize overflow"); // protect against overflow
|
||||
}
|
||||
sz *= 2;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
private:
|
||||
size_type enlarge_threshold_; // table.size() * enlarge_factor
|
||||
size_type shrink_threshold_; // table.size() * shrink_factor
|
||||
float enlarge_factor_; // how full before resize
|
||||
float shrink_factor_; // how empty before resize
|
||||
// consider_shrink=true if we should try to shrink before next insert
|
||||
bool consider_shrink_;
|
||||
bool use_empty_; // used only by densehashtable, not sparsehashtable
|
||||
bool use_deleted_; // false until delkey has been set
|
||||
// num_ht_copies is a counter incremented every Copy/Move
|
||||
unsigned int num_ht_copies_;
|
||||
};
|
||||
|
||||
#endif // UTIL_GTL_HASHTABLE_COMMON_H_
|
121
external/google/sparsehash/libc_allocator_with_realloc.h
vendored
Normal file
121
external/google/sparsehash/libc_allocator_with_realloc.h
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Guilin Chen
|
||||
|
||||
#ifndef UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
|
||||
#define UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
|
||||
|
||||
#include <google/sparsehash/sparseconfig.h>
|
||||
|
||||
#include <stdlib.h> // for malloc/realloc/free
|
||||
#include <stddef.h> // for ptrdiff_t
|
||||
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template<class T>
|
||||
class libc_allocator_with_realloc {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
|
||||
libc_allocator_with_realloc() {}
|
||||
libc_allocator_with_realloc(const libc_allocator_with_realloc&) {}
|
||||
~libc_allocator_with_realloc() {}
|
||||
|
||||
pointer address(reference r) const { return &r; }
|
||||
const_pointer address(const_reference r) const { return &r; }
|
||||
|
||||
pointer allocate(size_type n, const_pointer = 0) {
|
||||
return static_cast<pointer>(malloc(n * sizeof(value_type)));
|
||||
}
|
||||
void deallocate(pointer p, size_type) {
|
||||
free(p);
|
||||
}
|
||||
pointer reallocate(pointer p, size_type n) {
|
||||
return static_cast<pointer>(realloc(p, n * sizeof(value_type)));
|
||||
}
|
||||
|
||||
size_type max_size() const {
|
||||
return static_cast<size_type>(-1) / sizeof(value_type);
|
||||
}
|
||||
|
||||
void construct(pointer p, const value_type& val) {
|
||||
new(p) value_type(val);
|
||||
}
|
||||
void destroy(pointer p) { p->~value_type(); }
|
||||
|
||||
template <class U>
|
||||
libc_allocator_with_realloc(const libc_allocator_with_realloc<U>&) {}
|
||||
|
||||
template<class U>
|
||||
struct rebind {
|
||||
typedef libc_allocator_with_realloc<U> other;
|
||||
};
|
||||
};
|
||||
|
||||
// libc_allocator_with_realloc<void> specialization.
|
||||
template<>
|
||||
class libc_allocator_with_realloc<void> {
|
||||
public:
|
||||
typedef void value_type;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
|
||||
template<class U>
|
||||
struct rebind {
|
||||
typedef libc_allocator_with_realloc<U> other;
|
||||
};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline bool operator==(const libc_allocator_with_realloc<T>&,
|
||||
const libc_allocator_with_realloc<T>&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator!=(const libc_allocator_with_realloc<T>&,
|
||||
const libc_allocator_with_realloc<T>&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif // UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
|
37
external/google/sparsehash/os_config.h
vendored
Normal file
37
external/google/sparsehash/os_config.h
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef _MSC_VER
|
||||
//non-win version
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `uint16_t'. */
|
||||
#define HAVE_UINT16_T 1
|
||||
|
||||
/* Define to 1 if the system has the type `u_int16_t'. */
|
||||
#define HAVE_U_INT16_T 1
|
||||
|
||||
/* Define to 1 if the system has the type `__uint16'. */
|
||||
/* #undef HAVE___UINT16 */
|
||||
|
||||
#else
|
||||
//win version
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if the system has the type `uint16_t'. */
|
||||
#undef HAVE_UINT16_T
|
||||
|
||||
/* Define to 1 if the system has the type `u_int16_t'. */
|
||||
#undef HAVE_U_INT16_T
|
||||
|
||||
/* Define to 1 if the system has the type `__uint16'. */
|
||||
#define HAVE___UINT16 1
|
||||
|
||||
#endif
|
39
external/google/sparsehash/sparseconfig.h
vendored
Normal file
39
external/google/sparsehash/sparseconfig.h
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* NOTE: This file is for internal use only.
|
||||
* Do not use these #defines in your own program!
|
||||
*/
|
||||
|
||||
/* Namespace for Google classes */
|
||||
#define GOOGLE_NAMESPACE ::google
|
||||
|
||||
/* the location of the header defining hash functions */
|
||||
#define HASH_FUN_H <functional>
|
||||
|
||||
/* the namespace of the hash<> function */
|
||||
#define HASH_NAMESPACE std
|
||||
|
||||
/* Define to 1 if the system has the type `long long'. */
|
||||
#define HAVE_LONG_LONG 1
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#define HAVE_MEMCPY 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* The system-provided hash function including the namespace. */
|
||||
#define SPARSEHASH_HASH HASH_NAMESPACE::hash
|
||||
|
||||
/* The system-provided hash function, in namespace HASH_NAMESPACE. */
|
||||
#define SPARSEHASH_HASH_NO_NAMESPACE hash
|
||||
|
||||
/* the namespace where STL code like vector<> is defined */
|
||||
#define STL_NAMESPACE std
|
||||
|
||||
/* Stops putting the code inside the Google namespace */
|
||||
#define _END_GOOGLE_NAMESPACE_ }
|
||||
|
||||
/* Puts following code inside the Google namespace */
|
||||
#define _START_GOOGLE_NAMESPACE_ namespace google {
|
||||
|
||||
#include "os_config.h"
|
37
external/google/sparsehash/sparseconfig_win.h
vendored
Normal file
37
external/google/sparsehash/sparseconfig_win.h
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* NOTE: This file is for internal use only.
|
||||
* Do not use these #defines in your own program!
|
||||
*/
|
||||
|
||||
/* Namespace for Google classes */
|
||||
#define GOOGLE_NAMESPACE ::google
|
||||
|
||||
/* the location of the header defining hash functions */
|
||||
#define HASH_FUN_H <functional>
|
||||
|
||||
/* the namespace of the hash<> function */
|
||||
#define HASH_NAMESPACE std
|
||||
|
||||
/* Define to 1 if the system has the type `long long'. */
|
||||
#define HAVE_LONG_LONG 1
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#define HAVE_MEMCPY 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* The system-provided hash function including the namespace. */
|
||||
#define SPARSEHASH_HASH HASH_NAMESPACE::hash
|
||||
|
||||
/* The system-provided hash function, in namespace HASH_NAMESPACE. */
|
||||
#define SPARSEHASH_HASH_NO_NAMESPACE hash
|
||||
|
||||
/* the namespace where STL code like vector<> is defined */
|
||||
#define STL_NAMESPACE std
|
||||
|
||||
/* Stops putting the code inside the Google namespace */
|
||||
#define _END_GOOGLE_NAMESPACE_ }
|
||||
|
||||
/* Puts following code inside the Google namespace */
|
||||
#define _START_GOOGLE_NAMESPACE_ namespace google {
|
1190
external/google/sparsehash/sparsehashtable.h
vendored
Normal file
1190
external/google/sparsehash/sparsehashtable.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
1598
external/google/sparsetable
vendored
Normal file
1598
external/google/sparsetable
vendored
Normal file
File diff suppressed because it is too large
Load diff
336
external/google/type_traits.h
vendored
Normal file
336
external/google/type_traits.h
vendored
Normal file
|
@ -0,0 +1,336 @@
|
|||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
// Author: Matt Austern
|
||||
//
|
||||
// Define a small subset of tr1 type traits. The traits we define are:
|
||||
// is_integral
|
||||
// is_floating_point
|
||||
// is_pointer
|
||||
// is_enum
|
||||
// is_reference
|
||||
// is_pod
|
||||
// has_trivial_constructor
|
||||
// has_trivial_copy
|
||||
// has_trivial_assign
|
||||
// has_trivial_destructor
|
||||
// remove_const
|
||||
// remove_volatile
|
||||
// remove_cv
|
||||
// remove_reference
|
||||
// add_reference
|
||||
// remove_pointer
|
||||
// is_same
|
||||
// is_convertible
|
||||
// We can add more type traits as required.
|
||||
|
||||
#ifndef BASE_TYPE_TRAITS_H_
|
||||
#define BASE_TYPE_TRAITS_H_
|
||||
|
||||
#include <google/sparsehash/sparseconfig.h>
|
||||
#include <utility> // For pair
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
// integral_constant, defined in tr1, is a wrapper for an integer
|
||||
// value. We don't really need this generality; we could get away
|
||||
// with hardcoding the integer type to bool. We use the fully
|
||||
// general integer_constant for compatibility with tr1.
|
||||
|
||||
template<class T, T v>
|
||||
struct integral_constant {
|
||||
static const T value = v;
|
||||
typedef T value_type;
|
||||
typedef integral_constant<T, v> type;
|
||||
};
|
||||
|
||||
template <class T, T v> const T integral_constant<T, v>::value;
|
||||
|
||||
// Abbreviations: true_type and false_type are structs that represent
|
||||
// boolean true and false values.
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
|
||||
// Types small_ and big_ are guaranteed such that sizeof(small_) <
|
||||
// sizeof(big_)
|
||||
typedef char small_;
|
||||
|
||||
struct big_ {
|
||||
char dummy[2];
|
||||
};
|
||||
|
||||
template <class T> struct is_integral;
|
||||
template <class T> struct is_floating_point;
|
||||
template <class T> struct is_pointer;
|
||||
// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least)
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
// is_enum uses is_convertible, which is not available on MSVC.
|
||||
template <class T> struct is_enum;
|
||||
#endif
|
||||
template <class T> struct is_reference;
|
||||
template <class T> struct is_pod;
|
||||
template <class T> struct has_trivial_constructor;
|
||||
template <class T> struct has_trivial_copy;
|
||||
template <class T> struct has_trivial_assign;
|
||||
template <class T> struct has_trivial_destructor;
|
||||
template <class T> struct remove_const;
|
||||
template <class T> struct remove_volatile;
|
||||
template <class T> struct remove_cv;
|
||||
template <class T> struct remove_reference;
|
||||
template <class T> struct add_reference;
|
||||
template <class T> struct remove_pointer;
|
||||
template <class T, class U> struct is_same;
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
template <class From, class To> struct is_convertible;
|
||||
#endif
|
||||
|
||||
// is_integral is false except for the built-in integer types.
|
||||
template <class T> struct is_integral : false_type { };
|
||||
template<> struct is_integral<bool> : true_type { };
|
||||
template<> struct is_integral<char> : true_type { };
|
||||
template<> struct is_integral<unsigned char> : true_type { };
|
||||
template<> struct is_integral<signed char> : true_type { };
|
||||
#if defined(_MSC_VER)
|
||||
// wchar_t is not by default a distinct type from unsigned short in
|
||||
// Microsoft C.
|
||||
// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
|
||||
template<> struct is_integral<__wchar_t> : true_type { };
|
||||
#else
|
||||
template<> struct is_integral<wchar_t> : true_type { };
|
||||
#endif
|
||||
template<> struct is_integral<short> : true_type { };
|
||||
template<> struct is_integral<unsigned short> : true_type { };
|
||||
template<> struct is_integral<int> : true_type { };
|
||||
template<> struct is_integral<unsigned int> : true_type { };
|
||||
template<> struct is_integral<long> : true_type { };
|
||||
template<> struct is_integral<unsigned long> : true_type { };
|
||||
#ifdef HAVE_LONG_LONG
|
||||
template<> struct is_integral<long long> : true_type { };
|
||||
template<> struct is_integral<unsigned long long> : true_type { };
|
||||
#endif
|
||||
|
||||
|
||||
// is_floating_point is false except for the built-in floating-point types.
|
||||
template <class T> struct is_floating_point : false_type { };
|
||||
template<> struct is_floating_point<float> : true_type { };
|
||||
template<> struct is_floating_point<double> : true_type { };
|
||||
template<> struct is_floating_point<long double> : true_type { };
|
||||
|
||||
|
||||
// is_pointer is false except for pointer types.
|
||||
template <class T> struct is_pointer : false_type { };
|
||||
template <class T> struct is_pointer<T*> : true_type { };
|
||||
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class T> struct is_class_or_union {
|
||||
template <class U> static small_ tester(void (U::*)());
|
||||
template <class U> static big_ tester(...);
|
||||
static const bool value = sizeof(tester<T>(0)) == sizeof(small_);
|
||||
};
|
||||
|
||||
// is_convertible chokes if the first argument is an array. That's why
|
||||
// we use add_reference here.
|
||||
template <bool NotUnum, class T> struct is_enum_impl
|
||||
: is_convertible<typename add_reference<T>::type, int> { };
|
||||
|
||||
template <class T> struct is_enum_impl<true, T> : false_type { };
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Specified by TR1 [4.5.1] primary type categories.
|
||||
|
||||
// Implementation note:
|
||||
//
|
||||
// Each type is either void, integral, floating point, array, pointer,
|
||||
// reference, member object pointer, member function pointer, enum,
|
||||
// union or class. Out of these, only integral, floating point, reference,
|
||||
// class and enum types are potentially convertible to int. Therefore,
|
||||
// if a type is not a reference, integral, floating point or class and
|
||||
// is convertible to int, it's a enum.
|
||||
//
|
||||
// Is-convertible-to-int check is done only if all other checks pass,
|
||||
// because it can't be used with some types (e.g. void or classes with
|
||||
// inaccessible conversion operators).
|
||||
template <class T> struct is_enum
|
||||
: internal::is_enum_impl<
|
||||
is_same<T, void>::value ||
|
||||
is_integral<T>::value ||
|
||||
is_floating_point<T>::value ||
|
||||
is_reference<T>::value ||
|
||||
internal::is_class_or_union<T>::value,
|
||||
T> { };
|
||||
|
||||
template <class T> struct is_enum<const T> : is_enum<T> { };
|
||||
template <class T> struct is_enum<volatile T> : is_enum<T> { };
|
||||
template <class T> struct is_enum<const volatile T> : is_enum<T> { };
|
||||
|
||||
#endif
|
||||
|
||||
// is_reference is false except for reference types.
|
||||
template<typename T> struct is_reference : false_type {};
|
||||
template<typename T> struct is_reference<T&> : true_type {};
|
||||
|
||||
|
||||
// We can't get is_pod right without compiler help, so fail conservatively.
|
||||
// We will assume it's false except for arithmetic types, enumerations,
|
||||
// pointers and const versions thereof. Note that std::pair is not a POD.
|
||||
template <class T> struct is_pod
|
||||
: integral_constant<bool, (is_integral<T>::value ||
|
||||
is_floating_point<T>::value ||
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
// is_enum is not available on MSVC.
|
||||
is_enum<T>::value ||
|
||||
#endif
|
||||
is_pointer<T>::value)> { };
|
||||
template <class T> struct is_pod<const T> : is_pod<T> { };
|
||||
|
||||
|
||||
// We can't get has_trivial_constructor right without compiler help, so
|
||||
// fail conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial
|
||||
// constructors. (3) array of a type with a trivial constructor.
|
||||
// (4) const versions thereof.
|
||||
template <class T> struct has_trivial_constructor : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_constructor<T>::value &&
|
||||
has_trivial_constructor<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_constructor<A[N]>
|
||||
: has_trivial_constructor<A> { };
|
||||
template <class T> struct has_trivial_constructor<const T>
|
||||
: has_trivial_constructor<T> { };
|
||||
|
||||
// We can't get has_trivial_copy right without compiler help, so fail
|
||||
// conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial copy
|
||||
// constructors. (3) array of a type with a trivial copy constructor.
|
||||
// (4) const versions thereof.
|
||||
template <class T> struct has_trivial_copy : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_copy<T>::value &&
|
||||
has_trivial_copy<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_copy<A[N]>
|
||||
: has_trivial_copy<A> { };
|
||||
template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
|
||||
|
||||
// We can't get has_trivial_assign right without compiler help, so fail
|
||||
// conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial copy
|
||||
// constructors. (3) array of a type with a trivial assign constructor.
|
||||
template <class T> struct has_trivial_assign : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_assign<T>::value &&
|
||||
has_trivial_assign<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_assign<A[N]>
|
||||
: has_trivial_assign<A> { };
|
||||
|
||||
// We can't get has_trivial_destructor right without compiler help, so
|
||||
// fail conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial
|
||||
// destructors. (3) array of a type with a trivial destructor.
|
||||
// (4) const versions thereof.
|
||||
template <class T> struct has_trivial_destructor : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_destructor<T>::value &&
|
||||
has_trivial_destructor<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_destructor<A[N]>
|
||||
: has_trivial_destructor<A> { };
|
||||
template <class T> struct has_trivial_destructor<const T>
|
||||
: has_trivial_destructor<T> { };
|
||||
|
||||
// Specified by TR1 [4.7.1]
|
||||
template<typename T> struct remove_const { typedef T type; };
|
||||
template<typename T> struct remove_const<T const> { typedef T type; };
|
||||
template<typename T> struct remove_volatile { typedef T type; };
|
||||
template<typename T> struct remove_volatile<T volatile> { typedef T type; };
|
||||
template<typename T> struct remove_cv {
|
||||
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
// Specified by TR1 [4.7.2] Reference modifications.
|
||||
template<typename T> struct remove_reference { typedef T type; };
|
||||
template<typename T> struct remove_reference<T&> { typedef T type; };
|
||||
|
||||
template <typename T> struct add_reference { typedef T& type; };
|
||||
template <typename T> struct add_reference<T&> { typedef T& type; };
|
||||
|
||||
// Specified by TR1 [4.7.4] Pointer modifications.
|
||||
template<typename T> struct remove_pointer { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T*> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const volatile> {
|
||||
typedef T type; };
|
||||
|
||||
// Specified by TR1 [4.6] Relationships between types
|
||||
template<typename T, typename U> struct is_same : public false_type { };
|
||||
template<typename T> struct is_same<T, T> : public true_type { };
|
||||
|
||||
// Specified by TR1 [4.6] Relationships between types
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
namespace internal {
|
||||
|
||||
// This class is an implementation detail for is_convertible, and you
|
||||
// don't need to know how it works to use is_convertible. For those
|
||||
// who care: we declare two different functions, one whose argument is
|
||||
// of type To and one with a variadic argument list. We give them
|
||||
// return types of different size, so we can use sizeof to trick the
|
||||
// compiler into telling us which function it would have chosen if we
|
||||
// had called it with an argument of type From. See Alexandrescu's
|
||||
// _Modern C++ Design_ for more details on this sort of trick.
|
||||
|
||||
template <typename From, typename To>
|
||||
struct ConvertHelper {
|
||||
static small_ Test(To);
|
||||
static big_ Test(...);
|
||||
static From Create();
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
// Inherits from true_type if From is convertible to To, false_type otherwise.
|
||||
template <typename From, typename To>
|
||||
struct is_convertible
|
||||
: integral_constant<bool,
|
||||
sizeof(internal::ConvertHelper<From, To>::Test(
|
||||
internal::ConvertHelper<From, To>::Create()))
|
||||
== sizeof(small_)> {
|
||||
};
|
||||
#endif
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif // BASE_TYPE_TRAITS_H_
|
|
@ -62,7 +62,7 @@ public:
|
|||
virtual uint64_t getLastLocalBlockHeight() const = 0;
|
||||
virtual uint64_t getLastKnownBlockHeight() const = 0;
|
||||
|
||||
virtual void relayTransaction(const cryptonote::transaction& transaction, const Callback& callback) = 0;
|
||||
virtual void relayTransaction(const cryptonote::Transaction& transaction, const Callback& callback) = 0;
|
||||
virtual void getRandomOutsByAmounts(std::vector<uint64_t>&& amounts, uint64_t outsCount, std::vector<cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount>& result, const Callback& callback) = 0;
|
||||
virtual void getNewBlocks(std::list<crypto::hash>&& knownBlockIds, std::list<cryptonote::block_complete_entry>& newBlocks, uint64_t& startHeight, const Callback& callback) = 0;
|
||||
virtual void getTransactionOutsGlobalIndices(const crypto::hash& transactionHash, std::vector<uint64_t>& outsGlobalIndices, const Callback& callback) = 0;
|
||||
|
|
|
@ -41,7 +41,7 @@ const TransactionId INVALID_TRANSACTION_ID = std::numeric_limits<TransactionI
|
|||
const TransferId INVALID_TRANSFER_ID = std::numeric_limits<TransferId>::max();
|
||||
const uint64_t UNCONFIRMED_TRANSACTION_HEIGHT = std::numeric_limits<uint64_t>::max();
|
||||
|
||||
struct Transaction {
|
||||
struct TransactionInfo {
|
||||
TransferId firstTransferId;
|
||||
size_t transferCount;
|
||||
int64_t totalAmount;
|
||||
|
@ -89,7 +89,7 @@ public:
|
|||
|
||||
virtual TransactionId findTransactionByTransferId(TransferId transferId) = 0;
|
||||
|
||||
virtual bool getTransaction(TransactionId transactionId, Transaction& transaction) = 0;
|
||||
virtual bool getTransaction(TransactionId transactionId, TransactionInfo& transaction) = 0;
|
||||
virtual bool getTransfer(TransferId transferId, Transfer& transfer) = 0;
|
||||
|
||||
virtual TransactionId sendTransaction(const Transfer& transfer, uint64_t fee, const std::string& extra = "", uint64_t mixIn = 0, uint64_t unlockTimestamp = 0) = 0;
|
||||
|
|
|
@ -2,7 +2,7 @@ add_definitions(-DSTATICLIB)
|
|||
|
||||
file(GLOB_RECURSE COMMON common/*)
|
||||
file(GLOB_RECURSE CRYPTO crypto/*)
|
||||
file(GLOB_RECURSE CRYPTONOTE_CORE cryptonote_core/*)
|
||||
file(GLOB_RECURSE CRYPTONOTE_CORE cryptonote_core/* cryptonote_config.h)
|
||||
file(GLOB_RECURSE CRYPTONOTE_PROTOCOL cryptonote_protocol/*)
|
||||
file(GLOB_RECURSE DAEMON daemon/*)
|
||||
file(GLOB_RECURSE P2P p2p/*)
|
||||
|
@ -32,15 +32,16 @@ add_library(cryptonote_core ${CRYPTONOTE_CORE})
|
|||
add_executable(daemon ${DAEMON} ${P2P} ${CRYPTONOTE_PROTOCOL})
|
||||
add_executable(connectivity_tool ${CONN_TOOL})
|
||||
add_executable(simpleminer ${MINER})
|
||||
target_link_libraries(daemon rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES})
|
||||
target_link_libraries(connectivity_tool cryptonote_core crypto common ${Boost_LIBRARIES})
|
||||
target_link_libraries(simpleminer cryptonote_core crypto common ${Boost_LIBRARIES})
|
||||
target_link_libraries(daemon epee rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES})
|
||||
target_link_libraries(connectivity_tool epee cryptonote_core crypto common ${Boost_LIBRARIES})
|
||||
target_link_libraries(simpleminer epee cryptonote_core crypto common ${Boost_LIBRARIES})
|
||||
add_library(rpc ${RPC})
|
||||
add_library(wallet ${WALLET})
|
||||
add_executable(simplewallet ${SIMPLEWALLET} )
|
||||
target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES})
|
||||
target_link_libraries(simplewallet epee wallet rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES})
|
||||
add_library(node_rpc_proxy ${NODE_RPC_PROXY})
|
||||
|
||||
add_dependencies(connectivity_tool version)
|
||||
add_dependencies(daemon version)
|
||||
add_dependencies(rpc version)
|
||||
add_dependencies(simplewallet version)
|
||||
|
|
18
src/common/BlockingQueue.cpp
Normal file
18
src/common/BlockingQueue.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "BlockingQueue.h"
|
126
src/common/BlockingQueue.h
Normal file
126
src/common/BlockingQueue.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
template < typename T, typename Container = std::deque<T> >
|
||||
class BlockingQueue {
|
||||
public:
|
||||
|
||||
typedef BlockingQueue<T, Container> ThisType;
|
||||
|
||||
BlockingQueue(size_t maxSize = 1) :
|
||||
m_maxSize(maxSize), m_closed(false) {}
|
||||
|
||||
template <typename TT>
|
||||
bool push(TT&& v) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
|
||||
while (!m_closed && m_queue.size() >= m_maxSize) {
|
||||
m_haveSpace.wait(lk);
|
||||
}
|
||||
|
||||
if (m_closed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_queue.push_back(std::forward<TT>(v));
|
||||
m_haveData.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pop(T& v) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
|
||||
while (m_queue.empty()) {
|
||||
if (m_closed) {
|
||||
// all data has been processed, queue is closed
|
||||
return false;
|
||||
}
|
||||
m_haveData.wait(lk);
|
||||
}
|
||||
|
||||
v = std::move(m_queue.front());
|
||||
m_queue.pop_front();
|
||||
|
||||
// we can have several waiting threads to unblock
|
||||
if (m_closed && m_queue.empty())
|
||||
m_haveSpace.notify_all();
|
||||
else
|
||||
m_haveSpace.notify_one();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void close(bool wait = false) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_closed = true;
|
||||
m_haveData.notify_all(); // wake up threads in pop()
|
||||
|
||||
if (wait) {
|
||||
while (!m_queue.empty()) {
|
||||
m_haveSpace.wait(lk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
return m_queue.size();
|
||||
}
|
||||
|
||||
size_t capacity() const {
|
||||
return m_maxSize;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const size_t m_maxSize;
|
||||
Container m_queue;
|
||||
bool m_closed;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_haveData;
|
||||
std::condition_variable m_haveSpace;
|
||||
};
|
||||
|
||||
template <typename QueueT>
|
||||
class GroupClose {
|
||||
public:
|
||||
|
||||
GroupClose(QueueT& queue, size_t groupSize)
|
||||
: m_queue(queue), m_count(groupSize) {}
|
||||
|
||||
void close() {
|
||||
if (m_count == 0)
|
||||
return;
|
||||
if (m_count.fetch_sub(1) == 1)
|
||||
m_queue.close();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::atomic<size_t> m_count;
|
||||
QueueT& m_queue;
|
||||
|
||||
};
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
|
|
54
src/common/SignalHandler.cpp
Normal file
54
src/common/SignalHandler.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "SignalHandler.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
|
||||
// epee
|
||||
#include "include_base_utils.h"
|
||||
|
||||
|
||||
namespace tools {
|
||||
std::function<void(void)> SignalHandler::m_handler;
|
||||
|
||||
#if defined(WIN32)
|
||||
BOOL WINAPI SignalHandler::winHandler(DWORD type) {
|
||||
if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type) {
|
||||
handleSignal();
|
||||
return TRUE;
|
||||
} else {
|
||||
LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving...");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void SignalHandler::posixHandler(int /*type*/) {
|
||||
handleSignal();
|
||||
}
|
||||
#endif
|
||||
|
||||
void SignalHandler::handleSignal() {
|
||||
static std::mutex m_mutex;
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_handler();
|
||||
}
|
||||
}
|
59
src/common/SignalHandler.h
Normal file
59
src/common/SignalHandler.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <signal.h>
|
||||
|
||||
#include "misc_os_dependent.h"
|
||||
|
||||
namespace tools {
|
||||
class SignalHandler
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static bool install(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
bool r = TRUE == ::SetConsoleCtrlHandler(&winHandler, TRUE);
|
||||
if (r)
|
||||
{
|
||||
m_handler = t;
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
signal(SIGINT, posixHandler);
|
||||
signal(SIGTERM, posixHandler);
|
||||
m_handler = t;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
static BOOL WINAPI winHandler(DWORD type);
|
||||
#else
|
||||
static void posixHandler(int /*type*/);
|
||||
#endif
|
||||
|
||||
static void handleSignal();
|
||||
|
||||
private:
|
||||
static std::function<void(void)> m_handler;
|
||||
};
|
||||
}
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include "crypto/hash.h"
|
||||
#include "int-util.h"
|
||||
#include "util.h"
|
||||
#include "varint.h"
|
||||
|
||||
namespace tools
|
||||
|
|
|
@ -17,9 +17,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
|
||||
// epee
|
||||
#include "include_base_utils.h"
|
||||
#include "misc_os_dependent.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "google/sparse_hash_set"
|
||||
#include "google/sparse_hash_map"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
|
@ -108,6 +111,70 @@ namespace boost
|
|||
}
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void save(Archive &a, const ::google::sparse_hash_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void load(Archive &a, ::google::sparse_hash_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
hval v;
|
||||
a >> v;
|
||||
x.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void serialize(Archive &a, ::google::sparse_hash_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void save(Archive &a, const ::google::sparse_hash_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v.first;
|
||||
a << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void load(Archive &a, ::google::sparse_hash_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
h_key k;
|
||||
hval v;
|
||||
a >> k;
|
||||
a >> v;
|
||||
x.insert(std::pair<h_key, hval>(k, v));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void serialize(Archive &a, ::google::sparse_hash_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
|
|
|
@ -15,12 +15,16 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "util.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -34,8 +38,6 @@ using namespace epee;
|
|||
|
||||
namespace tools
|
||||
{
|
||||
std::function<void(void)> signal_handler::m_handler;
|
||||
|
||||
#ifdef WIN32
|
||||
std::string get_windows_version_display_string()
|
||||
{
|
||||
|
@ -311,7 +313,7 @@ std::string get_nix_version_display_string()
|
|||
std::string config_folder;
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CRYPTONOTE_NAME;
|
||||
config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + cryptonote::CRYPTONOTE_NAME;
|
||||
#else
|
||||
std::string pathRet;
|
||||
char* pszHome = getenv("HOME");
|
||||
|
@ -322,10 +324,10 @@ std::string get_nix_version_display_string()
|
|||
#ifdef MAC_OSX
|
||||
// Mac
|
||||
pathRet /= "Library/Application Support";
|
||||
config_folder = (pathRet + "/" + CRYPTONOTE_NAME);
|
||||
config_folder = (pathRet + "/" + cryptonote::CRYPTONOTE_NAME);
|
||||
#else
|
||||
// Unix
|
||||
config_folder = (pathRet + "/." + CRYPTONOTE_NAME);
|
||||
config_folder = (pathRet + "/." + cryptonote::CRYPTONOTE_NAME);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -374,4 +376,12 @@ std::string get_nix_version_display_string()
|
|||
#endif
|
||||
return std::error_code(code, std::system_category());
|
||||
}
|
||||
|
||||
crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot)
|
||||
{
|
||||
std::string s;
|
||||
s.append(reinterpret_cast<const char*>(&pot.peer_id), sizeof(pot.peer_id));
|
||||
s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time));
|
||||
return crypto::cn_fast_hash(s.data(), s.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,15 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
|
||||
|
||||
namespace nodetool {
|
||||
struct proof_of_trust;
|
||||
}
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
@ -32,68 +33,5 @@ namespace tools
|
|||
std::string get_os_version_string();
|
||||
bool create_directories_if_necessary(const std::string& path);
|
||||
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);
|
||||
|
||||
inline crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot)
|
||||
{
|
||||
std::string s;
|
||||
s.append(reinterpret_cast<const char*>(&pot.peer_id), sizeof(pot.peer_id));
|
||||
s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time));
|
||||
return crypto::cn_fast_hash(s.data(), s.size());
|
||||
}
|
||||
|
||||
|
||||
class signal_handler
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static bool install(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE);
|
||||
if (r)
|
||||
{
|
||||
m_handler = t;
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
signal(SIGINT, posix_handler);
|
||||
signal(SIGTERM, posix_handler);
|
||||
m_handler = t;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
static BOOL WINAPI win_handler(DWORD type)
|
||||
{
|
||||
if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
|
||||
{
|
||||
handle_signal();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving...");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
static void posix_handler(int /*type*/)
|
||||
{
|
||||
handle_signal();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void handle_signal()
|
||||
{
|
||||
static std::mutex m_mutex;
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_handler();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::function<void(void)> m_handler;
|
||||
};
|
||||
crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot);
|
||||
}
|
||||
|
|
|
@ -15,26 +15,27 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "version.h"
|
||||
|
||||
using namespace epee;
|
||||
#include <boost/program_options.hpp>
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
|
||||
// epee
|
||||
#include "include_base_utils.h"
|
||||
#include "net/http_client.h"
|
||||
#include "net/levin_client.h"
|
||||
#include "storages/http_abstract_invoke.h"
|
||||
#include "storages/levin_abstract_invoke2.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
|
||||
#include "common/command_line.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "net/levin_client.h"
|
||||
#include "storages/levin_abstract_invoke2.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "storages/http_abstract_invoke.h"
|
||||
#include "net/http_client.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace cryptonote;
|
||||
using namespace epee;
|
||||
using namespace nodetool;
|
||||
|
||||
namespace
|
||||
|
|
|
@ -76,3 +76,6 @@ void hash_extra_jh(const void *data, size_t length, char *hash);
|
|||
void hash_extra_skein(const void *data, size_t length, char *hash);
|
||||
|
||||
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash);
|
||||
size_t tree_depth(size_t count);
|
||||
void tree_branch(const char (*hashes)[HASH_SIZE], size_t count, char (*branch)[HASH_SIZE]);
|
||||
void tree_hash_from_branch(const char (*branch)[HASH_SIZE], size_t depth, const char *leaf, const void *path, char *root_hash);
|
||||
|
|
|
@ -74,6 +74,14 @@ namespace crypto {
|
|||
tree_hash(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char *>(&root_hash));
|
||||
}
|
||||
|
||||
inline void tree_branch(const hash *hashes, std::size_t count, hash *branch) {
|
||||
tree_branch(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char (*)[HASH_SIZE]>(branch));
|
||||
}
|
||||
|
||||
inline void tree_hash_from_branch(const hash *branch, std::size_t depth, const hash &leaf, const void *path, hash &root_hash) {
|
||||
tree_hash_from_branch(reinterpret_cast<const char (*)[HASH_SIZE]>(branch), depth, reinterpret_cast<const char *>(&leaf), path, reinterpret_cast<char *>(&root_hash));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CRYPTO_MAKE_HASHABLE(hash)
|
||||
|
|
|
@ -51,3 +51,75 @@ void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
|
|||
cn_fast_hash(ints[0], 64, root_hash);
|
||||
}
|
||||
}
|
||||
|
||||
size_t tree_depth(size_t count) {
|
||||
size_t i;
|
||||
size_t depth = 0;
|
||||
assert(count > 0);
|
||||
for (i = sizeof(size_t) << 2; i > 0; i >>= 1) {
|
||||
if (count >> i > 0) {
|
||||
count >>= i;
|
||||
depth += i;
|
||||
}
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
void tree_branch(const char (*hashes)[HASH_SIZE], size_t count, char (*branch)[HASH_SIZE]) {
|
||||
size_t i, j;
|
||||
size_t cnt = 1;
|
||||
size_t depth = 0;
|
||||
char (*ints)[HASH_SIZE];
|
||||
assert(count > 0);
|
||||
for (i = sizeof(size_t) << 2; i > 0; i >>= 1) {
|
||||
if (cnt << i <= count) {
|
||||
cnt <<= i;
|
||||
depth += i;
|
||||
}
|
||||
}
|
||||
assert(cnt == 1ULL << depth);
|
||||
assert(depth == tree_depth(count));
|
||||
ints = alloca((cnt - 1) * HASH_SIZE);
|
||||
memcpy(ints, hashes + 1, (2 * cnt - count - 1) * HASH_SIZE);
|
||||
for (i = 2 * cnt - count, j = 2 * cnt - count - 1; j < cnt - 1; i += 2, ++j) {
|
||||
cn_fast_hash(hashes[i], 2 * HASH_SIZE, ints[j]);
|
||||
}
|
||||
assert(i == count);
|
||||
while (depth > 0) {
|
||||
assert(cnt == 1ULL << depth);
|
||||
cnt >>= 1;
|
||||
--depth;
|
||||
memcpy(branch[depth], ints[0], HASH_SIZE);
|
||||
for (i = 1, j = 0; j < cnt - 1; i += 2, ++j) {
|
||||
cn_fast_hash(ints[i], 2 * HASH_SIZE, ints[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tree_hash_from_branch(const char (*branch)[HASH_SIZE], size_t depth, const char *leaf, const void *path, char *root_hash) {
|
||||
if (depth == 0) {
|
||||
memcpy(root_hash, leaf, HASH_SIZE);
|
||||
} else {
|
||||
char buffer[2][HASH_SIZE];
|
||||
int from_leaf = 1;
|
||||
char *leaf_path, *branch_path;
|
||||
while (depth > 0) {
|
||||
--depth;
|
||||
if (path && (((const char *) path)[depth >> 3] & (1 << (depth & 7))) != 0) {
|
||||
leaf_path = buffer[1];
|
||||
branch_path = buffer[0];
|
||||
} else {
|
||||
leaf_path = buffer[0];
|
||||
branch_path = buffer[1];
|
||||
}
|
||||
if (from_leaf) {
|
||||
memcpy(leaf_path, leaf, HASH_SIZE);
|
||||
from_leaf = 0;
|
||||
} else {
|
||||
cn_fast_hash(buffer, 2 * HASH_SIZE, leaf_path);
|
||||
}
|
||||
memcpy(branch_path, branch[depth], HASH_SIZE);
|
||||
}
|
||||
cn_fast_hash(buffer, 2 * HASH_SIZE, root_hash);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,77 +17,133 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define CRYPTONOTE_MAX_BLOCK_NUMBER 500000000
|
||||
#define CRYPTONOTE_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
|
||||
#define CRYPTONOTE_MAX_TX_SIZE 1000000000
|
||||
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
|
||||
#define CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX 6 // addresses start with "2"
|
||||
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 10
|
||||
#define CURRENT_TRANSACTION_VERSION 1
|
||||
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
||||
#define CURRENT_BLOCK_MINOR_VERSION 0
|
||||
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
|
||||
#include <cstdint>
|
||||
|
||||
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 60
|
||||
namespace cryptonote {
|
||||
namespace parameters {
|
||||
|
||||
const uint64_t CRYPTONOTE_MAX_BLOCK_NUMBER = 500000000;
|
||||
const size_t CRYPTONOTE_MAX_BLOCK_BLOB_SIZE = 500000000;
|
||||
const size_t CRYPTONOTE_MAX_TX_SIZE = 1000000000;
|
||||
const uint64_t CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 6; // addresses start with "2"
|
||||
const size_t CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW = 10;
|
||||
const uint64_t CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT = 60 * 60 * 2;
|
||||
|
||||
const size_t BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW = 60;
|
||||
|
||||
// MONEY_SUPPLY - total number coins to be generated
|
||||
#define MONEY_SUPPLY ((uint64_t)(-1))
|
||||
#define EMISSION_SPEED_FACTOR (18)
|
||||
const uint64_t MONEY_SUPPLY = static_cast<uint64_t>(-1);
|
||||
const unsigned EMISSION_SPEED_FACTOR = 18;
|
||||
static_assert(EMISSION_SPEED_FACTOR <= 8 * sizeof(uint64_t), "Bad EMISSION_SPEED_FACTOR");
|
||||
|
||||
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100
|
||||
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE 10000 //size of block (bytes) after which reward for block calculated using block size
|
||||
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE 600
|
||||
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT 8
|
||||
const size_t CRYPTONOTE_REWARD_BLOCKS_WINDOW = 100;
|
||||
const size_t CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE = 10000; //size of block (bytes) after which reward for block calculated using block size
|
||||
const size_t CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE = 600;
|
||||
const size_t CRYPTONOTE_DISPLAY_DECIMAL_POINT = 8;
|
||||
// COIN - number of smallest units in one coin
|
||||
#define COIN ((uint64_t)100000000) // pow(10, 8)
|
||||
#define MINIMUM_FEE ((uint64_t)1000000000) // pow(10, 9)
|
||||
#define DEFAULT_DUST_THRESHOLD ((uint64_t)1000000) // pow(10, 6)
|
||||
const uint64_t COIN = UINT64_C(100000000); // pow(10, 8)
|
||||
const uint64_t MINIMUM_FEE = UINT64_C(1000000); // pow(10, 6)
|
||||
const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(1000000); // pow(10, 6)
|
||||
|
||||
const uint64_t DIFFICULTY_TARGET = 120; // seconds
|
||||
const uint64_t EXPECTED_NUMBER_OF_BLOCKS_PER_DAY = 24 * 60 * 60 / DIFFICULTY_TARGET;
|
||||
const size_t DIFFICULTY_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks
|
||||
const size_t DIFFICULTY_CUT = 60; // timestamps to cut after sorting
|
||||
const size_t DIFFICULTY_LAG = 15; // !!!
|
||||
static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Bad DIFFICULTY_WINDOW or DIFFICULTY_CUT");
|
||||
|
||||
#define DIFFICULTY_TARGET 120 // seconds
|
||||
#define DIFFICULTY_WINDOW 720 // blocks
|
||||
#define DIFFICULTY_LAG 15 // !!!
|
||||
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting
|
||||
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
|
||||
const size_t MAX_BLOCK_SIZE_INITIAL = 20 * 1024;
|
||||
const uint64_t MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR = 100 * 1024;
|
||||
const uint64_t MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR = 365 * 24 * 60 * 60 / DIFFICULTY_TARGET;
|
||||
|
||||
const uint64_t CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS = 1;
|
||||
const uint64_t CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS = DIFFICULTY_TARGET * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS;
|
||||
|
||||
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS DIFFICULTY_TARGET * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
|
||||
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS 1
|
||||
const uint64_t CRYPTONOTE_MEMPOOL_TX_LIVETIME = 60 * 60 * 24; //seconds, one day
|
||||
const uint64_t CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME = 60 * 60 * 24 * 7; //seconds, one week
|
||||
|
||||
const unsigned UPGRADE_VOTING_THRESHOLD = 90; // percent
|
||||
const size_t UPGRADE_VOTING_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks
|
||||
const size_t UPGRADE_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks
|
||||
static_assert(0 < UPGRADE_VOTING_THRESHOLD && UPGRADE_VOTING_THRESHOLD <= 100, "Bad UPGRADE_VOTING_THRESHOLD");
|
||||
static_assert(UPGRADE_VOTING_WINDOW > 1, "Bad UPGRADE_VOTING_WINDOW");
|
||||
|
||||
#define DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN DIFFICULTY_TARGET //just alias
|
||||
const char CRYPTONOTE_BLOCKCHAINDATA_FILENAME[] = "blockchain.bin"; // Obsolete blockchain format
|
||||
const char CRYPTONOTE_BLOCKS_FILENAME[] = "blocks.dat";
|
||||
const char CRYPTONOTE_BLOCKINDEXES_FILENAME[] = "blockindexes.dat";
|
||||
const char CRYPTONOTE_BLOCKSCACHE_FILENAME[] = "blockscache.dat";
|
||||
const char CRYPTONOTE_POOLDATA_FILENAME[] = "poolstate.bin";
|
||||
const char P2P_NET_DATA_FILENAME[] = "p2pstate.bin";
|
||||
const char MINER_CONFIG_FILE_NAME[] = "miner_conf.json";
|
||||
} // parameters
|
||||
|
||||
const char CRYPTONOTE_NAME[] = "bytecoin";
|
||||
|
||||
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing
|
||||
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 200 //by default, blocks count in blocks downloading
|
||||
#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block
|
||||
const uint8_t CURRENT_TRANSACTION_VERSION = 1;
|
||||
const uint8_t BLOCK_MAJOR_VERSION_1 = 1;
|
||||
const uint8_t BLOCK_MAJOR_VERSION_2 = 2;
|
||||
const uint8_t BLOCK_MINOR_VERSION_0 = 0;
|
||||
const uint8_t BLOCK_MINOR_VERSION_1 = 1;
|
||||
|
||||
const size_t BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT = 10000; //by default, blocks ids count in synchronizing
|
||||
const size_t BLOCKS_SYNCHRONIZING_DEFAULT_COUNT = 200; //by default, blocks count in blocks downloading
|
||||
const size_t COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT = 1000;
|
||||
|
||||
#define P2P_DEFAULT_PORT 8080
|
||||
#define RPC_DEFAULT_PORT 8081
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000
|
||||
const int P2P_DEFAULT_PORT = 8080;
|
||||
const int RPC_DEFAULT_PORT = 8081;
|
||||
|
||||
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
|
||||
#define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000
|
||||
const size_t P2P_LOCAL_WHITE_PEERLIST_LIMIT = 1000;
|
||||
const size_t P2P_LOCAL_GRAY_PEERLIST_LIMIT = 5000;
|
||||
|
||||
#define P2P_DEFAULT_CONNECTIONS_COUNT 8
|
||||
#define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes
|
||||
#define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size
|
||||
#define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250
|
||||
#define P2P_DEFAULT_CONNECTION_TIMEOUT 5000 //5 seconds
|
||||
#define P2P_DEFAULT_PING_CONNECTION_TIMEOUT 2000 //2 seconds
|
||||
#define P2P_DEFAULT_INVOKE_TIMEOUT 60*2*1000 //2 minutes
|
||||
#define P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT 5000 //5 seconds
|
||||
#define P2P_STAT_TRUSTED_PUB_KEY "8f80f9a5a434a9f1510d13336228debfee9c918ce505efe225d8c94d045fa115"
|
||||
#define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70
|
||||
const uint32_t P2P_DEFAULT_CONNECTIONS_COUNT = 8;
|
||||
const uint32_t P2P_DEFAULT_HANDSHAKE_INTERVAL = 60; // seconds
|
||||
const uint32_t P2P_DEFAULT_PACKET_MAX_SIZE = 50000000; // 50000000 bytes maximum packet size
|
||||
const uint32_t P2P_DEFAULT_PEERS_IN_HANDSHAKE = 250;
|
||||
const uint32_t P2P_DEFAULT_CONNECTION_TIMEOUT = 5000; // 5 seconds
|
||||
const uint32_t P2P_DEFAULT_PING_CONNECTION_TIMEOUT = 2000; // 2 seconds
|
||||
const uint64_t P2P_DEFAULT_INVOKE_TIMEOUT = 60 * 2 * 1000; // 2 minutes
|
||||
const size_t P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT = 5000; // 5 seconds
|
||||
const char P2P_STAT_TRUSTED_PUB_KEY[] = "8f80f9a5a434a9f1510d13336228debfee9c918ce505efe225d8c94d045fa115";
|
||||
const size_t P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT = 70;
|
||||
|
||||
const unsigned THREAD_STACK_SIZE = 5 * 1024 * 1024;
|
||||
|
||||
const char* const SEED_NODES[] = {
|
||||
"seed.bytecoin.org:8080",
|
||||
"85.25.201.95:8080",
|
||||
"85.25.196.145:8080",
|
||||
"85.25.196.146:8080",
|
||||
"85.25.196.144:8080",
|
||||
"5.199.168.138:8080",
|
||||
"62.75.236.152:8080",
|
||||
"85.25.194.245:8080",
|
||||
"95.211.224.160:8080",
|
||||
"144.76.200.44:8080"
|
||||
};
|
||||
|
||||
struct CheckpointData {
|
||||
uint64_t height;
|
||||
const char* blockId;
|
||||
};
|
||||
|
||||
const CheckpointData CHECKPOINTS[] = {
|
||||
{79000, "cae33204e624faeb64938d80073bb7bbacc27017dc63f36c5c0f313cad455a02"},
|
||||
{140000, "993059fb6ab92db7d80d406c67a52d9c02d873ca34b6290a12b744c970208772"},
|
||||
{200000, "a5f74c7542077df6859f48b5b1f9c3741f29df38f91a47e14c94b5696e6c3073"},
|
||||
{230580, "32bd7cb6c68a599cf2861941f29002a5e203522b9af54f08dfced316f6459103"},
|
||||
{260000, "f68e70b360ca194f48084da7a7fd8e0251bbb4b5587f787ca65a6f5baf3f5947"},
|
||||
{300000, "8e80861713f68354760dc10ea6ea79f5f3ff28f39b3f0835a8637463b09d70ff"},
|
||||
{390285, "e00bdc9bf407aeace2f3109de11889ed25894bf194231d075eddaec838097eb7"},
|
||||
{417000, "2dc96f8fc4d4a4d76b3ed06722829a7ab09d310584b8ecedc9b578b2c458a69f"},
|
||||
{427193, "00feabb08f2d5759ed04fd6b799a7513187478696bba2db2af10d4347134e311"},
|
||||
{453537, "d17de6916c5aa6ffcae575309c80b0f8fdcd0a84b5fa8e41a841897d4b5a4e97"},
|
||||
{462250, "13468d210a5ec884cf839f0259f247ccf3efef0414ac45172033d32c739beb3e"},
|
||||
{468000, "251bcbd398b1f593193a7210934a3d87f692b2cb0c45206150f59683dd7e9ba1"},
|
||||
{480200, "363544ac9920c778b815c2fdbcbca70a0d79b21f662913a42da9b49e859f0e5b"},
|
||||
{484500, "5cdf2101a0a62a0ab2a1ca0c15a6212b21f6dbdc42a0b7c0bcf65ca40b7a14fb"},
|
||||
{506000, "3d54c1132f503d98d3f0d78bb46a4503c1a19447cb348361a2232e241cb45a3c"},
|
||||
{544000, "f69dc61b6a63217f32fa64d5d0f9bd920873f57dfd79ebe1d7d6fb1345b56fe0"}
|
||||
};
|
||||
} // cryptonote
|
||||
|
||||
#define ALLOW_DEBUG_COMMANDS
|
||||
|
||||
#define CRYPTONOTE_NAME "bytecoin"
|
||||
#define CRYPTONOTE_POOLDATA_FILENAME "poolstate.bin"
|
||||
#define CRYPTONOTE_BLOCKCHAINDATA_FILENAME "blockchain.bin"
|
||||
#define CRYPTONOTE_BLOCKCHAINDATA_TEMP_FILENAME "blockchain.bin.tmp"
|
||||
#define P2P_NET_DATA_FILENAME "p2pstate.bin"
|
||||
#define MINER_CONFIG_FILE_NAME "miner_conf.json"
|
||||
|
||||
#define THREAD_STACK_SIZE 5 * 1024 * 1024
|
||||
|
|
113
src/cryptonote_core/AccountKVSerialization.h
Normal file
113
src/cryptonote_core/AccountKVSerialization.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_core/account.h"
|
||||
|
||||
// epee
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
namespace cryptonote {
|
||||
template<bool is_store> struct AccountPublicAddressSerializer;
|
||||
template<bool is_store> struct AccountKeysSerializer;
|
||||
template<bool is_store> struct AccountBaseSerializer;
|
||||
|
||||
template<>
|
||||
struct AccountPublicAddressSerializer<true> {
|
||||
const AccountPublicAddress& m_account_address;
|
||||
|
||||
AccountPublicAddressSerializer(const AccountPublicAddress& account_address) : m_account_address(account_address) {
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_account_address.m_spendPublicKey, "m_spend_public_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_account_address.m_viewPublicKey, "m_view_public_key")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AccountPublicAddressSerializer<false> {
|
||||
AccountPublicAddress& m_account_address;
|
||||
|
||||
AccountPublicAddressSerializer(AccountPublicAddress& account_address) : m_account_address(account_address) {
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_account_address.m_spendPublicKey, "m_spend_public_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_account_address.m_viewPublicKey, "m_view_public_key")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AccountKeysSerializer<true> {
|
||||
const account_keys& m_keys;
|
||||
|
||||
AccountKeysSerializer(const account_keys& keys) : m_keys(keys) {
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
AccountPublicAddressSerializer<is_store> addressSerializer(this_ref.m_keys.m_account_address);
|
||||
epee::serialization::selector<is_store>::serialize(addressSerializer, stg, hparent_section, "m_account_address");
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_keys.m_spend_secret_key, "m_spend_secret_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_keys.m_view_secret_key, "m_view_secret_key")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AccountKeysSerializer<false> {
|
||||
account_keys& m_keys;
|
||||
|
||||
AccountKeysSerializer(account_keys& keys) : m_keys(keys) {
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
AccountPublicAddressSerializer<is_store> addressSerializer(this_ref.m_keys.m_account_address);
|
||||
epee::serialization::selector<is_store>::serialize(addressSerializer, stg, hparent_section, "m_account_address");
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_keys.m_spend_secret_key, "m_spend_secret_key")
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(m_keys.m_view_secret_key, "m_view_secret_key")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AccountBaseSerializer<true> {
|
||||
const account_base& m_account;
|
||||
|
||||
AccountBaseSerializer(const account_base& account) : m_account(account) {
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
AccountKeysSerializer<is_store> keysSerializer(this_ref.m_account.m_keys);
|
||||
epee::serialization::selector<is_store>::serialize(keysSerializer, stg, hparent_section, "m_keys");
|
||||
KV_SERIALIZE_N(m_account.m_creation_timestamp, "m_creation_timestamp")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
template<>
|
||||
struct AccountBaseSerializer<false> {
|
||||
account_base& m_account;
|
||||
|
||||
AccountBaseSerializer(account_base& account) : m_account(account) {
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
AccountKeysSerializer<is_store> keysSerializer(this_ref.m_account.m_keys);
|
||||
epee::serialization::selector<is_store>::serialize(keysSerializer, stg, hparent_section, "m_keys");
|
||||
KV_SERIALIZE_N(m_account.m_creation_timestamp, "m_creation_timestamp")
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
87
src/cryptonote_core/BlockIndex.cpp
Normal file
87
src/cryptonote_core/BlockIndex.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "BlockIndex.h"
|
||||
#include <boost/utility/value_init.hpp>
|
||||
|
||||
namespace CryptoNote
|
||||
{
|
||||
crypto::hash BlockIndex::getBlockId(uint64_t height) const {
|
||||
if (height >= m_container.size())
|
||||
return boost::value_initialized<crypto::hash>();
|
||||
return m_container[static_cast<size_t>(height)];
|
||||
}
|
||||
|
||||
bool BlockIndex::getBlockIds(uint64_t startHeight, size_t maxCount, std::list<crypto::hash>& items) const {
|
||||
if (startHeight >= m_container.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = startHeight; i < (startHeight + maxCount) && i < m_container.size(); ++i) {
|
||||
items.push_back(m_container[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BlockIndex::findSupplement(const std::list<crypto::hash>& ids, uint64_t& offset) const {
|
||||
|
||||
for (const auto& id : ids) {
|
||||
if (getBlockHeight(id, offset))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlockIndex::getShortChainHistory(std::list<crypto::hash>& ids) const {
|
||||
size_t i = 0;
|
||||
size_t current_multiplier = 1;
|
||||
size_t sz = size();
|
||||
|
||||
if (!sz)
|
||||
return true;
|
||||
|
||||
size_t current_back_offset = 1;
|
||||
bool genesis_included = false;
|
||||
|
||||
while (current_back_offset < sz) {
|
||||
ids.push_back(m_container[sz - current_back_offset]);
|
||||
if (sz - current_back_offset == 0)
|
||||
genesis_included = true;
|
||||
if (i < 10) {
|
||||
++current_back_offset;
|
||||
} else {
|
||||
current_back_offset += current_multiplier *= 2;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if (!genesis_included)
|
||||
ids.push_back(m_container[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
crypto::hash BlockIndex::getTailId() const {
|
||||
if (m_container.empty())
|
||||
return boost::value_initialized<crypto::hash>();
|
||||
return m_container.back();
|
||||
}
|
||||
|
||||
|
||||
}
|
90
src/cryptonote_core/BlockIndex.h
Normal file
90
src/cryptonote_core/BlockIndex.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// multi index
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/random_access_index.hpp>
|
||||
|
||||
#include "crypto/hash.h"
|
||||
#include <list>
|
||||
|
||||
namespace CryptoNote
|
||||
{
|
||||
class BlockIndex {
|
||||
|
||||
public:
|
||||
|
||||
BlockIndex() :
|
||||
m_index(m_container.get<1>()) {}
|
||||
|
||||
void pop() {
|
||||
m_container.pop_back();
|
||||
}
|
||||
|
||||
// returns true if new element was inserted, false if already exists
|
||||
bool push(const crypto::hash& h) {
|
||||
auto result = m_container.push_back(h);
|
||||
return result.second;
|
||||
}
|
||||
|
||||
bool hasBlock(const crypto::hash& h) const {
|
||||
return m_index.find(h) != m_index.end();
|
||||
}
|
||||
|
||||
bool getBlockHeight(const crypto::hash& h, uint64_t& height) const {
|
||||
auto hi = m_index.find(h);
|
||||
if (hi == m_index.end())
|
||||
return false;
|
||||
|
||||
height = std::distance(m_container.begin(), m_container.project<0>(hi));
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return m_container.size();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_container.clear();
|
||||
}
|
||||
|
||||
crypto::hash getBlockId(uint64_t height) const;
|
||||
bool getBlockIds(uint64_t startHeight, size_t maxCount, std::list<crypto::hash>& items) const;
|
||||
bool findSupplement(const std::list<crypto::hash>& ids, uint64_t& offset) const;
|
||||
bool getShortChainHistory(std::list<crypto::hash>& ids) const;
|
||||
crypto::hash getTailId() const;
|
||||
|
||||
template <class Archive> void serialize(Archive& ar, const unsigned int version) {
|
||||
ar & m_container;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef boost::multi_index_container <
|
||||
crypto::hash,
|
||||
boost::multi_index::indexed_by<
|
||||
boost::multi_index::random_access<>,
|
||||
boost::multi_index::hashed_unique<boost::multi_index::identity<crypto::hash>>
|
||||
>
|
||||
> ContainerT;
|
||||
|
||||
ContainerT m_container;
|
||||
ContainerT::nth_index<1>::type& m_index;
|
||||
|
||||
};
|
||||
}
|
435
src/cryptonote_core/Currency.cpp
Normal file
435
src/cryptonote_core/Currency.cpp
Normal file
|
@ -0,0 +1,435 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Currency.h"
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
// epee
|
||||
#include "include_base_utils.h"
|
||||
#include "string_tools.h"
|
||||
|
||||
#include "common/base58.h"
|
||||
#include "common/int-util.h"
|
||||
#include "cryptonote_core/account.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/UpgradeDetector.h"
|
||||
|
||||
namespace cryptonote {
|
||||
bool Currency::init() {
|
||||
bool r;
|
||||
r = generateGenesisBlock();
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate genesis block");
|
||||
|
||||
r = get_block_hash(m_genesisBlock, m_genesisBlockHash);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to get genesis block hash");
|
||||
|
||||
if (isTestnet()) {
|
||||
m_blocksFileName = "testnet_" + m_blocksFileName;
|
||||
m_blocksCacheFileName = "testnet_" + m_blocksCacheFileName;
|
||||
m_blockIndexesFileName = "testnet_" + m_blockIndexesFileName;
|
||||
m_txPoolFileName = "testnet_" + m_txPoolFileName;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Currency::generateGenesisBlock() {
|
||||
m_genesisBlock = boost::value_initialized<Block>();
|
||||
|
||||
//account_public_address ac = boost::value_initialized<AccountPublicAddress>();
|
||||
//std::vector<size_t> sz;
|
||||
//constructMinerTx(0, 0, 0, 0, 0, ac, m_genesisBlock.minerTx); // zero fee in genesis
|
||||
//blobdata txb = tx_to_blob(m_genesisBlock.minerTx);
|
||||
//std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
|
||||
|
||||
// Hard code coinbase tx in genesis block, because through generating tx use random, but genesis should be always the same
|
||||
std::string genesisCoinbaseTxHex = "010a01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121013c086a48c15fb637a96991bc6d53caf77068b5ba6eeb3c82357228c49790584a";
|
||||
|
||||
blobdata minerTxBlob;
|
||||
epee::string_tools::parse_hexstr_to_binbuff(genesisCoinbaseTxHex, minerTxBlob);
|
||||
bool r = parse_and_validate_tx_from_blob(minerTxBlob, m_genesisBlock.minerTx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
|
||||
m_genesisBlock.majorVersion = BLOCK_MAJOR_VERSION_1;
|
||||
m_genesisBlock.minorVersion = BLOCK_MINOR_VERSION_0;
|
||||
m_genesisBlock.timestamp = 0;
|
||||
m_genesisBlock.nonce = 70;
|
||||
if (m_testnet) {
|
||||
++m_genesisBlock.nonce;
|
||||
}
|
||||
//miner::find_nonce_for_given_block(bl, 1, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Currency::getBlockReward(size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins,
|
||||
uint64_t fee, bool penalizeFee, uint64_t& reward, int64_t& emissionChange) const {
|
||||
assert(alreadyGeneratedCoins <= m_moneySupply);
|
||||
assert(m_emissionSpeedFactor > 0 && m_emissionSpeedFactor <= 8 * sizeof(uint64_t));
|
||||
|
||||
uint64_t baseReward = (m_moneySupply - alreadyGeneratedCoins) >> m_emissionSpeedFactor;
|
||||
|
||||
medianSize = std::max(medianSize, m_blockGrantedFullRewardZone);
|
||||
if (currentBlockSize > UINT64_C(2) * medianSize) {
|
||||
LOG_PRINT_L4("Block cumulative size is too big: " << currentBlockSize << ", expected less than " << 2 * medianSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t penalizedBaseReward = getPenalizedAmount(baseReward, medianSize, currentBlockSize);
|
||||
uint64_t penalizedFee = penalizeFee ? getPenalizedAmount(fee, medianSize, currentBlockSize) : fee;
|
||||
|
||||
emissionChange = penalizedBaseReward - (fee - penalizedFee);
|
||||
reward = penalizedBaseReward + penalizedFee;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Currency::maxBlockCumulativeSize(uint64_t height) const {
|
||||
assert(height <= std::numeric_limits<uint64_t>::max() / m_maxBlockSizeGrowthSpeedNumerator);
|
||||
size_t maxSize = static_cast<size_t>(m_maxBlockSizeInitial +
|
||||
(height * m_maxBlockSizeGrowthSpeedNumerator) / m_maxBlockSizeGrowthSpeedDenominator);
|
||||
assert(maxSize >= m_maxBlockSizeInitial);
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
bool Currency::constructMinerTx(size_t height, size_t medianSize, uint64_t alreadyGeneratedCoins, size_t currentBlockSize,
|
||||
uint64_t fee, const AccountPublicAddress& minerAddress, Transaction& tx,
|
||||
const blobdata& extraNonce/* = blobdata()*/, size_t maxOuts/* = 1*/,
|
||||
bool penalizeFee/* = false*/) const {
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.extra.clear();
|
||||
|
||||
KeyPair txkey = KeyPair::generate();
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
if (!extraNonce.empty()) {
|
||||
if (!add_extra_nonce_to_tx_extra(tx.extra, extraNonce)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TransactionInputGenerate in;
|
||||
in.height = height;
|
||||
|
||||
uint64_t blockReward;
|
||||
int64_t emissionChange;
|
||||
if (!getBlockReward(medianSize, currentBlockSize, alreadyGeneratedCoins, fee, penalizeFee, blockReward, emissionChange)) {
|
||||
LOG_PRINT_L0("Block is too big");
|
||||
return false;
|
||||
}
|
||||
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
|
||||
LOG_PRINT_L1("Creating block template: reward " << blockReward << ", fee " << fee);
|
||||
#endif
|
||||
|
||||
std::vector<uint64_t> outAmounts;
|
||||
decompose_amount_into_digits(blockReward, m_defaultDustThreshold,
|
||||
[&outAmounts](uint64_t a_chunk) { outAmounts.push_back(a_chunk); },
|
||||
[&outAmounts](uint64_t a_dust) { outAmounts.push_back(a_dust); });
|
||||
|
||||
CHECK_AND_ASSERT_MES(1 <= maxOuts, false, "max_out must be non-zero");
|
||||
while (maxOuts < outAmounts.size()) {
|
||||
outAmounts[outAmounts.size() - 2] += outAmounts.back();
|
||||
outAmounts.resize(outAmounts.size() - 1);
|
||||
}
|
||||
|
||||
uint64_t summaryAmounts = 0;
|
||||
for (size_t no = 0; no < outAmounts.size(); no++) {
|
||||
crypto::key_derivation derivation = boost::value_initialized<crypto::key_derivation>();
|
||||
crypto::public_key outEphemeralPubKey = boost::value_initialized<crypto::public_key>();
|
||||
bool r = crypto::generate_key_derivation(minerAddress.m_viewPublicKey, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" <<
|
||||
minerAddress.m_viewPublicKey << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, no, minerAddress.m_spendPublicKey, outEphemeralPubKey);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " <<
|
||||
no << ", "<< minerAddress.m_spendPublicKey << ")");
|
||||
|
||||
TransactionOutputToKey tk;
|
||||
tk.key = outEphemeralPubKey;
|
||||
|
||||
TransactionOutput out;
|
||||
summaryAmounts += out.amount = outAmounts[no];
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(summaryAmounts == blockReward, false,
|
||||
"Failed to construct miner tx, summaryAmounts = " << summaryAmounts << " not equal blockReward = " << blockReward);
|
||||
|
||||
tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
//lock
|
||||
tx.unlockTime = height + m_minedMoneyUnlockWindow;
|
||||
tx.vin.push_back(in);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Currency::accountAddressAsString(const account_base& account) const {
|
||||
return getAccountAddressAsStr(m_publicAddressBase58Prefix, account.get_keys().m_account_address);
|
||||
}
|
||||
|
||||
bool Currency::parseAccountAddressString(const std::string& str, AccountPublicAddress& addr) const {
|
||||
uint64_t prefix;
|
||||
if (!cryptonote::parseAccountAddressString(prefix, addr, str)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (prefix != m_publicAddressBase58Prefix) {
|
||||
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << m_publicAddressBase58Prefix);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Currency::formatAmount(uint64_t amount) const {
|
||||
std::string s = std::to_string(amount);
|
||||
if (s.size() < m_numberOfDecimalPlaces + 1) {
|
||||
s.insert(0, m_numberOfDecimalPlaces + 1 - s.size(), '0');
|
||||
}
|
||||
s.insert(s.size() - m_numberOfDecimalPlaces, ".");
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Currency::parseAmount(const std::string& str, uint64_t& amount) const {
|
||||
std::string strAmount = str;
|
||||
boost::algorithm::trim(strAmount);
|
||||
|
||||
size_t pointIndex = strAmount.find_first_of('.');
|
||||
size_t fractionSize;
|
||||
if (std::string::npos != pointIndex) {
|
||||
fractionSize = strAmount.size() - pointIndex - 1;
|
||||
while (m_numberOfDecimalPlaces < fractionSize && '0' == strAmount.back()) {
|
||||
strAmount.erase(strAmount.size() - 1, 1);
|
||||
--fractionSize;
|
||||
}
|
||||
if (m_numberOfDecimalPlaces < fractionSize) {
|
||||
return false;
|
||||
}
|
||||
strAmount.erase(pointIndex, 1);
|
||||
} else {
|
||||
fractionSize = 0;
|
||||
}
|
||||
|
||||
if (strAmount.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fractionSize < m_numberOfDecimalPlaces) {
|
||||
strAmount.append(m_numberOfDecimalPlaces - fractionSize, '0');
|
||||
}
|
||||
|
||||
return epee::string_tools::get_xtype_from_string(amount, strAmount);
|
||||
}
|
||||
|
||||
difficulty_type Currency::nextDifficulty(std::vector<uint64_t> timestamps,
|
||||
std::vector<difficulty_type> cumulativeDifficulties) const {
|
||||
assert(m_difficultyWindow >= 2);
|
||||
|
||||
if (timestamps.size() > m_difficultyWindow) {
|
||||
timestamps.resize(m_difficultyWindow);
|
||||
cumulativeDifficulties.resize(m_difficultyWindow);
|
||||
}
|
||||
|
||||
size_t length = timestamps.size();
|
||||
assert(length == cumulativeDifficulties.size());
|
||||
assert(length <= m_difficultyWindow);
|
||||
if (length <= 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
sort(timestamps.begin(), timestamps.end());
|
||||
|
||||
size_t cutBegin, cutEnd;
|
||||
assert(2 * m_difficultyCut <= m_difficultyWindow - 2);
|
||||
if (length <= m_difficultyWindow - 2 * m_difficultyCut) {
|
||||
cutBegin = 0;
|
||||
cutEnd = length;
|
||||
} else {
|
||||
cutBegin = (length - (m_difficultyWindow - 2 * m_difficultyCut) + 1) / 2;
|
||||
cutEnd = cutBegin + (m_difficultyWindow - 2 * m_difficultyCut);
|
||||
}
|
||||
assert(/*cut_begin >= 0 &&*/ cutBegin + 2 <= cutEnd && cutEnd <= length);
|
||||
uint64_t timeSpan = timestamps[cutEnd - 1] - timestamps[cutBegin];
|
||||
if (timeSpan == 0) {
|
||||
timeSpan = 1;
|
||||
}
|
||||
|
||||
difficulty_type totalWork = cumulativeDifficulties[cutEnd - 1] - cumulativeDifficulties[cutBegin];
|
||||
assert(totalWork > 0);
|
||||
|
||||
uint64_t low, high;
|
||||
low = mul128(totalWork, m_difficultyTarget, &high);
|
||||
if (high != 0 || low + timeSpan - 1 < low) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (low + timeSpan - 1) / timeSpan;
|
||||
}
|
||||
|
||||
bool Currency::checkProofOfWorkV1(crypto::cn_context& context, const Block& block, difficulty_type currentDiffic,
|
||||
crypto::hash& proofOfWork) const {
|
||||
if (BLOCK_MAJOR_VERSION_1 != block.majorVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!get_block_longhash(context, block, proofOfWork)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return check_hash(proofOfWork, currentDiffic);
|
||||
}
|
||||
|
||||
bool Currency::checkProofOfWorkV2(crypto::cn_context& context, const Block& block, difficulty_type currentDiffic,
|
||||
crypto::hash& proofOfWork) const {
|
||||
if (BLOCK_MAJOR_VERSION_2 != block.majorVersion) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!get_block_longhash(context, block, proofOfWork)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_hash(proofOfWork, currentDiffic)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tx_extra_merge_mining_tag mmTag;
|
||||
if (!get_mm_tag_from_extra(block.parentBlock.minerTx.extra, mmTag)) {
|
||||
LOG_ERROR("merge mining tag wasn't found in extra of the parent block miner transaction");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (8 * sizeof(m_genesisBlockHash) < block.parentBlock.blockchainBranch.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash auxBlockHeaderHash;
|
||||
if (!get_aux_block_header_hash(block, auxBlockHeaderHash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::hash auxBlocksMerkleRoot;
|
||||
crypto::tree_hash_from_branch(block.parentBlock.blockchainBranch.data(), block.parentBlock.blockchainBranch.size(),
|
||||
auxBlockHeaderHash, &m_genesisBlockHash, auxBlocksMerkleRoot);
|
||||
CHECK_AND_NO_ASSERT_MES(auxBlocksMerkleRoot == mmTag.merkle_root, false, "Aux block hash wasn't found in merkle tree");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Currency::checkProofOfWork(crypto::cn_context& context, const Block& block, difficulty_type currentDiffic, crypto::hash& proofOfWork) const {
|
||||
switch (block.majorVersion) {
|
||||
case BLOCK_MAJOR_VERSION_1: return checkProofOfWorkV1(context, block, currentDiffic, proofOfWork);
|
||||
case BLOCK_MAJOR_VERSION_2: return checkProofOfWorkV2(context, block, currentDiffic, proofOfWork);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(false, false, "Unknown block major version: " << block.majorVersion << "." << block.minorVersion);
|
||||
}
|
||||
|
||||
CurrencyBuilder::CurrencyBuilder() {
|
||||
maxBlockNumber(parameters::CRYPTONOTE_MAX_BLOCK_NUMBER);
|
||||
maxBlockBlobSize(parameters::CRYPTONOTE_MAX_BLOCK_BLOB_SIZE);
|
||||
maxTxSize(parameters::CRYPTONOTE_MAX_TX_SIZE);
|
||||
publicAddressBase58Prefix(parameters::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX);
|
||||
minedMoneyUnlockWindow(parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW);
|
||||
|
||||
timestampCheckWindow(parameters::BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW);
|
||||
blockFutureTimeLimit(parameters::CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT);
|
||||
|
||||
moneySupply(parameters::MONEY_SUPPLY);
|
||||
emissionSpeedFactor(parameters::EMISSION_SPEED_FACTOR);
|
||||
|
||||
rewardBlocksWindow(parameters::CRYPTONOTE_REWARD_BLOCKS_WINDOW);
|
||||
blockGrantedFullRewardZone(parameters::CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE);
|
||||
minerTxBlobReservedSize(parameters::CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
|
||||
|
||||
numberOfDecimalPlaces(parameters::CRYPTONOTE_DISPLAY_DECIMAL_POINT);
|
||||
|
||||
mininumFee(parameters::MINIMUM_FEE);
|
||||
defaultDustThreshold(parameters::DEFAULT_DUST_THRESHOLD);
|
||||
|
||||
difficultyTarget(parameters::DIFFICULTY_TARGET);
|
||||
difficultyWindow(parameters::DIFFICULTY_WINDOW);
|
||||
difficultyLag(parameters::DIFFICULTY_LAG);
|
||||
difficultyCut(parameters::DIFFICULTY_CUT);
|
||||
|
||||
maxBlockSizeInitial(parameters::MAX_BLOCK_SIZE_INITIAL);
|
||||
maxBlockSizeGrowthSpeedNumerator(parameters::MAX_BLOCK_SIZE_GROWTH_SPEED_NUMERATOR);
|
||||
maxBlockSizeGrowthSpeedDenominator(parameters::MAX_BLOCK_SIZE_GROWTH_SPEED_DENOMINATOR);
|
||||
|
||||
lockedTxAllowedDeltaSeconds(parameters::CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS);
|
||||
lockedTxAllowedDeltaBlocks(parameters::CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
|
||||
|
||||
mempoolTxLiveTime(parameters::CRYPTONOTE_MEMPOOL_TX_LIVETIME);
|
||||
mempoolTxFromAltBlockLiveTime(parameters::CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME);
|
||||
|
||||
upgradeHeight(UpgradeDetectorBase::UNDEF_HEIGHT);
|
||||
upgradeVotingThreshold(parameters::UPGRADE_VOTING_THRESHOLD);
|
||||
upgradeVotingWindow(parameters::UPGRADE_VOTING_WINDOW);
|
||||
upgradeWindow(parameters::UPGRADE_WINDOW);
|
||||
|
||||
blocksFileName(parameters::CRYPTONOTE_BLOCKS_FILENAME);
|
||||
blocksCacheFileName(parameters::CRYPTONOTE_BLOCKSCACHE_FILENAME);
|
||||
blockIndexesFileName(parameters::CRYPTONOTE_BLOCKINDEXES_FILENAME);
|
||||
txPoolFileName(parameters::CRYPTONOTE_POOLDATA_FILENAME);
|
||||
|
||||
testnet(false);
|
||||
}
|
||||
|
||||
CurrencyBuilder& CurrencyBuilder::emissionSpeedFactor(unsigned int val) {
|
||||
if (val <= 0 || val > 8 * sizeof(uint64_t)) {
|
||||
throw std::invalid_argument("val at emissionSpeedFactor()");
|
||||
}
|
||||
|
||||
m_currency.m_emissionSpeedFactor = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CurrencyBuilder& CurrencyBuilder::numberOfDecimalPlaces(size_t val) {
|
||||
m_currency.m_numberOfDecimalPlaces = val;
|
||||
m_currency.m_coin = 1;
|
||||
for (size_t i = 0; i < m_currency.m_numberOfDecimalPlaces; ++i) {
|
||||
m_currency.m_coin *= 10;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CurrencyBuilder& CurrencyBuilder::difficultyWindow(size_t val) {
|
||||
if (val < 2) {
|
||||
throw std::invalid_argument("val at difficultyWindow()");
|
||||
}
|
||||
m_currency.m_difficultyWindow = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CurrencyBuilder& CurrencyBuilder::upgradeVotingThreshold(unsigned int val) {
|
||||
if (val <= 0 || val > 100) {
|
||||
throw std::invalid_argument("val at upgradeVotingThreshold()");
|
||||
}
|
||||
m_currency.m_upgradeVotingThreshold = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CurrencyBuilder& CurrencyBuilder::upgradeWindow(size_t val) {
|
||||
if (val <= 0) {
|
||||
throw std::invalid_argument("val at upgradeWindow()");
|
||||
}
|
||||
m_currency.m_upgradeWindow = val;
|
||||
return *this;
|
||||
}
|
||||
}
|
238
src/cryptonote_core/Currency.h
Normal file
238
src/cryptonote_core/Currency.h
Normal file
|
@ -0,0 +1,238 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_core/difficulty.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_protocol/blobdatatype.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class Currency {
|
||||
public:
|
||||
uint64_t maxBlockHeight() const { return m_maxBlockHeight; }
|
||||
size_t maxBlockBlobSize() const { return m_maxBlockBlobSize; }
|
||||
size_t maxTxSize() const { return m_maxTxSize; }
|
||||
uint64_t publicAddressBase58Prefix() const { return m_publicAddressBase58Prefix; }
|
||||
size_t minedMoneyUnlockWindow() const { return m_minedMoneyUnlockWindow; }
|
||||
|
||||
size_t timestampCheckWindow() const { return m_timestampCheckWindow; }
|
||||
uint64_t blockFutureTimeLimit() const { return m_blockFutureTimeLimit; }
|
||||
|
||||
uint64_t moneySupply() const { return m_moneySupply; }
|
||||
unsigned int emissionSpeedFactor() const { return m_emissionSpeedFactor; }
|
||||
|
||||
size_t rewardBlocksWindow() const { return m_rewardBlocksWindow; }
|
||||
size_t blockGrantedFullRewardZone() const { return m_blockGrantedFullRewardZone; }
|
||||
size_t minerTxBlobReservedSize() const { return m_minerTxBlobReservedSize; }
|
||||
|
||||
size_t numberOfDecimalPlaces() const { return m_numberOfDecimalPlaces; }
|
||||
uint64_t coin() const { return m_coin; }
|
||||
|
||||
uint64_t minimumFee() const { return m_mininumFee; }
|
||||
uint64_t defaultDustThreshold() const { return m_defaultDustThreshold; }
|
||||
|
||||
uint64_t difficultyTarget() const { return m_difficultyTarget; }
|
||||
size_t difficultyWindow() const { return m_difficultyWindow; }
|
||||
size_t difficultyLag() const { return m_difficultyLag; }
|
||||
size_t difficultyCut() const { return m_difficultyCut; }
|
||||
size_t difficultyBlocksCount() const { return m_difficultyWindow + m_difficultyLag; }
|
||||
|
||||
size_t maxBlockSizeInitial() const { return m_maxBlockSizeInitial; }
|
||||
uint64_t maxBlockSizeGrowthSpeedNumerator() const { return m_maxBlockSizeGrowthSpeedNumerator; }
|
||||
uint64_t maxBlockSizeGrowthSpeedDenominator() const { return m_maxBlockSizeGrowthSpeedDenominator; }
|
||||
|
||||
uint64_t lockedTxAllowedDeltaSeconds() const { return m_lockedTxAllowedDeltaSeconds; }
|
||||
size_t lockedTxAllowedDeltaBlocks() const { return m_lockedTxAllowedDeltaBlocks; }
|
||||
|
||||
uint64_t mempoolTxLiveTime() const { return m_mempoolTxLiveTime; }
|
||||
uint64_t mempoolTxFromAltBlockLiveTime() const { return m_mempoolTxFromAltBlockLiveTime; }
|
||||
|
||||
uint64_t upgradeHeight() const { return m_upgradeHeight; }
|
||||
unsigned int upgradeVotingThreshold() const { return m_upgradeVotingThreshold; }
|
||||
size_t upgradeVotingWindow() const { return m_upgradeVotingWindow; }
|
||||
size_t upgradeWindow() const { return m_upgradeWindow; }
|
||||
size_t minNumberVotingBlocks() const { return (m_upgradeVotingWindow * m_upgradeVotingThreshold + 99) / 100; }
|
||||
uint64_t maxUpgradeDistance() const { return static_cast<uint64_t>(m_upgradeWindow); }
|
||||
uint64_t calculateUpgradeHeight(uint64_t voteCompleteHeight) const { return voteCompleteHeight + m_upgradeWindow; }
|
||||
|
||||
const std::string& blocksFileName() const { return m_blocksFileName; }
|
||||
const std::string& blocksCacheFileName() const { return m_blocksCacheFileName; }
|
||||
const std::string& blockIndexesFileName() const { return m_blockIndexesFileName; }
|
||||
const std::string& txPoolFileName() const { return m_txPoolFileName; }
|
||||
|
||||
bool isTestnet() const { return m_testnet; }
|
||||
|
||||
const Block& genesisBlock() const { return m_genesisBlock; }
|
||||
const crypto::hash& genesisBlockHash() const { return m_genesisBlockHash; }
|
||||
|
||||
bool getBlockReward(size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, uint64_t fee,
|
||||
bool penalizeFee, uint64_t& reward, int64_t& emissionChange) const;
|
||||
size_t maxBlockCumulativeSize(uint64_t height) const;
|
||||
|
||||
bool constructMinerTx(size_t height, size_t medianSize, uint64_t alreadyGeneratedCoins, size_t currentBlockSize,
|
||||
uint64_t fee, const AccountPublicAddress& minerAddress, Transaction& tx,
|
||||
const blobdata& extraNonce = blobdata(), size_t maxOuts = 1, bool penalizeFee = false) const;
|
||||
|
||||
std::string accountAddressAsString(const account_base& account) const;
|
||||
bool parseAccountAddressString(const std::string& str, AccountPublicAddress& addr) const;
|
||||
|
||||
std::string formatAmount(uint64_t amount) const;
|
||||
bool parseAmount(const std::string& str, uint64_t& amount) const;
|
||||
|
||||
difficulty_type nextDifficulty(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulativeDifficulties) const;
|
||||
|
||||
bool checkProofOfWorkV1(crypto::cn_context& context, const Block& block, difficulty_type currentDiffic, crypto::hash& proofOfWork) const;
|
||||
bool checkProofOfWorkV2(crypto::cn_context& context, const Block& block, difficulty_type currentDiffic, crypto::hash& proofOfWork) const;
|
||||
bool checkProofOfWork(crypto::cn_context& context, const Block& block, difficulty_type currentDiffic, crypto::hash& proofOfWork) const;
|
||||
|
||||
private:
|
||||
Currency() {
|
||||
}
|
||||
|
||||
bool init();
|
||||
|
||||
bool generateGenesisBlock();
|
||||
|
||||
private:
|
||||
uint64_t m_maxBlockHeight;
|
||||
size_t m_maxBlockBlobSize;
|
||||
size_t m_maxTxSize;
|
||||
uint64_t m_publicAddressBase58Prefix;
|
||||
size_t m_minedMoneyUnlockWindow;
|
||||
|
||||
size_t m_timestampCheckWindow;
|
||||
uint64_t m_blockFutureTimeLimit;
|
||||
|
||||
uint64_t m_moneySupply;
|
||||
unsigned int m_emissionSpeedFactor;
|
||||
|
||||
size_t m_rewardBlocksWindow;
|
||||
size_t m_blockGrantedFullRewardZone;
|
||||
size_t m_minerTxBlobReservedSize;
|
||||
|
||||
size_t m_numberOfDecimalPlaces;
|
||||
uint64_t m_coin;
|
||||
|
||||
uint64_t m_mininumFee;
|
||||
uint64_t m_defaultDustThreshold;
|
||||
|
||||
uint64_t m_difficultyTarget;
|
||||
size_t m_difficultyWindow;
|
||||
size_t m_difficultyLag;
|
||||
size_t m_difficultyCut;
|
||||
|
||||
size_t m_maxBlockSizeInitial;
|
||||
uint64_t m_maxBlockSizeGrowthSpeedNumerator;
|
||||
uint64_t m_maxBlockSizeGrowthSpeedDenominator;
|
||||
|
||||
uint64_t m_lockedTxAllowedDeltaSeconds;
|
||||
size_t m_lockedTxAllowedDeltaBlocks;
|
||||
|
||||
uint64_t m_mempoolTxLiveTime;
|
||||
uint64_t m_mempoolTxFromAltBlockLiveTime;
|
||||
|
||||
uint64_t m_upgradeHeight;
|
||||
unsigned int m_upgradeVotingThreshold;
|
||||
size_t m_upgradeVotingWindow;
|
||||
size_t m_upgradeWindow;
|
||||
|
||||
std::string m_blocksFileName;
|
||||
std::string m_blocksCacheFileName;
|
||||
std::string m_blockIndexesFileName;
|
||||
std::string m_txPoolFileName;
|
||||
|
||||
bool m_testnet;
|
||||
|
||||
Block m_genesisBlock;
|
||||
crypto::hash m_genesisBlockHash;
|
||||
|
||||
friend class CurrencyBuilder;
|
||||
};
|
||||
|
||||
class CurrencyBuilder : boost::noncopyable {
|
||||
public:
|
||||
CurrencyBuilder();
|
||||
|
||||
Currency currency() {
|
||||
if (!m_currency.init()) {
|
||||
throw std::runtime_error("Failed to initialize currency object");
|
||||
}
|
||||
return m_currency;
|
||||
}
|
||||
|
||||
CurrencyBuilder& maxBlockNumber(uint64_t val) { m_currency.m_maxBlockHeight = val; return *this; }
|
||||
CurrencyBuilder& maxBlockBlobSize(size_t val) { m_currency.m_maxBlockBlobSize = val; return *this; }
|
||||
CurrencyBuilder& maxTxSize(size_t val) { m_currency.m_maxTxSize = val; return *this; }
|
||||
CurrencyBuilder& publicAddressBase58Prefix(uint64_t val) { m_currency.m_publicAddressBase58Prefix = val; return *this; }
|
||||
CurrencyBuilder& minedMoneyUnlockWindow(size_t val) { m_currency.m_minedMoneyUnlockWindow = val; return *this; }
|
||||
|
||||
CurrencyBuilder& timestampCheckWindow(size_t val) { m_currency.m_timestampCheckWindow = val; return *this; }
|
||||
CurrencyBuilder& blockFutureTimeLimit(uint64_t val) { m_currency.m_blockFutureTimeLimit = val; return *this; }
|
||||
|
||||
CurrencyBuilder& moneySupply(uint64_t val) { m_currency.m_moneySupply = val; return *this; }
|
||||
CurrencyBuilder& emissionSpeedFactor(unsigned int val);
|
||||
|
||||
CurrencyBuilder& rewardBlocksWindow(size_t val) { m_currency.m_rewardBlocksWindow = val; return *this; }
|
||||
CurrencyBuilder& blockGrantedFullRewardZone(size_t val) { m_currency.m_blockGrantedFullRewardZone = val; return *this; }
|
||||
CurrencyBuilder& minerTxBlobReservedSize(size_t val) { m_currency.m_minerTxBlobReservedSize = val; return *this; }
|
||||
|
||||
CurrencyBuilder& numberOfDecimalPlaces(size_t val);
|
||||
|
||||
CurrencyBuilder& mininumFee(uint64_t val) { m_currency.m_mininumFee = val; return *this; }
|
||||
CurrencyBuilder& defaultDustThreshold(uint64_t val) { m_currency.m_defaultDustThreshold = val; return *this; }
|
||||
|
||||
CurrencyBuilder& difficultyTarget(uint64_t val) { m_currency.m_difficultyTarget = val; return *this; }
|
||||
CurrencyBuilder& difficultyWindow(size_t val);
|
||||
CurrencyBuilder& difficultyLag(size_t val) { m_currency.m_difficultyLag = val; return *this; }
|
||||
CurrencyBuilder& difficultyCut(size_t val) { m_currency.m_difficultyCut = val; return *this; }
|
||||
|
||||
CurrencyBuilder& maxBlockSizeInitial(size_t val) { m_currency.m_maxBlockSizeInitial = val; return *this; }
|
||||
CurrencyBuilder& maxBlockSizeGrowthSpeedNumerator(uint64_t val) { m_currency.m_maxBlockSizeGrowthSpeedNumerator = val; return *this; }
|
||||
CurrencyBuilder& maxBlockSizeGrowthSpeedDenominator(uint64_t val) { m_currency.m_maxBlockSizeGrowthSpeedDenominator = val; return *this; }
|
||||
|
||||
CurrencyBuilder& lockedTxAllowedDeltaSeconds(uint64_t val) { m_currency.m_lockedTxAllowedDeltaSeconds = val; return *this; }
|
||||
CurrencyBuilder& lockedTxAllowedDeltaBlocks(size_t val) { m_currency.m_lockedTxAllowedDeltaBlocks = val; return *this; }
|
||||
|
||||
CurrencyBuilder& mempoolTxLiveTime(uint64_t val) { m_currency.m_mempoolTxLiveTime = val; return *this; }
|
||||
CurrencyBuilder& mempoolTxFromAltBlockLiveTime(uint64_t val) { m_currency.m_mempoolTxFromAltBlockLiveTime = val; return *this; }
|
||||
|
||||
CurrencyBuilder& upgradeHeight(uint64_t val) { m_currency.m_upgradeHeight = val; return *this; }
|
||||
CurrencyBuilder& upgradeVotingThreshold(unsigned int val);
|
||||
CurrencyBuilder& upgradeVotingWindow(size_t val) { m_currency.m_upgradeVotingWindow = val; return *this; }
|
||||
CurrencyBuilder& upgradeWindow(size_t val);
|
||||
|
||||
CurrencyBuilder& blocksFileName(const std::string& val) { m_currency.m_blocksFileName = val; return *this; }
|
||||
CurrencyBuilder& blocksCacheFileName(const std::string& val) { m_currency.m_blocksCacheFileName = val; return *this; }
|
||||
CurrencyBuilder& blockIndexesFileName(const std::string& val) { m_currency.m_blockIndexesFileName = val; return *this; }
|
||||
CurrencyBuilder& txPoolFileName(const std::string& val) { m_currency.m_txPoolFileName = val; return *this; }
|
||||
|
||||
CurrencyBuilder& testnet(bool val) { m_currency.m_testnet = val; return *this; }
|
||||
|
||||
private:
|
||||
Currency m_currency;
|
||||
};
|
||||
}
|
18
src/cryptonote_core/ITimeProvider.cpp
Normal file
18
src/cryptonote_core/ITimeProvider.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ITimeProvider.h"
|
35
src/cryptonote_core/ITimeProvider.h
Normal file
35
src/cryptonote_core/ITimeProvider.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
namespace CryptoNote {
|
||||
|
||||
struct ITimeProvider {
|
||||
virtual time_t now() = 0;
|
||||
virtual ~ITimeProvider() {}
|
||||
};
|
||||
|
||||
struct RealTimeProvider : public ITimeProvider {
|
||||
virtual time_t now() {
|
||||
return time(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
51
src/cryptonote_core/ITransactionValidator.h
Normal file
51
src/cryptonote_core/ITransactionValidator.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
|
||||
namespace CryptoNote {
|
||||
|
||||
struct BlockInfo {
|
||||
uint64_t height;
|
||||
crypto::hash id;
|
||||
|
||||
BlockInfo() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
height = 0;
|
||||
id = cryptonote::null_hash;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return id == cryptonote::null_hash;
|
||||
}
|
||||
};
|
||||
|
||||
class ITransactionValidator {
|
||||
public:
|
||||
virtual ~ITransactionValidator() {}
|
||||
|
||||
virtual bool checkTransactionInputs(const cryptonote::Transaction& tx, BlockInfo& maxUsedBlock) = 0;
|
||||
virtual bool checkTransactionInputs(const cryptonote::Transaction& tx, BlockInfo& maxUsedBlock, BlockInfo& lastFailed) = 0;
|
||||
virtual bool haveSpentKeyImages(const cryptonote::Transaction& tx) = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -25,12 +25,119 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
//#include <boost/archive/binary_iarchive.hpp>
|
||||
//#include <boost/archive/binary_oarchive.hpp>
|
||||
#include "serialization/binary_archive.h"
|
||||
|
||||
template<class T> class SwappedVector {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
class const_iterator {
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef std::random_access_iterator_tag iterator_category;
|
||||
typedef const T* pointer;
|
||||
typedef const T& reference;
|
||||
typedef T value_type;
|
||||
|
||||
const_iterator() {
|
||||
}
|
||||
|
||||
const_iterator(SwappedVector* swappedVector, std::size_t index) : m_swappedVector(swappedVector), m_index(index) {
|
||||
}
|
||||
|
||||
bool operator!=(const const_iterator& other) const {
|
||||
return m_index != other.m_index;
|
||||
}
|
||||
|
||||
bool operator<(const const_iterator& other) const {
|
||||
return m_index < other.m_index;
|
||||
}
|
||||
|
||||
bool operator<=(const const_iterator& other) const {
|
||||
return m_index <= other.m_index;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator& other) const {
|
||||
return m_index == other.m_index;
|
||||
}
|
||||
|
||||
bool operator>(const const_iterator& other) const {
|
||||
return m_index > other.m_index;
|
||||
}
|
||||
|
||||
bool operator>=(const const_iterator& other) const {
|
||||
return m_index >= other.m_index;
|
||||
}
|
||||
|
||||
const_iterator& operator++() {
|
||||
++m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator++(int) {
|
||||
const_iterator i = *this;
|
||||
++m_index;
|
||||
return i;
|
||||
}
|
||||
|
||||
const_iterator& operator--() {
|
||||
--m_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator--(int) {
|
||||
const_iterator i = *this;
|
||||
--m_index;
|
||||
return i;
|
||||
}
|
||||
|
||||
const_iterator& operator+=(difference_type n) {
|
||||
m_index += n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator& operator-=(difference_type n) {
|
||||
m_index -= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator+(difference_type n) const {
|
||||
return const_iterator(m_swappedVector, m_index + n);
|
||||
}
|
||||
|
||||
friend const_iterator operator+(difference_type n, const const_iterator& i) {
|
||||
return const_iterator(i.m_swappedVector, n + i.m_index);
|
||||
}
|
||||
|
||||
difference_type operator-(const const_iterator& other) const {
|
||||
return m_index - other.m_index;
|
||||
}
|
||||
|
||||
const_iterator& operator-(difference_type n) const {
|
||||
return const_iterator(m_swappedVector, m_index - n);
|
||||
}
|
||||
|
||||
const T& operator*() const {
|
||||
return (*m_swappedVector)[m_index];
|
||||
}
|
||||
|
||||
const T* operator->() const {
|
||||
return &(*m_swappedVector)[m_index];
|
||||
}
|
||||
|
||||
const T& operator[](difference_type offset) const {
|
||||
return (*m_swappedVector)[m_index + offset];
|
||||
}
|
||||
|
||||
std::size_t index() const {
|
||||
return m_index;
|
||||
}
|
||||
|
||||
private:
|
||||
SwappedVector* m_swappedVector;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
SwappedVector();
|
||||
//SwappedVector(const SwappedVector&) = delete;
|
||||
~SwappedVector();
|
||||
|
@ -41,6 +148,8 @@ public:
|
|||
|
||||
bool empty() const;
|
||||
uint64_t size() const;
|
||||
const_iterator begin();
|
||||
const_iterator end();
|
||||
const T& operator[](uint64_t index);
|
||||
const T& front();
|
||||
const T& back();
|
||||
|
@ -149,6 +258,14 @@ template<class T> uint64_t SwappedVector<T>::size() const {
|
|||
return m_offsets.size();
|
||||
}
|
||||
|
||||
template<class T> typename SwappedVector<T>::const_iterator SwappedVector<T>::begin() {
|
||||
return const_iterator(this, 0);
|
||||
}
|
||||
|
||||
template<class T> typename SwappedVector<T>::const_iterator SwappedVector<T>::end() {
|
||||
return const_iterator(this, m_offsets.size());
|
||||
}
|
||||
|
||||
template<class T> const T& SwappedVector<T>::operator[](uint64_t index) {
|
||||
auto itemIter = m_items.find(index);
|
||||
if (itemIter != m_items.end()) {
|
||||
|
@ -170,13 +287,6 @@ template<class T> const T& SwappedVector<T>::operator[](uint64_t index) {
|
|||
|
||||
m_itemsFile.seekg(m_offsets[index]);
|
||||
T tempItem;
|
||||
//try {
|
||||
//boost::archive::binary_iarchive archive(m_itemsFile);
|
||||
//archive & tempItem;
|
||||
//} catch (std::exception&) {
|
||||
// throw std::runtime_error("SwappedVector::operator[]");
|
||||
//}
|
||||
|
||||
binary_archive<false> archive(m_itemsFile);
|
||||
if (!do_serialize(archive, tempItem)) {
|
||||
throw std::runtime_error("SwappedVector::operator[]");
|
||||
|
@ -244,13 +354,6 @@ template<class T> void SwappedVector<T>::push_back(const T& item) {
|
|||
}
|
||||
|
||||
m_itemsFile.seekp(m_itemsFileSize);
|
||||
//try {
|
||||
// boost::archive::binary_oarchive archive(m_itemsFile);
|
||||
// archive & item;
|
||||
//} catch (std::exception&) {
|
||||
// throw std::runtime_error("SwappedVector::push_back");
|
||||
//}
|
||||
|
||||
binary_archive<true> archive(m_itemsFile);
|
||||
if (!do_serialize(archive, *const_cast<T*>(&item))) {
|
||||
throw std::runtime_error("SwappedVector::push_back");
|
||||
|
|
18
src/cryptonote_core/UpgradeDetector.cpp
Normal file
18
src/cryptonote_core/UpgradeDetector.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "UpgradeDetector.h"
|
193
src/cryptonote_core/UpgradeDetector.h
Normal file
193
src/cryptonote_core/UpgradeDetector.h
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
// epee
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "cryptonote_core/Currency.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
namespace cryptonote {
|
||||
class UpgradeDetectorBase {
|
||||
public:
|
||||
enum : uint64_t {
|
||||
UNDEF_HEIGHT = static_cast<uint64_t>(-1),
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(cryptonote::UpgradeDetectorBase::UNDEF_HEIGHT == UINT64_C(0xFFFFFFFFFFFFFFFF), "UpgradeDetectorBase::UNDEF_HEIGHT has invalid value");
|
||||
|
||||
template <typename BC>
|
||||
class BasicUpgradeDetector : public UpgradeDetectorBase {
|
||||
public:
|
||||
BasicUpgradeDetector(const Currency& currency, BC& blockchain, uint8_t targetVersion) :
|
||||
m_currency(currency),
|
||||
m_blockchain(blockchain),
|
||||
m_targetVersion(targetVersion),
|
||||
m_votingCompleteHeight(UNDEF_HEIGHT) {
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if (m_currency.upgradeHeight() == UNDEF_HEIGHT) {
|
||||
if (m_blockchain.empty()) {
|
||||
m_votingCompleteHeight = UNDEF_HEIGHT;
|
||||
|
||||
} else if (m_targetVersion - 1 == m_blockchain.back().bl.majorVersion) {
|
||||
m_votingCompleteHeight = findVotingCompleteHeight(m_blockchain.size() - 1);
|
||||
|
||||
} else if (m_targetVersion <= m_blockchain.back().bl.majorVersion) {
|
||||
auto it = std::lower_bound(m_blockchain.begin(), m_blockchain.end(), m_targetVersion,
|
||||
[](const typename BC::value_type& b, uint8_t v) { return b.bl.majorVersion < v; });
|
||||
CHECK_AND_ASSERT_MES(it != m_blockchain.end() && it->bl.majorVersion == m_targetVersion, false,
|
||||
"Internal error: upgrade height isn't found");
|
||||
uint64_t upgradeHeight = it - m_blockchain.begin();
|
||||
m_votingCompleteHeight = findVotingCompleteHeight(upgradeHeight);
|
||||
CHECK_AND_ASSERT_MES(m_votingCompleteHeight != UNDEF_HEIGHT, false,
|
||||
"Internal error: voting complete height isn't found, upgrade height = " << upgradeHeight);
|
||||
|
||||
} else {
|
||||
m_votingCompleteHeight = UNDEF_HEIGHT;
|
||||
}
|
||||
} else if (!m_blockchain.empty()) {
|
||||
if (m_blockchain.size() <= m_currency.upgradeHeight() + 1) {
|
||||
CHECK_AND_ASSERT_MES(m_blockchain.back().bl.majorVersion == m_targetVersion - 1, false,
|
||||
"Internal error: block at height " << (m_blockchain.size() - 1) << " has invalid version " <<
|
||||
static_cast<int>(m_blockchain.back().bl.majorVersion) << ", expected " << static_cast<int>(m_targetVersion));
|
||||
} else {
|
||||
int blockVersionAtUpgradeHeight = m_blockchain[m_currency.upgradeHeight()].bl.majorVersion;
|
||||
CHECK_AND_ASSERT_MES(blockVersionAtUpgradeHeight == m_targetVersion - 1, false,
|
||||
"Internal error: block at height " << m_currency.upgradeHeight() << " has invalid version " <<
|
||||
blockVersionAtUpgradeHeight << ", expected " << static_cast<int>(m_targetVersion - 1));
|
||||
|
||||
int blockVersionAfterUpgradeHeight = m_blockchain[m_currency.upgradeHeight() + 1].bl.majorVersion;
|
||||
CHECK_AND_ASSERT_MES(blockVersionAfterUpgradeHeight == m_targetVersion, false,
|
||||
"Internal error: block at height " << (m_currency.upgradeHeight() + 1) << " has invalid version " <<
|
||||
blockVersionAfterUpgradeHeight << ", expected " << static_cast<int>(m_targetVersion));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t targetVersion() const { return m_targetVersion; }
|
||||
uint64_t votingCompleteHeight() const { return m_votingCompleteHeight; }
|
||||
|
||||
uint64_t upgradeHeight() const {
|
||||
if (m_currency.upgradeHeight() == UNDEF_HEIGHT) {
|
||||
return m_votingCompleteHeight == UNDEF_HEIGHT ? UNDEF_HEIGHT : m_currency.calculateUpgradeHeight(m_votingCompleteHeight);
|
||||
} else {
|
||||
return m_currency.upgradeHeight();
|
||||
}
|
||||
}
|
||||
|
||||
void blockPushed() {
|
||||
assert(!m_blockchain.empty());
|
||||
|
||||
if (m_currency.upgradeHeight() != UNDEF_HEIGHT) {
|
||||
if (m_blockchain.size() <= m_currency.upgradeHeight() + 1) {
|
||||
assert(m_blockchain.back().bl.majorVersion == m_targetVersion - 1);
|
||||
} else {
|
||||
assert(m_blockchain.back().bl.majorVersion == m_targetVersion);
|
||||
}
|
||||
|
||||
} else if (m_votingCompleteHeight != UNDEF_HEIGHT) {
|
||||
assert(m_blockchain.size() > m_votingCompleteHeight);
|
||||
|
||||
if (m_blockchain.size() <= upgradeHeight()) {
|
||||
assert(m_blockchain.back().bl.majorVersion == m_targetVersion - 1);
|
||||
|
||||
if (m_blockchain.size() % (60 * 60 / m_currency.difficultyTarget()) == 0) {
|
||||
LOG_PRINT_GREEN("###### UPGRADE is going to happen after height " << upgradeHeight() << "!", LOG_LEVEL_2);
|
||||
}
|
||||
} else if (m_blockchain.size() == upgradeHeight() + 1) {
|
||||
assert(m_blockchain.back().bl.majorVersion == m_targetVersion - 1);
|
||||
|
||||
LOG_PRINT_GREEN("###### UPGRADE has happened! Starting from height " << (upgradeHeight() + 1) <<
|
||||
" blocks with major version below " << static_cast<int>(m_targetVersion) << " will be rejected!", LOG_LEVEL_2);
|
||||
} else {
|
||||
assert(m_blockchain.back().bl.majorVersion == m_targetVersion);
|
||||
}
|
||||
|
||||
} else {
|
||||
uint64_t lastBlockHeight = m_blockchain.size() - 1;
|
||||
if (isVotingComplete(lastBlockHeight)) {
|
||||
m_votingCompleteHeight = lastBlockHeight;
|
||||
LOG_PRINT_GREEN("###### UPGRADE voting complete at height " << m_votingCompleteHeight <<
|
||||
"! UPGRADE is going to happen after height " << upgradeHeight() << "!", LOG_LEVEL_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blockPopped() {
|
||||
if (m_votingCompleteHeight != UNDEF_HEIGHT) {
|
||||
assert(m_currency.upgradeHeight() == UNDEF_HEIGHT);
|
||||
|
||||
if (m_blockchain.size() == m_votingCompleteHeight) {
|
||||
LOG_PRINT_YELLOW("###### UPGRADE after height " << upgradeHeight() << " has been cancelled!", LOG_LEVEL_2);
|
||||
m_votingCompleteHeight = UNDEF_HEIGHT;
|
||||
} else {
|
||||
assert(m_blockchain.size() > m_votingCompleteHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t findVotingCompleteHeight(uint64_t probableUpgradeHeight) {
|
||||
assert(m_currency.upgradeHeight() == UNDEF_HEIGHT);
|
||||
|
||||
uint64_t probableVotingCompleteHeight = probableUpgradeHeight > m_currency.maxUpgradeDistance() ?
|
||||
probableUpgradeHeight - m_currency.maxUpgradeDistance() : 0;
|
||||
for (size_t i = probableVotingCompleteHeight; i <= probableUpgradeHeight; ++i) {
|
||||
if (isVotingComplete(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return UNDEF_HEIGHT;
|
||||
}
|
||||
|
||||
bool isVotingComplete(uint64_t height) {
|
||||
assert(m_currency.upgradeHeight() == UNDEF_HEIGHT);
|
||||
assert(m_currency.upgradeVotingWindow() > 1);
|
||||
assert(m_currency.upgradeVotingThreshold() > 0 && m_currency.upgradeVotingThreshold() <= 100);
|
||||
|
||||
if (height < static_cast<uint64_t>(m_currency.upgradeVotingWindow()) - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int voteCounter = 0;
|
||||
for (size_t i = height + 1 - m_currency.upgradeVotingWindow(); i <= height; ++i) {
|
||||
const auto& b = m_blockchain[i].bl;
|
||||
voteCounter += (b.majorVersion == m_targetVersion - 1) && (b.minorVersion == BLOCK_MINOR_VERSION_1) ? 1 : 0;
|
||||
}
|
||||
|
||||
return m_currency.upgradeVotingThreshold() * m_currency.upgradeVotingWindow() <= 100 * voteCounter;
|
||||
}
|
||||
|
||||
private:
|
||||
const Currency& m_currency;
|
||||
BC& m_blockchain;
|
||||
uint8_t m_targetVersion;
|
||||
uint64_t m_votingCompleteHeight;
|
||||
};
|
||||
}
|
|
@ -15,21 +15,18 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "account.h"
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
#include <fstream>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "account.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
namespace cryptonote
|
||||
namespace cryptonote
|
||||
{
|
||||
//-----------------------------------------------------------------
|
||||
account_base::account_base()
|
||||
|
@ -44,8 +41,8 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||
//-----------------------------------------------------------------
|
||||
void account_base::generate()
|
||||
{
|
||||
generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key);
|
||||
generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key);
|
||||
crypto::generate_keys(m_keys.m_account_address.m_spendPublicKey, m_keys.m_spend_secret_key);
|
||||
crypto::generate_keys(m_keys.m_account_address.m_viewPublicKey, m_keys.m_view_secret_key);
|
||||
m_creation_timestamp = time(NULL);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
|
@ -54,10 +51,4 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||
return m_keys;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_address_str()
|
||||
{
|
||||
//TODO: change this code into base 58
|
||||
return get_account_address_as_str(m_keys.m_account_address);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -19,34 +19,24 @@
|
|||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
namespace cryptonote {
|
||||
template<bool is_store> struct AccountBaseSerializer;
|
||||
|
||||
struct account_keys
|
||||
{
|
||||
account_public_address m_account_address;
|
||||
struct account_keys {
|
||||
AccountPublicAddress m_account_address;
|
||||
crypto::secret_key m_spend_secret_key;
|
||||
crypto::secret_key m_view_secret_key;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_account_address)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class account_base
|
||||
{
|
||||
class account_base {
|
||||
public:
|
||||
account_base();
|
||||
void generate();
|
||||
const account_keys& get_keys() const;
|
||||
std::string get_public_address_str();
|
||||
|
||||
uint64_t get_createtime() const { return m_creation_timestamp; }
|
||||
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
|
||||
|
@ -55,20 +45,17 @@ namespace cryptonote
|
|||
bool store(const std::string& file_path);
|
||||
|
||||
template <class t_archive>
|
||||
inline void serialize(t_archive &a, const unsigned int /*ver*/)
|
||||
{
|
||||
inline void serialize(t_archive &a, const unsigned int /*ver*/) {
|
||||
a & m_keys;
|
||||
a & m_creation_timestamp;
|
||||
}
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_keys)
|
||||
KV_SERIALIZE(m_creation_timestamp)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
private:
|
||||
void set_null();
|
||||
account_keys m_keys;
|
||||
uint64_t m_creation_timestamp;
|
||||
|
||||
friend struct AccountBaseSerializer<true>;
|
||||
friend struct AccountBaseSerializer<false>;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -34,10 +34,10 @@ namespace boost
|
|||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::account_public_address &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::AccountPublicAddress &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.m_spend_public_key;
|
||||
a & x.m_view_public_key;
|
||||
a & x.m_spendPublicKey;
|
||||
a & x.m_viewPublicKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,54 +17,80 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "Currency.h"
|
||||
#include "SwappedVector.h"
|
||||
#include "UpgradeDetector.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "tx_pool.h"
|
||||
#include "common/util.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
#include "checkpoints.h"
|
||||
|
||||
#include "google/sparse_hash_set"
|
||||
#include "google/sparse_hash_map"
|
||||
|
||||
#include "ITransactionValidator.h"
|
||||
#include "BlockIndex.h"
|
||||
|
||||
namespace cryptonote {
|
||||
class blockchain_storage {
|
||||
struct NOTIFY_RESPONSE_CHAIN_ENTRY_request;
|
||||
struct NOTIFY_REQUEST_GET_OBJECTS_request;
|
||||
struct NOTIFY_RESPONSE_GET_OBJECTS_request;
|
||||
struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request;
|
||||
struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response;
|
||||
struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount;
|
||||
|
||||
using CryptoNote::BlockInfo;
|
||||
class blockchain_storage : public CryptoNote::ITransactionValidator {
|
||||
public:
|
||||
blockchain_storage(tx_memory_pool& tx_pool):m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false)
|
||||
{};
|
||||
blockchain_storage(const Currency& currency, tx_memory_pool& tx_pool);
|
||||
|
||||
// ITransactionValidator
|
||||
virtual bool checkTransactionInputs(const cryptonote::Transaction& tx, BlockInfo& maxUsedBlock);
|
||||
virtual bool checkTransactionInputs(const cryptonote::Transaction& tx, BlockInfo& maxUsedBlock, BlockInfo& lastFailed);
|
||||
virtual bool haveSpentKeyImages(const cryptonote::Transaction& tx);
|
||||
|
||||
bool init() { return init(tools::get_default_data_dir(), true); }
|
||||
bool init(const std::string& config_folder, bool load_existing);
|
||||
bool deinit();
|
||||
|
||||
bool getLowerBound(uint64_t timestamp, uint64_t startOffset, uint64_t& height);
|
||||
bool getBlockIds(uint64_t startHeight, size_t maxCount, std::list<crypto::hash>& items);
|
||||
|
||||
void set_checkpoints(checkpoints&& chk_pts) { m_checkpoints = chk_pts; }
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks);
|
||||
bool get_alternative_blocks(std::list<block>& blocks);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<Block>& blocks, std::list<Transaction>& txs);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<Block>& blocks);
|
||||
bool get_alternative_blocks(std::list<Block>& blocks);
|
||||
size_t get_alternative_blocks_count();
|
||||
crypto::hash get_block_id_by_height(uint64_t height);
|
||||
bool get_block_by_hash(const crypto::hash &h, block &blk);
|
||||
bool get_block_by_hash(const crypto::hash &h, Block &blk);
|
||||
|
||||
template<class archive_t> void serialize(archive_t & ar, const unsigned int version);
|
||||
|
||||
bool have_tx(const crypto::hash &id);
|
||||
bool have_tx_keyimges_as_spent(const transaction &tx);
|
||||
bool have_tx_keyimges_as_spent(const Transaction &tx);
|
||||
|
||||
uint64_t get_current_blockchain_height();
|
||||
crypto::hash get_tail_id();
|
||||
crypto::hash get_tail_id(uint64_t& height);
|
||||
difficulty_type get_difficulty_for_next_block();
|
||||
bool add_new_block(const block& bl_, block_verification_context& bvc);
|
||||
bool reset_and_set_genesis_block(const block& b);
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce);
|
||||
uint64_t getCoinsInCirculation();
|
||||
uint8_t get_block_major_version_for_height(uint64_t height) const;
|
||||
bool add_new_block(const Block& bl_, block_verification_context& bvc);
|
||||
bool reset_and_set_genesis_block(const Block& b);
|
||||
bool create_block_template(Block& b, const AccountPublicAddress& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce);
|
||||
bool have_block(const crypto::hash& id);
|
||||
size_t get_total_transactions();
|
||||
bool get_short_chain_history(std::list<crypto::hash>& ids);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction>>>& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count);
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp);
|
||||
bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset); // !!!!
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY_request& resp);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<Block, std::list<Transaction>>>& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count);
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS_request& arg, NOTIFY_RESPONSE_GET_OBJECTS_request& rsp);
|
||||
bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res);
|
||||
bool get_backward_blocks_sizes(size_t from_height, std::vector<size_t>& sz, size_t count);
|
||||
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs);
|
||||
bool store_blockchain();
|
||||
bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id);
|
||||
bool check_tx_inputs(const Transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, BlockInfo* tail = 0);
|
||||
uint64_t get_current_comulative_blocksize_limit();
|
||||
bool is_storing_blockchain(){return m_is_blockchain_storing;}
|
||||
uint64_t block_difficulty(size_t i);
|
||||
|
@ -74,13 +100,13 @@ namespace cryptonote {
|
|||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
for (const auto& bl_id : block_ids) {
|
||||
auto it = m_blockMap.find(bl_id);
|
||||
if (it == m_blockMap.end()) {
|
||||
uint64_t height = 0;
|
||||
if (!m_blockIndex.getBlockHeight(bl_id, height)) {
|
||||
missed_bs.push_back(bl_id);
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(it->second < m_blocks.size(), false, "Internal error: bl_id=" << epee::string_tools::pod_to_hex(bl_id)
|
||||
<< " have index record with offset="<<it->second<< ", bigger then m_blocks.size()=" << m_blocks.size());
|
||||
blocks.push_back(m_blocks[it->second].bl);
|
||||
CHECK_AND_ASSERT_MES(height < m_blocks.size(), false, "Internal error: bl_id=" << epee::string_tools::pod_to_hex(bl_id)
|
||||
<< " have index record with offset=" << height << ", bigger then m_blocks.size()=" << m_blocks.size());
|
||||
blocks.push_back(m_blocks[height].bl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +114,7 @@ namespace cryptonote {
|
|||
}
|
||||
|
||||
template<class t_ids_container, class t_tx_container, class t_missed_container>
|
||||
void get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) {
|
||||
void get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs, bool checkTxPool = false) {
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
for (const auto& tx_id : txs_ids) {
|
||||
|
@ -99,6 +125,12 @@ namespace cryptonote {
|
|||
txs.push_back(transactionByIndex(it->second).tx);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkTxPool) {
|
||||
auto poolTxIds = std::move(missed_txs);
|
||||
missed_txs.clear();
|
||||
m_tx_pool.getTransactions(poolTxIds, txs, missed_txs);
|
||||
}
|
||||
}
|
||||
|
||||
//debug functions
|
||||
|
@ -107,8 +139,8 @@ namespace cryptonote {
|
|||
void print_blockchain_outs(const std::string& file);
|
||||
|
||||
private:
|
||||
struct Transaction {
|
||||
transaction tx;
|
||||
struct TransactionEntry {
|
||||
Transaction tx;
|
||||
std::vector<uint32_t> m_global_output_indexes;
|
||||
|
||||
template<class archive_t> void serialize(archive_t & ar, unsigned int version);
|
||||
|
@ -119,13 +151,13 @@ namespace cryptonote {
|
|||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct Block {
|
||||
block bl;
|
||||
struct BlockEntry {
|
||||
Block bl;
|
||||
uint32_t height;
|
||||
uint64_t block_cumulative_size;
|
||||
difficulty_type cumulative_difficulty;
|
||||
uint64_t already_generated_coins;
|
||||
std::vector<Transaction> transactions;
|
||||
std::vector<TransactionEntry> transactions;
|
||||
|
||||
template<class Archive> void serialize(Archive& archive, unsigned int version);
|
||||
|
||||
|
@ -146,10 +178,20 @@ namespace cryptonote {
|
|||
template<class Archive> void serialize(Archive& archive, unsigned int version);
|
||||
};
|
||||
|
||||
typedef std::unordered_set<crypto::key_image> key_images_container;
|
||||
typedef std::unordered_map<crypto::hash, Block> blocks_ext_by_hash;
|
||||
typedef std::map<uint64_t, std::vector<std::pair<TransactionIndex, uint16_t>>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction
|
||||
struct MultisignatureOutputUsage {
|
||||
TransactionIndex transactionIndex;
|
||||
uint16_t outputIndex;
|
||||
bool isUsed;
|
||||
|
||||
template<class Archive> void serialize(Archive& archive, unsigned int version);
|
||||
};
|
||||
|
||||
typedef google::sparse_hash_set<crypto::key_image> key_images_container;
|
||||
typedef std::unordered_map<crypto::hash, BlockEntry> blocks_ext_by_hash;
|
||||
typedef google::sparse_hash_map<uint64_t, std::vector<std::pair<TransactionIndex, uint16_t>>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction
|
||||
typedef std::map<uint64_t, std::vector<MultisignatureOutputUsage>> MultisignatureOutputsContainer;
|
||||
|
||||
const Currency& m_currency;
|
||||
tx_memory_pool& m_tx_pool;
|
||||
epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock
|
||||
crypto::cn_context m_cn_context;
|
||||
|
@ -164,53 +206,80 @@ namespace cryptonote {
|
|||
std::atomic<bool> m_is_in_checkpoint_zone;
|
||||
std::atomic<bool> m_is_blockchain_storing;
|
||||
|
||||
typedef SwappedVector<Block> Blocks;
|
||||
typedef SwappedVector<BlockEntry> Blocks;
|
||||
typedef std::unordered_map<crypto::hash, uint32_t> BlockMap;
|
||||
typedef std::unordered_map<crypto::hash, TransactionIndex> TransactionMap;
|
||||
typedef BasicUpgradeDetector<Blocks> UpgradeDetector;
|
||||
|
||||
friend class BlockCacheSerializer;
|
||||
|
||||
Blocks m_blocks;
|
||||
BlockMap m_blockMap;
|
||||
CryptoNote::BlockIndex m_blockIndex;
|
||||
TransactionMap m_transactionMap;
|
||||
MultisignatureOutputsContainer m_multisignatureOutputs;
|
||||
UpgradeDetector m_upgradeDetector;
|
||||
|
||||
template<class visitor_t> bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL);
|
||||
bool storeCache();
|
||||
template<class visitor_t> bool scan_outputkeys_for_indexes(const TransactionInputToKey& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL);
|
||||
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::iterator>& alt_chain, bool discard_disconnected_chain);
|
||||
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc);
|
||||
difficulty_type get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, Block& bei);
|
||||
bool prevalidate_miner_transaction(const block& b, uint64_t height);
|
||||
bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins);
|
||||
bool validate_transaction(const block& b, uint64_t height, const transaction& tx);
|
||||
bool rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height);
|
||||
bool handle_alternative_block(const Block& b, const crypto::hash& id, block_verification_context& bvc);
|
||||
difficulty_type get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, BlockEntry& bei);
|
||||
bool prevalidate_miner_transaction(const Block& b, uint64_t height);
|
||||
bool validate_miner_transaction(const Block& b, uint64_t height, size_t cumulativeBlockSize, uint64_t alreadyGeneratedCoins, uint64_t fee, uint64_t& reward, int64_t& emissionChange);
|
||||
bool validate_transaction(const Block& b, uint64_t height, const Transaction& tx);
|
||||
bool rollback_blockchain_switching(std::list<Block>& original_chain, size_t rollback_height);
|
||||
bool get_last_n_blocks_sizes(std::vector<size_t>& sz, size_t count);
|
||||
bool add_out_to_get_random_outs(std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i);
|
||||
bool add_out_to_get_random_outs(std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_outs_for_amount& result_outs, uint64_t amount, size_t i);
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time);
|
||||
size_t find_end_of_allowed_index(const std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs);
|
||||
bool check_block_timestamp_main(const block& b);
|
||||
bool check_block_timestamp(std::vector<uint64_t> timestamps, const block& b);
|
||||
bool check_block_timestamp_main(const Block& b);
|
||||
bool check_block_timestamp(std::vector<uint64_t> timestamps, const Block& b);
|
||||
uint64_t get_adjusted_time();
|
||||
bool complete_timestamps_vector(uint64_t start_height, std::vector<uint64_t>& timestamps);
|
||||
bool checkBlockVersion(const Block& b, const crypto::hash& blockHash);
|
||||
bool checkParentBlockSize(const Block& b, const crypto::hash& blockHash);
|
||||
bool checkCumulativeBlockSize(const crypto::hash& blockId, size_t cumulativeBlockSize, uint64_t height);
|
||||
bool getBlockCumulativeSize(const Block& block, size_t& cumulativeSize);
|
||||
bool update_next_comulative_size_limit();
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, uint64_t& starter_offset);
|
||||
bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height = NULL);
|
||||
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL);
|
||||
bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL);
|
||||
bool check_tx_input(const TransactionInputToKey& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t* pmax_related_block_height = NULL);
|
||||
bool check_tx_inputs(const Transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL);
|
||||
bool check_tx_inputs(const Transaction& tx, uint64_t* pmax_used_block_height = NULL);
|
||||
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im);
|
||||
const Transaction& transactionByIndex(TransactionIndex index);
|
||||
bool pushBlock(const block& blockData, block_verification_context& bvc);
|
||||
bool pushBlock(Block& block);
|
||||
const TransactionEntry& transactionByIndex(TransactionIndex index);
|
||||
bool pushBlock(const Block& blockData, block_verification_context& bvc);
|
||||
bool pushBlock(BlockEntry& block);
|
||||
void popBlock(const crypto::hash& blockHash);
|
||||
bool pushTransaction(Block& block, const crypto::hash& transactionHash, TransactionIndex transactionIndex);
|
||||
void popTransaction(const transaction& transaction, const crypto::hash& transactionHash);
|
||||
void popTransactions(const Block& block, const crypto::hash& minerTransactionHash);
|
||||
bool pushTransaction(BlockEntry& block, const crypto::hash& transactionHash, TransactionIndex transactionIndex);
|
||||
void popTransaction(const Transaction& transaction, const crypto::hash& transactionHash);
|
||||
void popTransactions(const BlockEntry& block, const crypto::hash& minerTransactionHash);
|
||||
bool validateInput(const TransactionInputMultisignature& input, const crypto::hash& transactionHash, const crypto::hash& transactionPrefixHash, const std::vector<crypto::signature>& transactionSignatures);
|
||||
|
||||
friend class LockedBlockchainStorage;
|
||||
};
|
||||
|
||||
class LockedBlockchainStorage: boost::noncopyable {
|
||||
public:
|
||||
|
||||
template<class visitor_t> bool blockchain_storage::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) {
|
||||
LockedBlockchainStorage(blockchain_storage& bc)
|
||||
: m_bc(bc), m_lock(bc.m_blockchain_lock) {}
|
||||
|
||||
blockchain_storage* operator -> () {
|
||||
return &m_bc;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
blockchain_storage& m_bc;
|
||||
epee::critical_region_t<epee::critical_section> m_lock;
|
||||
};
|
||||
|
||||
template<class visitor_t> bool blockchain_storage::scan_outputkeys_for_indexes(const TransactionInputToKey& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) {
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
auto it = m_outputs.find(tx_in_to_key.amount);
|
||||
if (it == m_outputs.end() || !tx_in_to_key.key_offsets.size())
|
||||
if (it == m_outputs.end() || !tx_in_to_key.keyOffsets.size())
|
||||
return false;
|
||||
|
||||
std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets);
|
||||
std::vector<uint64_t> absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.keyOffsets);
|
||||
std::vector<std::pair<TransactionIndex, uint16_t>>& amount_outs_vec = it->second;
|
||||
size_t count = 0;
|
||||
for (uint64_t i : absolute_offsets) {
|
||||
|
@ -222,7 +291,7 @@ namespace cryptonote {
|
|||
//auto tx_it = m_transactionMap.find(amount_outs_vec[i].first);
|
||||
//CHECK_AND_ASSERT_MES(tx_it != m_transactionMap.end(), false, "Wrong transaction id in output indexes: " << epee::string_tools::pod_to_hex(amount_outs_vec[i].first));
|
||||
|
||||
const Transaction& tx = transactionByIndex(amount_outs_vec[i].first);
|
||||
const TransactionEntry& tx = transactionByIndex(amount_outs_vec[i].first);
|
||||
CHECK_AND_ASSERT_MES(amount_outs_vec[i].second < tx.tx.vout.size(), false,
|
||||
"Wrong index in transaction outputs: " << amount_outs_vec[i].second << ", expected less then " << tx.tx.vout.size());
|
||||
if (!vis.handle_output(tx.tx, tx.tx.vout[amount_outs_vec[i].second])) {
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "checkpoints.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false);
|
||||
|
||||
namespace cryptonote {
|
||||
inline bool create_checkpoints(cryptonote::checkpoints& checkpoints)
|
||||
{
|
||||
ADD_CHECKPOINT(79000, "cae33204e624faeb64938d80073bb7bbacc27017dc63f36c5c0f313cad455a02");
|
||||
ADD_CHECKPOINT(140000, "993059fb6ab92db7d80d406c67a52d9c02d873ca34b6290a12b744c970208772");
|
||||
ADD_CHECKPOINT(200000, "a5f74c7542077df6859f48b5b1f9c3741f29df38f91a47e14c94b5696e6c3073");
|
||||
ADD_CHECKPOINT(230580, "32bd7cb6c68a599cf2861941f29002a5e203522b9af54f08dfced316f6459103");
|
||||
ADD_CHECKPOINT(260000, "f68e70b360ca194f48084da7a7fd8e0251bbb4b5587f787ca65a6f5baf3f5947");
|
||||
ADD_CHECKPOINT(300000, "8e80861713f68354760dc10ea6ea79f5f3ff28f39b3f0835a8637463b09d70ff");
|
||||
ADD_CHECKPOINT(390285, "e00bdc9bf407aeace2f3109de11889ed25894bf194231d075eddaec838097eb7");
|
||||
ADD_CHECKPOINT(417000, "2dc96f8fc4d4a4d76b3ed06722829a7ab09d310584b8ecedc9b578b2c458a69f");
|
||||
ADD_CHECKPOINT(427193, "00feabb08f2d5759ed04fd6b799a7513187478696bba2db2af10d4347134e311");
|
||||
ADD_CHECKPOINT(453537, "d17de6916c5aa6ffcae575309c80b0f8fdcd0a84b5fa8e41a841897d4b5a4e97");
|
||||
ADD_CHECKPOINT(462250, "13468d210a5ec884cf839f0259f247ccf3efef0414ac45172033d32c739beb3e");
|
||||
ADD_CHECKPOINT(468000, "251bcbd398b1f593193a7210934a3d87f692b2cb0c45206150f59683dd7e9ba1");
|
||||
ADD_CHECKPOINT(480200, "363544ac9920c778b815c2fdbcbca70a0d79b21f662913a42da9b49e859f0e5b");
|
||||
ADD_CHECKPOINT(484500, "5cdf2101a0a62a0ab2a1ca0c15a6212b21f6dbdc42a0b7c0bcf65ca40b7a14fb");
|
||||
ADD_CHECKPOINT(506000, "3d54c1132f503d98d3f0d78bb46a4503c1a19447cb348361a2232e241cb45a3c");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -16,11 +16,16 @@
|
|||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
#include <unordered_set>
|
||||
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "net/net_utils_base.h"
|
||||
#include "copyable_atomic.h"
|
||||
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
|
|
|
@ -17,344 +17,421 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <cstring> // memcmp
|
||||
#include <sstream>
|
||||
#include "serialization/serialization.h"
|
||||
#include "serialization/variant.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/json_archive.h"
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h" // eepe named serialization
|
||||
#include "string_tools.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "tx_extra.h"
|
||||
#include "cryptonote_core/tx_extra.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/crypto.h"
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/json_archive.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "serialization/variant.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
namespace cryptonote {
|
||||
class account_base;
|
||||
struct account_keys;
|
||||
struct Block;
|
||||
struct Transaction;
|
||||
struct tx_extra_merge_mining_tag;
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
|
||||
const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
|
||||
|
||||
typedef std::vector<crypto::signature> ring_signature;
|
||||
|
||||
|
||||
/* outputs */
|
||||
|
||||
struct txout_to_script
|
||||
{
|
||||
std::vector<crypto::public_key> keys;
|
||||
std::vector<uint8_t> script;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(keys)
|
||||
FIELD(script)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txout_to_scripthash
|
||||
{
|
||||
crypto::hash hash;
|
||||
};
|
||||
|
||||
struct txout_to_key
|
||||
{
|
||||
txout_to_key() { }
|
||||
txout_to_key(const crypto::public_key &_key) : key(_key) { }
|
||||
crypto::public_key key;
|
||||
};
|
||||
// Implemented in cryptonote_format_utils.cpp
|
||||
bool get_transaction_hash(const Transaction& t, crypto::hash& res);
|
||||
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx, tx_extra_merge_mining_tag& mm_tag);
|
||||
|
||||
const static crypto::hash null_hash = boost::value_initialized<crypto::hash>();
|
||||
const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>();
|
||||
|
||||
/* inputs */
|
||||
|
||||
struct txin_gen
|
||||
{
|
||||
struct TransactionInputGenerate {
|
||||
size_t height;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(height)
|
||||
VARINT_FIELD(height);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_script
|
||||
{
|
||||
crypto::hash prev;
|
||||
size_t prevout;
|
||||
std::vector<uint8_t> sigset;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(prev)
|
||||
VARINT_FIELD(prevout)
|
||||
FIELD(sigset)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_scripthash
|
||||
{
|
||||
crypto::hash prev;
|
||||
size_t prevout;
|
||||
txout_to_script script;
|
||||
std::vector<uint8_t> sigset;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(prev)
|
||||
VARINT_FIELD(prevout)
|
||||
FIELD(script)
|
||||
FIELD(sigset)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct txin_to_key
|
||||
{
|
||||
struct TransactionInputToKey {
|
||||
uint64_t amount;
|
||||
std::vector<uint64_t> key_offsets;
|
||||
crypto::key_image k_image; // double spending protection
|
||||
std::vector<uint64_t> keyOffsets;
|
||||
crypto::key_image keyImage; // double spending protection
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(key_offsets)
|
||||
FIELD(k_image)
|
||||
VARINT_FIELD(amount);
|
||||
FIELD(keyOffsets);
|
||||
FIELD(keyImage);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
typedef boost::variant<txin_gen, txin_to_script, txin_to_scripthash, txin_to_key> txin_v;
|
||||
|
||||
typedef boost::variant<txout_to_script, txout_to_scripthash, txout_to_key> txout_target_v;
|
||||
|
||||
//typedef std::pair<uint64_t, txout> out_t;
|
||||
struct tx_out
|
||||
{
|
||||
struct TransactionInputMultisignature {
|
||||
uint64_t amount;
|
||||
txout_target_v target;
|
||||
uint32_t signatures;
|
||||
uint64_t outputIndex;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(target)
|
||||
VARINT_FIELD(amount);
|
||||
VARINT_FIELD(signatures);
|
||||
VARINT_FIELD(outputIndex);
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
};
|
||||
|
||||
class transaction_prefix
|
||||
{
|
||||
/* outputs */
|
||||
|
||||
public:
|
||||
struct TransactionOutputToKey {
|
||||
TransactionOutputToKey() { }
|
||||
TransactionOutputToKey(const crypto::public_key &_key) : key(_key) { }
|
||||
crypto::public_key key;
|
||||
};
|
||||
|
||||
struct TransactionOutputMultisignature {
|
||||
std::vector<crypto::public_key> keys;
|
||||
uint32_t requiredSignatures;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(keys);
|
||||
VARINT_FIELD(requiredSignatures);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct TransactionInputToScript {
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct TransactionInputToScriptHash {
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct TransactionOutputToScript {
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct TransactionOutputToScriptHash {
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
typedef boost::variant<
|
||||
TransactionInputGenerate,
|
||||
TransactionInputToScript,
|
||||
TransactionInputToScriptHash,
|
||||
TransactionInputToKey,
|
||||
TransactionInputMultisignature> TransactionInput;
|
||||
|
||||
typedef boost::variant<
|
||||
TransactionOutputToScript,
|
||||
TransactionOutputToScriptHash,
|
||||
TransactionOutputToKey,
|
||||
TransactionOutputMultisignature> TransactionOutputTarget;
|
||||
|
||||
struct TransactionOutput {
|
||||
uint64_t amount;
|
||||
TransactionOutputTarget target;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(amount);
|
||||
FIELD(target);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct TransactionPrefix {
|
||||
// tx information
|
||||
size_t version;
|
||||
uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
|
||||
uint64_t unlockTime; //number of block (or time), used as a limitation like: spend this tx not early then block/time
|
||||
|
||||
std::vector<txin_v> vin;
|
||||
std::vector<tx_out> vout;
|
||||
std::vector<TransactionInput> vin;
|
||||
std::vector<TransactionOutput> vout;
|
||||
//extra
|
||||
std::vector<uint8_t> extra;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if(CURRENT_TRANSACTION_VERSION < version) return false;
|
||||
VARINT_FIELD(unlock_time)
|
||||
FIELD(vin)
|
||||
FIELD(vout)
|
||||
FIELD(extra)
|
||||
VARINT_FIELD(version);
|
||||
if(CURRENT_TRANSACTION_VERSION < version) {
|
||||
return false;
|
||||
}
|
||||
VARINT_FIELD(unlockTime);
|
||||
FIELD(vin);
|
||||
FIELD(vout);
|
||||
FIELD(extra);
|
||||
END_SERIALIZE()
|
||||
|
||||
|
||||
protected:
|
||||
transaction_prefix(){}
|
||||
TransactionPrefix() {}
|
||||
};
|
||||
|
||||
class transaction: public transaction_prefix
|
||||
{
|
||||
public:
|
||||
struct Transaction: public TransactionPrefix {
|
||||
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
|
||||
|
||||
transaction();
|
||||
virtual ~transaction();
|
||||
void set_null();
|
||||
Transaction() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
version = 0;
|
||||
unlockTime = 0;
|
||||
vin.clear();
|
||||
vout.clear();
|
||||
extra.clear();
|
||||
signatures.clear();
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<transaction_prefix *>(this))
|
||||
FIELDS(*static_cast<TransactionPrefix *>(this))
|
||||
|
||||
ar.tag("signatures");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
|
||||
bool signatures_not_expected = signatures.empty();
|
||||
if (!signatures_not_expected && vin.size() != signatures.size())
|
||||
if (!signatures_not_expected && vin.size() != signatures.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < vin.size(); ++i)
|
||||
{
|
||||
size_t signature_size = get_signature_size(vin[i]);
|
||||
if (signatures_not_expected)
|
||||
{
|
||||
if (0 == signature_size)
|
||||
for (size_t i = 0; i < vin.size(); ++i) {
|
||||
size_t signatureSize = getSignatureSize(vin[i]);
|
||||
if (signatures_not_expected) {
|
||||
if (0 == signatureSize) {
|
||||
continue;
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
|
||||
if (signature_size != signatures[i].size())
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signatureSize, signatures[i]);
|
||||
if (signatureSize != signatures[i].size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FIELDS(signatures[i]);
|
||||
|
||||
if (vin.size() - i > 1)
|
||||
if (vin.size() - i > 1) {
|
||||
ar.delimit_array();
|
||||
}
|
||||
}
|
||||
ar.end_array();
|
||||
END_SERIALIZE()
|
||||
|
||||
private:
|
||||
static size_t get_signature_size(const txin_v& tx_in);
|
||||
static size_t getSignatureSize(const TransactionInput& input) {
|
||||
struct txin_signature_size_visitor : public boost::static_visitor<size_t> {
|
||||
size_t operator()(const TransactionInputGenerate& txin) const { return 0; }
|
||||
size_t operator()(const TransactionInputToScript& txin) const { assert(false); return 0; }
|
||||
size_t operator()(const TransactionInputToScriptHash& txin) const { assert(false); return 0; }
|
||||
size_t operator()(const TransactionInputToKey& txin) const { return txin.keyOffsets.size();}
|
||||
size_t operator()(const TransactionInputMultisignature& txin) const { return txin.signatures; }
|
||||
};
|
||||
|
||||
return boost::apply_visitor(txin_signature_size_visitor(), input);
|
||||
}
|
||||
};
|
||||
|
||||
struct ParentBlock {
|
||||
uint8_t majorVersion;
|
||||
uint8_t minorVersion;
|
||||
crypto::hash prevId;
|
||||
size_t numberOfTransactions;
|
||||
std::vector<crypto::hash> minerTxBranch;
|
||||
Transaction minerTx;
|
||||
std::vector<crypto::hash> blockchainBranch;
|
||||
};
|
||||
|
||||
inline
|
||||
transaction::transaction()
|
||||
{
|
||||
set_null();
|
||||
}
|
||||
struct ParentBlockSerializer {
|
||||
ParentBlockSerializer(ParentBlock& parentBlock, uint64_t& timestamp, uint32_t& nonce, bool hashingSerialization, bool headerOnly) :
|
||||
m_parentBlock(parentBlock), m_timestamp(timestamp), m_nonce(nonce), m_hashingSerialization(hashingSerialization), m_headerOnly(headerOnly) {
|
||||
}
|
||||
|
||||
inline
|
||||
transaction::~transaction()
|
||||
{
|
||||
//set_null();
|
||||
}
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD_N("majorVersion", m_parentBlock.majorVersion);
|
||||
if (BLOCK_MAJOR_VERSION_1 < m_parentBlock.majorVersion) {
|
||||
return false;
|
||||
}
|
||||
VARINT_FIELD_N("minorVersion", m_parentBlock.minorVersion);
|
||||
VARINT_FIELD_N("timestamp", m_timestamp);
|
||||
FIELD_N("prevId", m_parentBlock.prevId);
|
||||
FIELD_N("nonce", m_nonce);
|
||||
|
||||
inline
|
||||
void transaction::set_null()
|
||||
{
|
||||
version = 0;
|
||||
unlock_time = 0;
|
||||
vin.clear();
|
||||
vout.clear();
|
||||
extra.clear();
|
||||
signatures.clear();
|
||||
}
|
||||
if (m_hashingSerialization) {
|
||||
crypto::hash minerTxHash;
|
||||
if (!get_transaction_hash(m_parentBlock.minerTx, minerTxHash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
size_t transaction::get_signature_size(const txin_v& tx_in)
|
||||
{
|
||||
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
|
||||
{
|
||||
size_t operator()(const txin_gen& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_script& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_scripthash& txin) const{return 0;}
|
||||
size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();}
|
||||
};
|
||||
crypto::hash merkleRoot;
|
||||
crypto::tree_hash_from_branch(m_parentBlock.minerTxBranch.data(), m_parentBlock.minerTxBranch.size(), minerTxHash, 0, merkleRoot);
|
||||
|
||||
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
|
||||
}
|
||||
FIELD(merkleRoot);
|
||||
}
|
||||
|
||||
VARINT_FIELD_N("numberOfTransactions", m_parentBlock.numberOfTransactions);
|
||||
if (m_parentBlock.numberOfTransactions < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_headerOnly) {
|
||||
ar.tag("minerTxBranch");
|
||||
ar.begin_array();
|
||||
size_t branchSize = crypto::tree_depth(m_parentBlock.numberOfTransactions);
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(branchSize, const_cast<ParentBlock&>(m_parentBlock).minerTxBranch);
|
||||
if (m_parentBlock.minerTxBranch.size() != branchSize) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < branchSize; ++i) {
|
||||
FIELDS(m_parentBlock.minerTxBranch[i]);
|
||||
if (i + 1 < branchSize) {
|
||||
ar.delimit_array();
|
||||
}
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct block_header
|
||||
{
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint64_t timestamp;
|
||||
crypto::hash prev_id;
|
||||
FIELD(m_parentBlock.minerTx);
|
||||
|
||||
tx_extra_merge_mining_tag mmTag;
|
||||
if (!get_mm_tag_from_extra(m_parentBlock.minerTx.extra, mmTag)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mmTag.depth > 8 * sizeof(crypto::hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ar.tag("blockchainBranch");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mmTag.depth, const_cast<ParentBlock&>(m_parentBlock).blockchainBranch);
|
||||
if (mmTag.depth != m_parentBlock.blockchainBranch.size()) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < mmTag.depth; ++i) {
|
||||
FIELDS(m_parentBlock.blockchainBranch[i]);
|
||||
if (i + 1 < mmTag.depth) {
|
||||
ar.delimit_array();
|
||||
}
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
END_SERIALIZE()
|
||||
|
||||
private:
|
||||
ParentBlock& m_parentBlock;
|
||||
uint64_t& m_timestamp;
|
||||
uint32_t& m_nonce;
|
||||
bool m_hashingSerialization;
|
||||
bool m_headerOnly;
|
||||
};
|
||||
|
||||
// Implemented below
|
||||
inline ParentBlockSerializer makeParentBlockSerializer(const Block& b, bool hashingSerialization, bool headerOnly);
|
||||
|
||||
struct BlockHeader {
|
||||
uint8_t majorVersion;
|
||||
uint8_t minorVersion;
|
||||
uint32_t nonce;
|
||||
uint64_t timestamp;
|
||||
crypto::hash prevId;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(major_version)
|
||||
if(major_version > CURRENT_BLOCK_MAJOR_VERSION) return false;
|
||||
VARINT_FIELD(minor_version)
|
||||
VARINT_FIELD(timestamp)
|
||||
FIELD(prev_id)
|
||||
FIELD(nonce)
|
||||
VARINT_FIELD(majorVersion)
|
||||
if (majorVersion > BLOCK_MAJOR_VERSION_2) {
|
||||
return false;
|
||||
}
|
||||
VARINT_FIELD(minorVersion)
|
||||
if (majorVersion == BLOCK_MAJOR_VERSION_1) {
|
||||
VARINT_FIELD(timestamp);
|
||||
FIELD(prevId);
|
||||
FIELD(nonce);
|
||||
} else if (majorVersion == BLOCK_MAJOR_VERSION_2) {
|
||||
FIELD(prevId);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct block: public block_header
|
||||
{
|
||||
transaction miner_tx;
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
struct Block: public BlockHeader {
|
||||
ParentBlock parentBlock;
|
||||
|
||||
Transaction minerTx;
|
||||
std::vector<crypto::hash> txHashes;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<block_header *>(this))
|
||||
FIELD(miner_tx)
|
||||
FIELD(tx_hashes)
|
||||
FIELDS(*static_cast<BlockHeader *>(this));
|
||||
if (majorVersion == BLOCK_MAJOR_VERSION_2) {
|
||||
auto serializer = makeParentBlockSerializer(*this, false, false);
|
||||
FIELD_N("parentBlock", serializer);
|
||||
}
|
||||
FIELD(minerTx);
|
||||
FIELD(txHashes);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline ParentBlockSerializer makeParentBlockSerializer(const Block& b, bool hashingSerialization, bool headerOnly) {
|
||||
Block& blockRef = const_cast<Block&>(b);
|
||||
return ParentBlockSerializer(blockRef.parentBlock, blockRef.timestamp, blockRef.nonce, hashingSerialization, headerOnly);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct account_public_address
|
||||
{
|
||||
crypto::public_key m_spend_public_key;
|
||||
crypto::public_key m_view_public_key;
|
||||
struct AccountPublicAddress {
|
||||
crypto::public_key m_spendPublicKey;
|
||||
crypto::public_key m_viewPublicKey;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(m_spend_public_key)
|
||||
FIELD(m_view_public_key)
|
||||
FIELD(m_spendPublicKey);
|
||||
FIELD(m_viewPublicKey);
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct keypair
|
||||
{
|
||||
struct KeyPair {
|
||||
crypto::public_key pub;
|
||||
crypto::secret_key sec;
|
||||
|
||||
static inline keypair generate()
|
||||
{
|
||||
keypair k;
|
||||
static KeyPair generate() {
|
||||
KeyPair k;
|
||||
generate_keys(k.pub, k.sec);
|
||||
return k;
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(cryptonote::txout_to_key);
|
||||
BLOB_SERIALIZER(cryptonote::txout_to_scripthash);
|
||||
BLOB_SERIALIZER(cryptonote::TransactionOutputToKey);
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
|
||||
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionInputGenerate, 0xff);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionInputToScript, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionInputToScriptHash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionInputToKey, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionInputMultisignature, 0x3);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionOutputToScript, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionOutputToScriptHash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionOutputToKey, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::TransactionOutputMultisignature, 0x3);
|
||||
VARIANT_TAG(binary_archive, cryptonote::Transaction, 0xcc);
|
||||
VARIANT_TAG(binary_archive, cryptonote::Block, 0xbb);
|
||||
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_gen, "gen");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_script, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(json_archive, cryptonote::block, "block");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionInputGenerate, "generate");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionInputToScript, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionInputToScriptHash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionInputToKey, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionInputMultisignature, "multisignature");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionOutputToScript, "script");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionOutputToScriptHash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionOutputToKey, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::TransactionOutputMultisignature, "multisignature");
|
||||
VARIANT_TAG(json_archive, cryptonote::Transaction, "Transaction");
|
||||
VARIANT_TAG(json_archive, cryptonote::Block, "Block");
|
||||
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_gen, "gen");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_script, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(debug_archive, cryptonote::block, "block");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionInputGenerate, "generate");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionInputToScript, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionInputToScriptHash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionInputToKey, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionInputMultisignature, "multisignature");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionOutputToScript, "script");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionOutputToScriptHash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionOutputToKey, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::TransactionOutputMultisignature, "multisignature");
|
||||
VARIANT_TAG(debug_archive, cryptonote::Transaction, "Transaction");
|
||||
VARIANT_TAG(debug_archive, cryptonote::Block, "Block");
|
||||
|
|
|
@ -35,158 +35,78 @@ namespace cryptonote {
|
|||
/* Cryptonote helper functions */
|
||||
/************************************************************************/
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t get_max_block_size()
|
||||
{
|
||||
return CRYPTONOTE_MAX_BLOCK_SIZE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t get_max_tx_size()
|
||||
{
|
||||
return CRYPTONOTE_MAX_TX_SIZE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward) {
|
||||
uint64_t base_reward = (MONEY_SUPPLY - already_generated_coins) >> EMISSION_SPEED_FACTOR;
|
||||
uint64_t getPenalizedAmount(uint64_t amount, size_t medianSize, size_t currentBlockSize) {
|
||||
static_assert(sizeof(size_t) >= sizeof(uint32_t), "size_t is too small");
|
||||
assert(currentBlockSize <= 2 * medianSize);
|
||||
assert(medianSize <= std::numeric_limits<uint32_t>::max());
|
||||
assert(currentBlockSize <= std::numeric_limits<uint32_t>::max());
|
||||
|
||||
//make it soft
|
||||
if (median_size < CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) {
|
||||
median_size = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE;
|
||||
if (amount == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (current_block_size <= median_size) {
|
||||
reward = base_reward;
|
||||
return true;
|
||||
if (currentBlockSize <= medianSize) {
|
||||
return amount;
|
||||
}
|
||||
|
||||
if(current_block_size > 2 * median_size) {
|
||||
LOG_PRINT_L4("Block cumulative size is too big: " << current_block_size << ", expected less than " << 2 * median_size);
|
||||
uint64_t productHi;
|
||||
uint64_t productLo = mul128(amount, currentBlockSize * (UINT64_C(2) * medianSize - currentBlockSize), &productHi);
|
||||
|
||||
uint64_t penalizedAmountHi;
|
||||
uint64_t penalizedAmountLo;
|
||||
div128_32(productHi, productLo, static_cast<uint32_t>(medianSize), &penalizedAmountHi, &penalizedAmountLo);
|
||||
div128_32(penalizedAmountHi, penalizedAmountLo, static_cast<uint32_t>(medianSize), &penalizedAmountHi, &penalizedAmountLo);
|
||||
|
||||
assert(0 == penalizedAmountHi);
|
||||
assert(penalizedAmountLo < amount);
|
||||
|
||||
return penalizedAmountLo;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
std::string getAccountAddressAsStr(uint64_t prefix, const AccountPublicAddress& adr) {
|
||||
blobdata blob;
|
||||
bool r = t_serializable_object_to_blob(adr, blob);
|
||||
assert(r);
|
||||
return tools::base58::encode_addr(prefix, blob);
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool is_coinbase(const Transaction& tx) {
|
||||
if(tx.vin.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(median_size < std::numeric_limits<uint32_t>::max());
|
||||
assert(current_block_size < std::numeric_limits<uint32_t>::max());
|
||||
|
||||
uint64_t product_hi;
|
||||
uint64_t product_lo = mul128(base_reward, current_block_size * (2 * median_size - current_block_size), &product_hi);
|
||||
|
||||
uint64_t reward_hi;
|
||||
uint64_t reward_lo;
|
||||
div128_32(product_hi, product_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
|
||||
div128_32(reward_hi, reward_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
|
||||
assert(0 == reward_hi);
|
||||
assert(reward_lo < base_reward);
|
||||
|
||||
reward = reward_lo;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------
|
||||
uint8_t get_account_address_checksum(const public_address_outer_blob& bl)
|
||||
{
|
||||
const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
|
||||
uint8_t summ = 0;
|
||||
for(size_t i = 0; i!= sizeof(public_address_outer_blob)-1; i++)
|
||||
summ += pbuf[i];
|
||||
|
||||
return summ;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
std::string get_account_address_as_str(const account_public_address& adr)
|
||||
{
|
||||
return tools::base58::encode_addr(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX, t_serializable_object_to_blob(adr));
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool is_coinbase(const transaction& tx)
|
||||
{
|
||||
if(tx.vin.size() != 1)
|
||||
return false;
|
||||
|
||||
if(tx.vin[0].type() != typeid(txin_gen))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool get_account_address_from_str(uint64_t& prefix, account_public_address& adr, const std::string& str)
|
||||
{
|
||||
if (2 * sizeof(public_address_outer_blob) != str.size())
|
||||
{
|
||||
blobdata data;
|
||||
if (!tools::base58::decode_addr(str, prefix, data))
|
||||
{
|
||||
LOG_PRINT_L1("Invalid address format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!::serialization::parse_binary(data, adr))
|
||||
{
|
||||
LOG_PRINT_L1("Account public address keys can't be parsed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to validate address keys");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old address format
|
||||
prefix = CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||
|
||||
std::string buff;
|
||||
if(!string_tools::parse_hexstr_to_binbuff(str, buff))
|
||||
return false;
|
||||
|
||||
if(buff.size()!=sizeof(public_address_outer_blob))
|
||||
{
|
||||
LOG_PRINT_L1("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob));
|
||||
return false;
|
||||
}
|
||||
|
||||
public_address_outer_blob blob = *reinterpret_cast<const public_address_outer_blob*>(buff.data());
|
||||
|
||||
|
||||
if(blob.m_ver > CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER)
|
||||
{
|
||||
LOG_PRINT_L1("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(blob.check_sum != get_account_address_checksum(blob))
|
||||
{
|
||||
LOG_PRINT_L1("Wrong public address checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
//we success
|
||||
adr = blob.m_address;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool get_account_address_from_str(account_public_address& adr, const std::string& str)
|
||||
{
|
||||
uint64_t prefix;
|
||||
if(!get_account_address_from_str(prefix, adr, str))
|
||||
return false;
|
||||
|
||||
if(CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX != prefix)
|
||||
{
|
||||
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX);
|
||||
if(tx.vin[0].type() != typeid(TransactionInputGenerate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool parseAccountAddressString(uint64_t& prefix, AccountPublicAddress& adr, const std::string& str) {
|
||||
blobdata data;
|
||||
if (!tools::base58::decode_addr(str, prefix, data)) {
|
||||
LOG_PRINT_L1("Invalid address format");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
|
||||
if (!::serialization::parse_binary(data, adr)) {
|
||||
LOG_PRINT_L1("Account public address keys can't be parsed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!crypto::check_key(adr.m_spendPublicKey) || !crypto::check_key(adr.m_viewPublicKey)) {
|
||||
LOG_PRINT_L1("Failed to validate address keys");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------
|
||||
bool operator ==(const cryptonote::Transaction& a, const cryptonote::Transaction& b) {
|
||||
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
|
||||
}
|
||||
|
||||
bool operator ==(const cryptonote::block& a, const cryptonote::block& b) {
|
||||
//-----------------------------------------------------------------------
|
||||
bool operator ==(const cryptonote::Block& a, const cryptonote::Block& b) {
|
||||
return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_basic.h"
|
||||
//epee
|
||||
#include "string_tools.h"
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
|
||||
|
||||
namespace cryptonote {
|
||||
|
@ -35,31 +38,16 @@ namespace cryptonote {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct public_address_outer_blob
|
||||
{
|
||||
uint8_t m_ver;
|
||||
account_public_address m_address;
|
||||
uint8_t check_sum;
|
||||
};
|
||||
#pragma pack (pop)
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Cryptonote helper functions */
|
||||
/************************************************************************/
|
||||
size_t get_max_block_size();
|
||||
size_t get_max_tx_size();
|
||||
bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward);
|
||||
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
|
||||
std::string get_account_address_as_str(const account_public_address& adr);
|
||||
bool get_account_address_from_str(uint64_t& prefix, account_public_address& adr, const std::string& str);
|
||||
bool get_account_address_from_str(account_public_address& adr, const std::string& str);
|
||||
bool is_coinbase(const transaction& tx);
|
||||
uint64_t getPenalizedAmount(uint64_t amount, size_t medianSize, size_t currentBlockSize);
|
||||
std::string getAccountAddressAsStr(uint64_t prefix, const AccountPublicAddress& adr);
|
||||
bool parseAccountAddressString(uint64_t& prefix, AccountPublicAddress& adr, const std::string& str);
|
||||
bool is_coinbase(const Transaction& tx);
|
||||
|
||||
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b);
|
||||
bool operator ==(const cryptonote::block& a, const cryptonote::block& b);
|
||||
bool operator ==(const cryptonote::Transaction& a, const cryptonote::Transaction& b);
|
||||
bool operator ==(const cryptonote::Block& a, const cryptonote::Block& b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -67,59 +67,55 @@ namespace boost
|
|||
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txout_to_script &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.keys;
|
||||
a & x.script;
|
||||
template <class Archive> void serialize(Archive& archive, cryptonote::TransactionInputToScript&, unsigned int version) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <class Archive> void serialize(Archive& archive, cryptonote::TransactionInputToScriptHash&, unsigned int version) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <class Archive> void serialize(Archive& archive, cryptonote::TransactionOutputToScript&, unsigned int version) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <class Archive> void serialize(Archive& archive, cryptonote::TransactionOutputToScriptHash&, unsigned int version) {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <class Archive> void serialize(Archive& archive, cryptonote::TransactionInputMultisignature &output, unsigned int version) {
|
||||
archive & output.amount;
|
||||
archive & output.signatures;
|
||||
archive & output.outputIndex;
|
||||
}
|
||||
|
||||
template <class Archive> void serialize(Archive& archive, cryptonote::TransactionOutputMultisignature &output, unsigned int version) {
|
||||
archive & output.keys;
|
||||
archive & output.requiredSignatures;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txout_to_key &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::TransactionOutputToKey &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.key;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txout_to_scripthash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.hash;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_gen &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::TransactionInputGenerate &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.height;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_to_script &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.prev;
|
||||
a & x.prevout;
|
||||
a & x.sigset;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_to_scripthash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.prev;
|
||||
a & x.prevout;
|
||||
a & x.script;
|
||||
a & x.sigset;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::txin_to_key &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::TransactionInputToKey &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.amount;
|
||||
a & x.key_offsets;
|
||||
a & x.k_image;
|
||||
a & x.keyOffsets;
|
||||
a & x.keyImage;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::tx_out &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::TransactionOutput &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.amount;
|
||||
a & x.target;
|
||||
|
@ -127,10 +123,10 @@ namespace boost
|
|||
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::Transaction &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.unlock_time;
|
||||
a & x.unlockTime;
|
||||
a & x.vin;
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
|
@ -139,16 +135,16 @@ namespace boost
|
|||
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::block &b, const boost::serialization::version_type ver)
|
||||
inline void serialize(Archive &a, cryptonote::Block &b, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & b.major_version;
|
||||
a & b.minor_version;
|
||||
a & b.majorVersion;
|
||||
a & b.minorVersion;
|
||||
a & b.timestamp;
|
||||
a & b.prev_id;
|
||||
a & b.prevId;
|
||||
a & b.nonce;
|
||||
//------------------
|
||||
a & b.miner_tx;
|
||||
a & b.tx_hashes;
|
||||
a & b.minerTx;
|
||||
a & b.txHashes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,19 +15,29 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <unordered_set>
|
||||
#include "cryptonote_core.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include "misc_language.h"
|
||||
#include "warnings.h"
|
||||
|
||||
#include "common/command_line.h"
|
||||
#include "common/util.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/cryptonote_stat_info.h"
|
||||
#include "cryptonote_core/miner.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "misc_language.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
|
||||
|
||||
using namespace epee;
|
||||
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
||||
|
@ -35,15 +45,19 @@ namespace cryptonote
|
|||
{
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
core::core(i_cryptonote_protocol* pprotocol):
|
||||
m_mempool(m_blockchain_storage),
|
||||
m_blockchain_storage(m_mempool),
|
||||
m_miner(this),
|
||||
m_miner_address(boost::value_initialized<account_public_address>()),
|
||||
core::core(const Currency& currency, i_cryptonote_protocol* pprotocol):
|
||||
m_currency(currency),
|
||||
m_mempool(currency, m_blockchain_storage, m_timeProvider),
|
||||
m_blockchain_storage(currency, m_mempool),
|
||||
m_miner(new miner(currency, this)),
|
||||
m_starter_message_showed(false)
|
||||
{
|
||||
set_cryptonote_protocol(pprotocol);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
core::~core() {
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::set_cryptonote_protocol(i_cryptonote_protocol* pprotocol)
|
||||
{
|
||||
if(pprotocol)
|
||||
|
@ -78,21 +92,21 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs)
|
||||
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<Block>& blocks, std::list<Transaction>& txs)
|
||||
{
|
||||
return m_blockchain_storage.get_blocks(start_offset, count, blocks, txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks)
|
||||
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<Block>& blocks)
|
||||
{
|
||||
return m_blockchain_storage.get_blocks(start_offset, count, blocks);
|
||||
} //-----------------------------------------------------------------------------------------------
|
||||
void core::get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<transaction>& txs, std::list<crypto::hash>& missed_txs)
|
||||
void core::get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<Transaction>& txs, std::list<crypto::hash>& missed_txs)
|
||||
{
|
||||
m_blockchain_storage.get_transactions(txs_ids, txs, missed_txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_alternative_blocks(std::list<block>& blocks)
|
||||
bool core::get_alternative_blocks(std::list<Block>& blocks)
|
||||
{
|
||||
return m_blockchain_storage.get_alternative_blocks(blocks);
|
||||
}
|
||||
|
@ -112,13 +126,13 @@ namespace cryptonote
|
|||
r = m_blockchain_storage.init(m_config_folder, load_existing);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
|
||||
|
||||
r = m_miner.init(vm);
|
||||
r = m_miner->init(vm);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
|
||||
|
||||
return load_state_data();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::set_genesis_block(const block& b)
|
||||
bool core::set_genesis_block(const Block& b)
|
||||
{
|
||||
return m_blockchain_storage.reset_and_set_genesis_block(b);
|
||||
}
|
||||
|
@ -131,7 +145,7 @@ namespace cryptonote
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::deinit()
|
||||
{
|
||||
m_miner.stop();
|
||||
m_miner->stop();
|
||||
m_mempool.deinit();
|
||||
m_blockchain_storage.deinit();
|
||||
return true;
|
||||
|
@ -143,7 +157,7 @@ namespace cryptonote
|
|||
//want to process all transactions sequentially
|
||||
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
|
||||
|
||||
if(tx_blob.size() > get_max_tx_size())
|
||||
if(tx_blob.size() > m_currency.maxTxSize())
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
|
@ -152,7 +166,7 @@ namespace cryptonote
|
|||
|
||||
crypto::hash tx_hash = null_hash;
|
||||
crypto::hash tx_prefixt_hash = null_hash;
|
||||
transaction tx;
|
||||
Transaction tx;
|
||||
|
||||
if(!parse_tx_from_blob(tx, tx_hash, tx_prefixt_hash, tx_blob))
|
||||
{
|
||||
|
@ -177,19 +191,26 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
bool r = add_new_tx(tx, tx_hash, tx_prefixt_hash, tx_blob.size(), tvc, keeped_by_block);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash);}
|
||||
else if(tvc.m_verifivation_impossible)
|
||||
{LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash);}
|
||||
if(tvc.m_verifivation_failed) {
|
||||
if (!tvc.m_tx_fee_too_small) {
|
||||
LOG_PRINT_RED_L0("Transaction verification failed: " << tx_hash);
|
||||
} else {
|
||||
LOG_PRINT_L0("Transaction verification failed: " << tx_hash);
|
||||
}
|
||||
} else if(tvc.m_verifivation_impossible) {
|
||||
LOG_PRINT_RED_L0("Transaction verification impossible: " << tx_hash);
|
||||
}
|
||||
|
||||
if(tvc.m_added_to_pool)
|
||||
if (tvc.m_added_to_pool) {
|
||||
LOG_PRINT_L1("tx added: " << tx_hash);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_stat_info(core_stat_info& st_inf)
|
||||
{
|
||||
st_inf.mining_speed = m_miner.get_speed();
|
||||
st_inf.mining_speed = m_miner->get_speed();
|
||||
st_inf.alternative_blocks = m_blockchain_storage.get_alternative_blocks_count();
|
||||
st_inf.blockchain_height = m_blockchain_storage.get_current_blockchain_height();
|
||||
st_inf.tx_pool_size = m_mempool.get_transactions_count();
|
||||
|
@ -198,7 +219,7 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_semantic(const transaction& tx, bool keeped_by_block)
|
||||
bool core::check_tx_semantic(const Transaction& tx, bool keeped_by_block)
|
||||
{
|
||||
if(!tx.vin.size())
|
||||
{
|
||||
|
@ -234,36 +255,41 @@ namespace cryptonote
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!keeped_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_comulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE)
|
||||
if(!keeped_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_comulative_blocksize_limit() - m_currency.minerTxBlobReservedSize())
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx have to big size " << get_object_blobsize(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
|
||||
LOG_PRINT_RED_L0("tx have to big size " << get_object_blobsize(tx) << ", expected not bigger than " <<
|
||||
(m_blockchain_storage.get_current_comulative_blocksize_limit() - m_currency.minerTxBlobReservedSize()));
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if tx use different key images
|
||||
if(!check_tx_inputs_keyimages_diff(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx have to big size " << get_object_blobsize(tx) << ", expected not bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE);
|
||||
LOG_PRINT_RED_L0("tx has a few inputs with identical keyimages");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkMultisignatureInputsDiff(tx)) {
|
||||
LOG_PRINT_RED_L0("tx has a few multisignature inputs with identical output indexes");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_inputs_keyimages_diff(const transaction& tx)
|
||||
bool core::check_tx_inputs_keyimages_diff(const Transaction& tx)
|
||||
{
|
||||
std::unordered_set<crypto::key_image> ki;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if(!ki.insert(tokey_in.k_image).second)
|
||||
return false;
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
if (!ki.insert(boost::get<TransactionInputToKey>(in).keyImage).second)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block)
|
||||
bool core::add_new_tx(const Transaction& tx, tx_verification_context& tvc, bool keeped_by_block)
|
||||
{
|
||||
crypto::hash tx_hash = get_transaction_hash(tx);
|
||||
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
|
@ -282,7 +308,7 @@ namespace cryptonote
|
|||
// return m_blockchain_storage.get_outs(amount, pkeys);
|
||||
//}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block) {
|
||||
bool core::add_new_tx(const Transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block) {
|
||||
if (m_blockchain_storage.have_tx(tx_hash)) {
|
||||
LOG_PRINT_L2("tx " << tx_hash << " is already in blockchain");
|
||||
return true;
|
||||
|
@ -299,7 +325,7 @@ namespace cryptonote
|
|||
return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
|
||||
bool core::get_block_template(Block& b, const AccountPublicAddress& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, ex_nonce);
|
||||
}
|
||||
|
@ -309,7 +335,7 @@ namespace cryptonote
|
|||
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)
|
||||
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<Block, std::list<Transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)
|
||||
{
|
||||
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, blocks, total_height, start_height, max_count);
|
||||
}
|
||||
|
@ -339,109 +365,85 @@ namespace cryptonote
|
|||
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::pause_mine()
|
||||
{
|
||||
m_miner.pause();
|
||||
void core::pause_mining() {
|
||||
m_miner->pause();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::resume_mine()
|
||||
{
|
||||
m_miner.resume();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_block_found(block& b)
|
||||
{
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
m_miner.pause();
|
||||
m_blockchain_storage.add_new_block(b, bvc);
|
||||
//anyway - update miner template
|
||||
void core::update_block_template_and_resume_mining() {
|
||||
update_miner_block_template();
|
||||
m_miner.resume();
|
||||
m_miner->resume();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_block_found(Block& b) {
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
handle_incoming_block(b, bvc, true, true);
|
||||
|
||||
|
||||
CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "mined block failed verification");
|
||||
if(bvc.m_added_to_main_chain)
|
||||
{
|
||||
cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>();
|
||||
NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
|
||||
arg.hop = 0;
|
||||
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
|
||||
std::list<crypto::hash> missed_txs;
|
||||
std::list<transaction> txs;
|
||||
m_blockchain_storage.get_transactions(b.tx_hashes, txs, missed_txs);
|
||||
if(missed_txs.size() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b))
|
||||
{
|
||||
LOG_PRINT_L0("Block found but, seems that reorganize just happened after that, do not relay this block");
|
||||
return true;
|
||||
}
|
||||
CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size() && !missed_txs.size(), false, "cant find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size()
|
||||
<< ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
|
||||
|
||||
block_to_blob(b, arg.b.block);
|
||||
//pack transactions
|
||||
BOOST_FOREACH(auto& tx, txs)
|
||||
arg.b.txs.push_back(t_serializable_object_to_blob(tx));
|
||||
|
||||
m_pprotocol->relay_block(arg, exclude_context);
|
||||
if (bvc.m_verifivation_failed) {
|
||||
LOG_ERROR("mined block failed verification");
|
||||
}
|
||||
|
||||
return bvc.m_added_to_main_chain;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::on_synchronized()
|
||||
{
|
||||
m_miner.on_synchronized();
|
||||
m_miner->on_synchronized();
|
||||
}
|
||||
//bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector<size_t>& sizes, size_t count)
|
||||
//{
|
||||
// return m_blockchain_storage.get_backward_blocks_sizes(from_height, sizes, count);
|
||||
//}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate)
|
||||
{
|
||||
bvc = boost::value_initialized<block_verification_context>();
|
||||
if(block_blob.size() > get_max_block_size())
|
||||
{
|
||||
bool core::handle_incoming_block_blob(const blobdata& block_blob, block_verification_context& bvc, bool control_miner, bool relay_block) {
|
||||
if (block_blob.size() > m_currency.maxBlockBlobSize()) {
|
||||
LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected");
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
if(!parse_and_validate_block_from_blob(block_blob, b))
|
||||
{
|
||||
Block b = AUTO_VAL_INIT(b);
|
||||
if (!parse_and_validate_block_from_blob(block_blob, b)) {
|
||||
LOG_PRINT_L0("Failed to parse and validate new block");
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return handle_incoming_block(b, bvc, control_miner, relay_block);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_block(const Block& b, block_verification_context& bvc, bool control_miner, bool relay_block) {
|
||||
if (control_miner) {
|
||||
pause_mining();
|
||||
}
|
||||
|
||||
m_blockchain_storage.add_new_block(b, bvc);
|
||||
if (bvc.m_added_to_main_chain && update_miner_blocktemplate) {
|
||||
update_miner_block_template();
|
||||
|
||||
if (control_miner) {
|
||||
update_block_template_and_resume_mining();
|
||||
}
|
||||
|
||||
if (relay_block && bvc.m_added_to_main_chain) {
|
||||
std::list<crypto::hash> missed_txs;
|
||||
std::list<Transaction> txs;
|
||||
m_blockchain_storage.get_transactions(b.txHashes, txs, missed_txs);
|
||||
if (!missed_txs.empty() && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b)) {
|
||||
LOG_PRINT_L0("Block added, but it seems that reorganize just happened after that, do not relay this block");
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(txs.size() == b.txHashes.size() && missed_txs.empty(), false, "can't find some transactions in found block:" <<
|
||||
get_block_hash(b) << " txs.size()=" << txs.size() << ", b.txHashes.size()=" << b.txHashes.size() << ", missed_txs.size()" << missed_txs.size());
|
||||
|
||||
NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
|
||||
arg.hop = 0;
|
||||
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
|
||||
bool r = block_to_blob(b, arg.b.block);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to serialize block");
|
||||
for (auto& tx : txs) {
|
||||
arg.b.txs.push_back(t_serializable_object_to_blob(tx));
|
||||
}
|
||||
|
||||
cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>();
|
||||
m_pprotocol->relay_block(arg, exclude_context);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void core::notify_new_block(const block& b) {
|
||||
cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>();
|
||||
NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
|
||||
arg.hop = 0;
|
||||
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
|
||||
std::list<crypto::hash> missed_txs;
|
||||
std::list<transaction> txs;
|
||||
m_blockchain_storage.get_transactions(b.tx_hashes, txs, missed_txs);
|
||||
if (missed_txs.size() > 0 && m_blockchain_storage.get_block_id_by_height(get_block_height(b)) != get_block_hash(b)) {
|
||||
LOG_PRINT_L0("Block found but reorganize happened after that, block will not be relayed");
|
||||
} else {
|
||||
if (txs.size() != b.tx_hashes.size() || missed_txs.size()) {
|
||||
LOG_ERROR("cant find some transactions in found block:" << get_block_hash(b) << " txs.size()=" << txs.size() << ", b.tx_hashes.size()=" << b.tx_hashes.size() << ", missed_txs.size()" << missed_txs.size());
|
||||
return;
|
||||
}
|
||||
block_to_blob(b, arg.b.block);
|
||||
BOOST_FOREACH(auto& tx, txs) arg.b.txs.push_back(t_serializable_object_to_blob(tx));
|
||||
m_pprotocol->relay_block(arg, exclude_context);
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
crypto::hash core::get_tail_id()
|
||||
{
|
||||
|
@ -458,17 +460,17 @@ namespace cryptonote
|
|||
return m_blockchain_storage.have_block(id);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob)
|
||||
bool core::parse_tx_from_blob(Transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob)
|
||||
{
|
||||
return parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_syntax(const transaction& tx)
|
||||
bool core::check_tx_syntax(const Transaction& tx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void core::get_pool_transactions(std::list<transaction>& txs)
|
||||
void core::get_pool_transactions(std::list<Transaction>& txs)
|
||||
{
|
||||
m_mempool.get_transactions(txs);
|
||||
}
|
||||
|
@ -488,7 +490,7 @@ namespace cryptonote
|
|||
return m_blockchain_storage.get_block_id_by_height(height);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_by_hash(const crypto::hash &h, block &blk) {
|
||||
bool core::get_block_by_hash(const crypto::hash &h, Block &blk) {
|
||||
return m_blockchain_storage.get_block_by_hash(h, blk);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
@ -503,7 +505,7 @@ namespace cryptonote
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::update_miner_block_template()
|
||||
{
|
||||
m_miner.on_block_chain_update();
|
||||
m_miner->on_block_chain_update();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
@ -523,8 +525,8 @@ namespace cryptonote
|
|||
m_starter_message_showed = true;
|
||||
}
|
||||
|
||||
m_store_blockchain_interval.do_call(boost::bind(&blockchain_storage::store_blockchain, &m_blockchain_storage));
|
||||
m_miner.on_idle();
|
||||
m_miner->on_idle();
|
||||
m_mempool.on_idle();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -22,78 +22,77 @@
|
|||
|
||||
#include "p2p/net_node_common.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "Currency.h"
|
||||
#include "tx_pool.h"
|
||||
#include "blockchain_storage.h"
|
||||
#include "miner.h"
|
||||
#include "cryptonote_core/i_miner_handler.h"
|
||||
#include "connection_context.h"
|
||||
#include "cryptonote_core/cryptonote_stat_info.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class core: public i_miner_handler
|
||||
{
|
||||
namespace cryptonote {
|
||||
struct core_stat_info;
|
||||
class miner;
|
||||
|
||||
class core: public i_miner_handler {
|
||||
public:
|
||||
core(i_cryptonote_protocol* pprotocol);
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote_connection_context& context);
|
||||
core(const Currency& currency, i_cryptonote_protocol* pprotocol);
|
||||
~core();
|
||||
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS_request& arg, NOTIFY_RESPONSE_GET_OBJECTS_request& rsp, cryptonote_connection_context& context);
|
||||
bool on_idle();
|
||||
bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true);
|
||||
bool handle_incoming_block_blob(const blobdata& block_blob, block_verification_context& bvc, bool control_miner, bool relay_block);
|
||||
const Currency& currency() const { return m_currency; }
|
||||
i_cryptonote_protocol* get_protocol(){return m_pprotocol;}
|
||||
|
||||
//-------------------- i_miner_handler -----------------------
|
||||
virtual bool handle_block_found( block& b);
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce);
|
||||
virtual bool handle_block_found(Block& b);
|
||||
virtual bool get_block_template(Block& b, const AccountPublicAddress& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce);
|
||||
|
||||
|
||||
miner& get_miner(){return m_miner;}
|
||||
miner& get_miner() { return *m_miner; }
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool init(const boost::program_options::variables_map& vm, bool load_existing);
|
||||
bool set_genesis_block(const block& b);
|
||||
bool set_genesis_block(const Block& b);
|
||||
bool deinit();
|
||||
uint64_t get_current_blockchain_height();
|
||||
bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks, std::list<transaction>& txs);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<block>& blocks);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<Block>& blocks, std::list<Transaction>& txs);
|
||||
bool get_blocks(uint64_t start_offset, size_t count, std::list<Block>& blocks);
|
||||
template<class t_ids_container, class t_blocks_container, class t_missed_container>
|
||||
bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs)
|
||||
{
|
||||
return m_blockchain_storage.get_blocks(block_ids, blocks, missed_bs);
|
||||
}
|
||||
crypto::hash get_block_id_by_height(uint64_t height);
|
||||
void get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<transaction>& txs, std::list<crypto::hash>& missed_txs);
|
||||
bool get_block_by_hash(const crypto::hash &h, block &blk);
|
||||
void get_transactions(const std::vector<crypto::hash>& txs_ids, std::list<Transaction>& txs, std::list<crypto::hash>& missed_txs);
|
||||
bool get_block_by_hash(const crypto::hash &h, Block &blk);
|
||||
//void get_all_known_block_ids(std::list<crypto::hash> &main, std::list<crypto::hash> &alt, std::list<crypto::hash> &invalid);
|
||||
|
||||
bool get_alternative_blocks(std::list<block>& blocks);
|
||||
bool get_alternative_blocks(std::list<Block>& blocks);
|
||||
size_t get_alternative_blocks_count();
|
||||
|
||||
void set_cryptonote_protocol(i_cryptonote_protocol* pprotocol);
|
||||
void set_checkpoints(checkpoints&& chk_pts);
|
||||
|
||||
void get_pool_transactions(std::list<transaction>& txs);
|
||||
void get_pool_transactions(std::list<Transaction>& txs);
|
||||
size_t get_pool_transactions_count();
|
||||
size_t get_blockchain_total_transactions();
|
||||
//bool get_outs(uint64_t amount, std::list<crypto::public_key>& pkeys);
|
||||
bool have_block(const crypto::hash& id);
|
||||
bool get_short_chain_history(std::list<crypto::hash>& ids);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<block, std::list<transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY_request& resp);
|
||||
bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::list<std::pair<Block, std::list<Transaction> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count);
|
||||
bool get_stat_info(core_stat_info& st_inf);
|
||||
//bool get_backward_blocks_sizes(uint64_t from_height, std::vector<size_t>& sizes, size_t count);
|
||||
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs);
|
||||
crypto::hash get_tail_id();
|
||||
bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
|
||||
void pause_mine();
|
||||
void resume_mine();
|
||||
bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_response& res);
|
||||
void pause_mining();
|
||||
void update_block_template_and_resume_mining();
|
||||
blockchain_storage& get_blockchain_storage(){return m_blockchain_storage;}
|
||||
//debug functions
|
||||
void print_blockchain(uint64_t start_index, uint64_t end_index);
|
||||
|
@ -101,39 +100,37 @@ namespace cryptonote
|
|||
std::string print_pool(bool short_format);
|
||||
void print_blockchain_outs(const std::string& file);
|
||||
void on_synchronized();
|
||||
void notify_new_block(const block& b);
|
||||
|
||||
private:
|
||||
bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_new_tx(const Transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_new_tx(const Transaction& tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool load_state_data();
|
||||
bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob);
|
||||
bool parse_tx_from_blob(Transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob);
|
||||
bool handle_incoming_block(const Block& b, block_verification_context& bvc, bool control_miner, bool relay_block);
|
||||
|
||||
bool check_tx_syntax(const transaction& tx);
|
||||
bool check_tx_syntax(const Transaction& tx);
|
||||
//check correct values, amounts and all lightweight checks not related with database
|
||||
bool check_tx_semantic(const transaction& tx, bool keeped_by_block);
|
||||
bool check_tx_semantic(const Transaction& tx, bool keeped_by_block);
|
||||
//check if tx already in memory pool or in main blockchain
|
||||
|
||||
bool is_key_image_spent(const crypto::key_image& key_im);
|
||||
|
||||
bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig);
|
||||
bool check_tx_ring_signature(const TransactionInputToKey& tx, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig);
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time);
|
||||
bool update_miner_block_template();
|
||||
bool handle_command_line(const boost::program_options::variables_map& vm);
|
||||
bool on_update_blocktemplate_interval();
|
||||
bool check_tx_inputs_keyimages_diff(const transaction& tx);
|
||||
|
||||
bool check_tx_inputs_keyimages_diff(const Transaction& tx);
|
||||
|
||||
const Currency& m_currency;
|
||||
CryptoNote::RealTimeProvider m_timeProvider;
|
||||
tx_memory_pool m_mempool;
|
||||
blockchain_storage m_blockchain_storage;
|
||||
i_cryptonote_protocol* m_pprotocol;
|
||||
epee::critical_section m_incoming_tx_lock;
|
||||
//m_miner and m_miner_addres are probably temporary here
|
||||
miner m_miner;
|
||||
account_public_address m_miner_address;
|
||||
std::unique_ptr<miner> m_miner;
|
||||
std::string m_config_folder;
|
||||
cryptonote_protocol_stub m_protocol_stub;
|
||||
epee::math_helper::once_a_time_seconds<60*60*12, false> m_store_blockchain_interval;
|
||||
friend class tx_validate_inputs;
|
||||
std::atomic<bool> m_starter_message_showed;
|
||||
};
|
||||
|
|
|
@ -15,35 +15,40 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
#include <set>
|
||||
|
||||
// epee
|
||||
#include "include_base_utils.h"
|
||||
#include "misc_language.h"
|
||||
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include "cryptonote_config.h"
|
||||
#include "miner.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/account.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "serialization/binary_utils.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
|
||||
void get_transaction_prefix_hash(const TransactionPrefix& tx, crypto::hash& h)
|
||||
{
|
||||
std::ostringstream s;
|
||||
binary_archive<true> a(s);
|
||||
::serialization::serialize(a, const_cast<transaction_prefix&>(tx));
|
||||
::serialization::serialize(a, const_cast<TransactionPrefix&>(tx));
|
||||
crypto::cn_fast_hash(s.str().data(), s.str().size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx)
|
||||
crypto::hash get_transaction_prefix_hash(const TransactionPrefix& tx)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_prefix_hash(tx, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx)
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, Transaction& tx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
|
@ -53,7 +58,7 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, Transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
|
@ -67,83 +72,14 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs) {
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.extra.clear();
|
||||
|
||||
keypair txkey = keypair::generate();
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
if(!extra_nonce.empty())
|
||||
if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
|
||||
return false;
|
||||
|
||||
txin_gen in;
|
||||
in.height = height;
|
||||
|
||||
uint64_t block_reward;
|
||||
if(!get_block_reward(median_size, current_block_size, already_generated_coins, block_reward))
|
||||
{
|
||||
LOG_PRINT_L0("Block is too big");
|
||||
return false;
|
||||
}
|
||||
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
|
||||
LOG_PRINT_L1("Creating block template: reward " << block_reward <<
|
||||
", fee " << fee)
|
||||
#endif
|
||||
block_reward += fee;
|
||||
|
||||
std::vector<uint64_t> out_amounts;
|
||||
decompose_amount_into_digits(block_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); });
|
||||
|
||||
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
|
||||
while (max_outs < out_amounts.size())
|
||||
{
|
||||
out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
||||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
|
||||
uint64_t summary_amounts = 0;
|
||||
for (size_t no = 0; no < out_amounts.size(); no++)
|
||||
{
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);;
|
||||
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
|
||||
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")");
|
||||
|
||||
txout_to_key tk;
|
||||
tk.key = out_eph_public_key;
|
||||
|
||||
tx_out out;
|
||||
summary_amounts += out.amount = out_amounts[no];
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward);
|
||||
|
||||
tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
//lock
|
||||
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
tx.vin.push_back(in);
|
||||
//LOG_PRINT("MINER_TX generated ok, block_reward=" << print_money(block_reward) << "(" << print_money(block_reward - fee) << "+" << print_money(fee)
|
||||
// << "), current_block_size=" << current_block_size << ", already_generated_coins=" << already_generated_coins << ", tx_id=" << get_transaction_hash(tx), LOG_LEVEL_2);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, KeyPair& in_ephemeral, crypto::key_image& ki)
|
||||
{
|
||||
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
|
||||
bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
|
||||
|
||||
r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")");
|
||||
r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spendPublicKey, in_ephemeral.pub);
|
||||
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spendPublicKey << ")");
|
||||
|
||||
crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec);
|
||||
|
||||
|
@ -161,59 +97,29 @@ namespace cryptonote
|
|||
return total;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_amount(uint64_t& amount, const std::string& str_amount_)
|
||||
{
|
||||
std::string str_amount = str_amount_;
|
||||
boost::algorithm::trim(str_amount);
|
||||
|
||||
size_t point_index = str_amount.find_first_of('.');
|
||||
size_t fraction_size;
|
||||
if (std::string::npos != point_index)
|
||||
{
|
||||
fraction_size = str_amount.size() - point_index - 1;
|
||||
while (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back())
|
||||
{
|
||||
str_amount.erase(str_amount.size() - 1, 1);
|
||||
--fraction_size;
|
||||
}
|
||||
if (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size)
|
||||
return false;
|
||||
str_amount.erase(point_index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fraction_size = 0;
|
||||
}
|
||||
|
||||
if (str_amount.empty())
|
||||
return false;
|
||||
|
||||
if (fraction_size < CRYPTONOTE_DISPLAY_DECIMAL_POINT)
|
||||
{
|
||||
str_amount.append(CRYPTONOTE_DISPLAY_DECIMAL_POINT - fraction_size, '0');
|
||||
}
|
||||
|
||||
return string_tools::get_xtype_from_string(amount, str_amount);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee)
|
||||
bool get_tx_fee(const Transaction& tx, uint64_t & fee)
|
||||
{
|
||||
uint64_t amount_in = 0;
|
||||
uint64_t amount_out = 0;
|
||||
BOOST_FOREACH(auto& in, tx.vin)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction");
|
||||
amount_in += boost::get<txin_to_key>(in).amount;
|
||||
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
amount_in += boost::get<TransactionInputToKey>(in).amount;
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
amount_in += boost::get<TransactionInputMultisignature>(in).amount;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(auto& o, tx.vout)
|
||||
|
||||
for (const auto& o : tx.vout) {
|
||||
amount_out += o.amount;
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <<amount_in << ") more than it has (" << amount_out << ")");
|
||||
fee = amount_in - amount_out;
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_tx_fee(const transaction& tx)
|
||||
uint64_t get_tx_fee(const Transaction& tx)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
if(!get_tx_fee(tx, r))
|
||||
|
@ -233,18 +139,26 @@ namespace cryptonote
|
|||
binary_archive<false> ar(iss);
|
||||
|
||||
bool eof = false;
|
||||
while (!eof)
|
||||
{
|
||||
while (!eof) {
|
||||
tx_extra_field field;
|
||||
bool r = ::do_serialize(ar, field);
|
||||
CHECK_AND_NO_ASSERT_MES(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||
if (!r) {
|
||||
LOG_PRINT_L4("failed to deserialize extra field. extra = " <<
|
||||
string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||
return false;
|
||||
}
|
||||
tx_extra_fields.push_back(field);
|
||||
|
||||
std::ios_base::iostate state = iss.rdstate();
|
||||
eof = (EOF == iss.peek());
|
||||
iss.clear(state);
|
||||
}
|
||||
CHECK_AND_NO_ASSERT_MES(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||
|
||||
if (!::serialization::check_stream_state(ar)) {
|
||||
LOG_PRINT_L4("failed to deserialize extra field. extra = " <<
|
||||
string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -261,12 +175,12 @@ namespace cryptonote
|
|||
return pub_key_field.pub_key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx)
|
||||
crypto::public_key get_tx_pub_key_from_extra(const Transaction& tx)
|
||||
{
|
||||
return get_tx_pub_key_from_extra(tx.extra);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
|
||||
bool add_tx_pub_key_to_extra(Transaction& tx, const crypto::public_key& tx_pub_key)
|
||||
{
|
||||
tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key));
|
||||
tx.extra[tx.extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY;
|
||||
|
@ -290,6 +204,24 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool append_mm_tag_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_merge_mining_tag& mm_tag) {
|
||||
blobdata blob;
|
||||
if (!t_serializable_object_to_blob(mm_tag, blob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tx_extra.push_back(TX_EXTRA_MERGE_MINING_TAG);
|
||||
std::copy(reinterpret_cast<const uint8_t*>(blob.data()), reinterpret_cast<const uint8_t*>(blob.data() + blob.size()), std::back_inserter(tx_extra));
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_merge_mining_tag& mm_tag) {
|
||||
std::vector<tx_extra_field> tx_extra_fields;
|
||||
parse_tx_extra(tx_extra, tx_extra_fields);
|
||||
|
||||
return find_tx_extra_field_by_type(tx_extra_fields, mm_tag);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
|
||||
{
|
||||
extra_nonce.clear();
|
||||
|
@ -308,29 +240,29 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, Transaction& tx, uint64_t unlock_time)
|
||||
{
|
||||
tx.vin.clear();
|
||||
tx.vout.clear();
|
||||
tx.signatures.clear();
|
||||
|
||||
tx.version = CURRENT_TRANSACTION_VERSION;
|
||||
tx.unlock_time = unlock_time;
|
||||
tx.unlockTime = unlock_time;
|
||||
|
||||
tx.extra = extra;
|
||||
keypair txkey = keypair::generate();
|
||||
KeyPair txkey = KeyPair::generate();
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
|
||||
struct input_generation_context_data
|
||||
{
|
||||
keypair in_ephemeral;
|
||||
KeyPair in_ephemeral;
|
||||
};
|
||||
std::vector<input_generation_context_data> in_contexts;
|
||||
|
||||
|
||||
uint64_t summary_inputs_money = 0;
|
||||
//fill inputs
|
||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||
for (const tx_source_entry& src_entr : sources)
|
||||
{
|
||||
if(src_entr.real_output >= src_entr.outputs.size())
|
||||
{
|
||||
|
@ -341,7 +273,7 @@ namespace cryptonote
|
|||
|
||||
//key_derivation recv_derivation;
|
||||
in_contexts.push_back(input_generation_context_data());
|
||||
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
KeyPair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
crypto::key_image img;
|
||||
if(!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img))
|
||||
return false;
|
||||
|
@ -356,15 +288,16 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
//put key image into tx input
|
||||
txin_to_key input_to_key;
|
||||
TransactionInputToKey input_to_key;
|
||||
input_to_key.amount = src_entr.amount;
|
||||
input_to_key.k_image = img;
|
||||
input_to_key.keyImage = img;
|
||||
|
||||
//fill outputs array and use relative offsets
|
||||
BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs)
|
||||
input_to_key.key_offsets.push_back(out_entry.first);
|
||||
for (const tx_source_entry::output_entry& out_entry : src_entr.outputs) {
|
||||
input_to_key.keyOffsets.push_back(out_entry.first);
|
||||
}
|
||||
|
||||
input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets);
|
||||
input_to_key.keyOffsets = absolute_output_offsets_to_relative(input_to_key.keyOffsets);
|
||||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
|
||||
|
@ -375,20 +308,19 @@ namespace cryptonote
|
|||
uint64_t summary_outs_money = 0;
|
||||
//fill outputs
|
||||
size_t output_index = 0;
|
||||
BOOST_FOREACH(const tx_destination_entry& dst_entr, shuffled_dsts)
|
||||
{
|
||||
for (const tx_destination_entry& dst_entr : shuffled_dsts) {
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount);
|
||||
crypto::key_derivation derivation;
|
||||
crypto::public_key out_eph_public_key;
|
||||
bool r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << txkey.sec << ")");
|
||||
bool r = crypto::generate_key_derivation(dst_entr.addr.m_viewPublicKey, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_viewPublicKey << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")");
|
||||
r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spendPublicKey, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spendPublicKey << ")");
|
||||
|
||||
tx_out out;
|
||||
TransactionOutput out;
|
||||
out.amount = dst_entr.amount;
|
||||
txout_to_key tk;
|
||||
TransactionOutputToKey tk;
|
||||
tk.key = out_eph_public_key;
|
||||
out.target = tk;
|
||||
tx.vout.push_back(out);
|
||||
|
@ -410,12 +342,10 @@ namespace cryptonote
|
|||
|
||||
std::stringstream ss_ring_s;
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const tx_source_entry& src_entr, sources)
|
||||
{
|
||||
for (const tx_source_entry& src_entr : sources) {
|
||||
ss_ring_s << "pub_keys:" << ENDL;
|
||||
std::vector<const crypto::public_key*> keys_ptrs;
|
||||
BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs)
|
||||
{
|
||||
for (const tx_source_entry::output_entry& o : src_entr.outputs) {
|
||||
keys_ptrs.push_back(&o.second);
|
||||
ss_ring_s << o.second << ENDL;
|
||||
}
|
||||
|
@ -423,10 +353,12 @@ namespace cryptonote
|
|||
tx.signatures.push_back(std::vector<crypto::signature>());
|
||||
std::vector<crypto::signature>& sigs = tx.signatures.back();
|
||||
sigs.resize(src_entr.outputs.size());
|
||||
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
crypto::generate_ring_signature(tx_prefix_hash, boost::get<TransactionInputToKey>(tx.vin[i]).keyImage, keys_ptrs,
|
||||
in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
ss_ring_s << "signatures:" << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;});
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output;
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec <<
|
||||
ENDL << "real_output: " << src_entr.real_output;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -435,75 +367,118 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
|
||||
bool get_inputs_money_amount(const Transaction& tx, uint64_t& money)
|
||||
{
|
||||
money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
money += tokey_in.amount;
|
||||
|
||||
for (const auto& in : tx.vin) {
|
||||
uint64_t amount = 0;
|
||||
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
amount = boost::get<TransactionInputToKey>(in).amount;
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
amount = boost::get<TransactionInputMultisignature>(in).amount;
|
||||
}
|
||||
|
||||
money += amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_block_height(const block& b)
|
||||
uint64_t get_block_height(const Block& b)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1");
|
||||
CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0);
|
||||
CHECK_AND_ASSERT_MES(b.minerTx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.minerTx.vin.size() != 1");
|
||||
CHECKED_GET_SPECIFIC_VARIANT(b.minerTx.vin[0], const TransactionInputGenerate, coinbase_in, 0);
|
||||
return coinbase_in.height;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_inputs_types_supported(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: "
|
||||
<< in.type().name() << ", expected " << typeid(txin_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_outs_valid(const transaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(const tx_out& out, tx.vout)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: "
|
||||
<< out.target.type().name() << ", expected " << typeid(txout_to_key).name()
|
||||
<< ", in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount ouput in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
if(!check_key(boost::get<txout_to_key>(out.target).key))
|
||||
bool check_inputs_types_supported(const Transaction& tx) {
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() != typeid(TransactionInputToKey) && in.type() != typeid(TransactionInputMultisignature)) {
|
||||
LOG_PRINT_L1("Transaction << " << get_transaction_hash(tx) << " contains inputs with invalid type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_money_overflow(const transaction& tx)
|
||||
bool check_outs_valid(const Transaction& tx) {
|
||||
for (const TransactionOutput& out : tx.vout) {
|
||||
//assert(out.target.type() == typeid(TransactionOutputToKey) || out.target.type() == typeid(TransactionOutputMultisignature));
|
||||
if (out.target.type() == typeid(TransactionOutputToKey)) {
|
||||
CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount ouput in transaction id=" << get_transaction_hash(tx));
|
||||
|
||||
if (!check_key(boost::get<TransactionOutputToKey>(out.target).key)) {
|
||||
return false;
|
||||
}
|
||||
} else if (out.target.type() == typeid(TransactionOutputMultisignature)) {
|
||||
const TransactionOutputMultisignature& multisignatureOutput = ::boost::get<TransactionOutputMultisignature>(out.target);
|
||||
if (multisignatureOutput.requiredSignatures > multisignatureOutput.keys.size()) {
|
||||
LOG_PRINT_L1("Transaction << " << get_transaction_hash(tx) << " contains multisignature output with invalid required signature count.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const crypto::public_key& key : multisignatureOutput.keys) {
|
||||
if (!check_key(key)) {
|
||||
LOG_PRINT_L1("Transaction << " << get_transaction_hash(tx) << " contains multisignature output with invalid public keys.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_PRINT_L1("Transaction << " << get_transaction_hash(tx) << " contains outputs with invalid type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool checkMultisignatureInputsDiff(const Transaction& tx) {
|
||||
std::set<std::pair<uint64_t, uint32_t>> inputsUsage;
|
||||
for (const auto& inv : tx.vin) {
|
||||
if (inv.type() == typeid(TransactionInputMultisignature)) {
|
||||
const TransactionInputMultisignature& in = ::boost::get<TransactionInputMultisignature>(inv);
|
||||
if (!inputsUsage.insert(std::make_pair(in.amount, static_cast<uint32_t>(in.outputIndex))).second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_money_overflow(const Transaction& tx)
|
||||
{
|
||||
return check_inputs_overflow(tx) && check_outs_overflow(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_inputs_overflow(const transaction& tx)
|
||||
bool check_inputs_overflow(const Transaction& tx)
|
||||
{
|
||||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if(money > tokey_in.amount + money)
|
||||
|
||||
for (const auto& in : tx.vin) {
|
||||
uint64_t amount = 0;
|
||||
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
amount = boost::get<TransactionInputToKey>(in).amount;
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
amount = boost::get<TransactionInputMultisignature>(in).amount;
|
||||
}
|
||||
|
||||
if (money > amount + money)
|
||||
return false;
|
||||
money += tokey_in.amount;
|
||||
|
||||
money += amount;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool check_outs_overflow(const transaction& tx)
|
||||
bool check_outs_overflow(const Transaction& tx)
|
||||
{
|
||||
uint64_t money = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
{
|
||||
for (const auto& o : tx.vout) {
|
||||
if(money > o.amount + money)
|
||||
return false;
|
||||
money += o.amount;
|
||||
|
@ -511,11 +486,12 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_outs_money_amount(const transaction& tx)
|
||||
uint64_t get_outs_money_amount(const Transaction& tx)
|
||||
{
|
||||
uint64_t outputs_amount = 0;
|
||||
BOOST_FOREACH(const auto& o, tx.vout)
|
||||
for (const auto& o : tx.vout) {
|
||||
outputs_amount += o.amount;
|
||||
}
|
||||
return outputs_amount;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
@ -527,17 +503,25 @@ namespace cryptonote
|
|||
res.insert(8, "....");
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index)
|
||||
bool is_out_to_acc(const account_keys& acc, const TransactionOutputToKey& out_key, const crypto::key_derivation& derivation, size_t keyIndex)
|
||||
{
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, keyIndex, acc.m_account_address.m_spendPublicKey, pk);
|
||||
return pk == out_key.key;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const TransactionOutputToKey& out_key, const crypto::public_key& tx_pub_key, size_t keyIndex)
|
||||
{
|
||||
crypto::key_derivation derivation;
|
||||
generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
|
||||
return pk == out_key.key;
|
||||
return is_out_to_acc(acc, out_key, derivation, keyIndex);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
bool lookup_acc_outs(const account_keys& acc, const Transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
|
||||
if(null_pkey == tx_pub_key)
|
||||
|
@ -545,19 +529,29 @@ namespace cryptonote
|
|||
return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
bool lookup_acc_outs(const account_keys& acc, const Transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
|
||||
{
|
||||
money_transfered = 0;
|
||||
size_t i = 0;
|
||||
BOOST_FOREACH(const tx_out& o, tx.vout)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" );
|
||||
if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, i))
|
||||
{
|
||||
outs.push_back(i);
|
||||
money_transfered += o.amount;
|
||||
size_t keyIndex = 0;
|
||||
size_t outputIndex = 0;
|
||||
|
||||
crypto::key_derivation derivation;
|
||||
generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
|
||||
for (const TransactionOutput& o : tx.vout) {
|
||||
assert(o.target.type() == typeid(TransactionOutputToKey) || o.target.type() == typeid(TransactionOutputMultisignature));
|
||||
if (o.target.type() == typeid(TransactionOutputToKey)) {
|
||||
if (is_out_to_acc(acc, boost::get<TransactionOutputToKey>(o.target), derivation, keyIndex)) {
|
||||
outs.push_back(outputIndex);
|
||||
money_transfered += o.amount;
|
||||
}
|
||||
|
||||
++keyIndex;
|
||||
} else if (o.target.type() == typeid(TransactionOutputMultisignature)) {
|
||||
keyIndex += boost::get<TransactionOutputMultisignature>(o.target).keys.size();
|
||||
}
|
||||
i++;
|
||||
|
||||
++outputIndex;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -567,17 +561,6 @@ namespace cryptonote
|
|||
cn_fast_hash(blob.data(), blob.size(), res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string print_money(uint64_t amount)
|
||||
{
|
||||
std::string s = std::to_string(amount);
|
||||
if(s.size() < CRYPTONOTE_DISPLAY_DECIMAL_POINT+1)
|
||||
{
|
||||
s.insert(0, CRYPTONOTE_DISPLAY_DECIMAL_POINT+1 - s.size(), '0');
|
||||
}
|
||||
s.insert(s.size() - CRYPTONOTE_DISPLAY_DECIMAL_POINT, ".");
|
||||
return s;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_blob_hash(const blobdata& blob)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
|
@ -585,7 +568,7 @@ namespace cryptonote
|
|||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_hash(const transaction& t)
|
||||
crypto::hash get_transaction_hash(const Transaction& t)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
size_t blob_size = 0;
|
||||
|
@ -593,75 +576,79 @@ namespace cryptonote
|
|||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res)
|
||||
bool get_transaction_hash(const Transaction& t, crypto::hash& res)
|
||||
{
|
||||
size_t blob_size = 0;
|
||||
return get_object_hash(t, res, blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
|
||||
bool get_transaction_hash(const Transaction& t, crypto::hash& res, size_t& blob_size)
|
||||
{
|
||||
return get_object_hash(t, res, blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hashing_blob(const block& b, blobdata& blob)
|
||||
{
|
||||
if(!t_serializable_object_to_blob(static_cast<const block_header&>(b), blob))
|
||||
bool get_block_hashing_blob(const Block& b, blobdata& blob) {
|
||||
if (!t_serializable_object_to_blob(static_cast<const BlockHeader&>(b), blob)) {
|
||||
return false;
|
||||
}
|
||||
crypto::hash tree_root_hash = get_tx_tree_hash(b);
|
||||
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size() + 1));
|
||||
blob.append(tools::get_varint_data(b.txHashes.size() + 1));
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hash(const block& b, crypto::hash& res)
|
||||
{
|
||||
bool get_parent_block_hashing_blob(const Block& b, blobdata& blob) {
|
||||
auto serializer = makeParentBlockSerializer(b, true, true);
|
||||
return t_serializable_object_to_blob(serializer, blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hash(const Block& b, crypto::hash& res) {
|
||||
blobdata blob;
|
||||
if (!get_block_hashing_blob(b, blob))
|
||||
if (!get_block_hashing_blob(b, blob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (BLOCK_MAJOR_VERSION_2 <= b.majorVersion) {
|
||||
blobdata parent_blob;
|
||||
auto serializer = makeParentBlockSerializer(b, true, false);
|
||||
if (!t_serializable_object_to_blob(serializer, parent_blob))
|
||||
return false;
|
||||
|
||||
blob.append(parent_blob);
|
||||
}
|
||||
|
||||
return get_object_hash(blob, res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_block_hash(const block& b)
|
||||
{
|
||||
crypto::hash get_block_hash(const Block& b) {
|
||||
crypto::hash p = null_hash;
|
||||
get_block_hash(b, p);
|
||||
return p;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_genesis_block(block& bl)
|
||||
{
|
||||
//genesis block
|
||||
bl = boost::value_initialized<block>();
|
||||
bool get_aux_block_header_hash(const Block& b, crypto::hash& res) {
|
||||
blobdata blob;
|
||||
if (!get_block_hashing_blob(b, blob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
account_public_address ac = boost::value_initialized<account_public_address>();
|
||||
std::vector<size_t> sz;
|
||||
construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis
|
||||
blobdata txb = tx_to_blob(bl.miner_tx);
|
||||
std::string hex_tx_represent = string_tools::buff_to_hex_nodelimer(txb);
|
||||
|
||||
//hard code coinbase tx in genesis block, because "tru" generating tx use random, but genesis should be always the same
|
||||
std::string genesis_coinbase_tx_hex = "010a01ff0001ffffffffffff0f029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121013c086a48c15fb637a96991bc6d53caf77068b5ba6eeb3c82357228c49790584a";
|
||||
|
||||
blobdata tx_bl;
|
||||
string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
|
||||
bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
|
||||
bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
|
||||
bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
|
||||
bl.timestamp = 0;
|
||||
bl.nonce = 70;
|
||||
//miner::find_nonce_for_given_block(bl, 1, 0);
|
||||
return true;
|
||||
return get_object_hash(blob, res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_longhash(crypto::cn_context &context, const block& b, crypto::hash& res, uint64_t height)
|
||||
{
|
||||
bool get_block_longhash(crypto::cn_context &context, const Block& b, crypto::hash& res) {
|
||||
blobdata bd;
|
||||
if(!get_block_hashing_blob(b, bd))
|
||||
if (b.majorVersion == BLOCK_MAJOR_VERSION_1) {
|
||||
if (!get_block_hashing_blob(b, bd)) {
|
||||
return false;
|
||||
}
|
||||
} else if (b.majorVersion == BLOCK_MAJOR_VERSION_2) {
|
||||
if (!get_parent_block_hashing_blob(b, bd)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
crypto::cn_slow_hash(context, bd.data(), bd.size(), res);
|
||||
return true;
|
||||
}
|
||||
|
@ -686,14 +673,7 @@ namespace cryptonote
|
|||
return res;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_block_longhash(crypto::cn_context &context, const block& b, uint64_t height)
|
||||
{
|
||||
crypto::hash p = null_hash;
|
||||
get_block_longhash(context, b, p, height);
|
||||
return p;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, Block& b)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << b_blob;
|
||||
|
@ -703,22 +683,22 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata block_to_blob(const block& b)
|
||||
blobdata block_to_blob(const Block& b)
|
||||
{
|
||||
return t_serializable_object_to_blob(b);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool block_to_blob(const block& b, blobdata& b_blob)
|
||||
bool block_to_blob(const Block& b, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(b, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata tx_to_blob(const transaction& tx)
|
||||
blobdata tx_to_blob(const Transaction& tx)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool tx_to_blob(const transaction& tx, blobdata& b_blob)
|
||||
bool tx_to_blob(const Transaction& tx, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx, b_blob);
|
||||
}
|
||||
|
@ -735,15 +715,16 @@ namespace cryptonote
|
|||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const block& b)
|
||||
crypto::hash get_tx_tree_hash(const Block& b)
|
||||
{
|
||||
std::vector<crypto::hash> txs_ids;
|
||||
crypto::hash h = null_hash;
|
||||
size_t bl_sz = 0;
|
||||
get_transaction_hash(b.miner_tx, h, bl_sz);
|
||||
get_transaction_hash(b.minerTx, h, bl_sz);
|
||||
txs_ids.push_back(h);
|
||||
BOOST_FOREACH(auto& th, b.tx_hashes)
|
||||
for (auto& th : b.txHashes) {
|
||||
txs_ids.push_back(th);
|
||||
}
|
||||
return get_tx_tree_hash(txs_ids);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
|
@ -16,22 +16,27 @@
|
|||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "account.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <boost/utility/value_init.hpp>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/difficulty.h"
|
||||
#include "cryptonote_protocol/blobdatatype.h"
|
||||
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
|
||||
bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1);
|
||||
void get_transaction_prefix_hash(const TransactionPrefix& tx, crypto::hash& h);
|
||||
crypto::hash get_transaction_prefix_hash(const TransactionPrefix& tx);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, Transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, Transaction& tx);
|
||||
|
||||
struct tx_source_entry
|
||||
{
|
||||
|
@ -47,14 +52,14 @@ namespace cryptonote
|
|||
struct tx_destination_entry
|
||||
{
|
||||
uint64_t amount; //money
|
||||
account_public_address addr; //destination address
|
||||
AccountPublicAddress addr; //destination address
|
||||
|
||||
tx_destination_entry() : amount(0), addr(AUTO_VAL_INIT(addr)) { }
|
||||
tx_destination_entry(uint64_t a, const account_public_address &ad) : amount(a), addr(ad) { }
|
||||
tx_destination_entry() : amount(0), addr(boost::value_initialized<AccountPublicAddress>()) { }
|
||||
tx_destination_entry(uint64_t a, const AccountPublicAddress &ad) : amount(a), addr(ad) { }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
|
||||
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, Transaction& tx, uint64_t unlock_time);
|
||||
|
||||
template<typename T>
|
||||
bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field)
|
||||
|
@ -69,44 +74,46 @@ namespace cryptonote
|
|||
|
||||
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx);
|
||||
bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
|
||||
crypto::public_key get_tx_pub_key_from_extra(const Transaction& tx);
|
||||
bool add_tx_pub_key_to_extra(Transaction& tx, const crypto::public_key& tx_pub_key);
|
||||
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
|
||||
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
|
||||
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee);
|
||||
uint64_t get_tx_fee(const transaction& tx);
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
|
||||
bool append_mm_tag_to_extra(std::vector<uint8_t>& tx_extra, const tx_extra_merge_mining_tag& mm_tag);
|
||||
bool get_mm_tag_from_extra(const std::vector<uint8_t>& tx_extra, tx_extra_merge_mining_tag& mm_tag);
|
||||
bool is_out_to_acc(const account_keys& acc, const TransactionOutputToKey& out_key, const crypto::public_key& tx_pub_key, size_t keyIndex);
|
||||
bool is_out_to_acc(const account_keys& acc, const TransactionOutputToKey& out_key, const crypto::key_derivation& derivation, size_t keyIndex);
|
||||
bool lookup_acc_outs(const account_keys& acc, const Transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool lookup_acc_outs(const account_keys& acc, const Transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool get_tx_fee(const Transaction& tx, uint64_t & fee);
|
||||
uint64_t get_tx_fee(const Transaction& tx);
|
||||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, KeyPair& in_ephemeral, crypto::key_image& ki);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
crypto::hash get_blob_hash(const blobdata& blob);
|
||||
std::string short_hash_str(const crypto::hash& h);
|
||||
|
||||
crypto::hash get_transaction_hash(const transaction& t);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
|
||||
bool get_block_hashing_blob(const block& b, blobdata& blob);
|
||||
bool get_block_hash(const block& b, crypto::hash& res);
|
||||
crypto::hash get_block_hash(const block& b);
|
||||
bool get_block_longhash(crypto::cn_context &context, const block& b, crypto::hash& res, uint64_t height);
|
||||
crypto::hash get_block_longhash(crypto::cn_context &context, const block& b, uint64_t height);
|
||||
bool generate_genesis_block(block& bl);
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
|
||||
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
|
||||
uint64_t get_outs_money_amount(const transaction& tx);
|
||||
bool check_inputs_types_supported(const transaction& tx);
|
||||
bool check_outs_valid(const transaction& tx);
|
||||
bool parse_amount(uint64_t& amount, const std::string& str_amount);
|
||||
crypto::hash get_transaction_hash(const Transaction& t);
|
||||
bool get_transaction_hash(const Transaction& t, crypto::hash& res);
|
||||
bool get_transaction_hash(const Transaction& t, crypto::hash& res, size_t& blob_size);
|
||||
bool get_block_hashing_blob(const Block& b, blobdata& blob);
|
||||
bool get_parent_block_hashing_blob(const Block& b, blobdata& blob);
|
||||
bool get_aux_block_header_hash(const Block& b, crypto::hash& res);
|
||||
bool get_block_hash(const Block& b, crypto::hash& res);
|
||||
crypto::hash get_block_hash(const Block& b);
|
||||
bool get_block_longhash(crypto::cn_context &context, const Block& b, crypto::hash& res);
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, Block& b);
|
||||
bool get_inputs_money_amount(const Transaction& tx, uint64_t& money);
|
||||
uint64_t get_outs_money_amount(const Transaction& tx);
|
||||
bool check_inputs_types_supported(const Transaction& tx);
|
||||
bool check_outs_valid(const Transaction& tx);
|
||||
bool checkMultisignatureInputsDiff(const Transaction& tx);
|
||||
|
||||
bool check_money_overflow(const transaction& tx);
|
||||
bool check_outs_overflow(const transaction& tx);
|
||||
bool check_inputs_overflow(const transaction& tx);
|
||||
uint64_t get_block_height(const block& b);
|
||||
bool check_money_overflow(const Transaction& tx);
|
||||
bool check_outs_overflow(const Transaction& tx);
|
||||
bool check_inputs_overflow(const Transaction& tx);
|
||||
uint64_t get_block_height(const Block& b);
|
||||
std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off);
|
||||
std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off);
|
||||
std::string print_money(uint64_t amount);
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool t_serializable_object_to_blob(const t_object& to, blobdata& b_blob)
|
||||
|
@ -134,10 +141,22 @@ namespace cryptonote
|
|||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool get_object_blobsize(const t_object& o, size_t& size) {
|
||||
blobdata blob;
|
||||
if (!t_serializable_object_to_blob(o, blob)) {
|
||||
size = (std::numeric_limits<size_t>::max)();
|
||||
return false;
|
||||
}
|
||||
size = blob.size();
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
size_t get_object_blobsize(const t_object& o)
|
||||
{
|
||||
blobdata b = t_serializable_object_to_blob(o);
|
||||
return b.size();
|
||||
size_t size;
|
||||
get_object_blobsize(o, size);
|
||||
return size;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
|
@ -150,11 +169,10 @@ namespace cryptonote
|
|||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename T>
|
||||
std::string obj_to_json_str(T& obj)
|
||||
{
|
||||
std::string obj_to_json_str(const T& obj) {
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss, true);
|
||||
bool r = ::serialization::serialize(ar, obj);
|
||||
bool r = ::serialization::serialize(ar, *const_cast<T*>(&obj));
|
||||
CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false");
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -201,13 +219,13 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata block_to_blob(const block& b);
|
||||
bool block_to_blob(const block& b, blobdata& b_blob);
|
||||
blobdata tx_to_blob(const transaction& b);
|
||||
bool tx_to_blob(const transaction& b, blobdata& b_blob);
|
||||
blobdata block_to_blob(const Block& b);
|
||||
bool block_to_blob(const Block& b, blobdata& b_blob);
|
||||
blobdata tx_to_blob(const Transaction& b);
|
||||
bool tx_to_blob(const Transaction& b, blobdata& b_blob);
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
|
||||
crypto::hash get_tx_tree_hash(const block& b);
|
||||
crypto::hash get_tx_tree_hash(const Block& b);
|
||||
|
||||
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \
|
||||
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
|
||||
|
|
|
@ -75,50 +75,4 @@ namespace cryptonote {
|
|||
carry = cadc(high, top, carry);
|
||||
return !carry;
|
||||
}
|
||||
|
||||
difficulty_type next_difficulty(vector<uint64_t> timestamps, vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
|
||||
//cutoff DIFFICULTY_LAG
|
||||
if(timestamps.size() > DIFFICULTY_WINDOW)
|
||||
{
|
||||
timestamps.resize(DIFFICULTY_WINDOW);
|
||||
cumulative_difficulties.resize(DIFFICULTY_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
size_t length = timestamps.size();
|
||||
assert(length == cumulative_difficulties.size());
|
||||
if (length <= 1) {
|
||||
return 1;
|
||||
}
|
||||
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");
|
||||
assert(length <= DIFFICULTY_WINDOW);
|
||||
sort(timestamps.begin(), timestamps.end());
|
||||
size_t cut_begin, cut_end;
|
||||
static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large");
|
||||
if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) {
|
||||
cut_begin = 0;
|
||||
cut_end = length;
|
||||
} else {
|
||||
cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2;
|
||||
cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT);
|
||||
}
|
||||
assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length);
|
||||
uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin];
|
||||
if (time_span == 0) {
|
||||
time_span = 1;
|
||||
}
|
||||
difficulty_type total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin];
|
||||
assert(total_work > 0);
|
||||
uint64_t low, high;
|
||||
mul(total_work, target_seconds, low, high);
|
||||
if (high != 0 || low + time_span - 1 < low) {
|
||||
return 0;
|
||||
}
|
||||
return (low + time_span - 1) / time_span;
|
||||
}
|
||||
|
||||
difficulty_type next_difficulty(vector<uint64_t> timestamps, vector<difficulty_type> cumulative_difficulties)
|
||||
{
|
||||
return next_difficulty(std::move(timestamps), std::move(cumulative_difficulties), DIFFICULTY_TARGET);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,4 @@ namespace cryptonote
|
|||
typedef std::uint64_t difficulty_type;
|
||||
|
||||
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
|
||||
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties);
|
||||
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
|
||||
}
|
||||
|
|
31
src/cryptonote_core/i_miner_handler.h
Normal file
31
src/cryptonote_core/i_miner_handler.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2012-2014, The CryptoNote developers, The Bytecoin developers
|
||||
//
|
||||
// This file is part of Bytecoin.
|
||||
//
|
||||
// Bytecoin is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Bytecoin is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_core/difficulty.h"
|
||||
|
||||
namespace cryptonote {
|
||||
struct i_miner_handler {
|
||||
virtual bool handle_block_found(Block& b) = 0;
|
||||
virtual bool get_block_template(Block& b, const AccountPublicAddress& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) = 0;
|
||||
|
||||
protected:
|
||||
~i_miner_handler(){};
|
||||
};
|
||||
}
|
|
@ -17,10 +17,13 @@
|
|||
|
||||
#include <sstream>
|
||||
#include <numeric>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/interprocess/detail/atomic.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "include_base_utils.h"
|
||||
#include "cryptonote_basic_impl.h"
|
||||
|
@ -35,8 +38,8 @@
|
|||
using namespace epee;
|
||||
|
||||
#include "miner.h"
|
||||
|
||||
|
||||
#include <thread>
|
||||
#include <future>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
@ -49,13 +52,14 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
|
||||
miner::miner(i_miner_handler* phandler):m_stop(1),
|
||||
m_template(boost::value_initialized<block>()),
|
||||
miner::miner(const Currency& currency, i_miner_handler* phandler):
|
||||
m_currency(currency),
|
||||
m_stop(1),
|
||||
m_template(boost::value_initialized<Block>()),
|
||||
m_template_no(0),
|
||||
m_diffic(0),
|
||||
m_thread_index(0),
|
||||
m_phandler(phandler),
|
||||
m_height(0),
|
||||
m_pausers_count(0),
|
||||
m_threads_total(0),
|
||||
m_starter_nonce(0),
|
||||
|
@ -65,38 +69,47 @@ namespace cryptonote
|
|||
m_do_mining(false),
|
||||
m_current_hash_rate(0)
|
||||
{
|
||||
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
miner::~miner()
|
||||
{
|
||||
miner::~miner() {
|
||||
stop();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
|
||||
{
|
||||
bool miner::set_block_template(const Block& bl, const difficulty_type& di) {
|
||||
CRITICAL_REGION_LOCAL(m_template_lock);
|
||||
m_template = bl;
|
||||
|
||||
if (BLOCK_MAJOR_VERSION_2 == m_template.majorVersion) {
|
||||
cryptonote::tx_extra_merge_mining_tag mm_tag;
|
||||
mm_tag.depth = 0;
|
||||
if (!cryptonote::get_aux_block_header_hash(m_template, mm_tag.merkle_root)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_template.parentBlock.minerTx.extra.clear();
|
||||
if (!cryptonote::append_mm_tag_to_extra(m_template.parentBlock.minerTx.extra, mm_tag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_diffic = di;
|
||||
m_height = height;
|
||||
++m_template_no;
|
||||
m_starter_nonce = crypto::rand<uint32_t>();
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::on_block_chain_update()
|
||||
{
|
||||
if(!is_mining())
|
||||
bool miner::on_block_chain_update() {
|
||||
if (!is_mining()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return request_block_template();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::request_block_template()
|
||||
{
|
||||
block bl = AUTO_VAL_INIT(bl);
|
||||
bool miner::request_block_template() {
|
||||
Block bl = AUTO_VAL_INIT(bl);
|
||||
difficulty_type di = AUTO_VAL_INIT(di);
|
||||
uint64_t height = AUTO_VAL_INIT(height);
|
||||
uint64_t height;
|
||||
cryptonote::blobdata extra_nonce;
|
||||
if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
|
||||
{
|
||||
|
@ -108,7 +121,7 @@ namespace cryptonote
|
|||
LOG_ERROR("Failed to get_block_template(), stopping mining");
|
||||
return false;
|
||||
}
|
||||
set_block_template(bl, di, height);
|
||||
set_block_template(bl, di);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
@ -180,14 +193,13 @@ namespace cryptonote
|
|||
}
|
||||
m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
|
||||
m_config = AUTO_VAL_INIT(m_config);
|
||||
epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
|
||||
epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + cryptonote::parameters::MINER_CONFIG_FILE_NAME);
|
||||
LOG_PRINT_L0("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
|
||||
}
|
||||
|
||||
if(command_line::has_arg(vm, arg_start_mining))
|
||||
{
|
||||
if(!cryptonote::get_account_address_from_str(m_mine_address, command_line::get_arg(vm, arg_start_mining)))
|
||||
{
|
||||
if (!m_currency.parseAccountAddressString(command_line::get_arg(vm, arg_start_mining), m_mine_address)) {
|
||||
LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
|
||||
return false;
|
||||
}
|
||||
|
@ -207,7 +219,7 @@ namespace cryptonote
|
|||
return !m_stop;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
|
||||
bool miner::start(const AccountPublicAddress& adr, size_t threads_count, const boost::thread::attributes& attrs)
|
||||
{
|
||||
m_mine_address = adr;
|
||||
m_threads_total = static_cast<uint32_t>(threads_count);
|
||||
|
@ -266,18 +278,61 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::find_nonce_for_given_block(crypto::cn_context &context, block& bl, const difficulty_type& diffic, uint64_t height)
|
||||
{
|
||||
for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
|
||||
{
|
||||
crypto::hash h;
|
||||
get_block_longhash(context, bl, h, height);
|
||||
bool miner::find_nonce_for_given_block(crypto::cn_context &context, Block& bl, const difficulty_type& diffic) {
|
||||
|
||||
if(check_hash(h, diffic))
|
||||
{
|
||||
return true;
|
||||
unsigned nthreads = std::thread::hardware_concurrency();
|
||||
|
||||
if (nthreads > 0 && diffic > 5) {
|
||||
std::vector<std::future<void>> threads(nthreads);
|
||||
std::atomic<uint32_t> foundNonce;
|
||||
std::atomic<bool> found(false);
|
||||
uint32_t startNonce = crypto::rand<uint32_t>();
|
||||
|
||||
for (unsigned i = 0; i < nthreads; ++i) {
|
||||
threads[i] = std::async(std::launch::async, [&, i]() {
|
||||
crypto::cn_context localctx;
|
||||
crypto::hash h;
|
||||
|
||||
Block lb(bl); // copy to local block
|
||||
|
||||
for (uint32_t nonce = startNonce + i; !found; nonce += nthreads) {
|
||||
lb.nonce = nonce;
|
||||
|
||||
if (!get_block_longhash(localctx, lb, h)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_hash(h, diffic)) {
|
||||
foundNonce = nonce;
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& t : threads) {
|
||||
t.wait();
|
||||
}
|
||||
|
||||
if (found) {
|
||||
bl.nonce = foundNonce.load();
|
||||
}
|
||||
|
||||
return found;
|
||||
} else {
|
||||
for (; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++) {
|
||||
crypto::hash h;
|
||||
if (!get_block_longhash(context, bl, h)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (check_hash(h, diffic)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
@ -319,11 +374,10 @@ namespace cryptonote
|
|||
LOG_PRINT_L0("Miner thread was started ["<< th_local_index << "]");
|
||||
log_space::log_singletone::set_thread_log_prefix(std::string("[miner ") + std::to_string(th_local_index) + "]");
|
||||
uint32_t nonce = m_starter_nonce + th_local_index;
|
||||
uint64_t height = 0;
|
||||
difficulty_type local_diff = 0;
|
||||
uint32_t local_template_ver = 0;
|
||||
crypto::cn_context context;
|
||||
block b;
|
||||
Block b;
|
||||
while(!m_stop)
|
||||
{
|
||||
if(m_pausers_count)//anti split workaround
|
||||
|
@ -338,7 +392,6 @@ namespace cryptonote
|
|||
CRITICAL_REGION_BEGIN(m_template_lock);
|
||||
b = m_template;
|
||||
local_diff = m_diffic;
|
||||
height = m_height;
|
||||
CRITICAL_REGION_END();
|
||||
local_template_ver = m_template_no;
|
||||
nonce = m_starter_nonce + th_local_index;
|
||||
|
@ -353,9 +406,12 @@ namespace cryptonote
|
|||
|
||||
b.nonce = nonce;
|
||||
crypto::hash h;
|
||||
get_block_longhash(context, b, h, height);
|
||||
if (!m_stop && !get_block_longhash(context, b, h)) {
|
||||
LOG_ERROR("Failed to get block long hash");
|
||||
m_stop = true;
|
||||
}
|
||||
|
||||
if(!m_stop && check_hash(h, local_diff))
|
||||
if (!m_stop && check_hash(h, local_diff))
|
||||
{
|
||||
//we lucky!
|
||||
++m_config.current_extra_message_index;
|
||||
|
@ -366,7 +422,7 @@ namespace cryptonote
|
|||
}else
|
||||
{
|
||||
//success update, lets update config
|
||||
epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
|
||||
epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + cryptonote::parameters::MINER_CONFIG_FILE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,37 +17,29 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <atomic>
|
||||
#include "cryptonote_basic.h"
|
||||
#include "difficulty.h"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
// epee
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "math_helper.h"
|
||||
|
||||
#include "cryptonote_core/cryptonote_basic.h"
|
||||
#include "cryptonote_core/Currency.h"
|
||||
#include "cryptonote_core/difficulty.h"
|
||||
#include "cryptonote_core/i_miner_handler.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
struct i_miner_handler
|
||||
{
|
||||
virtual bool handle_block_found(block& b) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) = 0;
|
||||
protected:
|
||||
~i_miner_handler(){};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class miner
|
||||
{
|
||||
namespace cryptonote {
|
||||
class miner {
|
||||
public:
|
||||
miner(i_miner_handler* phandler);
|
||||
miner(const Currency& currency, i_miner_handler* phandler);
|
||||
~miner();
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height);
|
||||
bool set_block_template(const Block& bl, const difficulty_type& diffic);
|
||||
bool on_block_chain_update();
|
||||
bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs);
|
||||
bool start(const AccountPublicAddress& adr, size_t threads_count, const boost::thread::attributes& attrs);
|
||||
uint64_t get_speed();
|
||||
void send_stop_signal();
|
||||
bool stop();
|
||||
|
@ -55,7 +47,7 @@ namespace cryptonote
|
|||
bool on_idle();
|
||||
void on_synchronized();
|
||||
//synchronous analog (for fast calls)
|
||||
static bool find_nonce_for_given_block(crypto::cn_context &context, block& bl, const difficulty_type& diffic, uint64_t height);
|
||||
static bool find_nonce_for_given_block(crypto::cn_context &context, Block& bl, const difficulty_type& diffic);
|
||||
void pause();
|
||||
void resume();
|
||||
void do_print_hashrate(bool do_hr);
|
||||
|
@ -75,13 +67,13 @@ namespace cryptonote
|
|||
};
|
||||
|
||||
|
||||
const Currency& m_currency;
|
||||
volatile uint32_t m_stop;
|
||||
epee::critical_section m_template_lock;
|
||||
block m_template;
|
||||
Block m_template;
|
||||
std::atomic<uint32_t> m_template_no;
|
||||
std::atomic<uint32_t> m_starter_nonce;
|
||||
difficulty_type m_diffic;
|
||||
uint64_t m_height;
|
||||
volatile uint32_t m_thread_index;
|
||||
volatile uint32_t m_threads_total;
|
||||
std::atomic<int32_t> m_pausers_count;
|
||||
|
@ -90,7 +82,7 @@ namespace cryptonote
|
|||
std::list<boost::thread> m_threads;
|
||||
epee::critical_section m_threads_lock;
|
||||
i_miner_handler* m_phandler;
|
||||
account_public_address m_mine_address;
|
||||
AccountPublicAddress m_mine_address;
|
||||
epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval;
|
||||
epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval;
|
||||
std::vector<blobdata> m_extra_messages;
|
||||
|
@ -103,6 +95,5 @@ namespace cryptonote
|
|||
std::list<uint64_t> m_last_hash_rates;
|
||||
bool m_do_print_hashrate;
|
||||
bool m_do_mining;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "serialization/binary_archive.h"
|
||||
#include "serialization/crypto.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "serialization/variant.h"
|
||||
|
||||
#define TX_EXTRA_PADDING_MAX_COUNT 255
|
||||
#define TX_EXTRA_NONCE_MAX_COUNT 255
|
||||
|
|
|
@ -15,32 +15,100 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "tx_pool.h"
|
||||
#include "cryptonote_format_utils.h"
|
||||
#include "cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "blockchain_storage.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// epee
|
||||
#include "misc_language.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include "warnings.h"
|
||||
|
||||
#include "common/boost_serialization_helper.h"
|
||||
#include "common/int-util.h"
|
||||
#include "misc_language.h"
|
||||
#include "warnings.h"
|
||||
#include "common/util.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
|
||||
|
||||
#define TRANSACTION_SIZE_LIMIT (((CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE * 125) / 100) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE)
|
||||
|
||||
namespace cryptonote {
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
tx_memory_pool::tx_memory_pool(blockchain_storage& bchs): m_blockchain(bchs) {
|
||||
// BlockTemplate
|
||||
//---------------------------------------------------------------------------------
|
||||
class BlockTemplate {
|
||||
public:
|
||||
|
||||
bool addTransaction(const crypto::hash& txid, const Transaction& tx) {
|
||||
if (!canAdd(tx))
|
||||
return false;
|
||||
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
auto r = m_keyImages.insert(boost::get<TransactionInputToKey>(in).keyImage);
|
||||
(void)r; //just to make compiler to shut up
|
||||
assert(r.second);
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
const auto& msig = boost::get<TransactionInputMultisignature>(in);
|
||||
auto r = m_usedOutputs.insert(std::make_pair(msig.amount, msig.outputIndex));
|
||||
(void)r; //just to make compiler to shut up
|
||||
assert(r.second);
|
||||
}
|
||||
}
|
||||
|
||||
m_txHashes.push_back(txid);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<crypto::hash>& getTransactions() const {
|
||||
return m_txHashes;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool canAdd(const Transaction& tx) {
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
if (m_keyImages.count(boost::get<TransactionInputToKey>(in).keyImage)) {
|
||||
return false;
|
||||
}
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
const auto& msig = boost::get<TransactionInputMultisignature>(in);
|
||||
if (m_usedOutputs.count(std::make_pair(msig.amount, msig.outputIndex))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unordered_set<crypto::key_image> m_keyImages;
|
||||
std::set<std::pair<uint64_t, uint64_t>> m_usedOutputs;
|
||||
std::vector<crypto::hash> m_txHashes;
|
||||
};
|
||||
|
||||
using CryptoNote::BlockInfo;
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
tx_memory_pool::tx_memory_pool(const cryptonote::Currency& currency, CryptoNote::ITransactionValidator& validator, CryptoNote::ITimeProvider& timeProvider) :
|
||||
m_currency(currency),
|
||||
m_validator(validator),
|
||||
m_timeProvider(timeProvider),
|
||||
m_txCheckInterval(60, timeProvider),
|
||||
m_fee_index(boost::get<1>(m_transactions)) {
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(const transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block) {
|
||||
bool tx_memory_pool::add_tx(const Transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blobSize, tx_verification_context& tvc, bool keptByBlock) {
|
||||
if (!check_inputs_types_supported(tx)) {
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
|
@ -55,134 +123,103 @@ namespace cryptonote {
|
|||
uint64_t outputs_amount = get_outs_money_amount(tx);
|
||||
|
||||
if (outputs_amount >= inputs_amount) {
|
||||
LOG_PRINT_L0("transaction use more money then it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount));
|
||||
LOG_PRINT_L0("transaction use more money then it has: use " << m_currency.formatAmount(outputs_amount) <<
|
||||
", have " << m_currency.formatAmount(inputs_amount));
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t fee = inputs_amount - outputs_amount;
|
||||
if (!kept_by_block && fee < MINIMUM_FEE) {
|
||||
LOG_ERROR("transaction fee is not enought: " << print_money(fee) << ", minumim fee: " << print_money(MINIMUM_FEE));
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!kept_by_block && blob_size >= TRANSACTION_SIZE_LIMIT) {
|
||||
LOG_ERROR("transaction is too big: " << blob_size << " bytes, maximum size: " << TRANSACTION_SIZE_LIMIT);
|
||||
const uint64_t fee = inputs_amount - outputs_amount;
|
||||
if (!keptByBlock && fee < m_currency.minimumFee()) {
|
||||
LOG_PRINT_L0("transaction fee is not enought: " << m_currency.formatAmount(fee) <<
|
||||
", minumim fee: " << m_currency.formatAmount(m_currency.minimumFee()));
|
||||
tvc.m_verifivation_failed = true;
|
||||
tvc.m_tx_fee_too_small = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//check key images for transaction if it is not kept by block
|
||||
if (!kept_by_block) {
|
||||
if (have_tx_keyimges_as_spent(tx)) {
|
||||
LOG_ERROR("Transaction with id= "<< id << " used already spent key images");
|
||||
if (!keptByBlock) {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
if (haveSpentInputs(tx)) {
|
||||
LOG_PRINT_L0("Transaction with id= " << id << " used already spent inputs");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
crypto::hash max_used_block_id = null_hash;
|
||||
uint64_t max_used_block_height = 0;
|
||||
bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id);
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
if (!ch_inp_res) {
|
||||
if (kept_by_block) {
|
||||
//anyway add this transaction to pool, because it related to block
|
||||
auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool");
|
||||
txd_p.first->second.blob_size = blob_size;
|
||||
txd_p.first->second.tx = tx;
|
||||
txd_p.first->second.fee = inputs_amount - outputs_amount;
|
||||
txd_p.first->second.max_used_block_id = null_hash;
|
||||
txd_p.first->second.max_used_block_height = 0;
|
||||
txd_p.first->second.kept_by_block = kept_by_block;
|
||||
tvc.m_verifivation_impossible = true;
|
||||
tvc.m_added_to_pool = true;
|
||||
} else {
|
||||
BlockInfo maxUsedBlock;
|
||||
|
||||
// check inputs
|
||||
bool inputsValid = m_validator.checkTransactionInputs(tx, maxUsedBlock);
|
||||
|
||||
if (!inputsValid) {
|
||||
if (!keptByBlock) {
|
||||
LOG_PRINT_L0("tx used wrong inputs, rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
//update transactions container
|
||||
auto txd_p = m_transactions.insert(transactions_container::value_type(id, tx_details()));
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "intrnal error: transaction already exists at inserting in memorypool");
|
||||
txd_p.first->second.blob_size = blob_size;
|
||||
txd_p.first->second.tx = tx;
|
||||
txd_p.first->second.kept_by_block = kept_by_block;
|
||||
txd_p.first->second.fee = inputs_amount - outputs_amount;
|
||||
txd_p.first->second.max_used_block_id = max_used_block_id;
|
||||
txd_p.first->second.max_used_block_height = max_used_block_height;
|
||||
txd_p.first->second.last_failed_height = 0;
|
||||
txd_p.first->second.last_failed_id = null_hash;
|
||||
tvc.m_added_to_pool = true;
|
||||
|
||||
if (txd_p.first->second.fee > 0) {
|
||||
tvc.m_should_be_relayed = true;
|
||||
}
|
||||
maxUsedBlock.clear();
|
||||
tvc.m_verifivation_impossible = true;
|
||||
}
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
// add to pool
|
||||
{
|
||||
TransactionDetails txd;
|
||||
|
||||
txd.id = id;
|
||||
txd.blobSize = blobSize;
|
||||
txd.tx = tx;
|
||||
txd.fee = fee;
|
||||
txd.keptByBlock = keptByBlock;
|
||||
txd.receiveTime = m_timeProvider.now();
|
||||
|
||||
txd.maxUsedBlock = maxUsedBlock;
|
||||
txd.lastFailedBlock.clear();
|
||||
|
||||
auto txd_p = m_transactions.insert(std::move(txd));
|
||||
CHECK_AND_ASSERT_MES(txd_p.second, false, "transaction already exists at inserting in memory pool");
|
||||
}
|
||||
|
||||
tvc.m_added_to_pool = true;
|
||||
|
||||
if (inputsValid && fee > 0)
|
||||
tvc.m_should_be_relayed = true;
|
||||
|
||||
tvc.m_verifivation_failed = true;
|
||||
//update image_keys container, here should everything goes ok.
|
||||
for (const auto& in : tx.vin) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, txin, false);
|
||||
std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.k_image];
|
||||
CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: keeped_by_block=" << kept_by_block
|
||||
<< ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << txin.k_image << ENDL
|
||||
<< "tx_id=" << id );
|
||||
auto ins_res = kei_image_set.insert(id);
|
||||
CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
|
||||
}
|
||||
|
||||
if (!addTransactionInputs(id, tx, keptByBlock))
|
||||
return false;
|
||||
|
||||
tvc.m_verifivation_failed = false;
|
||||
//succeed
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block) {
|
||||
bool tx_memory_pool::add_tx(const Transaction &tx, tx_verification_context& tvc, bool keeped_by_block) {
|
||||
crypto::hash h = null_hash;
|
||||
size_t blob_size = 0;
|
||||
get_transaction_hash(tx, h, blob_size);
|
||||
return add_tx(tx, h, blob_size, tvc, keeped_by_block);
|
||||
size_t blobSize = 0;
|
||||
get_transaction_hash(tx, h, blobSize);
|
||||
return add_tx(tx, h, blobSize, tvc, keeped_by_block);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::remove_transaction_keyimages(const transaction& tx) {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
crypto::hash tx_id = get_transaction_hash(tx);
|
||||
for (const txin_v& vi : tx.vin) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(vi, const txin_to_key, txin, false);
|
||||
auto it = m_spent_key_images.find(txin.k_image);
|
||||
CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << txin.k_image << std::endl
|
||||
<< "transaction id = " << tx_id);
|
||||
std::unordered_set<crypto::hash>& key_image_set = it->second;
|
||||
CHECK_AND_ASSERT_MES(!key_image_set.empty(), false, "empty key_image set, img=" << txin.k_image << std::endl
|
||||
<< "transaction id = " << tx_id);
|
||||
|
||||
auto it_in_set = key_image_set.find(tx_id);
|
||||
CHECK_AND_ASSERT_MES(it_in_set != key_image_set.end(), false, "transaction id not found in key_image set, img=" << txin.k_image << std::endl
|
||||
<< "transaction id = " << tx_id);
|
||||
key_image_set.erase(it_in_set);
|
||||
if (key_image_set.empty()) {
|
||||
//it is now empty hash container for this key_image
|
||||
m_spent_key_images.erase(it);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee) {
|
||||
bool tx_memory_pool::take_tx(const crypto::hash &id, Transaction &tx, size_t& blobSize, uint64_t& fee) {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
auto it = m_transactions.find(id);
|
||||
if (it == m_transactions.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tx = it->second.tx;
|
||||
blob_size = it->second.blob_size;
|
||||
fee = it->second.fee;
|
||||
remove_transaction_keyimages(it->second.tx);
|
||||
m_transactions.erase(it);
|
||||
auto& txd = *it;
|
||||
|
||||
tx = txd.tx;
|
||||
blobSize = txd.blobSize;
|
||||
fee = txd.fee;
|
||||
|
||||
removeTransaction(it);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -191,10 +228,10 @@ namespace cryptonote {
|
|||
return m_transactions.size();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::get_transactions(std::list<transaction>& txs) const {
|
||||
void tx_memory_pool::get_transactions(std::list<Transaction>& txs) const {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
for (const auto& tx_vt : m_transactions) {
|
||||
txs.push_back(tx_vt.second.tx);
|
||||
txs.push_back(tx_vt.tx);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -214,22 +251,6 @@ namespace cryptonote {
|
|||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
for (const auto& in : tx.vin) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail
|
||||
if (have_tx_keyimg_as_spent(tokey_in.k_image)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
return m_spent_key_images.end() != m_spent_key_images.find(key_im);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::lock() const {
|
||||
m_transactions_lock.lock();
|
||||
}
|
||||
|
@ -238,110 +259,74 @@ namespace cryptonote {
|
|||
m_transactions_lock.unlock();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::is_transaction_ready_to_go(tx_details& txd) const {
|
||||
//not the best implementation at this time, sorry :(
|
||||
//check is ring_signature already checked ?
|
||||
if (txd.max_used_block_id == null_hash) {
|
||||
//not checked, lets try to check
|
||||
if (txd.last_failed_id != null_hash && m_blockchain.get_current_blockchain_height() > txd.last_failed_height && txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) {
|
||||
return false;//we already sure that this tx is broken for this height
|
||||
}
|
||||
bool tx_memory_pool::is_transaction_ready_to_go(const Transaction& tx, TransactionCheckInfo& txd) const {
|
||||
|
||||
if (!m_blockchain.check_tx_inputs(txd.tx, txd.max_used_block_height, txd.max_used_block_id)) {
|
||||
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
|
||||
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (txd.max_used_block_height >= m_blockchain.get_current_blockchain_height()) {
|
||||
return false;
|
||||
}
|
||||
if (m_blockchain.get_block_id_by_height(txd.max_used_block_height) != txd.max_used_block_id) {
|
||||
//if we already failed on this height and id, skip actual ring signature check
|
||||
if (txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) {
|
||||
return false;
|
||||
}
|
||||
//check ring signature again, it is possible (with very small chance) that this transaction become again valid
|
||||
if (!m_blockchain.check_tx_inputs(txd.tx, txd.max_used_block_height, txd.max_used_block_id)) {
|
||||
txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1;
|
||||
txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!m_validator.checkTransactionInputs(tx, txd.maxUsedBlock, txd.lastFailedBlock))
|
||||
return false;
|
||||
|
||||
//if we here, transaction seems valid, but, anyway, check for key_images collisions with blockchain, just to be sure
|
||||
if (m_blockchain.have_tx_keyimges_as_spent(txd.tx)) {
|
||||
if (m_validator.haveSpentKeyImages(tx))
|
||||
return false;
|
||||
}
|
||||
|
||||
//transaction is ok.
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_key_images(const std::unordered_set<crypto::key_image>& k_images, const transaction& tx) {
|
||||
for (size_t i = 0; i!= tx.vin.size(); i++) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false);
|
||||
if (k_images.count(itk.k_image)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::append_key_images(std::unordered_set<crypto::key_image>& k_images, const transaction& tx) {
|
||||
for (size_t i = 0; i!= tx.vin.size(); i++) {
|
||||
CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false);
|
||||
auto i_res = k_images.insert(itk.k_image);
|
||||
CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
std::string tx_memory_pool::print_pool(bool short_format) const {
|
||||
std::stringstream ss;
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
for (const transactions_container::value_type& txe : m_transactions) {
|
||||
const tx_details& txd = txe.second;
|
||||
ss << "id: " << txe.first << std::endl;
|
||||
for (const auto& txd : m_fee_index) {
|
||||
ss << "id: " << txd.id << std::endl;
|
||||
if (!short_format) {
|
||||
ss << obj_to_json_str(*const_cast<transaction*>(&txd.tx)) << std::endl;
|
||||
ss << obj_to_json_str(txd.tx) << std::endl;
|
||||
}
|
||||
ss << "blob_size: " << txd.blob_size << std::endl
|
||||
<< "fee: " << print_money(txd.fee) << std::endl
|
||||
<< "kept_by_block: " << (txd.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << txd.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << txd.max_used_block_id << std::endl
|
||||
<< "last_failed_height: " << txd.last_failed_height << std::endl
|
||||
<< "last_failed_id: " << txd.last_failed_id << std::endl;
|
||||
ss << "blobSize: " << txd.blobSize << std::endl
|
||||
<< "fee: " << m_currency.formatAmount(txd.fee) << std::endl
|
||||
<< "keptByBlock: " << (txd.keptByBlock ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << txd.maxUsedBlock.height << std::endl
|
||||
<< "max_used_block_id: " << txd.maxUsedBlock.id << std::endl
|
||||
<< "last_failed_height: " << txd.lastFailedBlock.height << std::endl
|
||||
<< "last_failed_id: " << txd.lastFailedBlock.id << std::endl
|
||||
<< "recieved: " << std::ctime(&txd.receiveTime) << std::endl;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::fill_block_template(block& bl, size_t median_size, uint64_t already_generated_coins, size_t& total_size, uint64_t& fee) {
|
||||
bool tx_memory_pool::fill_block_template(Block& bl, size_t median_size, size_t maxCumulativeSize,
|
||||
uint64_t already_generated_coins, size_t& total_size, uint64_t& fee) {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
total_size = 0;
|
||||
fee = 0;
|
||||
|
||||
size_t max_total_size = (125 * median_size) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
std::unordered_set<crypto::key_image> k_images;
|
||||
for (transactions_container::value_type& tx : m_transactions) {
|
||||
if (max_total_size < total_size + tx.second.blob_size) {
|
||||
size_t max_total_size = (125 * median_size) / 100 - m_currency.minerTxBlobReservedSize();
|
||||
max_total_size = std::min(max_total_size, maxCumulativeSize);
|
||||
|
||||
BlockTemplate blockTemplate;
|
||||
|
||||
for (auto i = m_fee_index.begin(); i != m_fee_index.end(); ++i) {
|
||||
const auto& txd = *i;
|
||||
|
||||
if (max_total_size < total_size + txd.blobSize) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_transaction_ready_to_go(tx.second) || have_key_images(k_images, tx.second.tx)) {
|
||||
continue;
|
||||
}
|
||||
TransactionCheckInfo checkInfo(txd);
|
||||
bool ready = is_transaction_ready_to_go(txd.tx, checkInfo);
|
||||
|
||||
bl.tx_hashes.push_back(tx.first);
|
||||
total_size += tx.second.blob_size;
|
||||
fee += tx.second.fee;
|
||||
append_key_images(k_images, tx.second.tx);
|
||||
// update item state
|
||||
m_fee_index.modify(i, [&checkInfo](TransactionCheckInfo& item) {
|
||||
item = checkInfo;
|
||||
});
|
||||
|
||||
if (ready && blockTemplate.addTransaction(txd.id, txd.tx)) {
|
||||
total_size += txd.blobSize;
|
||||
fee += txd.fee;
|
||||
}
|
||||
}
|
||||
|
||||
bl.txHashes = blockTemplate.getTransactions();
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -349,7 +334,7 @@ namespace cryptonote {
|
|||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
m_config_folder = config_folder;
|
||||
std::string state_file_path = config_folder + "/" + CRYPTONOTE_POOLDATA_FILENAME;
|
||||
std::string state_file_path = config_folder + "/" + m_currency.txPoolFileName();
|
||||
boost::system::error_code ec;
|
||||
if (!boost::filesystem::exists(state_file_path, ec)) {
|
||||
return true;
|
||||
|
@ -360,17 +345,8 @@ namespace cryptonote {
|
|||
|
||||
m_transactions.clear();
|
||||
m_spent_key_images.clear();
|
||||
m_spentOutputs.clear();
|
||||
}
|
||||
|
||||
for (auto it = m_transactions.begin(); it != m_transactions.end(); ) {
|
||||
auto it2 = it++;
|
||||
if (it2->second.blob_size >= TRANSACTION_SIZE_LIMIT) {
|
||||
LOG_PRINT_L0("Transaction " << get_transaction_hash(it2->second.tx) << " is too big (" << it2->second.blob_size << " bytes), removing it from pool");
|
||||
remove_transaction_keyimages(it2->second.tx);
|
||||
m_transactions.erase(it2);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore deserialization error
|
||||
return true;
|
||||
}
|
||||
|
@ -381,11 +357,116 @@ namespace cryptonote {
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string state_file_path = m_config_folder + "/" + CRYPTONOTE_POOLDATA_FILENAME;
|
||||
std::string state_file_path = m_config_folder + "/" + m_currency.txPoolFileName();
|
||||
bool res = tools::serialize_obj_to_file(*this, state_file_path);
|
||||
if (!res) {
|
||||
LOG_PRINT_L0("Failed to serialize memory pool to file " << state_file_path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::on_idle() {
|
||||
m_txCheckInterval.call([this](){ return removeExpiredTransactions(); });
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::removeExpiredTransactions() {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
auto now = m_timeProvider.now();
|
||||
|
||||
for (auto it = m_transactions.begin(); it != m_transactions.end();) {
|
||||
uint64_t txAge = now - it->receiveTime;
|
||||
bool remove = txAge > (it->keptByBlock ? m_currency.mempoolTxFromAltBlockLiveTime() : m_currency.mempoolTxLiveTime());
|
||||
|
||||
if (remove) {
|
||||
LOG_PRINT_L2("Tx " << it->id << " removed from tx pool due to outdated, age: " << txAge);
|
||||
it = removeTransaction(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
tx_memory_pool::tx_container_t::iterator tx_memory_pool::removeTransaction(tx_memory_pool::tx_container_t::iterator i) {
|
||||
removeTransactionInputs(i->id, i->tx, i->keptByBlock);
|
||||
return m_transactions.erase(i);
|
||||
}
|
||||
|
||||
bool tx_memory_pool::removeTransactionInputs(const crypto::hash& tx_id, const Transaction& tx, bool keptByBlock) {
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
const auto& txin = boost::get<TransactionInputToKey>(in);
|
||||
auto it = m_spent_key_images.find(txin.keyImage);
|
||||
CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << txin.keyImage << std::endl
|
||||
<< "transaction id = " << tx_id);
|
||||
std::unordered_set<crypto::hash>& key_image_set = it->second;
|
||||
CHECK_AND_ASSERT_MES(!key_image_set.empty(), false, "empty key_image set, img=" << txin.keyImage << std::endl
|
||||
<< "transaction id = " << tx_id);
|
||||
|
||||
auto it_in_set = key_image_set.find(tx_id);
|
||||
CHECK_AND_ASSERT_MES(it_in_set != key_image_set.end(), false, "transaction id not found in key_image set, img=" << txin.keyImage << std::endl
|
||||
<< "transaction id = " << tx_id);
|
||||
key_image_set.erase(it_in_set);
|
||||
if (key_image_set.empty()) {
|
||||
//it is now empty hash container for this key_image
|
||||
m_spent_key_images.erase(it);
|
||||
}
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
if (!keptByBlock) {
|
||||
const auto& msig = boost::get<TransactionInputMultisignature>(in);
|
||||
auto output = GlobalOutput(msig.amount, msig.outputIndex);
|
||||
assert(m_spentOutputs.count(output));
|
||||
m_spentOutputs.erase(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::addTransactionInputs(const crypto::hash& id, const Transaction& tx, bool keptByBlock) {
|
||||
// should not fail
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
const auto& txin = boost::get<TransactionInputToKey>(in);
|
||||
std::unordered_set<crypto::hash>& kei_image_set = m_spent_key_images[txin.keyImage];
|
||||
CHECK_AND_ASSERT_MES(keptByBlock || kei_image_set.size() == 0, false, "internal error: keptByBlock=" << keptByBlock
|
||||
<< ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.keyImage=" << txin.keyImage << ENDL
|
||||
<< "tx_id=" << id);
|
||||
auto ins_res = kei_image_set.insert(id);
|
||||
CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set");
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
if (!keptByBlock) {
|
||||
const auto& msig = boost::get<TransactionInputMultisignature>(in);
|
||||
auto r = m_spentOutputs.insert(GlobalOutput(msig.amount, msig.outputIndex));
|
||||
(void)r;
|
||||
assert(r.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::haveSpentInputs(const Transaction& tx) const {
|
||||
for (const auto& in : tx.vin) {
|
||||
if (in.type() == typeid(TransactionInputToKey)) {
|
||||
const auto& tokey_in = boost::get<TransactionInputToKey>(in);
|
||||
if (m_spent_key_images.count(tokey_in.keyImage)) {
|
||||
return true;
|
||||
}
|
||||
} else if (in.type() == typeid(TransactionInputMultisignature)) {
|
||||
const auto& msig = boost::get<TransactionInputMultisignature>(in);
|
||||
if (m_spentOutputs.count(GlobalOutput(msig.amount, msig.outputIndex))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,35 +21,80 @@
|
|||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
// multi index
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
|
||||
// epee
|
||||
#include "math_helper.h"
|
||||
#include "string_tools.h"
|
||||
#include "syncobj.h"
|
||||
#include "cryptonote_basic_impl.h"
|
||||
#include "verification_context.h"
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/int-util.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/Currency.h"
|
||||
#include "cryptonote_core/ITimeProvider.h"
|
||||
#include "cryptonote_core/ITransactionValidator.h"
|
||||
#include "cryptonote_core/verification_context.h"
|
||||
|
||||
|
||||
namespace cryptonote {
|
||||
class blockchain_storage;
|
||||
|
||||
|
||||
class OnceInTimeInterval {
|
||||
public:
|
||||
OnceInTimeInterval(unsigned interval, CryptoNote::ITimeProvider& timeProvider)
|
||||
: m_interval(interval), m_timeProvider(timeProvider) {
|
||||
m_lastWorkedTime = 0;
|
||||
}
|
||||
|
||||
template<class functor_t>
|
||||
bool call(functor_t functr) {
|
||||
time_t now = m_timeProvider.now();
|
||||
|
||||
if (now - m_lastWorkedTime > m_interval) {
|
||||
bool res = functr();
|
||||
m_lastWorkedTime = m_timeProvider.now();
|
||||
return res;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
time_t m_lastWorkedTime;
|
||||
unsigned m_interval;
|
||||
CryptoNote::ITimeProvider& m_timeProvider;
|
||||
};
|
||||
|
||||
using CryptoNote::BlockInfo;
|
||||
using namespace boost::multi_index;
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class tx_memory_pool: boost::noncopyable {
|
||||
public:
|
||||
tx_memory_pool(blockchain_storage& bchs);
|
||||
tx_memory_pool(const cryptonote::Currency& currency, CryptoNote::ITransactionValidator& validator,
|
||||
CryptoNote::ITimeProvider& timeProvider);
|
||||
|
||||
// load/store operations
|
||||
bool init(const std::string& config_folder);
|
||||
bool deinit();
|
||||
|
||||
bool have_tx(const crypto::hash &id) const;
|
||||
bool add_tx(const transaction &tx, const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_tx(const transaction &tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_tx(const Transaction &tx, const crypto::hash &id, size_t blobSize, tx_verification_context& tvc, bool keeped_by_block);
|
||||
bool add_tx(const Transaction &tx, tx_verification_context& tvc, bool keeped_by_block);
|
||||
//gets tx and remove it from pool
|
||||
bool take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee);
|
||||
bool take_tx(const crypto::hash &id, Transaction &tx, size_t& blobSize, uint64_t& fee);
|
||||
|
||||
bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id);
|
||||
bool on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id);
|
||||
|
@ -57,13 +102,28 @@ namespace cryptonote {
|
|||
void lock() const;
|
||||
void unlock() const;
|
||||
|
||||
bool fill_block_template(block &bl, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee);
|
||||
bool fill_block_template(Block &bl, size_t median_size, size_t maxCumulativeSize, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee);
|
||||
|
||||
void get_transactions(std::list<transaction>& txs) const;
|
||||
void get_transactions(std::list<Transaction>& txs) const;
|
||||
size_t get_transactions_count() const;
|
||||
std::string print_pool(bool short_format) const;
|
||||
void on_idle();
|
||||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER 7
|
||||
template<class t_ids_container, class t_tx_container, class t_missed_container>
|
||||
void getTransactions(const t_ids_container& txsIds, t_tx_container& txs, t_missed_container& missedTxs) {
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
|
||||
for (const auto& id : txsIds) {
|
||||
auto it = m_transactions.find(id);
|
||||
if (it == m_transactions.end()) {
|
||||
missedTxs.push_back(id);
|
||||
} else {
|
||||
txs.push_back(it->tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CURRENT_MEMPOOL_ARCHIVE_VER 10
|
||||
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & a, const unsigned int version) {
|
||||
|
@ -74,56 +134,79 @@ namespace cryptonote {
|
|||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
a & m_transactions;
|
||||
a & m_spent_key_images;
|
||||
a & m_spentOutputs;
|
||||
}
|
||||
|
||||
struct tx_details {
|
||||
transaction tx;
|
||||
size_t blob_size;
|
||||
struct TransactionCheckInfo {
|
||||
BlockInfo maxUsedBlock;
|
||||
BlockInfo lastFailedBlock;
|
||||
};
|
||||
|
||||
struct TransactionDetails : public TransactionCheckInfo {
|
||||
crypto::hash id;
|
||||
Transaction tx;
|
||||
size_t blobSize;
|
||||
uint64_t fee;
|
||||
crypto::hash max_used_block_id;
|
||||
uint64_t max_used_block_height;
|
||||
bool kept_by_block;
|
||||
//
|
||||
uint64_t last_failed_height;
|
||||
crypto::hash last_failed_id;
|
||||
bool keptByBlock;
|
||||
time_t receiveTime;
|
||||
};
|
||||
|
||||
private:
|
||||
bool have_tx_keyimg_as_spent(const crypto::key_image& key_im) const;
|
||||
bool have_tx_keyimges_as_spent(const transaction& tx) const;
|
||||
bool remove_transaction_keyimages(const transaction& tx);
|
||||
static bool have_key_images(const std::unordered_set<crypto::key_image>& kic, const transaction& tx);
|
||||
static bool append_key_images(std::unordered_set<crypto::key_image>& kic, const transaction& tx);
|
||||
|
||||
bool is_transaction_ready_to_go(tx_details& txd) const;
|
||||
struct TransactionPriorityComparator {
|
||||
// lhs > hrs
|
||||
bool operator()(const TransactionDetails& lhs, const TransactionDetails& rhs) const {
|
||||
// price(lhs) = lhs.fee / lhs.blobSize
|
||||
// price(lhs) > price(rhs) -->
|
||||
// lhs.fee / lhs.blobSize > rhs.fee / rhs.blobSize -->
|
||||
// lhs.fee * rhs.blobSize > rhs.fee * lhs.blobSize
|
||||
uint64_t lhs_hi, lhs_lo = mul128(lhs.fee, rhs.blobSize, &lhs_hi);
|
||||
uint64_t rhs_hi, rhs_lo = mul128(rhs.fee, lhs.blobSize, &rhs_hi);
|
||||
|
||||
typedef std::unordered_map<crypto::hash, tx_details > transactions_container;
|
||||
return
|
||||
// prefer more profitable transactions
|
||||
(lhs_hi > rhs_hi) ||
|
||||
(lhs_hi == rhs_hi && lhs_lo > rhs_lo) ||
|
||||
// prefer smaller
|
||||
(lhs_hi == rhs_hi && lhs_lo == rhs_lo && lhs.blobSize < rhs.blobSize) ||
|
||||
// prefer older
|
||||
(lhs_hi == rhs_hi && lhs_lo == rhs_lo && lhs.blobSize == rhs.blobSize && lhs.receiveTime < rhs.receiveTime);
|
||||
}
|
||||
};
|
||||
|
||||
typedef hashed_unique<BOOST_MULTI_INDEX_MEMBER(TransactionDetails, crypto::hash, id)> main_index_t;
|
||||
typedef ordered_non_unique<identity<TransactionDetails>, TransactionPriorityComparator> fee_index_t;
|
||||
|
||||
typedef multi_index_container<TransactionDetails,
|
||||
indexed_by<main_index_t, fee_index_t>
|
||||
> tx_container_t;
|
||||
|
||||
typedef std::pair<uint64_t, uint64_t> GlobalOutput;
|
||||
typedef std::set<GlobalOutput> GlobalOutputsContainer;
|
||||
typedef std::unordered_map<crypto::key_image, std::unordered_set<crypto::hash> > key_images_container;
|
||||
|
||||
|
||||
// double spending checking
|
||||
bool addTransactionInputs(const crypto::hash& id, const Transaction& tx, bool keptByBlock);
|
||||
bool haveSpentInputs(const Transaction& tx) const;
|
||||
bool removeTransactionInputs(const crypto::hash& id, const Transaction& tx, bool keptByBlock);
|
||||
|
||||
tx_container_t::iterator removeTransaction(tx_container_t::iterator i);
|
||||
bool removeExpiredTransactions();
|
||||
bool is_transaction_ready_to_go(const Transaction& tx, TransactionCheckInfo& txd) const;
|
||||
|
||||
const cryptonote::Currency& m_currency;
|
||||
OnceInTimeInterval m_txCheckInterval;
|
||||
mutable epee::critical_section m_transactions_lock;
|
||||
transactions_container m_transactions;
|
||||
key_images_container m_spent_key_images;
|
||||
GlobalOutputsContainer m_spentOutputs;
|
||||
|
||||
std::string m_config_folder;
|
||||
blockchain_storage& m_blockchain;
|
||||
CryptoNote::ITransactionValidator& m_validator;
|
||||
CryptoNote::ITimeProvider& m_timeProvider;
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class amount_visitor: public boost::static_visitor<uint64_t> {
|
||||
public:
|
||||
uint64_t operator()(const txin_to_key& tx) const {
|
||||
return tx.amount;
|
||||
}
|
||||
|
||||
uint64_t operator()(const txin_gen& tx) const {
|
||||
CHECK_AND_ASSERT_MES(false, false, "coinbase transaction in memory pool");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t operator()(const txin_to_script& tx) const { return 0; }
|
||||
uint64_t operator()(const txin_to_scripthash& tx) const { return 0; }
|
||||
};
|
||||
tx_container_t m_transactions;
|
||||
tx_container_t::nth_index<1>::type& m_fee_index;
|
||||
|
||||
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
|
||||
friend class blockchain_storage;
|
||||
|
@ -134,14 +217,17 @@ namespace cryptonote {
|
|||
namespace boost {
|
||||
namespace serialization {
|
||||
template<class archive_t>
|
||||
void serialize(archive_t & ar, cryptonote::tx_memory_pool::tx_details& td, const unsigned int version) {
|
||||
ar & td.blob_size;
|
||||
void serialize(archive_t & ar, cryptonote::tx_memory_pool::TransactionDetails& td, const unsigned int version) {
|
||||
ar & td.id;
|
||||
ar & td.blobSize;
|
||||
ar & td.fee;
|
||||
ar & td.tx;
|
||||
ar & td.max_used_block_height;
|
||||
ar & td.max_used_block_id;
|
||||
ar & td.last_failed_height;
|
||||
ar & td.last_failed_id;
|
||||
ar & td.maxUsedBlock.height;
|
||||
ar & td.maxUsedBlock.id;
|
||||
ar & td.lastFailedBlock.height;
|
||||
ar & td.lastFailedBlock.id;
|
||||
ar & td.keptByBlock;
|
||||
ar & td.receiveTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace cryptonote
|
|||
bool m_verifivation_failed; //bad tx, should drop connection
|
||||
bool m_verifivation_impossible; //the transaction is related with an alternative blockchain
|
||||
bool m_added_to_pool;
|
||||
bool m_tx_fee_too_small;
|
||||
};
|
||||
|
||||
struct block_verification_context
|
||||
|
|
|
@ -45,77 +45,82 @@ namespace cryptonote
|
|||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct NOTIFY_NEW_BLOCK_request
|
||||
{
|
||||
block_complete_entry b;
|
||||
uint64_t current_blockchain_height;
|
||||
uint32_t hop;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(b)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
KV_SERIALIZE(hop)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct NOTIFY_NEW_BLOCK
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 1;
|
||||
|
||||
struct request
|
||||
{
|
||||
block_complete_entry b;
|
||||
uint64_t current_blockchain_height;
|
||||
uint32_t hop;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(b)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
KV_SERIALIZE(hop)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef NOTIFY_NEW_BLOCK_request request;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct NOTIFY_NEW_TRANSACTIONS_request
|
||||
{
|
||||
std::list<blobdata> txs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct NOTIFY_NEW_TRANSACTIONS
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 2;
|
||||
|
||||
struct request
|
||||
{
|
||||
std::list<blobdata> txs;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef NOTIFY_NEW_TRANSACTIONS_request request;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct NOTIFY_REQUEST_GET_OBJECTS_request
|
||||
{
|
||||
std::list<crypto::hash> txs;
|
||||
std::list<crypto::hash> blocks;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(txs)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blocks)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct NOTIFY_REQUEST_GET_OBJECTS
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 3;
|
||||
typedef NOTIFY_REQUEST_GET_OBJECTS_request request;
|
||||
};
|
||||
|
||||
struct request
|
||||
{
|
||||
std::list<crypto::hash> txs;
|
||||
std::list<crypto::hash> blocks;
|
||||
struct NOTIFY_RESPONSE_GET_OBJECTS_request
|
||||
{
|
||||
std::list<blobdata> txs;
|
||||
std::list<block_complete_entry> blocks;
|
||||
std::list<crypto::hash> missed_ids;
|
||||
uint64_t current_blockchain_height;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(txs)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blocks)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs)
|
||||
KV_SERIALIZE(blocks)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missed_ids)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct NOTIFY_RESPONSE_GET_OBJECTS
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 4;
|
||||
|
||||
struct request
|
||||
{
|
||||
std::list<blobdata> txs;
|
||||
std::list<block_complete_entry> blocks;
|
||||
std::list<crypto::hash> missed_ids;
|
||||
uint64_t current_blockchain_height;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs)
|
||||
KV_SERIALIZE(blocks)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missed_ids)
|
||||
KV_SERIALIZE(current_blockchain_height)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef NOTIFY_RESPONSE_GET_OBJECTS_request request;
|
||||
};
|
||||
|
||||
|
||||
|
@ -144,22 +149,23 @@ namespace cryptonote
|
|||
};
|
||||
};
|
||||
|
||||
struct NOTIFY_RESPONSE_CHAIN_ENTRY_request
|
||||
{
|
||||
uint64_t start_height;
|
||||
uint64_t total_height;
|
||||
std::list<crypto::hash> m_block_ids;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(start_height)
|
||||
KV_SERIALIZE(total_height)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct NOTIFY_RESPONSE_CHAIN_ENTRY
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 7;
|
||||
|
||||
struct request
|
||||
{
|
||||
uint64_t start_height;
|
||||
uint64_t total_height;
|
||||
std::list<crypto::hash> m_block_ids;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(start_height)
|
||||
KV_SERIALIZE(total_height)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef NOTIFY_RESPONSE_CHAIN_ENTRY_request request;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ namespace cryptonote
|
|||
|
||||
int64_t diff = static_cast<int64_t>(hshd.current_height) - static_cast<int64_t>(m_core.get_current_blockchain_height());
|
||||
LOG_PRINT_CCONTEXT_YELLOW("Sync data returned unknown top block: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
|
||||
<< " [" << std::abs(diff) << " blocks (" << diff / (24 * 60 * 60 / DIFFICULTY_TARGET) << " days) "
|
||||
<< " [" << std::abs(diff) << " blocks (" << diff / (24 * 60 * 60 / m_core.currency().difficultyTarget()) << " days) "
|
||||
<< (0 <= diff ? std::string("behind") : std::string("ahead"))
|
||||
<< "] " << ENDL << "SYNCHRONIZATION started", (is_inital ? LOG_LEVEL_0:LOG_LEVEL_1));
|
||||
LOG_PRINT_L1("Remote top block height: " << hshd.current_height << ", id: " << hshd.top_id);
|
||||
|
@ -153,50 +153,42 @@ namespace cryptonote
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context) {
|
||||
LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_BLOCK (hop " << arg.hop << ")");
|
||||
if(context.m_state != cryptonote_connection_context::state_normal)
|
||||
if (context.m_state != cryptonote_connection_context::state_normal) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
|
||||
{
|
||||
for (auto tx_blob_it = arg.b.txs.begin(); tx_blob_it != arg.b.txs.end(); tx_blob_it++) {
|
||||
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_core.handle_incoming_tx(*tx_blob_it, tvc, true);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{
|
||||
if (tvc.m_verifivation_failed) {
|
||||
LOG_PRINT_CCONTEXT_L0("Block verification failed: transaction verification failed, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
m_core.pause_mine();
|
||||
m_core.handle_incoming_block(arg.b.block, bvc);
|
||||
m_core.resume_mine();
|
||||
if(bvc.m_verifivation_failed)
|
||||
{
|
||||
m_core.handle_incoming_block_blob(arg.b.block, bvc, true, false);
|
||||
if (bvc.m_verifivation_failed) {
|
||||
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
if(bvc.m_added_to_main_chain)
|
||||
{
|
||||
if (bvc.m_added_to_main_chain) {
|
||||
++arg.hop;
|
||||
//TODO: Add here announce protocol usage
|
||||
relay_block(arg, context);
|
||||
}else if(bvc.m_marked_as_orphaned)
|
||||
{
|
||||
} else if (bvc.m_marked_as_orphaned) {
|
||||
context.m_state = cryptonote_connection_context::state_synchronizing;
|
||||
NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
LOG_PRINT_CCONTEXT_L2("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size());
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -266,14 +258,14 @@ namespace cryptonote
|
|||
BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
|
||||
{
|
||||
++count;
|
||||
block b;
|
||||
Block b;
|
||||
if(!parse_and_validate_block_from_blob(block_entry.block, b))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: \r\n"
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
//to avoid concurrency in core between connections, suspend connections which delivered block later then first one
|
||||
if(count == 2)
|
||||
{
|
||||
|
@ -286,7 +278,7 @@ namespace cryptonote
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto req_it = context.m_requested_objects.find(get_block_hash(b));
|
||||
if(req_it == context.m_requested_objects.end())
|
||||
{
|
||||
|
@ -295,10 +287,10 @@ namespace cryptonote
|
|||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
if(b.tx_hashes.size() != block_entry.txs.size())
|
||||
if (b.txHashes.size() != block_entry.txs.size())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
|
||||
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
|
||||
<< ", txHashes.size()=" << b.txHashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
@ -315,20 +307,17 @@ namespace cryptonote
|
|||
}
|
||||
|
||||
{
|
||||
m_core.pause_mine();
|
||||
m_core.pause_mining();
|
||||
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler(
|
||||
boost::bind(&t_core::resume_mine, &m_core));
|
||||
boost::bind(&t_core::update_block_template_and_resume_mining, &m_core));
|
||||
|
||||
BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks)
|
||||
{
|
||||
for (const block_complete_entry& block_entry : arg.blocks) {
|
||||
//process transactions
|
||||
TIME_MEASURE_START(transactions_process_time);
|
||||
BOOST_FOREACH(auto& tx_blob, block_entry.txs)
|
||||
{
|
||||
for (auto& tx_blob : block_entry.txs) {
|
||||
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_core.handle_incoming_tx(tx_blob, tvc, true);
|
||||
if(tvc.m_verifivation_failed)
|
||||
{
|
||||
if (tvc.m_verifivation_failed) {
|
||||
LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
|
||||
<< epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
|
@ -340,24 +329,21 @@ namespace cryptonote
|
|||
//process block
|
||||
TIME_MEASURE_START(block_process_time);
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
m_core.handle_incoming_block_blob(block_entry.block, bvc, false, false);
|
||||
|
||||
m_core.handle_incoming_block(block_entry.block, bvc, false);
|
||||
|
||||
if(bvc.m_verifivation_failed)
|
||||
{
|
||||
if (bvc.m_verifivation_failed) {
|
||||
LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
if(bvc.m_marked_as_orphaned)
|
||||
{
|
||||
} else if (bvc.m_marked_as_orphaned) {
|
||||
LOG_PRINT_CCONTEXT_L0("Block received at sync phase was marked as orphaned, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TIME_MEASURE_FINISH(block_process_time);
|
||||
LOG_PRINT_CCONTEXT_L2("Block process time: " << block_process_time + transactions_process_time << "(" << transactions_process_time << "/" << block_process_time << ")ms");
|
||||
LOG_PRINT_CCONTEXT_L2("Block process time: " << block_process_time + transactions_process_time <<
|
||||
" (" << transactions_process_time << " / " << block_process_time << ") ms");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,33 +18,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "p2p/net_node_common.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "cryptonote_core/connection_context.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct NOTIFY_NEW_BLOCK_request;
|
||||
struct NOTIFY_NEW_TRANSACTIONS_request;
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct i_cryptonote_protocol
|
||||
{
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
struct i_cryptonote_protocol {
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK_request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS_request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct cryptonote_protocol_stub: public i_cryptonote_protocol
|
||||
{
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
struct cryptonote_protocol_stub: public i_cryptonote_protocol {
|
||||
virtual bool relay_block(NOTIFY_NEW_BLOCK_request& arg, cryptonote_connection_context& exclude_context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS_request& arg, cryptonote_connection_context& exclude_context) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,14 +26,17 @@ using namespace epee;
|
|||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "crypto/hash.h"
|
||||
// epee
|
||||
#include "console_handler.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "cryptonote_core/checkpoints_create.h"
|
||||
|
||||
#include "common/SignalHandler.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "rpc/core_rpc_server.h"
|
||||
#include "cryptonote_core/Currency.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "daemon_commands_handler.h"
|
||||
#include "daemon/daemon_commands_handler.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "rpc/core_rpc_server.h"
|
||||
#include "version.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
|
@ -44,11 +47,13 @@ namespace po = boost::program_options;
|
|||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", "Specify configuration file", std::string(CRYPTONOTE_NAME ".conf")};
|
||||
const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", "Specify configuration file", std::string(cryptonote::CRYPTONOTE_NAME) + ".conf"};
|
||||
const command_line::arg_descriptor<bool> arg_os_version = {"os-version", ""};
|
||||
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", "", ""};
|
||||
const command_line::arg_descriptor<int> arg_log_level = {"log-level", "", LOG_LEVEL_0};
|
||||
const command_line::arg_descriptor<bool> arg_console = {"no-console", "Disable daemon console commands"};
|
||||
const command_line::arg_descriptor<bool> arg_testnet_on = {"testnet", "Used to deploy test nets. Checkpoints and hardcoded seeds are ignored, "
|
||||
"network id is changed. Use it with --data-dir flag. The wallet must be launched with --testnet flag.", false};
|
||||
}
|
||||
|
||||
bool command_line_preprocessor(const boost::program_options::variables_map& vm);
|
||||
|
@ -79,7 +84,7 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_cmd_sett, arg_log_file);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_console);
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, arg_testnet_on);
|
||||
|
||||
cryptonote::core::init_options(desc_cmd_sett);
|
||||
cryptonote::core_rpc_server::init_options(desc_cmd_sett);
|
||||
|
@ -96,7 +101,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (command_line::get_arg(vm, command_line::arg_help))
|
||||
{
|
||||
std::cout << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL;
|
||||
std::cout << cryptonote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL;
|
||||
std::cout << desc_options << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
@ -131,7 +136,7 @@ int main(int argc, char* argv[])
|
|||
log_dir = log_file_path.has_parent_path() ? log_file_path.parent_path().string() : log_space::log_singletone::get_default_log_folder();
|
||||
|
||||
log_space::log_singletone::add_logger(LOGGER_FILE, log_file_path.filename().string().c_str(), log_dir.c_str());
|
||||
LOG_PRINT_L0(CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG);
|
||||
LOG_PRINT_L0(cryptonote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG);
|
||||
|
||||
if (command_line_preprocessor(vm))
|
||||
{
|
||||
|
@ -140,14 +145,26 @@ int main(int argc, char* argv[])
|
|||
|
||||
LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0);
|
||||
|
||||
bool res = true;
|
||||
cryptonote::checkpoints checkpoints;
|
||||
res = cryptonote::create_checkpoints(checkpoints);
|
||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
|
||||
bool testnet_mode = command_line::get_arg(vm, arg_testnet_on);
|
||||
if (testnet_mode) {
|
||||
LOG_PRINT_L0("Starting in testnet mode!");
|
||||
}
|
||||
|
||||
//create objects and link them
|
||||
cryptonote::core ccore(NULL);
|
||||
ccore.set_checkpoints(std::move(checkpoints));
|
||||
cryptonote::CurrencyBuilder currencyBuilder;
|
||||
currencyBuilder.testnet(testnet_mode);
|
||||
cryptonote::Currency currency = currencyBuilder.currency();
|
||||
cryptonote::core ccore(currency, NULL);
|
||||
|
||||
cryptonote::checkpoints checkpoints;
|
||||
for (const auto& cp : cryptonote::CHECKPOINTS) {
|
||||
checkpoints.add_checkpoint(cp.height, cp.blockId);
|
||||
}
|
||||
|
||||
if (!testnet_mode) {
|
||||
ccore.set_checkpoints(std::move(checkpoints));
|
||||
}
|
||||
|
||||
cryptonote::t_cryptonote_protocol_handler<cryptonote::core> cprotocol(ccore, NULL);
|
||||
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> > p2psrv(cprotocol);
|
||||
cryptonote::core_rpc_server rpc_server(ccore, p2psrv);
|
||||
|
@ -157,7 +174,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
//initialize objects
|
||||
LOG_PRINT_L0("Initializing p2p server...");
|
||||
res = p2psrv.init(vm);
|
||||
bool res = p2psrv.init(vm, testnet_mode);
|
||||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize p2p server.");
|
||||
LOG_PRINT_L0("P2p server initialized OK");
|
||||
|
||||
|
@ -188,7 +205,7 @@ int main(int argc, char* argv[])
|
|||
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server.");
|
||||
LOG_PRINT_L0("Core rpc server started ok");
|
||||
|
||||
tools::signal_handler::install([&dch, &p2psrv] {
|
||||
tools::SignalHandler::install([&dch, &p2psrv] {
|
||||
dch.stop_handling();
|
||||
p2psrv.send_stop_signal();
|
||||
});
|
||||
|
@ -227,7 +244,7 @@ bool command_line_preprocessor(const boost::program_options::variables_map& vm)
|
|||
bool exit = false;
|
||||
if (command_line::get_arg(vm, command_line::arg_version))
|
||||
{
|
||||
std::cout << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
||||
std::cout << cryptonote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
||||
exit = true;
|
||||
}
|
||||
if (command_line::get_arg(vm, arg_os_version))
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "console_handler.h"
|
||||
#include "p2p/net_node.h"
|
||||
#include "cryptonote_core/miner.h"
|
||||
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
|
||||
#include "common/util.h"
|
||||
#include "crypto/hash.h"
|
||||
|
@ -47,7 +48,6 @@ public:
|
|||
m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_cmmands_handler::print_pool_sh, this, _1), "Print transaction pool (short format)");
|
||||
m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_cmmands_handler::show_hr, this, _1), "Start showing hash rate");
|
||||
m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_cmmands_handler::hide_hr, this, _1), "Stop showing hash rate");
|
||||
m_cmd_binder.set_handler("save", boost::bind(&daemon_cmmands_handler::save, this, _1), "Save blockchain");
|
||||
m_cmd_binder.set_handler("set_log", boost::bind(&daemon_cmmands_handler::set_log, this, _1), "set_log <level> - Change current log detalization level, <level> is a number 0-4");
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ private:
|
|||
std::string get_commands_str()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
||||
ss << cryptonote::CRYPTONOTE_NAME << " v" << PROJECT_VERSION_LONG << ENDL;
|
||||
ss << "Commands: " << ENDL;
|
||||
std::string usage = m_cmd_binder.get_usage();
|
||||
boost::replace_all(usage, "\n", "\n ");
|
||||
|
@ -90,12 +90,6 @@ private:
|
|||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool save(const std::vector<std::string>& args)
|
||||
{
|
||||
m_srv.get_payload_object().get_core().get_blockchain_storage().store_blockchain();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool show_hr(const std::vector<std::string>& args)
|
||||
{
|
||||
if(!m_srv.get_payload_object().get_core().get_miner().is_mining())
|
||||
|
@ -204,22 +198,20 @@ private:
|
|||
|
||||
//--------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
static bool print_as_json(T& obj)
|
||||
{
|
||||
static bool print_as_json(const T& obj) {
|
||||
std::cout << cryptonote::obj_to_json_str(obj) << ENDL;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
bool print_block_by_height(uint64_t height)
|
||||
{
|
||||
std::list<cryptonote::block> blocks;
|
||||
std::list<cryptonote::Block> blocks;
|
||||
m_srv.get_payload_object().get_core().get_blocks(height, 1, blocks);
|
||||
|
||||
if (1 == blocks.size())
|
||||
{
|
||||
cryptonote::block& block = blocks.front();
|
||||
std::cout << "block_id: " << get_block_hash(block) << ENDL;
|
||||
print_as_json(block);
|
||||
std::cout << "block_id: " << get_block_hash(blocks.front()) << ENDL;
|
||||
print_as_json(blocks.front());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -243,14 +235,13 @@ private:
|
|||
|
||||
std::list<crypto::hash> block_ids;
|
||||
block_ids.push_back(block_hash);
|
||||
std::list<cryptonote::block> blocks;
|
||||
std::list<cryptonote::Block> blocks;
|
||||
std::list<crypto::hash> missed_ids;
|
||||
m_srv.get_payload_object().get_core().get_blocks(block_ids, blocks, missed_ids);
|
||||
|
||||
if (1 == blocks.size())
|
||||
{
|
||||
cryptonote::block block = blocks.front();
|
||||
print_as_json(block);
|
||||
print_as_json(blocks.front());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -300,14 +291,13 @@ private:
|
|||
|
||||
std::vector<crypto::hash> tx_ids;
|
||||
tx_ids.push_back(tx_hash);
|
||||
std::list<cryptonote::transaction> txs;
|
||||
std::list<cryptonote::Transaction> txs;
|
||||
std::list<crypto::hash> missed_ids;
|
||||
m_srv.get_payload_object().get_core().get_transactions(tx_ids, txs, missed_ids);
|
||||
|
||||
if (1 == txs.size())
|
||||
{
|
||||
cryptonote::transaction tx = txs.front();
|
||||
print_as_json(tx);
|
||||
print_as_json(txs.front());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -336,8 +326,8 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
cryptonote::account_public_address adr;
|
||||
if(!cryptonote::get_account_address_from_str(adr, args.front()))
|
||||
cryptonote::AccountPublicAddress adr;
|
||||
if(!m_srv.get_payload_object().get_core().currency().parseAccountAddressString(args.front(), adr))
|
||||
{
|
||||
std::cout << "target account address has wrong format" << std::endl;
|
||||
return true;
|
||||
|
@ -350,7 +340,7 @@ private:
|
|||
}
|
||||
|
||||
boost::thread::attributes attrs;
|
||||
attrs.set_stack_size(THREAD_STACK_SIZE);
|
||||
attrs.set_stack_size(cryptonote::THREAD_STACK_SIZE);
|
||||
|
||||
m_srv.get_payload_object().get_core().get_miner().start(adr, threads_count, attrs);
|
||||
return true;
|
||||
|
|
|
@ -181,7 +181,7 @@ uint64_t NodeRpcProxy::getLastKnownBlockHeight() const {
|
|||
return m_networkHeight;
|
||||
}
|
||||
|
||||
void NodeRpcProxy::relayTransaction(const cryptonote::transaction& transaction, const Callback& callback) {
|
||||
void NodeRpcProxy::relayTransaction(const cryptonote::Transaction& transaction, const Callback& callback) {
|
||||
if (!m_initState.initialized()) {
|
||||
callback(make_error_code(error::NOT_INITIALIZED));
|
||||
return;
|
||||
|
@ -218,7 +218,7 @@ void NodeRpcProxy::getTransactionOutsGlobalIndices(const crypto::hash& transacti
|
|||
m_ioService.post(std::bind(&NodeRpcProxy::doGetTransactionOutsGlobalIndices, this, transactionHash, std::ref(outsGlobalIndices), callback));
|
||||
}
|
||||
|
||||
void NodeRpcProxy::doRelayTransaction(const cryptonote::transaction& transaction, const Callback& callback) {
|
||||
void NodeRpcProxy::doRelayTransaction(const cryptonote::Transaction& transaction, const Callback& callback) {
|
||||
COMMAND_RPC_SEND_RAW_TX::request req;
|
||||
COMMAND_RPC_SEND_RAW_TX::response rsp;
|
||||
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(transaction));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue