Multi-signatures added

This commit is contained in:
Antonio Juarez 2014-08-13 11:51:37 +01:00
parent ce6a3be646
commit 4363a9f100
197 changed files with 17996 additions and 5974 deletions

View file

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

View file

@ -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
View 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")

View file

@ -35,7 +35,4 @@
#define BOOST_FILESYSTEM_VERSION 3
#define ENABLE_RELEASE_LOGGING
#include "log_opt_defs.h"
#include "misc_log_ex.h"

View file

@ -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()

View file

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

View file

@ -37,6 +37,7 @@
#include <boost/uuid/random_generator.hpp>
#include "misc_os_dependent.h"
#include "pragma_comp_defs.h"
namespace epee
{

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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
}
}
}

View file

@ -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();
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -29,6 +29,7 @@
#pragma once
#include "http_base.h"
#include "include_base_utils.h"
#include "reg_exp_definer.h"

View file

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

View file

@ -28,6 +28,8 @@
#ifndef _PROFILE_TOOLS_H_
#define _PROFILE_TOOLS_H_
#include <boost/date_time/posix_time/ptime.hpp>
namespace epee
{

View file

@ -26,6 +26,11 @@
#pragma once
#include <cstdint>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/vector.hpp>
namespace epee
{
namespace serialization

View file

@ -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;
}*/
};
}

View file

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

View file

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

View file

@ -30,6 +30,7 @@
#include "misc_language.h"
#include "portable_storage_base.h"
#include "pragma_comp_defs.h"
namespace epee
{

View file

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

View 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
}
}

View file

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

View file

@ -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
View 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
View 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
View 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
View 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_ */

File diff suppressed because it is too large Load diff

View 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_

View 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
View 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

View 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"

View 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 {

File diff suppressed because it is too large Load diff

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
View 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_

View file

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

View file

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

View file

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

View 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
View 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;
};

View file

@ -17,6 +17,7 @@
#pragma once
#include <algorithm>
#include <mutex>
#include <vector>

View 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();
}
}

View 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;
};
}

View file

@ -23,7 +23,6 @@
#include "crypto/hash.h"
#include "int-util.h"
#include "util.h"
#include "varint.h"
namespace tools

View file

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

View file

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

View file

@ -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());
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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()
};
}

View 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();
}
}

View 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;
};
}

View 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;
}
}

View 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;
};
}

View 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"

View 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);
}
};
}

View 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;
};
}

View file

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

View 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"

View 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;
};
}

View file

@ -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);
}
//-----------------------------------------------------------------
}

View file

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

View file

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

View file

@ -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])) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
}
//---------------------------------------------------------------

View file

@ -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()); \

View file

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

View file

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

View 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(){};
};
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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");
}
}

View file

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

View file

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

View file

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

View file

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